[
  {
    "path": ".coderabbit.yml",
    "content": "release_notes: false\n"
  },
  {
    "path": ".github/CODEOWNERS",
    "content": "*     @ajhollid @mohicody @Br0wnHammer @Owaiseimdad @karenvicent @shanikauwu1"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "# These are supported funding model platforms\n\ngithub: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]\npatreon: # Replace with a single Patreon username\nopen_collective: # Replace with a single Open Collective username\nko_fi: # Replace with a single Ko-fi username\ntidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel\ncommunity_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry\nliberapay: # Replace with a single Liberapay username\nissuehunt: # Replace with a single IssueHunt username\nlfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry\npolar: # Replace with a single Polar username\nbuy_me_a_coffee: gorkemcetin\nthanks_dev: # Replace with a single thanks.dev username\ncustom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Describe the bug**\nA clear and concise description of what the bug is.\n\n**To Reproduce**\nSteps to reproduce the behavior:\n1. Go to '...'\n2. Click on '....'\n3. Scroll down to '....'\n4. See error\n\n**Expected behavior**\nA clear and concise description of what you expected to happen.\n\n**Screenshots**\nIf applicable, add screenshots to help explain your problem.\n\n**Desktop (please complete the following information):**\n - Browser [e.g. Chrome, Safari]\n - Version [e.g. 22]\n\n**Additional context**\nAdd any other context about the problem here.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Is your feature request related to a problem? Please describe.**\nA clear and concise description of what the problem is. Ex. I'm always frustrated when [...]\n\n**Describe the solution you'd like**\nA clear and concise description of what you want to happen.\n\n**Describe alternatives you've considered**\nA clear and concise description of any alternative solutions or features you've considered.\n\n**Additional context**\nAdd any other context or screenshots about the feature request here.\n"
  },
  {
    "path": ".github/pull_request_template.md",
    "content": "**(Please remove this line only before submitting your PR. Ensure that all relevant items are checked before submission.)** \n\n## Describe your changes\n\nBriefly describe the changes you made and their purpose. \n\n## Write your issue number after \"Fixes \"\n\nFixes #123 \n\n## Please ensure all items are checked off before requesting a review. \"Checked off\" means you need to add an \"x\" character between brackets so they turn into checkmarks.\n\n- [ ] (Do not skip this or your PR will be closed) I deployed the application locally.\n- [ ] (Do not skip this or your PR will be closed) I have performed a self-review and testing of my code.\n- [ ] I have included the issue # in the PR.\n- [ ] I have added i18n support to visible strings (instead of `<div>Add</div>`, use): \n```Javascript\nconst { t } = useTranslation();\n<div>{t('add')}</div>\n```\n- [ ] I have **not** included any files that are not related to my pull request, including package-lock and package-json if dependencies have not changed\n- [ ] I didn't use any hardcoded values (otherwise it will not scale, and will make it difficult to maintain consistency across the application).\n- [ ] I made sure font sizes, color choices etc are all referenced from the theme. I don't have any hardcoded dimensions.\n- [ ] My PR is granular and targeted to one specific feature.\n- [ ] I ran `npm run format` in server and client directories, which automatically formats your code.\n- [ ] I took a screenshot or a video and attached to this PR if there is a UI change.\n\n"
  },
  {
    "path": ".github/scripts/download-translations.js",
    "content": "import axios from \"axios\";\nimport fs from \"fs-extra\";\nimport path from \"path\";\nimport { URLSearchParams } from \"url\";\n\n// POEditor API information\nconst API_TOKEN = process.env.POEDITOR_API;\nconst PROJECT_ID = process.env.POEDITOR_PROJECT_ID;\nconst LANGUAGES = (\n  process.env.LANGUAGES || \"ar,zh-tw,cs,en,fi,fr,de,pt-br,ru,es,tr,ja,zh-cn,th\"\n).split(\",\");\nconst EXPORT_FORMAT = process.env.EXPORT_FORMAT || \"key_value_json\";\n\n// POEditor API endpoint\nconst API_URL = \"https://api.poeditor.com/v2\";\n\nfunction normalizeLanguageCode(language) {\n  if (language.includes(\"-\")) {\n    const [base, region] = language.split(\"-\");\n    return `${base}-${region.toUpperCase()}`;\n  }\n  return language;\n}\n\n// Function to download translations\nasync function downloadTranslations() {\n  try {\n    console.log(\"Downloading translations from POEditor...\");\n    console.log(`Using export format: ${EXPORT_FORMAT}`);\n\n    for (const language of LANGUAGES) {\n      console.log(`Downloading translations for ${language} language...`);\n\n      // Get export URL from POEditor\n      const exportResponse = await axios.post(\n        `${API_URL}/projects/export`,\n        new URLSearchParams({\n          api_token: API_TOKEN,\n          id: PROJECT_ID,\n          language: language,\n          type: EXPORT_FORMAT,\n        })\n      );\n\n      if (exportResponse.data.response.status !== \"success\") {\n        throw new Error(\n          `Failed to get export URL for ${language} language: ${JSON.stringify(\n            exportResponse.data\n          )}`\n        );\n      }\n\n      const fileUrl = exportResponse.data.result.url;\n      console.log(`Export URL obtained for ${language}`);\n\n      // Download translation file\n      const downloadResponse = await axios.get(fileUrl, {\n        responseType: \"json\",\n      });\n      const translations = downloadResponse.data;\n      console.log(`Downloaded translations for ${language}`);\n\n      // Check the format of data returned from POEditor and convert if necessary\n      let formattedTranslations = translations;\n\n      // If data is in array format, convert it to key-value format\n      if (Array.isArray(translations)) {\n        console.log(\n          `Converting array format to key-value format for ${language}`\n        );\n        formattedTranslations = {};\n        translations.forEach((item) => {\n          if (item.term && item.definition) {\n            formattedTranslations[item.term] = item.definition;\n          }\n        });\n      }\n\n      // Determine the output filename based on language\n      const normalizedLanguage = normalizeLanguageCode(language);\n      const filename = `${normalizedLanguage}.json`;\n      const outputPath = path.join(process.cwd(), \"temp\", filename);\n      await fs.writeJson(outputPath, formattedTranslations, { spaces: 2 });\n\n      console.log(\n        `Translations for ${language} language successfully downloaded and saved as: ${filename}`\n      );\n    }\n\n    console.log(\"All translations successfully downloaded!\");\n  } catch (error) {\n    console.error(\"An error occurred while downloading translations:\", error);\n    process.exit(1);\n  }\n}\n\n// Main function\nasync function main() {\n  try {\n    // Clean temp folder\n    await fs.emptyDir(path.join(process.cwd(), \"temp\"));\n\n    // Download translations\n    await downloadTranslations();\n  } catch (error) {\n    console.error(\"An error occurred during the process:\", error);\n    process.exit(1);\n  }\n}\n\n// Run script\nmain();\n"
  },
  {
    "path": ".github/scripts/upload-translations.js",
    "content": "import axios from \"axios\";\nimport FormData from \"form-data\";\nimport fs from \"fs-extra\";\n\n// POEditor API information\nconst API_TOKEN = process.env.POEDITOR_API;\nconst PROJECT_ID = process.env.POEDITOR_PROJECT_ID;\nconst FILE_PATH = process.env.FILE_PATH;\nconst LANGUAGE = process.env.LANGUAGE;\n\n// POEditor API endpoint\nconst API_URL = 'https://api.poeditor.com/v2';\n\n// Function to upload translations\nasync function uploadTranslations() {\n  try {\n    console.log(`Uploading translations for ${LANGUAGE} language from ${FILE_PATH}... test1`);\n\n    // Check if file exists\n    if (!await fs.pathExists(FILE_PATH)) {\n      throw new Error(`File not found: ${FILE_PATH}`);\n    }\n\n    // Read file content\n    const fileContent = await fs.readFile(FILE_PATH, 'utf8');\n\n    // Validate JSON format\n    try {\n      JSON.parse(fileContent);\n    } catch (error) {\n      throw new Error(`Invalid JSON format in ${FILE_PATH}: ${error.message}`);\n    }\n\n    // Create form data for upload\n    const formData = new FormData();\n    formData.append('api_token', API_TOKEN);\n    formData.append('id', PROJECT_ID);\n    formData.append('language', LANGUAGE);\n    formData.append('updating', 'terms_translations');\n    formData.append('file', fs.createReadStream(FILE_PATH));\n    formData.append('overwrite', '1');\n    formData.append('sync_terms', '1');\n\n    // Upload to POEditor\n    const response = await axios.post(`${API_URL}/projects/upload`, formData, {\n      headers: {\n        'Content-Type': 'application/x-www-form-urlencoded',\n      }\n    });\n\n    if (response.data.response.status !== 'success') {\n      throw new Error(`Failed to upload translations: ${JSON.stringify(response.data)}`);\n    }\n\n    console.log(`Successfully uploaded translations for ${LANGUAGE} language.`);\n    console.log(`Statistics: ${JSON.stringify(response.data.result)}`);\n  } catch (error) {\n    console.error('An error occurred while uploading translations:', error);\n    process.exit(1);\n  }\n}\n\n// Run script\nuploadTranslations();\n"
  },
  {
    "path": ".github/workflows/README.md",
    "content": "# POEditor Translation Synchronization\n\nThis GitHub Actions workflow automatically downloads translation files from POEditor and integrates them into the project.\n\n## How It Works\n\nThe workflow can be triggered in two ways:\n\n1. **Manual Trigger**: You can manually run the \"POEditor Translation Synchronization\" workflow from the \"Actions\" tab in the GitHub interface.\n2. **Automatic Trigger**: The workflow runs automatically every day at midnight (UTC).\n\n## Required Settings\n\nFor this workflow to function, you need to define the following secrets in your GitHub repository:\n\n1. `POEDITOR_API_TOKEN`: Your POEditor API token\n2. `POEDITOR_PROJECT_ID`: Your POEditor project ID\n\nYou can add these secrets in the \"Settings > Secrets and variables > Actions\" section of your GitHub repository.\n\n## Manual Execution\n\nWhen running the workflow manually, you can specify which languages to download. Languages should be entered as comma-separated values (e.g., `tr,gb,es`).\n\nIf you don't specify any languages, the default languages `tr` and `en` will be downloaded.\n\n## Output\n\nWhen the workflow completes successfully:\n\n1. Translation files for the specified languages are downloaded from POEditor\n2. These files are copied to the `src/locales/` directory\n3. Changes are automatically committed and pushed to the main branch\n\n## Troubleshooting\n\nIf the workflow fails:\n\n1. Check the GitHub Actions logs\n2. Make sure your POEditor API token and project ID are correct\n3. Ensure that the languages you specified exist in your POEditor project\n\n# POEditor Upload Workflow\n\n## Summary of Implemented Translation Workflow\n\nWe have successfully created a GitHub Actions workflow that automatically uploads translation files to POEditor when changes are merged to the develop branch. Here's a summary of what we've implemented:\n### Created Files\n\n1. .github/scripts/upload-translations.js\n\n- A Node.js script that handles the upload of translation files to POEditor\n- Uses the POEditor API to upload JSON translation files\n- Validates file existence and JSON format before uploading\n- Provides detailed logging of the upload process\n\n2. .github/workflows/poeditor-upload-on-merge.yml - A GitHub Actions workflow that triggers when PRs are merged to the develop branch - Only runs when changes are made to files in the src/locales directory - Detects which translation files were changed in the PR - Extracts language codes from filenames (e.g., tr.json → \"tr\") - Calls the upload script for each changed file\n   ### Workflow Process\n1. When a PR is merged to the develop branch, the workflow checks if any files in src/locales were modified.\n\n1. If translation files were changed, the workflow:\n\n- Sets up the necessary Node.js environment\n- Installs required dependencies\n- Identifies which specific translation files were changed\n- For each changed file, extracts the language code and uploads to POEditor\n- Provides status notifications about the upload process\n\nThis automated workflow ensures that your translations are always in sync between your codebase and POEditor, eliminating the need for manual uploads and reducing the risk of translation inconsistencies.\n"
  },
  {
    "path": ".github/workflows/check-build.yml",
    "content": "name: Build Check (Client & Server)\non:\n  pull_request:\n  workflow_dispatch:\n\njobs:\n  build-client:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n\n      - name: Set up Node\n        uses: actions/setup-node@v4\n        with:\n          node-version: 22\n\n      - name: Install client dependencies\n        working-directory: client\n        run: npm install\n\n      - name: Check client build\n        working-directory: client\n        run: npm run build\n  build-server:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n\n      - name: Set up Node\n        uses: actions/setup-node@v4\n        with:\n          node-version: 22\n\n      - name: Install server dependencies\n        working-directory: server\n        run: npm install\n\n      - name: Check server build\n        working-directory: server\n        run: npm run build\n"
  },
  {
    "path": ".github/workflows/check-format.yml",
    "content": "name: Format Check (Client & Server)\non:\n  pull_request:\n  workflow_dispatch:\n\njobs:\n  format-client:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n\n      - name: Set up Node\n        uses: actions/setup-node@v4\n        with:\n          node-version: 22\n\n      - name: Install client dependencies\n        working-directory: client\n        run: npm install\n\n      - name: Check client formatting\n        working-directory: client\n        run: npm run format-check\n\n  format-server:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n\n      - name: Set up Node\n        uses: actions/setup-node@v4\n        with:\n          node-version: 22\n\n      - name: Install server dependencies\n        working-directory: server\n        run: npm install\n\n      - name: Check server formatting\n        working-directory: server\n        run: npm run format-check\n"
  },
  {
    "path": ".github/workflows/deploy-images-on-release.yml",
    "content": "name: Deploy images on release\n\non:\n  push:\n    tags:\n      - \"v*\"\n  workflow_dispatch:\njobs:\n  docker-build-and-push-client:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v4\n        with:\n          fetch-depth: 0\n\n      - name: Extract version from tag\n        id: extract_tag\n        run: echo \"version=${GITHUB_REF#refs/tags/}\" >> \"$GITHUB_OUTPUT\"\n\n      - name: Log in to GitHub Container Registry\n        uses: docker/login-action@v3\n        with:\n          registry: ghcr.io\n          username: ${{ github.actor }}\n          password: ${{ secrets.GITHUB_TOKEN }}\n\n      - name: Build Client Docker image\n        run: |\n          docker build \\\n            -t ghcr.io/bluewave-labs/checkmate-client:${{ steps.extract_tag.outputs.version }} \\\n            -f ./docker/dist/client.Dockerfile \\\n            --label org.opencontainers.image.source=https://github.com/bluewave-labs/checkmate \\\n            .\n\n      - name: Push Client Docker image\n        run: |\n          docker push ghcr.io/bluewave-labs/checkmate-client:${{ steps.extract_tag.outputs.version }}\n\n  docker-build-and-push-server:\n    needs: docker-build-and-push-client\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v4\n\n      - name: Extract version\n        id: extract_tag\n        run: echo \"version=${GITHUB_REF#refs/tags/}\" >> \"$GITHUB_OUTPUT\"\n\n      - name: Log in to GitHub Container Registry\n        uses: docker/login-action@v3\n        with:\n          registry: ghcr.io\n          username: ${{ github.actor }}\n          password: ${{ secrets.GITHUB_TOKEN }}\n\n      - name: Build Server Docker image\n        run: |\n          docker build \\\n            -t ghcr.io/bluewave-labs/checkmate-backend:${{ steps.extract_tag.outputs.version }} \\\n            -f ./docker/dist/server.Dockerfile \\\n            --label org.opencontainers.image.source=https://github.com/bluewave-labs/checkmate \\\n            .\n\n      - name: Push Server Docker image\n        run: |\n          docker push ghcr.io/bluewave-labs/checkmate-backend:${{ steps.extract_tag.outputs.version }}\n\n      - name: Build Mongo Docker image\n        run: |\n          docker build \\\n            -t ghcr.io/bluewave-labs/checkmate-mongo:${{ steps.extract_tag.outputs.version }} \\\n            -f ./docker/dist/mongoDB.Dockerfile \\\n            --label org.opencontainers.image.source=https://github.com/bluewave-labs/checkmate \\\n            .\n\n      - name: Push MongoDB Docker image\n        run: |\n          docker push ghcr.io/bluewave-labs/checkmate-mongo:${{ steps.extract_tag.outputs.version }}\n\n  docker-build-and-push-server-mono-multiarch:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v4\n        with:\n          fetch-depth: 0\n\n      - name: Set up Docker Buildx\n        uses: docker/setup-buildx-action@v3\n\n      - name: Extract version\n        id: extract_tag\n        run: echo \"version=${GITHUB_REF#refs/tags/}\" >> \"$GITHUB_OUTPUT\"\n\n      - name: Log in to GitHub Container Registry\n        uses: docker/login-action@v3\n        with:\n          registry: ghcr.io\n          username: ${{ github.actor }}\n          password: ${{ secrets.GITHUB_TOKEN }}\n\n      - name: Build and push multi-arch Docker image\n        uses: docker/build-push-action@v5\n        with:\n          context: .\n          file: ./docker/dist-arm/server.Dockerfile\n          push: true\n          no-cache: true\n          tags: |\n            ghcr.io/bluewave-labs/checkmate-backend-mono-multiarch:${{ steps.extract_tag.outputs.version }}\n          platforms: linux/amd64,linux/arm64\n          labels: |\n            org.opencontainers.image.source=https://github.com/bluewave-labs/checkmate\n          build-args: |\n            VITE_APP_VERSION=${{ steps.extract_tag.outputs.version }}\n\n  docker-build-and-push-server-mono:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v4\n        with:\n          fetch-depth: 0\n\n      - name: Extract version\n        id: extract_tag\n        run: echo \"version=${GITHUB_REF#refs/tags/}\" >> \"$GITHUB_OUTPUT\"\n\n      - name: Log in to GitHub Container Registry\n        uses: docker/login-action@v3\n        with:\n          registry: ghcr.io\n          username: ${{ github.actor }}\n          password: ${{ secrets.GITHUB_TOKEN }}\n\n      - name: Build Server Docker image\n        run: |\n          docker build \\\n            -t ghcr.io/bluewave-labs/checkmate-backend-mono:${{ steps.extract_tag.outputs.version }} \\\n            -f ./docker/dist-mono/server.Dockerfile \\\n            --label org.opencontainers.image.source=https://github.com/bluewave-labs/checkmate \\\n            --build-arg VITE_APP_VERSION=${{ steps.extract_tag.outputs.version }} \\\n            .\n\n      - name: Push Server Docker image\n        run: docker push ghcr.io/bluewave-labs/checkmate-backend-mono:${{ steps.extract_tag.outputs.version }}\n"
  },
  {
    "path": ".github/workflows/deploy-images.yml",
    "content": "name: Deploy images\n\non:\n  push:\n    branches: [\"master\"]\n  workflow_dispatch:\njobs:\n  docker-build-and-push-client:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v4\n        with:\n          fetch-depth: 0\n\n      - name: Log in to GitHub Container Registry\n        uses: docker/login-action@v3\n        with:\n          registry: ghcr.io\n          username: ${{ github.actor }}\n          password: ${{ secrets.GITHUB_TOKEN }}\n\n      - name: Get version\n        id: vars\n        run: echo \"VERSION=$(git describe --tags --abbrev=0)\" >> $GITHUB_ENV\n      - name: Build Client Docker image\n        run: |\n          docker build \\\n            -t ghcr.io/bluewave-labs/checkmate-client:latest \\\n            -f ./docker/dist/client.Dockerfile \\\n            --label org.opencontainers.image.source=https://github.com/bluewave-labs/checkmate \\\n            --build-arg VITE_APP_VERSION=${{ env.VERSION }} \\\n            .\n\n      - name: Push Client Docker image\n        run: |\n          docker push ghcr.io/bluewave-labs/checkmate-client:latest\n\n  docker-build-and-push-server:\n    needs: docker-build-and-push-client\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v4\n\n      - name: Log in to GitHub Container Registry\n        uses: docker/login-action@v3\n        with:\n          registry: ghcr.io\n          username: ${{ github.actor }}\n          password: ${{ secrets.GITHUB_TOKEN }}\n\n      - name: Build Server Docker image\n        run: |\n          docker build \\\n            -t ghcr.io/bluewave-labs/checkmate-backend:latest \\\n            -f ./docker/dist/server.Dockerfile \\\n            --label org.opencontainers.image.source=https://github.com/bluewave-labs/checkmate \\\n            .\n\n      - name: Push Server Docker image\n        run: |\n          docker push ghcr.io/bluewave-labs/checkmate-backend:latest\n\n      - name: Build Mongo Docker image\n        run: |\n          docker build \\\n            -t ghcr.io/bluewave-labs/checkmate-mongo:latest \\\n            -f ./docker/dist/mongoDB.Dockerfile \\\n            --label org.opencontainers.image.source=https://github.com/bluewave-labs/checkmate \\\n            .\n\n      - name: Push MongoDB Docker image\n        run: |\n          docker push ghcr.io/bluewave-labs/checkmate-mongo:latest\n\n  docker-build-and-push-server-mono-multiarch:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v4\n        with:\n          fetch-depth: 0\n\n      - name: Set up Docker Buildx\n        uses: docker/setup-buildx-action@v3\n\n      - name: Log in to GitHub Container Registry\n        uses: docker/login-action@v3\n        with:\n          registry: ghcr.io\n          username: ${{ github.actor }}\n          password: ${{ secrets.GITHUB_TOKEN }}\n\n      - name: Get version\n        id: vars\n        run: echo \"VERSION=$(git describe --tags --abbrev=0)\" >> $GITHUB_ENV\n\n      - name: Build and push multi-arch Docker image\n        uses: docker/build-push-action@v5\n        with:\n          context: .\n          file: ./docker/dist-arm/server.Dockerfile\n          push: true\n          no-cache: true\n          tags: |\n            ghcr.io/bluewave-labs/checkmate-backend-mono-multiarch:latest\n          platforms: linux/amd64,linux/arm64\n          labels: |\n            org.opencontainers.image.source=https://github.com/bluewave-labs/checkmate\n          build-args: |\n            VITE_APP_VERSION=${{ env.VERSION }}\n\n  docker-build-and-push-server-mono:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v4\n        with:\n          fetch-depth: 0\n\n      - name: Log in to GitHub Container Registry\n        uses: docker/login-action@v3\n        with:\n          registry: ghcr.io\n          username: ${{ github.actor }}\n          password: ${{ secrets.GITHUB_TOKEN }}\n\n      - name: Get version\n        id: vars\n        run: echo \"VERSION=$(git describe --tags --abbrev=0)\" >> $GITHUB_ENV\n\n      - name: Build Server Docker image\n        run: |\n          docker build \\\n            -t ghcr.io/bluewave-labs/checkmate-backend-mono:latest \\\n            -f ./docker/dist-mono/server.Dockerfile \\\n            --label org.opencontainers.image.source=https://github.com/bluewave-labs/checkmate \\\n            --build-arg VITE_APP_VERSION=${{ env.VERSION }} \\\n            .\n\n      - name: Push Server Docker image\n        run: docker push ghcr.io/bluewave-labs/checkmate-backend-mono:latest\n"
  },
  {
    "path": ".github/workflows/poeditor-sync.yml",
    "content": "name: POEditor Translation Synchronization\n\non:\n  # For manual triggering\n  workflow_dispatch:\n    inputs:\n      languages:\n        description: \"Languages to synchronize (comma separated, e.g.: tr,en,es)\"\n        required: false\n        default: \"ar,zh-tw,cs,en,fi,fr,de,pt-br,ru,es,tr,ja,zh-cn,th\"\n      format:\n        description: \"Export format (key_value_json or json)\"\n        required: false\n        default: \"key_value_json\"\n\npermissions:\n  contents: write\n  pull-requests: write\n\njobs:\n  sync-translations:\n    runs-on: ubuntu-latest\n    permissions:\n      contents: write\n      issues: write\n      pull-requests: write\n\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v3\n        with:\n          token: ${{ secrets.GITHUB_TOKEN }}\n          fetch-depth: 0\n\n      - name: Setup Node.js\n        uses: actions/setup-node@v3\n        with:\n          node-version: \"22\"\n\n      - name: Create package.json for scripts\n        run: |\n          mkdir -p .github/scripts\n          cat > .github/scripts/package.json << EOF\n          {\n            \"name\": \"poeditor-scripts\",\n            \"version\": \"1.0.0\",\n            \"private\": true,\n            \"type\": \"module\",\n            \"dependencies\": {\n              \"axios\": \"^1.6.0\",\n              \"fs-extra\": \"^11.1.1\"\n            }\n          }\n          EOF\n\n      - name: Install dependencies\n        run: |\n          cd .github/scripts\n          npm install\n\n      - name: Download translations from POEditor\n        env:\n          POEDITOR_API: ${{ secrets.POEDITOR_API }}\n          POEDITOR_PROJECT_ID: ${{ secrets.POEDITOR_PROJECT_ID }}\n          LANGUAGES: ${{ github.event.inputs.languages || 'tr,en' }}\n          EXPORT_FORMAT: ${{ github.event.inputs.format || 'key_value_json' }}\n        run: |\n          mkdir -p temp\n          node .github/scripts/download-translations.js\n\n      - name: Verify translation files\n        run: |\n          echo \"Verifying translation files...\"\n          for file in temp/*.json; do\n            echo \"Checking $file\"\n            if [ ! -s \"$file\" ]; then\n              echo \"Error: $file is empty or does not exist\"\n              exit 1\n            fi\n            # Validate JSON format\n            cat \"$file\" | jq . > /dev/null || { echo \"Error: $file is not valid JSON\"; exit 1; }\n          done\n          echo \"All translation files are valid\"\n\n      - name: Copy translations to project\n        run: |\n          mkdir -p client/src/locales\n          cp -r temp/* client/src/locales/\n          echo \"Translation files copied to client/src/locales/\"\n\n      - name: Get current date\n        id: date\n        run: echo \"date=$(date +'%Y-%m-%d %H:%M:%S')\" >> $GITHUB_OUTPUT\n\n      - name: Format client code\n        run: |\n          cd client\n          npm ci\n          npm run format\n\n      - name: Create Pull Request\n        uses: peter-evans/create-pull-request@v7\n        with:\n          token: ${{ secrets.GITHUB_TOKEN }}\n          commit-message: \"feat: translations updated from POEditor\"\n          title: \"🌐 Updated Translations from POEditor\"\n          body: |\n            This PR contains the latest translations from POEditor.\n\n            📅 Update Date: ${{ steps.date.outputs.date }}\n            🔄 Updated Languages: ${{ github.event.inputs.languages || 'tr,en' }}\n\n            ⚠️ Please review the translations and approve the PR if everything looks correct.\n          branch: translation-update-${{ github.run_number }}\n          delete-branch: true\n          base: develop\n          add-paths: |\n            client/src/locales/*.json\n          committer: GitHub Action <github-actions[bot]@users.noreply.github.com>\n          author: GitHub Action <github-actions[bot]@users.noreply.github.com>\n"
  },
  {
    "path": ".github/workflows/production-deploy.yml",
    "content": "name: Demo deploy\n\non:\n  push:\n    branches: [\"demo\"]\n  workflow_dispatch:\njobs:\n  docker-build-and-push-client:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v4\n        with:\n          fetch-depth: 0\n\n      - name: Log in to GitHub Container Registry\n        uses: docker/login-action@v3\n        with:\n          registry: ghcr.io\n          username: ${{ github.actor }}\n          password: ${{ secrets.GITHUB_TOKEN }}\n\n      - name: Get version\n        id: vars\n        run: echo \"VERSION=$(git describe --tags --abbrev=0)\" >> $GITHUB_ENV\n      - name: Build Client Docker image\n        run: |\n          docker build \\\n            -t ghcr.io/bluewave-labs/checkmate:frontend-demo \\\n            -f ./docker/prod/client.Dockerfile \\\n            --label org.opencontainers.image.source=https://github.com/bluewave-labs/checkmate \\\n            --build-arg VITE_APP_VERSION=${{ env.VERSION }} \\\n            .\n\n      - name: Push Client Docker image\n        run: docker push ghcr.io/bluewave-labs/checkmate:frontend-demo\n\n  docker-build-and-push-server:\n    needs: docker-build-and-push-client\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v4\n\n      - name: Log in to GitHub Container Registry\n        uses: docker/login-action@v3\n        with:\n          registry: ghcr.io\n          username: ${{ github.actor }}\n          password: ${{ secrets.GITHUB_TOKEN }}\n\n      - name: Build Server Docker image\n        run: |\n          docker build \\\n            -t ghcr.io/bluewave-labs/checkmate:backend-demo \\\n            -f ./docker/prod/server.Dockerfile \\\n            --label org.opencontainers.image.source=https://github.com/bluewave-labs/checkmate \\\n            .\n\n      - name: Push Server Docker image\n        run: docker push ghcr.io/bluewave-labs/checkmate:backend-demo\n\n      - name: Build Mongo Docker image\n        run: |\n          docker build \\\n            -t ghcr.io/bluewave-labs/checkmate:mongo-demo \\\n            -f ./docker/prod/mongoDB.Dockerfile \\\n            --label org.opencontainers.image.source=https://github.com/bluewave-labs/checkmate \\\n            .\n\n      - name: Push MongoDB Docker image\n        run: docker push ghcr.io/bluewave-labs/checkmate:mongo-demo\n\n  deploy-to-demo:\n    needs: docker-build-and-push-server\n    runs-on: ubuntu-latest\n    steps:\n      - name: SSH into server and restart container using Docker Compose\n        uses: appleboy/ssh-action@v1.2.2\n        with:\n          host: ${{ secrets.DEMO_SERVER_HOST }}\n          username: ${{ secrets.DEMO_SERVER_USER }}\n          key: ${{ secrets.DEMO_SERVER_SSH_KEY }}\n          script: |\n            cd checkmate\n            git pull\n            cd docker/prod\n            docker compose down\n            docker compose pull\n            docker compose up -d\n"
  },
  {
    "path": ".github/workflows/staging-deploy.yml",
    "content": "name: Staging deploy\n\non:\n  push:\n    branches: [\"develop\"]\n\njobs:\n  docker-build-and-push-client:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v4\n        with:\n          fetch-depth: 0\n\n      - name: Log in to GitHub Container Registry\n        uses: docker/login-action@v3\n        with:\n          registry: ghcr.io\n          username: ${{ github.actor }}\n          password: ${{ secrets.GITHUB_TOKEN }}\n\n      - name: Get version\n        id: vars\n        run: echo \"VERSION=$(git describe --tags --abbrev=0)\" >> $GITHUB_ENV\n      - name: Build Client Docker image\n        run: |\n          docker build \\\n            -t ghcr.io/bluewave-labs/checkmate:frontend-staging \\\n            -f ./docker/staging/client.Dockerfile \\\n            --label org.opencontainers.image.source=https://github.com/bluewave-labs/checkmate \\\n            --build-arg VITE_APP_VERSION=${{ env.VERSION }} \\\n            .\n\n      - name: Push Client Docker image\n        run: docker push ghcr.io/bluewave-labs/checkmate:frontend-staging\n\n  docker-build-and-push-server:\n    needs: docker-build-and-push-client\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v4\n\n      - name: Log in to GitHub Container Registry\n        uses: docker/login-action@v3\n        with:\n          registry: ghcr.io\n          username: ${{ github.actor }}\n          password: ${{ secrets.GITHUB_TOKEN }}\n\n      - name: Build Server Docker image\n        run: |\n          docker build \\\n            -t ghcr.io/bluewave-labs/checkmate:backend-staging \\\n            -f ./docker/staging/server.Dockerfile \\\n            --label org.opencontainers.image.source=https://github.com/bluewave-labs/checkmate \\\n            .\n\n      - name: Push Server Docker image\n        run: docker push ghcr.io/bluewave-labs/checkmate:backend-staging\n\n      - name: Build Mongo Docker image\n        run: |\n          docker build \\\n            -t ghcr.io/bluewave-labs/checkmate:mongo-staging \\\n            -f ./docker/staging/mongoDB.Dockerfile \\\n            --label org.opencontainers.image.source=https://github.com/bluewave-labs/checkmate \\\n            .\n\n      - name: Push MongoDB Docker image\n        run: docker push ghcr.io/bluewave-labs/checkmate:mongo-staging\n\n  deploy-to-staging:\n    needs: docker-build-and-push-server\n    runs-on: ubuntu-latest\n    steps:\n      - name: SSH into server and restart container using Docker Compose\n        uses: appleboy/ssh-action@v1.2.2\n        with:\n          host: ${{ secrets.STAGING_SERVER_HOST }}\n          username: ${{ secrets.STAGING_SERVER_USER }}\n          key: ${{ secrets.STAGING_SERVER_SSH_KEY }}\n          script: |\n            cd checkmate\n            git pull\n            cd docker/staging\n            docker compose down\n            docker compose pull\n            docker compose up -d\n            docker system prune -af\n"
  },
  {
    "path": ".github/workflows/upload-poeditor.yml",
    "content": "name: Upload Translations to POEditor on PR Merge\n\non:\n  pull_request:\n    types: [closed]\n    branches:\n      - develop\n    paths:\n      - \"client/src/locales/**\"\n\njobs:\n  upload-translations:\n    # Only run if the PR was merged (not just closed) or manually triggered\n    if: github.event.pull_request.merged == true\n    runs-on: ubuntu-latest\n\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v3\n        with:\n          fetch-depth: 0 # Fetch all history to get changed files\n\n      - name: Setup Node.js\n        uses: actions/setup-node@v3\n        with:\n          node-version: \"22\"\n\n      - name: Create package.json for scripts\n        run: |\n          mkdir -p .github/scripts\n          cat > .github/scripts/package.json << EOF\n          {\n            \"name\": \"poeditor-scripts\",\n            \"version\": \"1.0.0\",\n            \"private\": true,\n            \"type\": \"module\",\n            \"dependencies\": {\n              \"axios\": \"^1.6.0\",\n              \"fs-extra\": \"^11.1.1\",\n              \"form-data\": \"^4.0.0\"\n            }\n          }\n          EOF\n\n      - name: Install dependencies\n        run: |\n          cd .github/scripts\n          npm install\n\n      - name: Get changed locale files\n        id: changed-files\n        if: github.event_name == 'pull_request'\n        run: |\n          # Get base and head commits\n          BASE_SHA=${{ github.event.pull_request.base.sha }}\n          HEAD_SHA=${{ github.event.pull_request.head.sha }}\n\n          echo \"Base SHA: $BASE_SHA\"\n          echo \"Head SHA: $HEAD_SHA\"\n\n          # Get list of changed files in client/src/locales directory\n          CHANGED_FILES=$(git diff --name-only $BASE_SHA..$HEAD_SHA -- 'client/src/locales/*.json' || git ls-files 'client/src/locales/*.json')\n\n          if [ -z \"$CHANGED_FILES\" ]; then\n            echo \"No changes detected in locale files\"\n            echo \"CHANGED_FILES=\" >> $GITHUB_ENV\n          else\n            echo \"Changed files:\"\n            echo \"$CHANGED_FILES\"\n            echo \"CHANGED_FILES<<EOF\" >> $GITHUB_ENV\n            echo \"$CHANGED_FILES\" >> $GITHUB_ENV\n            echo \"EOF\" >> $GITHUB_ENV\n          fi\n\n      - name: Upload changed translations to POEditor\n        if: env.CHANGED_FILES != ''\n        env:\n          POEDITOR_API: ${{ secrets.POEDITOR_API }}\n          POEDITOR_PROJECT_ID: ${{ secrets.POEDITOR_PROJECT_ID }}\n        run: |\n          # Process each changed file\n          for FILE in $CHANGED_FILES; do\n            if [[ -f \"$FILE\" ]]; then\n              # Extract language code from filename (e.g., client/src/locales/en.json -> en)\n              FILENAME=$(basename \"$FILE\")\n              \n              # Special case: map gb.json to en language code\n              if [ \"$FILENAME\" == \"gb.json\" ]; then\n                LANG=\"en\"\n                echo \"Found gb.json, mapping to language code 'en'\"\n              else\n                LANG=$(basename \"$FILE\" .json)\n              fi\n              \n              echo \"Processing $FILE for language $LANG\"\n              \n              # Upload to POEditor\n              LANGUAGE=$LANG FILE_PATH=$FILE node .github/scripts/upload-translations.js\n            fi\n          done\n\n      - name: Notify on success\n        if: success() && env.CHANGED_FILES != ''\n        run: |\n          echo \"Successfully uploaded translation files to POEditor.\"\n          if [ \"${{ github.event_name }}\" == \"workflow_dispatch\" ]; then\n            echo \"Manual trigger comment: ${{ github.event.inputs.comment }}\"\n          fi\n\n      - name: Notify on no changes\n        if: env.CHANGED_FILES == ''\n        run: |\n          echo \"No translation files were found to upload.\"\n"
  },
  {
    "path": ".gitignore",
    "content": ".idea\n.vscode\n.VSCodeCounter\n*.sh\nmongo\nnode_modules/\ndocs/architecture\ndocs/reviews\ndocs/todo\ndocs/frontend"
  },
  {
    "path": ".husky/pre-commit",
    "content": "#!/bin/sh\necho \"Running lint-staged...\"\ncd client && npx lint-staged && cd ..\ncd server && npx lint-staged && cd .."
  },
  {
    "path": "CLAUDE.md",
    "content": "# CLAUDE.md\n\nThis file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.\n\n## Project Overview\n\nCheckmate is an open-source uptime and infrastructure monitoring application. It monitors server hardware, uptime, response times, and incidents with real-time alerts. The companion agent [Capture](https://github.com/bluewave-labs/capture) provides infrastructure metrics (CPU, RAM, disk, temperature).\n\n## Development Commands\n\n### Client (React/Vite)\n```bash\ncd client\nnpm install\nnpm run dev              # Start dev server at http://localhost:5173\nnpm run build            # TypeScript check + production build\nnpm run lint             # ESLint (strict, max-warnings 0)\nnpm run format           # Prettier formatting\nnpm run format-check     # Check formatting\n```\n\n### Server (Node.js/Express)\n```bash\ncd server\nnpm install\nnpm run dev              # Start with hot-reload (nodemon + tsx) at http://localhost:52345\nnpm run build            # TypeScript compile + path alias resolution\nnpm run test             # Run Mocha tests with c8 coverage\nnpm run lint             # ESLint v9\nnpm run lint-fix         # Auto-fix lint issues\nnpm run format           # Prettier formatting\n```\n\n### Docker Development\n```bash\ncd docker/dev\n./build_images.sh\ndocker run -d -p 27017:27017 -v uptime_mongo_data:/data/db --name uptime_database_mongo mongo:6.0\n```\n\n## Environment Setup\n\n### Server `.env` (minimum required)\n```env\nCLIENT_HOST=\"http://localhost:5173\"\nJWT_SECRET=\"my_secret_key_change_this\"\nDB_CONNECTION_STRING=\"mongodb://localhost:27017/uptime_db\"\nTOKEN_TTL=\"99d\"\nORIGIN=\"localhost\"\nLOG_LEVEL=\"debug\"\n```\n\n### Client `.env`\n```env\nVITE_APP_API_BASE_URL=\"http://localhost:52345/api/v1\"\nVITE_APP_LOG_LEVEL=\"debug\"\n```\n\n## Architecture\n\n### Monorepo Structure\n- `/client` - React 18 + TypeScript + Vite + MUI frontend\n- `/server` - Node.js 20+ + Express + TypeScript backend\n- `/docker` - Multi-environment Docker configs (dev, staging, prod, arm, mono)\n\n### Backend Layers\n```\nserver/src/\n├── controllers/     # Route handlers (authController, monitorController, etc.)\n├── service/         # Business logic\n│   ├── business/    # Core monitoring logic\n│   ├── infrastructure/  # Server/system utilities\n│   └── system/      # App-level settings\n├── db/\n│   ├── models/      # Mongoose schemas (Monitor, Check, Incident, User, etc.)\n│   ├── migration/   # Database migrations (run on startup)\n│   └── modules/     # Database-specific modules\n├── middleware/v1/   # verifyJWT, rateLimiter, sanitization, responseHandler\n├── routes/v1/       # API route definitions\n├── validation/      # Joi input validation schemas\n└── repositories/    # Data access layer\n```\n\n### Frontend Structure\n```\nclient/src/\n├── Components/      # Reusable UI components\n├── Pages/           # Page components (Auth, Uptime, Infrastructure, Incidents, etc.)\n├── Features/        # Redux slices (Auth, UI)\n├── Hooks/           # Custom React hooks\n├── Utils/           # Utilities (NetworkService.js is main API client)\n├── Validation/      # Input validation\n└── locales/         # i18n translations\n```\n\n### API\n- Base URL: `/api/v1`\n- Documentation: `http://localhost:52345/api-docs` (Swagger UI)\n- OpenAPI spec: `/server/openapi.json`\n\n### Key Technologies\n- **State Management**: Redux Toolkit + Redux-Persist\n- **Data Fetching**: SWR + Axios\n- **Database**: MongoDB with Mongoose ODM\n- **Queue/Cache**: Redis + BullMQ + Pulse (cron scheduling)\n- **i18n**: i18next + react-i18next (translations via PoEditor)\n\n## Code Conventions\n\n### Internationalization\nAll user-facing strings must use the translation function:\n```javascript\nt('your.key')  // Never hardcode UI strings\n```\n\n### Branching\n- Always branch from `develop` (not master)\n- Use descriptive names: `feat/add-alerts`, `fix/login-error`\n- PRs target `develop` branch\n\n### Formatting\n- **Client**: Prettier with `printWidth: 90`, tabs, double quotes\n- **Server**: Prettier with `printWidth: 150`, tabs, double quotes\n- Both use ESLint with strict settings\n\n### Testing\nServer tests use Mocha + Chai + Sinon:\n```bash\nnpm test                    # Run all tests with coverage\nnpm test -- --grep \"pattern\"  # Run specific tests\n```\nTest files: `server/tests/**/*.test.js`\n\n## Database Models\n\nKey Mongoose models in `/server/src/db/models/`:\n- **Monitor** - Monitoring configuration (website, infrastructure, port, etc.)\n- **Check** - Individual monitoring check results\n- **Incident** - Downtime incidents\n- **User** - User accounts\n- **Team** - Team/workspace management\n- **StatusPage** - Public status pages\n- **Notification** - Alert configuration (email, Discord, Slack, webhooks)\n- **MaintenanceWindow** - Scheduled maintenance periods\n- **AppSettings** - Global application settings\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\r\n\r\n## Our Pledge\r\n\r\nWe as members, contributors, and leaders pledge to make participation in the **bluewave-uptime** project and community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.\r\n\r\nWe pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community, especially during Hacktoberfest, where we encourage new contributors to join and feel supported.\r\n\r\n## Our Standards\r\n\r\nExamples of behavior that contributes to a positive environment for our community include:\r\n\r\n- Demonstrating empathy and kindness toward other people\r\n- Being respectful of differing opinions, viewpoints, and experiences\r\n- Giving and gracefully accepting constructive feedback\r\n- Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience\r\n- Focusing on what is best not just for us as individuals, but for the overall community\r\n\r\nExamples of unacceptable behavior include:\r\n\r\n- The use of sexualized language or imagery, and sexual attention or advances of any kind\r\n- Trolling, insulting or derogatory comments, and personal or political attacks\r\n- Public or private harassment\r\n- Publishing others' private information, such as a physical or email address, without their explicit permission\r\n- Other conduct which could reasonably be considered inappropriate in a professional setting\r\n\r\n## Our Responsibilities\r\n\r\nProject maintainers are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful.\r\n\r\nProject maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned with this Code of Conduct, especially during Hacktoberfest to ensure a positive experience for all contributors.\r\n\r\n## Scope\r\n\r\nThis Code of Conduct applies within all project spaces, and it also applies when an individual is officially representing the project or its community in public spaces. Examples of representing our project include using an official project email address, posting via an official social media account, or acting as an appointed representative at an online or offline event.\r\n\r\n## Enforcement\r\n\r\nInstances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at hello@bluewavelabs.ca. All complaints will be reviewed and investigated promptly and fairly.\r\n\r\nAll project team members are obligated to respect the privacy and security of the reporter of any incident.\r\n\r\n## Enforcement Guidelines\r\n\r\nProject maintainers will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct:\r\n\r\n### 1. Correction\r\n**Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community.\r\n**Consequence**: A private, written warning from project maintainers, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested.\r\n\r\n### 2. Warning\r\n**Community Impact**: A violation through a single incident or series of actions.\r\n**Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban.\r\n\r\n### 3. Temporary Ban\r\n**Community Impact**: A serious violation of community standards, including sustained inappropriate behavior.\r\n**Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban.\r\n\r\n### 4. Permanent Ban\r\n**Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals.\r\n**Consequence**: A permanent ban from any sort of public interaction within the community.\r\n\r\n## Attribution\r\n\r\nThis Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org), version 2.0, available at https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.\r\n\r\n---\r\n\r\nBy following this Code of Conduct, we can ensure a welcoming and inclusive environment, encouraging new contributors to engage with the project and the community. Thank you for helping make **bluewave-uptime** a positive space for all!\r\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing to Checkmate\n\nThanks for your interest in contributing! Checkmate is an open-source, friendly project focused on learning and growth.\n\nWe truly appreciate all kinds of contributions — code, ideas, translations or documentation. Contributing helps you level up while making the project better for everyone.\n\nBefore you start, please take a moment to read the relevant section. It helps us review and accept contributions faster, and makes the whole process smoother for everyone. 💚\n\nPS: **We work closely with contributors on our [Discord channel](https://discord.com/invite/NAb6H3UTjK)**. You'll find community members, core maintainers, and first-timers helping each other out.\n\n---\n\n\n## 🚀 Quick Setup Checklist\n\nBefore you dive in, make sure you have these installed:\n\n```bash\n# Check Node.js (v16+ required)\nnode --version\n\n# Check npm\nnpm --version\n\n# Check Docker\ndocker --version\n\n# Check Git\ngit --version\n```\n\n**New to contributing?** Start here:\n1. Pick a [`good-first-issue`](https://github.com/bluewave-labs/checkmate/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22)\n2. Comment that you'd like to work on it\n3. Follow the [setup guide](#set-up-checkmate-locally) below\n4. Join our [Discord](https://discord.com/invite/NAb6H3UTjK) if you get stuck\n\n## Table of contents\n\n- [How do I...?](#how-do-i)\n  - [Get help or ask a question?](#get-help-or-ask-a-question)\n  - [Report a bug?](#report-a-bug)\n  - [Suggest a new feature?](#suggest-a-new-feature)\n  - [Set up Checkmate locally?](#set-up-checkmate-locally)\n  - [Start contributing code?](#start-contributing-code)\n  - [Improve the documentation?](#improve-the-documentation)\n  - [Help with translations?](#help-with-translations)\n  - [Submit a pull request?](#submit-a-pull-request)\n- [Code guidelines](#code-guidelines)\n- [Pull request checklist](#pull-request-checklist)\n- [Branching model](#branching-model)\n- [Thank you](#thank-you)\n\n---\n\n## How do I...\n\n### Get help or ask a question?\n\nAsk anything in our [Discord server](https://discord.com/invite/NAb6H3UTjK) — we're friendly and happy to help. [Our core contributors](https://github.com/bluewave-labs/checkmate?tab=readme-ov-file#-contributing) are active and ready to support you. You can also use [GitHub Discussions](https://github.com/bluewave-labs/Checkmate/discussions) section to ask your questions.\n\n### Report a bug?\n\n1. Search [existing issues](https://github.com/bluewave-labs/checkmate/issues).\n2. If it's not listed, open a **new issue**.\n3. Include as much detail as possible: what happened, what you expected, and steps to reproduce. Logs and screenshots help.\n\n### Suggest a new feature?\n\n1. Open a new issue with the **feature request** template.\n2. Share your use case and why it would help.\n3. You can discuss it in [Discord](https://discord.com/invite/NAb6H3UTjK) before you code.\n\n### Set up Checkmate locally?\n\n#### Prerequisites\n\n- Node.js (with npm)\n- Docker \n- Git\n\n#### Step 1: Clone the Repository\n\n```bash\ngit clone https://github.com/bluewave-labs/Checkmate.git\ncd Checkmate\n```\n\n#### Step 2: Set Up Docker Containers (MongoDB)\n\nNavigate to the Docker dev directory:\n\n```bash\ncd docker/dev\n```\n\nBuild the Docker images:\n\n```bash\n./build_images.sh\n```\n\nRun MongoDB container:\n\n```bash\ndocker run -d -p 27017:27017 -v uptime_mongo_data:/data/db --name uptime_database_mongo mongo:6.0\n```\n\nNavigate back to the root directory:\n\n```bash\ncd ../..\n```\n\n#### Step 3: Set Up the Backend (Server)\n\nNavigate to the server directory:\n\n```bash\ncd server\n```\n\nInstall dependencies:\n\n```bash\nnpm install\n```\n\nCreate a `.env` file in the `server` directory with the following minimum required configuration:\n\n```env\nCLIENT_HOST=\"http://localhost:5173\"\nJWT_SECRET=\"my_secret_key_change_this\"\nDB_CONNECTION_STRING=\"mongodb://localhost:27017/uptime_db\"\nTOKEN_TTL=\"99d\"\nORIGIN=\"localhost\"\nLOG_LEVEL=\"debug\"\n```\n\n**Environment Variables Explained:**\n\n- `CLIENT_HOST`: Frontend URL (default: http://localhost:5173)\n- `JWT_SECRET`: Secret key for JWT tokens (change to something secure)\n- `DB_CONNECTION_STRING`: MongoDB connection URL\n- `ORIGIN`: Origin for CORS purposes\n- `TOKEN_TTL`: Token time to live (in vercel/ms format)\n- `LOG_LEVEL`: Debug level (debug, info, warn, error)\n\nStart the backend server:\n\n```bash\nnpm run dev\n```\n\nThe server will run at `http://localhost:52345`.\n\n#### Step 4: Set Up the Frontend (Client)\n\nOpen a new terminal window and navigate to the client directory from the root:\n\n```bash\ncd client\n```\n\nInstall dependencies:\n\n```bash\nnpm install\n```\n\nCreate a `.env` file in the `client` directory:\n\n```env\nVITE_APP_API_BASE_URL=\"http://localhost:52345/api/v1\"\nVITE_APP_LOG_LEVEL=\"debug\"\n```\n\n**Environment Variables Explained:**\n\n- `VITE_APP_API_BASE_URL`: Backend API URL\n- `VITE_APP_LOG_LEVEL`: Log level (none, error, warn, debug, info)\n\nStart the frontend:\n\n```bash\nnpm run dev\n```\n\nThe client will run at `http://localhost:5173`.  \n\n#### Step 5: Access the Application\n\nOpen your browser and navigate to:\n\n- **Frontend**: http://localhost:5173\n- **Backend API**: http://localhost:52345\n- **API Documentation**: http://localhost:52345/api-docs\n\n#### Managing Docker Containers\n\nStop containers:\n\n```bash\ndocker stop uptime_database_mongo\n```\n\nStart containers:\n\n```bash\ndocker start uptime_database_mongo\n```\n\nRemove containers (if needed):\n\n```bash\ndocker rm uptime_database_mongo\n```\n\n#### Troubleshooting\n\n**Port already in use:**\n\n- Check if another service is using ports 5173, 52345, 27017, or 6379\n- Stop the conflicting service or change the port in `.env` files\n\n**MongoDB connection issues:**\n\n- Verify container is running: `docker ps`\n- Check container logs: `docker logs uptime_database_mongo` \n\n**Module not found errors:**\n\n- Ensure you ran `npm install` in both `client` and `server` directories\n\n**Need more help?**\n\n- Check the [full documentation](https://docs.checkmate.so)\n- Ask on [Discord](https://discord.com/invite/NAb6H3UTjK)\n\n### Start contributing code?\n\n1. Pick or open an issue (check `good-first-issue`s first)\n2. (optional but highly suggested) Read a detailed structure of [Checkmate](https://deepwiki.com/bluewave-labs/Checkmate) if you would like to deep dive into the architecture.\n3. Ask to be assigned. If there is already someone assigned and it's been more than 7 days, you can raise the flag and ask to be assigned as well.\n4. Create a branch from `develop`.\n5. Write your code.\n6. Run and test locally.\n7. Open a PR to `develop`.\n\nStart with [good first issues](https://github.com/bluewave-labs/checkmate/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22).\n\n### Improve the documentation?\n\nDocs live in [checkmate-documentation](https://github.com/bluewave-labs/checkmate-documentation). You can fix typos, add guides, or explain features better.\n\n### Help with translations?\n\nWe use [PoEditor](https://poeditor.com) for translations. You can:\n\n- [Sign up and join your language team](https://poeditor.com/join/project/lRUoGZFCsJ).\n- Translate UI strings.\n- Ask questions on Discord in the relevant #translations channel.\n\nMake sure all new UI strings in code use `t('key')`.\n\n### Submit a pull request?\n\nFollow the [pull request checklist](#pull-request-checklist). Your PR should:\n\n- Be focused on one issue.\n- Be tested locally.\n- Use our linting and translation rules.\n- Include the related issue (e.g. `Fixes #123`).\n- Be opened against the `develop` branch.\n\n---\n\n## Code guidelines\n\n- Use ESLint and Prettier (`npm run lint`).\n- Follow naming conventions: `camelCase` for variables, `PascalCase` for components, `UPPER_CASE` for constants.\n- No hard-coded strings — use `t('your.key')` for everything visible.\n- Use the shared theme and components. No magic numbers or hardcoded styles.\n- Follow structure and patterns already used in the codebase.\n\n---\n\n## Pull request checklist\n\nBefore submitting your pull request, please confirm the following:\n\n- **You have tested the app locally and confirmed your changes work.**\n- You reviewed your code and removed debug logs or leftover code.\n- The GitHub issue is assigned to you.\n- You included the related issue number in the PR description (e.g. `Fixes #123`).\n- All user-facing text uses the translation function `t('key')`; no hardcoded strings.\n- You avoided hardcoded URLs, config values, or sensitive data.\n- You used the shared theme for any styling — no magic numbers or inline styles.\n- The pull request addresses only one issue or topic.\n- You added screenshots or a video for any UI-related changes.\n- Your code passes linting and has no TypeScript errors.\n\nIf one or more of these are missing, we may ask you to update your pull request before we can merge it.\n\n---\n\n## Branching model\n\n- Code contributions should go to the `develop` branch.\n- `master` is used for stable releases.\n- Use descriptive branch names, like `fix/login-error` or `feat/add-alerts`.\n- Make sure that you are using the latest version.\n- Make sure you run the code locally. The Checkmate [documentation](https://docs.checkmate.so) covers it.\n- Find out if the functionality is already covered, maybe by an individual configuration.\n- Perform a [search](/issues) to see if the enhancement has already been suggested. If it has, add a comment to the existing issue instead of opening a new one.\n- Find out whether your idea fits with the scope and aims of the project. It's up to you to make a strong case to convince the project's developers of the merits of this feature. Keep in mind that we want features that will be useful to the majority of our users and not just a small subset. If you're just targeting a minority of users, consider writing an add-on/plugin library.\n\n---\n\n## Thank you\n\nThanks for making Checkmate better. We mean it. Whether it's your first pull request or your 50th, we're excited to build with you.\n\nPS: feel free to introduce yourself on [Discord](https://discord.gg/NAb6H3UTjK) and say hi.\n\n-- Checkmate team\n\nAlso make sure you read the [document about how to make a good pull request](/PULLREQUESTS.md).\n"
  },
  {
    "path": "Checkmate.CodeCanvas",
    "content": "{\n\t\"drawioXML\": \"<mxfile>\\n  <diagram id=\\\"89EWfH2uZ2hayMIEMftf\\\" name=\\\"Page-1\\\">\\n    <mxGraphModel dx=\\\"3249\\\" dy=\\\"1738\\\" grid=\\\"0\\\" gridSize=\\\"10\\\" guides=\\\"1\\\" tooltips=\\\"1\\\" connect=\\\"0\\\" arrows=\\\"1\\\" fold=\\\"1\\\" page=\\\"0\\\" pageScale=\\\"1\\\" pageWidth=\\\"850\\\" pageHeight=\\\"1100\\\" math=\\\"0\\\" shadow=\\\"0\\\">\\n      <root>\\n        <mxCell id=\\\"0\\\" />\\n        <mxCell id=\\\"1\\\" style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#fffefe\\\" parent=\\\"0\\\" />\\n        <UserObject label=\\\"client\\\" value=\\\"client\\\" id=\\\"0b23ea66-3e37-4643-b3b9-acb87ea02bae\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#fffefe\\\" vertex=\\\"1\\\" parent=\\\"1\\\">\\n            <mxGeometry x=\\\"245\\\" y=\\\"70\\\" width=\\\"4850\\\" height=\\\"11102.865179846314\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"src\\\" value=\\\"src\\\" id=\\\"d3264577-10f0-42fe-9411-7e9df0754d1e\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#f9f3f3\\\" vertex=\\\"1\\\" parent=\\\"0b23ea66-3e37-4643-b3b9-acb87ea02bae\\\">\\n            <mxGeometry x=\\\"175\\\" y=\\\"70\\\" width=\\\"4500\\\" height=\\\"10962.865179846314\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Pages\\\" value=\\\"Pages\\\" id=\\\"f0feab85-316a-41b5-a2f1-629220018846\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#f4e9e9\\\" vertex=\\\"1\\\" parent=\\\"d3264577-10f0-42fe-9411-7e9df0754d1e\\\">\\n            <mxGeometry x=\\\"875\\\" y=\\\"172\\\" width=\\\"2310\\\" height=\\\"10466.86517984631\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"v1\\\" value=\\\"v1\\\" id=\\\"1a083b4a-787c-4eb4-8029-6700de987679\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#efdfdf\\\" vertex=\\\"1\\\" parent=\\\"f0feab85-316a-41b5-a2f1-629220018846\\\">\\n            <mxGeometry x=\\\"175\\\" y=\\\"70\\\" width=\\\"1950\\\" height=\\\"10326.86517984631\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Uptime\\\" value=\\\"Uptime\\\" id=\\\"7090fcdb-09be-4c85-86fd-e73553bbb2ff\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#ead5d5\\\" vertex=\\\"1\\\" parent=\\\"1a083b4a-787c-4eb4-8029-6700de987679\\\">\\n            <mxGeometry x=\\\"350\\\" y=\\\"4492.607033820289\\\" width=\\\"1290\\\" height=\\\"2027.4731598690946\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Create\\\" value=\\\"Create\\\" id=\\\"3dba5acc-cf25-40b7-ad21-9cd715454cd5\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e5cbcb\\\" vertex=\\\"1\\\" parent=\\\"7090fcdb-09be-4c85-86fd-e73553bbb2ff\\\">\\n            <mxGeometry x=\\\"310\\\" y=\\\"70.00000000000006\\\" width=\\\"805\\\" height=\\\"370\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"index.jsx\\\" value=\\\"index.jsx\\\" id=\\\"391ad99e-3114-4f54-a6ca-fd89b33c7e06\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e0c1c1\\\" vertex=\\\"1\\\" parent=\\\"3dba5acc-cf25-40b7-ad21-9cd715454cd5\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"640\\\" height=\\\"230\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Uptime Monitor Creation: Display Form - index.jsx:L315-802\\\" value=\\\"Uptime Monitor Creation: Display Form - index.jsx:L315-802\\\" id=\\\"7a2da928-a65c-49d8-b0a3-c159a6df2bc5\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"391ad99e-3114-4f54-a6ca-fd89b33c7e06\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Uptime Monitor Creation: Handle Form Submission and Validation - index.jsx:L170-248\\\" value=\\\"Uptime Monitor Creation: Handle Form Submission and Validation - index.jsx:L170-248\\\" id=\\\"a81f4ae8-41fe-4d1b-95ce-86abcc67b53c\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"391ad99e-3114-4f54-a6ca-fd89b33c7e06\\\">\\n            <mxGeometry x=\\\"390\\\" y=\\\"70\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <mxCell id=\\\"0e09aa33-d7c7-4c89-9da8-f0937658f4d3\\\" value=\\\"Uptime Monitor&#xa;Creation: Form&#xa;Submission\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=11;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"391ad99e-3114-4f54-a6ca-fd89b33c7e06\\\" source=\\\"7a2da928-a65c-49d8-b0a3-c159a6df2bc5\\\" target=\\\"a81f4ae8-41fe-4d1b-95ce-86abcc67b53c\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\" />\\n          </mxGeometry>\\n        </mxCell>\\n        <UserObject label=\\\"Details\\\" value=\\\"Details\\\" id=\\\"273f3009-69d0-46fe-af57-3cd94a24b55b\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e5cbcb\\\" vertex=\\\"1\\\" parent=\\\"7090fcdb-09be-4c85-86fd-e73553bbb2ff\\\">\\n            <mxGeometry x=\\\"197.5\\\" y=\\\"1037.2632062932591\\\" width=\\\"815\\\" height=\\\"920.2099535758355\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"index.jsx\\\" value=\\\"index.jsx\\\" id=\\\"1807d5b9-54be-430b-8997-cada4dd9b521\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e0c1c1\\\" vertex=\\\"1\\\" parent=\\\"273f3009-69d0-46fe-af57-3cd94a24b55b\\\">\\n            <mxGeometry x=\\\"400\\\" y=\\\"620.2099535758355\\\" width=\\\"320\\\" height=\\\"230\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Navigate to Monitor Details - index.jsx:L27-188\\\" value=\\\"Navigate to Monitor Details - index.jsx:L27-188\\\" id=\\\"78a8a7c5-41d3-4453-a7f7-ac632bbef288\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"1807d5b9-54be-430b-8997-cada4dd9b521\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Components\\\" value=\\\"Components\\\" id=\\\"6aed78bb-62f1-4ac1-9b9a-9d5977e87404\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e0c1c1\\\" vertex=\\\"1\\\" parent=\\\"273f3009-69d0-46fe-af57-3cd94a24b55b\\\">\\n            <mxGeometry x=\\\"95\\\" y=\\\"70\\\" width=\\\"650\\\" height=\\\"510\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"ResponseTable\\\" value=\\\"ResponseTable\\\" id=\\\"5ac0878f-d238-4763-8464-a85b4885a40f\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e0c1c1\\\" vertex=\\\"1\\\" parent=\\\"6aed78bb-62f1-4ac1-9b9a-9d5977e87404\\\">\\n            <mxGeometry x=\\\"95\\\" y=\\\"70\\\" width=\\\"485\\\" height=\\\"370\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"index.jsx\\\" value=\\\"index.jsx\\\" id=\\\"d3f74ac7-3b9a-4cae-8d77-a0d5d605bb27\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e0c1c1\\\" vertex=\\\"1\\\" parent=\\\"5ac0878f-d238-4763-8464-a85b4885a40f\\\">\\n            <mxGeometry x=\\\"95\\\" y=\\\"70\\\" width=\\\"320\\\" height=\\\"230\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Render Historical Data Table - index.jsx:L11-92\\\" value=\\\"Render Historical Data Table - index.jsx:L11-92\\\" id=\\\"c996f7ca-9384-4252-b343-7bfc049d14bb\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"d3f74ac7-3b9a-4cae-8d77-a0d5d605bb27\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"BulkImport\\\" value=\\\"BulkImport\\\" id=\\\"56dae13e-5735-4089-a9a4-e18be315aff7\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e5cbcb\\\" vertex=\\\"1\\\" parent=\\\"7090fcdb-09be-4c85-86fd-e73553bbb2ff\\\">\\n            <mxGeometry x=\\\"95\\\" y=\\\"480.00000000000006\\\" width=\\\"1020\\\" height=\\\"517.2632062932591\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"index.jsx\\\" value=\\\"index.jsx\\\" id=\\\"29b6ad3c-9538-47bc-8796-aab942dc4b71\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e0c1c1\\\" vertex=\\\"1\\\" parent=\\\"56dae13e-5735-4089-a9a4-e18be315aff7\\\">\\n            <mxGeometry x=\\\"605\\\" y=\\\"70\\\" width=\\\"320\\\" height=\\\"360\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Flow 1: CSV Import - Submit Upload - index.jsx:L32-45\\\" value=\\\"Flow 1: CSV Import - Submit Upload - index.jsx:L32-45\\\" id=\\\"dd2f9356-fad3-47d4-81d5-a5e038298e2b\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"29b6ad3c-9538-47bc-8796-aab942dc4b71\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"200\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Flow 1: CSV Import - Client Handles Success - index.jsx:L37-41\\\" value=\\\"Flow 1: CSV Import - Client Handles Success - index.jsx:L37-41\\\" id=\\\"ae3b7e23-ed64-40aa-9760-389f0a869f8d\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"29b6ad3c-9538-47bc-8796-aab942dc4b71\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Upload.jsx\\\" value=\\\"Upload.jsx\\\" id=\\\"cd84476a-1c8b-4781-811f-58fb9944365b\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e0c1c1\\\" vertex=\\\"1\\\" parent=\\\"56dae13e-5735-4089-a9a4-e18be315aff7\\\">\\n            <mxGeometry x=\\\"95\\\" y=\\\"217.26320629325912\\\" width=\\\"320\\\" height=\\\"230\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Flow 1: CSV Import - User Selects File - Upload.jsx:L23-31\\\" value=\\\"Flow 1: CSV Import - User Selects File - Upload.jsx:L23-31\\\" id=\\\"6f1948fa-e84a-4f8e-8f3b-8f24c511b3d8\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"cd84476a-1c8b-4781-811f-58fb9944365b\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <mxCell id=\\\"e03a8ce2-c2cd-4147-8bab-63d6c2cf0a48\\\" value=\\\"Flow 1:&#xa;CSV Import&#xa;- File&#xa;State Update\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=12;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"56dae13e-5735-4089-a9a4-e18be315aff7\\\" source=\\\"6f1948fa-e84a-4f8e-8f3b-8f24c511b3d8\\\" target=\\\"dd2f9356-fad3-47d4-81d5-a5e038298e2b\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"480\\\" y=\\\"332.26320629325915\\\" />\\n              <mxPoint x=\\\"480\\\" y=\\\"315\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <UserObject label=\\\"Infrastructure\\\" value=\\\"Infrastructure\\\" id=\\\"3f26b33e-477f-41df-a78a-3e3e4f4209ae\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#ead5d5\\\" vertex=\\\"1\\\" parent=\\\"1a083b4a-787c-4eb4-8029-6700de987679\\\">\\n            <mxGeometry x=\\\"412.5\\\" y=\\\"8646.86517984631\\\" width=\\\"1165\\\" height=\\\"1610\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Create\\\" value=\\\"Create\\\" id=\\\"74019e8a-3148-4a32-aae2-5afd16f3eb9b\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e5cbcb\\\" vertex=\\\"1\\\" parent=\\\"3f26b33e-477f-41df-a78a-3e3e4f4209ae\\\">\\n            <mxGeometry x=\\\"340\\\" y=\\\"70\\\" width=\\\"650\\\" height=\\\"510\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Components\\\" value=\\\"Components\\\" id=\\\"ceded1fc-87a9-43c8-a756-746be3d4ad8d\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e0c1c1\\\" vertex=\\\"1\\\" parent=\\\"74019e8a-3148-4a32-aae2-5afd16f3eb9b\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"485\\\" height=\\\"370\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"CustomAlertsSection.jsx\\\" value=\\\"CustomAlertsSection.jsx\\\" id=\\\"83800be3-2a0e-4419-b379-3f995f4050e7\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e0c1c1\\\" vertex=\\\"1\\\" parent=\\\"ceded1fc-87a9-43c8-a756-746be3d4ad8d\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"320\\\" height=\\\"230\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Configuration: User Sets Alert Thresholds - CustomAlertsSection.jsx:L45-53\\\" value=\\\"Configuration: User Sets Alert Thresholds - CustomAlertsSection.jsx:L45-53\\\" id=\\\"9651d084-5c16-4417-89c1-f52ae6572a95\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"83800be3-2a0e-4419-b379-3f995f4050e7\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Details\\\" value=\\\"Details\\\" id=\\\"591128f9-0994-4e01-a1ab-f23357f97aff\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e5cbcb\\\" vertex=\\\"1\\\" parent=\\\"3f26b33e-477f-41df-a78a-3e3e4f4209ae\\\">\\n            <mxGeometry x=\\\"95\\\" y=\\\"619.9999999999999\\\" width=\\\"895\\\" height=\\\"920.0000000000001\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"index.jsx\\\" value=\\\"index.jsx\\\" id=\\\"e292c552-b3df-4bac-bd9a-8f44c260a5aa\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e0c1c1\\\" vertex=\\\"1\\\" parent=\\\"591128f9-0994-4e01-a1ab-f23357f97aff\\\">\\n            <mxGeometry x=\\\"327.5\\\" y=\\\"620\\\" width=\\\"320\\\" height=\\\"230\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Visualization: User Views Monitor Details - index.jsx:L23-31\\\" value=\\\"Visualization: User Views Monitor Details - index.jsx:L23-31\\\" id=\\\"801fe70a-1a19-406c-8f0d-770b0cb74409\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"e292c552-b3df-4bac-bd9a-8f44c260a5aa\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Components\\\" value=\\\"Components\\\" id=\\\"e97d4e61-483e-4ac5-85a1-0ff72fcdd449\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e0c1c1\\\" vertex=\\\"1\\\" parent=\\\"591128f9-0994-4e01-a1ab-f23357f97aff\\\">\\n            <mxGeometry x=\\\"175\\\" y=\\\"70\\\" width=\\\"650\\\" height=\\\"510\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"GaugeBoxes\\\" value=\\\"GaugeBoxes\\\" id=\\\"6a7c7720-a399-4d4d-8225-36e0b2f59731\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e0c1c1\\\" vertex=\\\"1\\\" parent=\\\"e97d4e61-483e-4ac5-85a1-0ff72fcdd449\\\">\\n            <mxGeometry x=\\\"95\\\" y=\\\"70\\\" width=\\\"485\\\" height=\\\"370\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"index.jsx\\\" value=\\\"index.jsx\\\" id=\\\"8fe3d890-3605-407d-b06c-1d890a354e46\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e0c1c1\\\" vertex=\\\"1\\\" parent=\\\"6a7c7720-a399-4d4d-8225-36e0b2f59731\\\">\\n            <mxGeometry x=\\\"95\\\" y=\\\"70\\\" width=\\\"320\\\" height=\\\"230\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Visualization: Frontend Renders Charts and Gauges - index.jsx:L22-51\\\" value=\\\"Visualization: Frontend Renders Charts and Gauges - index.jsx:L22-51\\\" id=\\\"9ea2e32d-1ea8-42f2-9a17-613844723ae6\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"8fe3d890-3605-407d-b06c-1d890a354e46\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Notifications\\\" value=\\\"Notifications\\\" id=\\\"b3575a92-df07-4cf7-810f-8e5e0672d666\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#ead5d5\\\" vertex=\\\"1\\\" parent=\\\"1a083b4a-787c-4eb4-8029-6700de987679\\\">\\n            <mxGeometry x=\\\"1125\\\" y=\\\"3942.607033820289\\\" width=\\\"650\\\" height=\\\"510\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"create\\\" value=\\\"create\\\" id=\\\"a6fb23f0-73bc-40ee-bb3c-ed93605a2bcb\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e5cbcb\\\" vertex=\\\"1\\\" parent=\\\"b3575a92-df07-4cf7-810f-8e5e0672d666\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"485\\\" height=\\\"370\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"index.jsx\\\" value=\\\"index.jsx\\\" id=\\\"b71b02fb-d08e-4fcf-b959-de1b9547d9c2\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e0c1c1\\\" vertex=\\\"1\\\" parent=\\\"a6fb23f0-73bc-40ee-bb3c-ed93605a2bcb\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"320\\\" height=\\\"230\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Flow 1: Render Notification Creation Form - index.jsx:L157-321\\\" value=\\\"Flow 1: Render Notification Creation Form - index.jsx:L157-321\\\" id=\\\"15486629-84b3-463a-962b-06083f69e4bf\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"b71b02fb-d08e-4fcf-b959-de1b9547d9c2\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"StatusPage\\\" value=\\\"StatusPage\\\" id=\\\"9d662180-8b65-4426-ad37-cfed4bc01fb4\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#ead5d5\\\" vertex=\\\"1\\\" parent=\\\"1a083b4a-787c-4eb4-8029-6700de987679\\\">\\n            <mxGeometry x=\\\"280\\\" y=\\\"1072.6070338202887\\\" width=\\\"1430\\\" height=\\\"1470\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Create\\\" value=\\\"Create\\\" id=\\\"08602a28-f073-484e-9403-7eb798126dd4\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e5cbcb\\\" vertex=\\\"1\\\" parent=\\\"9d662180-8b65-4426-ad37-cfed4bc01fb4\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"1185\\\" height=\\\"510\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"index.jsx\\\" value=\\\"index.jsx\\\" id=\\\"e2d2bbf6-dffd-4edf-8c5d-34088d9d4745\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e0c1c1\\\" vertex=\\\"1\\\" parent=\\\"08602a28-f073-484e-9403-7eb798126dd4\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"140\\\" width=\\\"320\\\" height=\\\"230\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Create Status Page: User Initiates Creation - index.jsx:L26-313\\\" value=\\\"Create Status Page: User Initiates Creation - index.jsx:L26-313\\\" id=\\\"00289d11-0015-4b2a-9c5b-dc9fd0f32b80\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"e2d2bbf6-dffd-4edf-8c5d-34088d9d4745\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Hooks\\\" value=\\\"Hooks\\\" id=\\\"56f6775e-9843-4ca2-bc8c-1c263b6c35e9\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e0c1c1\\\" vertex=\\\"1\\\" parent=\\\"08602a28-f073-484e-9403-7eb798126dd4\\\">\\n            <mxGeometry x=\\\"580\\\" y=\\\"70\\\" width=\\\"510\\\" height=\\\"370\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"useCreateStatusPage.jsx\\\" value=\\\"useCreateStatusPage.jsx\\\" id=\\\"3945e05f-2d99-4d6d-9a3e-b6c75ea3c45a\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e0c1c1\\\" vertex=\\\"1\\\" parent=\\\"56f6775e-9843-4ca2-bc8c-1c263b6c35e9\\\">\\n            <mxGeometry x=\\\"95\\\" y=\\\"70\\\" width=\\\"320\\\" height=\\\"230\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Create Status Page: Client Hook Sends API Request - useCreateStatusPage.jsx:L8-11\\\" value=\\\"Create Status Page: Client Hook Sends API Request - useCreateStatusPage.jsx:L8-11\\\" id=\\\"aa5d6d07-05f0-45f3-b19a-199af50e35f1\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"3945e05f-2d99-4d6d-9a3e-b6c75ea3c45a\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <mxCell id=\\\"de23eee2-b60a-4236-a890-3c5b78388bb3\\\" value=\\\"Create Status&#xa;Page: Form&#xa;Submission\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=10;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"08602a28-f073-484e-9403-7eb798126dd4\\\" source=\\\"00289d11-0015-4b2a-9c5b-dc9fd0f32b80\\\" target=\\\"aa5d6d07-05f0-45f3-b19a-199af50e35f1\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\" />\\n          </mxGeometry>\\n        </mxCell>\\n        <UserObject label=\\\"Status\\\" value=\\\"Status\\\" id=\\\"8ef70566-37d9-48fb-b5e8-37e5b68768a2\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e5cbcb\\\" vertex=\\\"1\\\" parent=\\\"9d662180-8b65-4426-ad37-cfed4bc01fb4\\\">\\n            <mxGeometry x=\\\"221.66666666666666\\\" y=\\\"620\\\" width=\\\"780\\\" height=\\\"780\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"index.jsx\\\" value=\\\"index.jsx\\\" id=\\\"e1e6f5e0-fd8c-4260-aa4f-cdb096c6b1c3\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e0c1c1\\\" vertex=\\\"1\\\" parent=\\\"8ef70566-37d9-48fb-b5e8-37e5b68768a2\\\">\\n            <mxGeometry x=\\\"175\\\" y=\\\"70\\\" width=\\\"320\\\" height=\\\"230\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"View Status Page: Component Renders UI - index.jsx:L145-163\\\" value=\\\"View Status Page: Component Renders UI - index.jsx:L145-163\\\" id=\\\"f59b91de-5196-4a43-9d57-3f28402c0672\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"e1e6f5e0-fd8c-4260-aa4f-cdb096c6b1c3\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Hooks\\\" value=\\\"Hooks\\\" id=\\\"79da0721-d810-4f7f-9cf9-3ea462bf0bff\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e0c1c1\\\" vertex=\\\"1\\\" parent=\\\"8ef70566-37d9-48fb-b5e8-37e5b68768a2\\\">\\n            <mxGeometry x=\\\"175\\\" y=\\\"340\\\" width=\\\"510\\\" height=\\\"370\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"useStatusPageFetch.jsx\\\" value=\\\"useStatusPageFetch.jsx\\\" id=\\\"5b2cdab8-66f1-40a1-9621-0efaf54e04ae\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e0c1c1\\\" vertex=\\\"1\\\" parent=\\\"79da0721-d810-4f7f-9cf9-3ea462bf0bff\\\">\\n            <mxGeometry x=\\\"95\\\" y=\\\"70\\\" width=\\\"320\\\" height=\\\"230\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"View Status Page: Client Hook Sends API Request - useStatusPageFetch.jsx:L15-18\\\" value=\\\"View Status Page: Client Hook Sends API Request - useStatusPageFetch.jsx:L15-18\\\" id=\\\"ecfb2d04-2681-4f16-af75-632f69e1a868\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"5b2cdab8-66f1-40a1-9621-0efaf54e04ae\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"PageSpeed\\\" value=\\\"PageSpeed\\\" id=\\\"043d3dac-d4bb-449b-a3a7-270d53b66dac\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#ead5d5\\\" vertex=\\\"1\\\" parent=\\\"1a083b4a-787c-4eb4-8029-6700de987679\\\">\\n            <mxGeometry x=\\\"670\\\" y=\\\"70\\\" width=\\\"650\\\" height=\\\"920.010195392\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Create\\\" value=\\\"Create\\\" id=\\\"414c500b-7b68-42ba-8110-e855efbee750\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e5cbcb\\\" vertex=\\\"1\\\" parent=\\\"043d3dac-d4bb-449b-a3a7-270d53b66dac\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"480.01019539199996\\\" width=\\\"485\\\" height=\\\"370\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"index.jsx\\\" value=\\\"index.jsx\\\" id=\\\"5ffe0baa-054a-4e5b-8b29-1254f07ea975\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e0c1c1\\\" vertex=\\\"1\\\" parent=\\\"414c500b-7b68-42ba-8110-e855efbee750\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"320\\\" height=\\\"230\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Create PageSpeed Monitor - index.jsx:L111-143\\\" value=\\\"Create PageSpeed Monitor - index.jsx:L111-143\\\" id=\\\"0622b212-3a4a-484d-9b7a-125864d785cd\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"5ffe0baa-054a-4e5b-8b29-1254f07ea975\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Details\\\" value=\\\"Details\\\" id=\\\"581b4919-8b0c-4f0d-ae67-ad6de11d8c8b\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e5cbcb\\\" vertex=\\\"1\\\" parent=\\\"043d3dac-d4bb-449b-a3a7-270d53b66dac\\\">\\n            <mxGeometry x=\\\"95\\\" y=\\\"70\\\" width=\\\"485\\\" height=\\\"370\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"index.jsx\\\" value=\\\"index.jsx\\\" id=\\\"c4a7bb58-1d9c-4690-b6b8-460c1cc33702\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e0c1c1\\\" vertex=\\\"1\\\" parent=\\\"581b4919-8b0c-4f0d-ae67-ad6de11d8c8b\\\">\\n            <mxGeometry x=\\\"95\\\" y=\\\"70\\\" width=\\\"320\\\" height=\\\"230\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Frontend Renders Performance Charts - index.jsx:L91-126\\\" value=\\\"Frontend Renders Performance Charts - index.jsx:L91-126\\\" id=\\\"9ef9e218-4742-487a-9a88-5c70e788ccdc\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"c4a7bb58-1d9c-4690-b6b8-460c1cc33702\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Maintenance\\\" value=\\\"Maintenance\\\" id=\\\"8021b55d-2d3a-4416-b598-e134e76c9434\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#ead5d5\\\" vertex=\\\"1\\\" parent=\\\"1a083b4a-787c-4eb4-8029-6700de987679\\\">\\n            <mxGeometry x=\\\"215\\\" y=\\\"6560.080193689384\\\" width=\\\"1560\\\" height=\\\"1366.78498615693\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"CreateMaintenance\\\" value=\\\"CreateMaintenance\\\" id=\\\"6f7119ac-d65a-4fdf-a6f2-31052e0f5549\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e5cbcb\\\" vertex=\\\"1\\\" parent=\\\"8021b55d-2d3a-4416-b598-e134e76c9434\\\">\\n            <mxGeometry x=\\\"175\\\" y=\\\"70\\\" width=\\\"1210\\\" height=\\\"546.7778279053807\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"index.jsx\\\" value=\\\"index.jsx\\\" id=\\\"92c244d2-e6a7-4804-a643-1e8d36baf9c6\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e0c1c1\\\" vertex=\\\"1\\\" parent=\\\"6f7119ac-d65a-4fdf-a6f2-31052e0f5549\\\">\\n            <mxGeometry x=\\\"95\\\" y=\\\"70\\\" width=\\\"320\\\" height=\\\"360.23526566400005\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Flow: Create Maintenance Window - User Interaction - index.jsx:L46-131\\\" value=\\\"Flow: Create Maintenance Window - User Interaction - index.jsx:L46-131\\\" id=\\\"20335f29-a2ac-4e0c-aba6-28707748ecd4\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"92c244d2-e6a7-4804-a643-1e8d36baf9c6\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"200.235265664\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Flow: Create Maintenance Window - UI Update - index.jsx:L111-119\\\" value=\\\"Flow: Create Maintenance Window - UI Update - index.jsx:L111-119\\\" id=\\\"a5a84b08-8c70-4023-8d08-b74e23aab4d7\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"92c244d2-e6a7-4804-a643-1e8d36baf9c6\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"hooks\\\" value=\\\"hooks\\\" id=\\\"015a17fc-3fcf-45e0-8936-19f5e2ca86a3\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e0c1c1\\\" vertex=\\\"1\\\" parent=\\\"6f7119ac-d65a-4fdf-a6f2-31052e0f5549\\\">\\n            <mxGeometry x=\\\"605\\\" y=\\\"106.77782790538079\\\" width=\\\"510\\\" height=\\\"370\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"useMaintenanceActions.jsx\\\" value=\\\"useMaintenanceActions.jsx\\\" id=\\\"6ad0396e-9b38-4f5d-9ad9-6c9fcb4434f4\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e0c1c1\\\" vertex=\\\"1\\\" parent=\\\"015a17fc-3fcf-45e0-8936-19f5e2ca86a3\\\">\\n            <mxGeometry x=\\\"95\\\" y=\\\"70\\\" width=\\\"320\\\" height=\\\"230\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Flow: Create Maintenance Window - Prepare API Request - useMaintenanceActions.jsx:L25-58\\\" value=\\\"Flow: Create Maintenance Window - Prepare API Request - useMaintenanceActions.jsx:L25-58\\\" id=\\\"5bdfdfa4-5d93-49fa-b05c-905813e6cf9d\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"6ad0396e-9b38-4f5d-9ad9-6c9fcb4434f4\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <mxCell id=\\\"d3bdc6ff-875e-472e-88c8-eb10b20c526e\\\" value=\\\"Flow: Create&#xa;Maintenance Window&#xa;- Form&#xa;Submission\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=12;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"6f7119ac-d65a-4fdf-a6f2-31052e0f5549\\\" source=\\\"20335f29-a2ac-4e0c-aba6-28707748ecd4\\\" target=\\\"5bdfdfa4-5d93-49fa-b05c-905813e6cf9d\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"480\\\" y=\\\"315.2352656640011\\\" />\\n              <mxPoint x=\\\"480\\\" y=\\\"291.77782790538186\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <UserObject label=\\\"index.jsx\\\" value=\\\"index.jsx\\\" id=\\\"1eae6263-aaa2-4206-b92e-1e67f529c1c9\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e5cbcb\\\" vertex=\\\"1\\\" parent=\\\"8021b55d-2d3a-4416-b598-e134e76c9434\\\">\\n            <mxGeometry x=\\\"1065\\\" y=\\\"656.7778279053807\\\" width=\\\"320\\\" height=\\\"230\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Flow: View Maintenance Windows - Page Load - index.jsx:L25-47\\\" value=\\\"Flow: View Maintenance Windows - Page Load - index.jsx:L25-47\\\" id=\\\"d145bb4c-e1e0-473a-b6bc-decc932b738b\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"1eae6263-aaa2-4206-b92e-1e67f529c1c9\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"MaintenanceTable\\\" value=\\\"MaintenanceTable\\\" id=\\\"5ad4d33f-0932-479c-bb57-22ce6405758f\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e5cbcb\\\" vertex=\\\"1\\\" parent=\\\"8021b55d-2d3a-4416-b598-e134e76c9434\\\">\\n            <mxGeometry x=\\\"175\\\" y=\\\"926.78498615693\\\" width=\\\"485\\\" height=\\\"370\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"index.jsx\\\" value=\\\"index.jsx\\\" id=\\\"e7ec5ca9-6d25-4bf2-9695-639556f7d141\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e0c1c1\\\" vertex=\\\"1\\\" parent=\\\"5ad4d33f-0932-479c-bb57-22ce6405758f\\\">\\n            <mxGeometry x=\\\"95\\\" y=\\\"70\\\" width=\\\"320\\\" height=\\\"230\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Flow: View Maintenance Windows - UI Rendering - index.jsx:L195-201\\\" value=\\\"Flow: View Maintenance Windows - UI Rendering - index.jsx:L195-201\\\" id=\\\"970e2002-7c0e-40ef-80d8-e5e6d0a60735\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"e7ec5ca9-6d25-4bf2-9695-639556f7d141\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Account\\\" value=\\\"Account\\\" id=\\\"3cad7666-0d1a-4e31-b6ca-70d9c3a46b19\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#ead5d5\\\" vertex=\\\"1\\\" parent=\\\"1a083b4a-787c-4eb4-8029-6700de987679\\\">\\n            <mxGeometry x=\\\"402.5\\\" y=\\\"2582.607033820289\\\" width=\\\"1185\\\" height=\\\"640\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"index.jsx\\\" value=\\\"index.jsx\\\" id=\\\"33960806-1b9e-4d61-a163-e4bebf82d87a\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e5cbcb\\\" vertex=\\\"1\\\" parent=\\\"3cad7666-0d1a-4e31-b6ca-70d9c3a46b19\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"287.5203768220729\\\" width=\\\"320\\\" height=\\\"230\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Client: Conditional UI Rendering Based on Role - index.jsx:L37-41\\\" value=\\\"Client: Conditional UI Rendering Based on Role - index.jsx:L37-41\\\" id=\\\"3de2d413-5e9b-49f4-9409-74be32c52e0f\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"33960806-1b9e-4d61-a163-e4bebf82d87a\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"components\\\" value=\\\"components\\\" id=\\\"425a4c15-043f-4d05-8832-da00e18f97b9\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e5cbcb\\\" vertex=\\\"1\\\" parent=\\\"3cad7666-0d1a-4e31-b6ca-70d9c3a46b19\\\">\\n            <mxGeometry x=\\\"580\\\" y=\\\"70\\\" width=\\\"510\\\" height=\\\"500\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"TeamPanel.jsx\\\" value=\\\"TeamPanel.jsx\\\" id=\\\"1145f351-2257-411d-86f7-30bf8c26ad68\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e0c1c1\\\" vertex=\\\"1\\\" parent=\\\"425a4c15-043f-4d05-8832-da00e18f97b9\\\">\\n            <mxGeometry x=\\\"95\\\" y=\\\"70\\\" width=\\\"320\\\" height=\\\"360\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Client: Initiate User Invitation - TeamPanel.jsx:L348-354\\\" value=\\\"Client: Initiate User Invitation - TeamPanel.jsx:L348-354\\\" id=\\\"b27f1bba-c655-40c6-a1dc-71e78c590c92\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"1145f351-2257-411d-86f7-30bf8c26ad68\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"200\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Client: Display Success Feedback - TeamPanel.jsx:L145-149\\\" value=\\\"Client: Display Success Feedback - TeamPanel.jsx:L145-149\\\" id=\\\"02d87257-883c-4822-a421-823c983532ec\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"1145f351-2257-411d-86f7-30bf8c26ad68\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <mxCell id=\\\"c441312f-f3c6-48c6-b1b9-7c12749d91bb\\\" value=\\\"Client: User&#xa;Navigates to&#xa;Team Panel\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=12;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"3cad7666-0d1a-4e31-b6ca-70d9c3a46b19\\\" source=\\\"3de2d413-5e9b-49f4-9409-74be32c52e0f\\\" target=\\\"b27f1bba-c655-40c6-a1dc-71e78c590c92\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"455\\\" y=\\\"402.52037682207174\\\" />\\n              <mxPoint x=\\\"455\\\" y=\\\"384.99999999999886\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <UserObject label=\\\"Settings\\\" value=\\\"Settings\\\" id=\\\"50f77798-f41b-4f5b-b096-7afc921a0419\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#ead5d5\\\" vertex=\\\"1\\\" parent=\\\"1a083b4a-787c-4eb4-8029-6700de987679\\\">\\n            <mxGeometry x=\\\"861.6666666666666\\\" y=\\\"7966.865179846312\\\" width=\\\"590\\\" height=\\\"640\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"index.jsx\\\" value=\\\"index.jsx\\\" id=\\\"d4b34195-7e1e-47a0-9303-603987c81f95\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e5cbcb\\\" vertex=\\\"1\\\" parent=\\\"50f77798-f41b-4f5b-b096-7afc921a0419\\\">\\n            <mxGeometry x=\\\"95\\\" y=\\\"70\\\" width=\\\"320\\\" height=\\\"230\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Flow 1: Render Settings Page - index.jsx:L25-52\\\" value=\\\"Flow 1: Render Settings Page - index.jsx:L25-52\\\" id=\\\"97908daf-d071-4df5-8366-1f5f4d8d534a\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"d4b34195-7e1e-47a0-9303-603987c81f95\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"SettingsEmail.jsx\\\" value=\\\"SettingsEmail.jsx\\\" id=\\\"d8aa5b9e-f2a7-44c8-8813-d79c3f3238ee\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e5cbcb\\\" vertex=\\\"1\\\" parent=\\\"50f77798-f41b-4f5b-b096-7afc921a0419\\\">\\n            <mxGeometry x=\\\"95\\\" y=\\\"340\\\" width=\\\"320\\\" height=\\\"230\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"User Interaction: Modify Email Settings - SettingsEmail.jsx:L119-167\\\" value=\\\"User Interaction: Modify Email Settings - SettingsEmail.jsx:L119-167\\\" id=\\\"09cb194a-0ea4-46e2-b32b-36b62fa87f40\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"d8aa5b9e-f2a7-44c8-8813-d79c3f3238ee\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Logs\\\" value=\\\"Logs\\\" id=\\\"1716ec41-8b42-4386-9850-55b8a607638e\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#ead5d5\\\" vertex=\\\"1\\\" parent=\\\"1a083b4a-787c-4eb4-8029-6700de987679\\\">\\n            <mxGeometry x=\\\"1125\\\" y=\\\"3262.607033820289\\\" width=\\\"650\\\" height=\\\"640\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Diagnostics\\\" value=\\\"Diagnostics\\\" id=\\\"e0cb598c-e300-4fd3-8554-db7ffd6201f1\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e5cbcb\\\" vertex=\\\"1\\\" parent=\\\"1716ec41-8b42-4386-9850-55b8a607638e\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"485\\\" height=\\\"500\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"index.jsx\\\" value=\\\"index.jsx\\\" id=\\\"87e0e2ea-4a6d-460d-95bc-31e2efd9c9cf\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e0c1c1\\\" vertex=\\\"1\\\" parent=\\\"e0cb598c-e300-4fd3-8554-db7ffd6201f1\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"320\\\" height=\\\"360\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Flow 2: Navigate to Diagnostics Page - index.jsx:L14-15\\\" value=\\\"Flow 2: Navigate to Diagnostics Page - index.jsx:L14-15\\\" id=\\\"704e2ec8-9f2f-47e5-852f-c6ada67a02e0\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"87e0e2ea-4a6d-460d-95bc-31e2efd9c9cf\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"200\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"UI Update: Display System Health - index.jsx:L59-63\\\" value=\\\"UI Update: Display System Health - index.jsx:L59-63\\\" id=\\\"4b418736-6b72-47e0-917a-d86d4bed9ecd\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"87e0e2ea-4a6d-460d-95bc-31e2efd9c9cf\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Hooks\\\" value=\\\"Hooks\\\" id=\\\"4295a047-076f-4c07-95dd-b3123b6614f7\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#f4e9e9\\\" vertex=\\\"1\\\" parent=\\\"d3264577-10f0-42fe-9411-7e9df0754d1e\\\">\\n            <mxGeometry x=\\\"3375\\\" y=\\\"7802.246623286175\\\" width=\\\"950\\\" height=\\\"1439.9999999999998\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"v1\\\" value=\\\"v1\\\" id=\\\"3bf0c0f9-cbb0-4f0c-8cb3-6e2a4abc0961\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#efdfdf\\\" vertex=\\\"1\\\" parent=\\\"4295a047-076f-4c07-95dd-b3123b6614f7\\\">\\n            <mxGeometry x=\\\"175\\\" y=\\\"70\\\" width=\\\"600\\\" height=\\\"1299.9999999999998\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"monitorHooks.js\\\" value=\\\"monitorHooks.js\\\" id=\\\"595cf0e8-2f86-4543-b51c-b2aeac307f4b\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=16;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"3bf0c0f9-cbb0-4f0c-8cb3-6e2a4abc0961\\\">\\n            <mxGeometry x=\\\"255\\\" y=\\\"740.0000000000001\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"useNotifications.js\\\" value=\\\"useNotifications.js\\\" id=\\\"cd2428fd-6545-48dd-b685-5261311b7532\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#ead5d5\\\" vertex=\\\"1\\\" parent=\\\"3bf0c0f9-cbb0-4f0c-8cb3-6e2a4abc0961\\\">\\n            <mxGeometry x=\\\"185\\\" y=\\\"70\\\" width=\\\"320\\\" height=\\\"230\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Flow 1: Frontend API Call - useNotifications.js:L14-17\\\" value=\\\"Flow 1: Frontend API Call - useNotifications.js:L14-17\\\" id=\\\"a07b805e-e55f-46cb-b54b-765b7813b0ca\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"cd2428fd-6545-48dd-b685-5261311b7532\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"checkHooks.js\\\" value=\\\"checkHooks.js\\\" id=\\\"933a6cdc-349c-4725-b7ae-14cf780bfde8\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#ead5d5\\\" vertex=\\\"1\\\" parent=\\\"3bf0c0f9-cbb0-4f0c-8cb3-6e2a4abc0961\\\">\\n            <mxGeometry x=\\\"185\\\" y=\\\"340\\\" width=\\\"320\\\" height=\\\"360\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Fetch Monitor Checks Hook - checkHooks.js:L89-121\\\" value=\\\"Fetch Monitor Checks Hook - checkHooks.js:L89-121\\\" id=\\\"4a5847d0-91a0-4b4c-8517-2f4ff9a7e8d4\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"933a6cdc-349c-4725-b7ae-14cf780bfde8\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"200\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Update Frontend State - checkHooks.js:L109-110\\\" value=\\\"Update Frontend State - checkHooks.js:L109-110\\\" id=\\\"ceb9cda3-968d-44aa-b223-49902adb93b4\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"933a6cdc-349c-4725-b7ae-14cf780bfde8\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"settingsHooks.js\\\" value=\\\"settingsHooks.js\\\" id=\\\"8ee5d524-e61d-4e39-a729-babf54929def\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#ead5d5\\\" vertex=\\\"1\\\" parent=\\\"3bf0c0f9-cbb0-4f0c-8cb3-6e2a4abc0961\\\">\\n            <mxGeometry x=\\\"185\\\" y=\\\"869.9999999999998\\\" width=\\\"320\\\" height=\\\"360\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"API Call: Update Application Settings - settingsHooks.js:L41-67\\\" value=\\\"API Call: Update Application Settings - settingsHooks.js:L41-67\\\" id=\\\"1b2cf182-9ee3-4218-a7ec-b74e427ccddf\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"8ee5d524-e61d-4e39-a729-babf54929def\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"UI Update: Display Success Confirmation - settingsHooks.js:L58\\\" value=\\\"UI Update: Display Success Confirmation - settingsHooks.js:L58\\\" id=\\\"fff5dde4-8eb8-4c21-9c6d-0845a9749ff3\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"8ee5d524-e61d-4e39-a729-babf54929def\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"200\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Utils\\\" value=\\\"Utils\\\" id=\\\"02b07589-ec21-4366-b7d2-9071e8f3bad8\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#f4e9e9\\\" vertex=\\\"1\\\" parent=\\\"d3264577-10f0-42fe-9411-7e9df0754d1e\\\">\\n            <mxGeometry x=\\\"3595\\\" y=\\\"5026.542220848842\\\" width=\\\"510\\\" height=\\\"500\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"NetworkService.js\\\" value=\\\"NetworkService.js\\\" id=\\\"16731e9d-3f73-4055-9d79-5ca9be679f68\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#efdfdf\\\" vertex=\\\"1\\\" parent=\\\"02b07589-ec21-4366-b7d2-9071e8f3bad8\\\">\\n            <mxGeometry x=\\\"95\\\" y=\\\"70\\\" width=\\\"320\\\" height=\\\"360\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Uptime Monitor Creation: Send API Request - NetworkService.js:L119-121\\\" value=\\\"Uptime Monitor Creation: Send API Request - NetworkService.js:L119-121\\\" id=\\\"a30ac765-c546-4993-988e-8c8cfdb7532f\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"16731e9d-3f73-4055-9d79-5ca9be679f68\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Flow 1: CSV Import - Send API Request - NetworkService.js:L978-983\\\" value=\\\"Flow 1: CSV Import - Send API Request - NetworkService.js:L978-983\\\" id=\\\"5967e576-f542-4c0b-a3f4-9446ae992721\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"16731e9d-3f73-4055-9d79-5ca9be679f68\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"200\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <mxCell id=\\\"1f6f04a9-0123-4729-b06a-8f3da6d1b58c\\\" value=\\\"Uptime Monitor&#xa;Creation: Call&#xa;Network Service\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=20;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"d3264577-10f0-42fe-9411-7e9df0754d1e\\\" source=\\\"a81f4ae8-41fe-4d1b-95ce-86abcc67b53c\\\" target=\\\"a30ac765-c546-4993-988e-8c8cfdb7532f\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"2580\\\" y=\\\"4989.607033820288\\\" />\\n              <mxPoint x=\\\"2580\\\" y=\\\"4990.369748321168\\\" />\\n              <mxPoint x=\\\"3290\\\" y=\\\"4990.36974832117\\\" />\\n              <mxPoint x=\\\"3290\\\" y=\\\"5211.5422208488435\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <mxCell id=\\\"54497b9a-4910-4df4-b016-480b9ac250a7\\\" value=\\\"Flow 1:&#xa;Submit Form&#xa;Data for&#xa;Creation\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=20;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"d3264577-10f0-42fe-9411-7e9df0754d1e\\\" source=\\\"15486629-84b3-463a-962b-06083f69e4bf\\\" target=\\\"a07b805e-e55f-46cb-b54b-765b7813b0ca\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"3280\\\" y=\\\"4439.607033820289\\\" />\\n              <mxPoint x=\\\"3280\\\" y=\\\"8192.650474325575\\\" />\\n              <mxPoint x=\\\"3485\\\" y=\\\"8192.650474325574\\\" />\\n              <mxPoint x=\\\"3485\\\" y=\\\"8192.124804485014\\\" />\\n              <mxPoint x=\\\"3660\\\" y=\\\"8192.124804485018\\\" />\\n              <mxPoint x=\\\"3660\\\" y=\\\"8057.246623286176\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <UserObject label=\\\"Routes\\\" value=\\\"Routes\\\" id=\\\"987f145b-5df6-4c30-bf1c-2a2d2b0e5cdc\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#f4e9e9\\\" vertex=\\\"1\\\" parent=\\\"d3264577-10f0-42fe-9411-7e9df0754d1e\\\">\\n            <mxGeometry x=\\\"175\\\" y=\\\"4690.325785083435\\\" width=\\\"510\\\" height=\\\"500.0000000000001\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"index.jsx\\\" value=\\\"index.jsx\\\" id=\\\"c4d7e7dd-75b1-44f1-a34a-6ed290a8e562\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#efdfdf\\\" vertex=\\\"1\\\" parent=\\\"987f145b-5df6-4c30-bf1c-2a2d2b0e5cdc\\\">\\n            <mxGeometry x=\\\"95\\\" y=\\\"70\\\" width=\\\"320\\\" height=\\\"360.00000000000006\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"View Status Page: User Navigates to URL - index.jsx:L148-152\\\" value=\\\"View Status Page: User Navigates to URL - index.jsx:L148-152\\\" id=\\\"30aaee38-f509-4e19-a917-e6d2f4bba61c\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"c4d7e7dd-75b1-44f1-a34a-6ed290a8e562\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"200.00000000000003\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Flow 1: CSV Import - Navigate to Bulk Import Page - index.jsx:L88-91\\\" value=\\\"Flow 1: CSV Import - Navigate to Bulk Import Page - index.jsx:L88-91\\\" id=\\\"c4caeba8-ed9a-4cbc-9888-38cc8ca55362\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"c4d7e7dd-75b1-44f1-a34a-6ed290a8e562\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <mxCell id=\\\"0575bf87-5362-4988-b895-7e514148d420\\\" value=\\\"View Status&#xa;Page: Component&#xa;Triggers Data&#xa;Fetch\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=20;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"d3264577-10f0-42fe-9411-7e9df0754d1e\\\" source=\\\"30aaee38-f509-4e19-a917-e6d2f4bba61c\\\" target=\\\"ecfb2d04-2681-4f16-af75-632f69e1a868\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"760\\\" y=\\\"5005.325785083435\\\" />\\n              <mxPoint x=\\\"760\\\" y=\\\"4700.621306201958\\\" />\\n              <mxPoint x=\\\"985\\\" y=\\\"4700.621306201958\\\" />\\n              <mxPoint x=\\\"985\\\" y=\\\"4700.584553505045\\\" />\\n              <mxPoint x=\\\"1180\\\" y=\\\"4700.584553505045\\\" />\\n              <mxPoint x=\\\"1180\\\" y=\\\"2459.607033820289\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <mxCell id=\\\"e90e4943-6108-46e3-8a2c-a9a1c7361279\\\" value=\\\"Trigger Check&#xa;History Fetch\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=20;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"d3264577-10f0-42fe-9411-7e9df0754d1e\\\" source=\\\"78a8a7c5-41d3-4453-a7f7-ac632bbef288\\\" target=\\\"4a5847d0-91a0-4b4c-8517-2f4ff9a7e8d4\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"3250\\\" y=\\\"6507.080193689383\\\" />\\n              <mxPoint x=\\\"3250\\\" y=\\\"8457.246623286175\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <mxCell id=\\\"74b0dd89-9fea-4219-af1f-9571316a9d5a\\\" value=\\\"Pass Data&#xa;to UI&#xa;Components\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=20;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"d3264577-10f0-42fe-9411-7e9df0754d1e\\\" source=\\\"ceb9cda3-968d-44aa-b223-49902adb93b4\\\" target=\\\"c996f7ca-9384-4252-b343-7bfc049d14bb\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"4390\\\" y=\\\"8327.246623286173\\\" />\\n              <mxPoint x=\\\"4390\\\" y=\\\"10688.865179846314\\\" />\\n              <mxPoint x=\\\"780\\\" y=\\\"10688.865179846314\\\" />\\n              <mxPoint x=\\\"780\\\" y=\\\"8549.135157943725\\\" />\\n              <mxPoint x=\\\"1170\\\" y=\\\"8549.135157943725\\\" />\\n              <mxPoint x=\\\"1170\\\" y=\\\"6096.870240113547\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <mxCell id=\\\"c9a012bc-d53f-494f-82f2-1ee3f40ce646\\\" value=\\\"Flow 1:&#xa;CSV Import&#xa;- Render&#xa;UI\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=20;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"d3264577-10f0-42fe-9411-7e9df0754d1e\\\" source=\\\"c4caeba8-ed9a-4cbc-9888-38cc8ca55362\\\" target=\\\"6f1948fa-e84a-4f8e-8f3b-8f24c511b3d8\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"750\\\" y=\\\"4875.325785083435\\\" />\\n              <mxPoint x=\\\"750\\\" y=\\\"4690.621306201958\\\" />\\n              <mxPoint x=\\\"985\\\" y=\\\"4690.621306201958\\\" />\\n              <mxPoint x=\\\"985\\\" y=\\\"4690.584553505045\\\" />\\n              <mxPoint x=\\\"1170\\\" y=\\\"4690.584553505045\\\" />\\n              <mxPoint x=\\\"1170\\\" y=\\\"5546.870240113548\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <mxCell id=\\\"b8c0292d-afbb-4648-b484-1c27be96d52f\\\" value=\\\"Flow 1:&#xa;CSV Import&#xa;- Prepare&#xa;Form Data\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=20;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"d3264577-10f0-42fe-9411-7e9df0754d1e\\\" source=\\\"dd2f9356-fad3-47d4-81d5-a5e038298e2b\\\" target=\\\"5967e576-f542-4c0b-a3f4-9446ae992721\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"3290\\\" y=\\\"5529.60703382029\\\" />\\n              <mxPoint x=\\\"3290\\\" y=\\\"5341.542220848843\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <mxCell id=\\\"8c107d79-f796-49eb-ab88-f553dd6f9d95\\\" value=\\\"User Action:&#xa;Save Settings\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=20;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"d3264577-10f0-42fe-9411-7e9df0754d1e\\\" source=\\\"09cb194a-0ea4-46e2-b32b-36b62fa87f40\\\" target=\\\"1b2cf182-9ee3-4218-a7ec-b74e427ccddf\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"3280\\\" y=\\\"8663.865179846309\\\" />\\n              <mxPoint x=\\\"3280\\\" y=\\\"8857.246623286173\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <UserObject label=\\\"server\\\" value=\\\"server\\\" id=\\\"98af25c7-efc2-43d2-a273-c8da4e1038ad\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#fffefe\\\" vertex=\\\"1\\\" parent=\\\"1\\\">\\n            <mxGeometry x=\\\"5345\\\" y=\\\"70\\\" width=\\\"9275\\\" height=\\\"10756.873756414825\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"src\\\" value=\\\"src\\\" id=\\\"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#f9f3f3\\\" vertex=\\\"1\\\" parent=\\\"98af25c7-efc2-43d2-a273-c8da4e1038ad\\\">\\n            <mxGeometry x=\\\"175\\\" y=\\\"70\\\" width=\\\"9005\\\" height=\\\"10616.873756414825\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"routes\\\" value=\\\"routes\\\" id=\\\"ffaaf471-ac3c-4ea3-a5a9-d5255169e54b\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#f4e9e9\\\" vertex=\\\"1\\\" parent=\\\"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\\\">\\n            <mxGeometry x=\\\"215\\\" y=\\\"783\\\" width=\\\"1030\\\" height=\\\"1984.0802430260385\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"v1\\\" value=\\\"v1\\\" id=\\\"d3375a20-2776-4771-b806-649bbeb541bd\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#efdfdf\\\" vertex=\\\"1\\\" parent=\\\"ffaaf471-ac3c-4ea3-a5a9-d5255169e54b\\\">\\n            <mxGeometry x=\\\"175\\\" y=\\\"70.00000000000006\\\" width=\\\"680\\\" height=\\\"1844.0802430260385\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"monitorRoute.js\\\" value=\\\"monitorRoute.js\\\" id=\\\"10611636-ec73-4a26-87a5-654ae64a4843\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#ead5d5\\\" vertex=\\\"1\\\" parent=\\\"d3375a20-2776-4771-b806-649bbeb541bd\\\">\\n            <mxGeometry x=\\\"185\\\" y=\\\"600.0000000000001\\\" width=\\\"320\\\" height=\\\"360.24710152500006\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Flow 1: CSV Import - Server Receives Request - monitorRoute.js:L46\\\" value=\\\"Flow 1: CSV Import - Server Receives Request - monitorRoute.js:L46\\\" id=\\\"c1ac3c26-996a-43ef-9c34-4c2776188784\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"10611636-ec73-4a26-87a5-654ae64a4843\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Flow 2: CSV Export - Initiate Export - monitorRoute.js:L45\\\" value=\\\"Flow 2: CSV Export - Initiate Export - monitorRoute.js:L45\\\" id=\\\"26d76516-fd7e-4ae8-956a-d077de4257fa\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"10611636-ec73-4a26-87a5-654ae64a4843\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"200.24710152500003\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"notificationRoute.js\\\" value=\\\"notificationRoute.js\\\" id=\\\"96250197-23af-4059-9904-fd6751f70ad5\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#ead5d5\\\" vertex=\\\"1\\\" parent=\\\"d3375a20-2776-4771-b806-649bbeb541bd\\\">\\n            <mxGeometry x=\\\"185\\\" y=\\\"1414.0802430260383\\\" width=\\\"320\\\" height=\\\"360\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Flow 1: Backend Route Handling - notificationRoute.js:L10\\\" value=\\\"Flow 1: Backend Route Handling - notificationRoute.js:L10\\\" id=\\\"d0a4737f-715f-4f50-b6d5-5e4b31f86f93\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"96250197-23af-4059-9904-fd6751f70ad5\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Flow 1: Backend Receives Test Request - notificationRoute.js:L13\\\" value=\\\"Flow 1: Backend Receives Test Request - notificationRoute.js:L13\\\" id=\\\"29c2c56e-9dc0-4304-bfbf-e0c0f8915a39\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"96250197-23af-4059-9904-fd6751f70ad5\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"200\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"statusPageRoute.js\\\" value=\\\"statusPageRoute.js\\\" id=\\\"773e1065-b0a5-46a9-b0cc-6b963f69f5cc\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#ead5d5\\\" vertex=\\\"1\\\" parent=\\\"d3375a20-2776-4771-b806-649bbeb541bd\\\">\\n            <mxGeometry x=\\\"185\\\" y=\\\"70\\\" width=\\\"320\\\" height=\\\"360\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Create Status Page: Backend Route Handling - statusPageRoute.js:L14\\\" value=\\\"Create Status Page: Backend Route Handling - statusPageRoute.js:L14\\\" id=\\\"3efddcad-588f-4492-9808-b0c81c823c96\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"773e1065-b0a5-46a9-b0cc-6b963f69f5cc\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"200\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"View Status Page: Backend Route Handling - statusPageRoute.js:L16\\\" value=\\\"View Status Page: Backend Route Handling - statusPageRoute.js:L16\\\" id=\\\"2e26cd2f-1413-4c16-8e63-ea7808ab6c52\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"773e1065-b0a5-46a9-b0cc-6b963f69f5cc\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"checkRoute.js\\\" value=\\\"checkRoute.js\\\" id=\\\"d18dbe1d-2f2c-4336-bd21-47c1670f7bab\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#ead5d5\\\" vertex=\\\"1\\\" parent=\\\"d3375a20-2776-4771-b806-649bbeb541bd\\\">\\n            <mxGeometry x=\\\"185\\\" y=\\\"1135.7525647938676\\\" width=\\\"320\\\" height=\\\"230\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Route Request to Controller - checkRoute.js:L19\\\" value=\\\"Route Request to Controller - checkRoute.js:L19\\\" id=\\\"cdd090be-0b62-45b4-baa0-fec01fc3ffd1\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"d18dbe1d-2f2c-4336-bd21-47c1670f7bab\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"maintenanceWindowRoute.js\\\" value=\\\"maintenanceWindowRoute.js\\\" id=\\\"5f21f109-1967-416f-a649-9b48e78b90f6\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"d3375a20-2776-4771-b806-649bbeb541bd\\\">\\n            <mxGeometry x=\\\"255\\\" y=\\\"470.0000000000001\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"inviteRoute.js\\\" value=\\\"inviteRoute.js\\\" id=\\\"9edafb8a-3661-4a7e-8510-a47f3cbc7564\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=16;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"d3375a20-2776-4771-b806-649bbeb541bd\\\">\\n            <mxGeometry x=\\\"255\\\" y=\\\"1000.2471015250001\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"controllers\\\" value=\\\"controllers\\\" id=\\\"478e649c-1d1b-41d2-9b7b-6927e1dec7e1\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#f4e9e9\\\" vertex=\\\"1\\\" parent=\\\"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\\\">\\n            <mxGeometry x=\\\"1465\\\" y=\\\"3609.569505991416\\\" width=\\\"1470\\\" height=\\\"3164.7713082929035\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"v1\\\" value=\\\"v1\\\" id=\\\"fc591f7a-d4ac-4565-949d-a87a58a79bbc\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#efdfdf\\\" vertex=\\\"1\\\" parent=\\\"478e649c-1d1b-41d2-9b7b-6927e1dec7e1\\\">\\n            <mxGeometry x=\\\"175\\\" y=\\\"70\\\" width=\\\"1120\\\" height=\\\"3024.7713082929035\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"monitorController.js\\\" value=\\\"monitorController.js\\\" id=\\\"341f2784-67ee-4477-9445-a8c240ee6261\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#ead5d5\\\" vertex=\\\"1\\\" parent=\\\"fc591f7a-d4ac-4565-949d-a87a58a79bbc\\\">\\n            <mxGeometry x=\\\"225\\\" y=\\\"600\\\" width=\\\"720\\\" height=\\\"750\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Uptime Monitor Creation: Controller to Service - monitorController.js:L195\\\" value=\\\"Uptime Monitor Creation: Controller to Service - monitorController.js:L195\\\" id=\\\"f0409948-75dc-457f-a02d-6b9774258e48\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"341f2784-67ee-4477-9445-a8c240ee6261\\\">\\n            <mxGeometry x=\\\"150\\\" y=\\\"200\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Flow 1: CSV Import - Controller Processes Data - monitorController.js:L228-232\\\" value=\\\"Flow 1: CSV Import - Controller Processes Data - monitorController.js:L228-232\\\" id=\\\"0e520a6d-34bf-467b-a894-e73979364478\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"341f2784-67ee-4477-9445-a8c240ee6261\\\">\\n            <mxGeometry x=\\\"150\\\" y=\\\"329.99999999999994\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Flow 1: CSV Import - Send Success Response - monitorController.js:L232-235\\\" value=\\\"Flow 1: CSV Import - Send Success Response - monitorController.js:L232-235\\\" id=\\\"72b55fa1-d944-4e46-ac98-f6a6cb201afa\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"341f2784-67ee-4477-9445-a8c240ee6261\\\">\\n            <mxGeometry x=\\\"150\\\" y=\\\"70.00000000000001\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Flow 2: CSV Export - Controller Handles Request - monitorController.js:L427-434\\\" value=\\\"Flow 2: CSV Export - Controller Handles Request - monitorController.js:L427-434\\\" id=\\\"a3106388-6a3d-4b68-a3fc-3761a0d54f98\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"341f2784-67ee-4477-9445-a8c240ee6261\\\">\\n            <mxGeometry x=\\\"150\\\" y=\\\"460.00000000000006\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Flow 2: CSV Export - Send File Response - monitorController.js:L434-440\\\" value=\\\"Flow 2: CSV Export - Send File Response - monitorController.js:L434-440\\\" id=\\\"f151f89d-6399-48f0-aecd-5eb1572b48cc\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"341f2784-67ee-4477-9445-a8c240ee6261\\\">\\n            <mxGeometry x=\\\"150\\\" y=\\\"590\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Flow 2: CSV Export - Browser Prompts Download - monitorController.js:L434-440\\\" value=\\\"Flow 2: CSV Export - Browser Prompts Download - monitorController.js:L434-440\\\" id=\\\"d8877474-7203-484f-bd47-fc69e3c7c482\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"341f2784-67ee-4477-9445-a8c240ee6261\\\">\\n            <mxGeometry x=\\\"470\\\" y=\\\"590\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <mxCell id=\\\"3dfb432a-2ce4-4f92-98ce-5d114b5f7f03\\\" value=\\\"Flow 2:&#xa;CSV Export&#xa;- Transmit&#xa;File to&#xa;Client\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=11;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"341f2784-67ee-4477-9445-a8c240ee6261\\\" source=\\\"f151f89d-6399-48f0-aecd-5eb1572b48cc\\\" target=\\\"d8877474-7203-484f-bd47-fc69e3c7c482\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\" />\\n          </mxGeometry>\\n        </mxCell>\\n        <UserObject label=\\\"notificationController.js\\\" value=\\\"notificationController.js\\\" id=\\\"8e5941e1-e577-455f-bbf2-83a418ad5908\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"fc591f7a-d4ac-4565-949d-a87a58a79bbc\\\">\\n            <mxGeometry x=\\\"495\\\" y=\\\"469.9999999999999\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"statusPageController.js\\\" value=\\\"statusPageController.js\\\" id=\\\"17a4f435-5a8e-4433-84a6-9ac17362709a\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#ead5d5\\\" vertex=\\\"1\\\" parent=\\\"fc591f7a-d4ac-4565-949d-a87a58a79bbc\\\">\\n            <mxGeometry x=\\\"345\\\" y=\\\"1920\\\" width=\\\"480\\\" height=\\\"620\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Create Status Page: Controller Logic - statusPageController.js:L18-24\\\" value=\\\"Create Status Page: Controller Logic - statusPageController.js:L18-24\\\" id=\\\"f15ef77e-380f-4768-98cb-7f0dd4113841\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"17a4f435-5a8e-4433-84a6-9ac17362709a\\\">\\n            <mxGeometry x=\\\"150\\\" y=\\\"199.99999999999997\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Create Status Page: Controller Sends Success Response - statusPageController.js:L25-28\\\" value=\\\"Create Status Page: Controller Sends Success Response - statusPageController.js:L25-28\\\" id=\\\"058ded1f-83ce-40a7-a99d-d178c81fe557\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"17a4f435-5a8e-4433-84a6-9ac17362709a\\\">\\n            <mxGeometry x=\\\"150\\\" y=\\\"329.9999999999999\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"View Status Page: Controller Logic - statusPageController.js:L75-78\\\" value=\\\"View Status Page: Controller Logic - statusPageController.js:L75-78\\\" id=\\\"9f217674-4cd7-4ef8-b088-d5620042a7ba\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"17a4f435-5a8e-4433-84a6-9ac17362709a\\\">\\n            <mxGeometry x=\\\"150\\\" y=\\\"70\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"View Status Page: Controller Sends Success Response - statusPageController.js:L79-82\\\" value=\\\"View Status Page: Controller Sends Success Response - statusPageController.js:L79-82\\\" id=\\\"d76e70e0-41f9-46cc-b775-b2027c5a0d5b\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"17a4f435-5a8e-4433-84a6-9ac17362709a\\\">\\n            <mxGeometry x=\\\"150\\\" y=\\\"460\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"checkController.js\\\" value=\\\"checkController.js\\\" id=\\\"d983e54f-2fbe-496a-932d-a827e1124804\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#ead5d5\\\" vertex=\\\"1\\\" parent=\\\"fc591f7a-d4ac-4565-949d-a87a58a79bbc\\\">\\n            <mxGeometry x=\\\"425\\\" y=\\\"70\\\" width=\\\"320\\\" height=\\\"230\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Return Check Data - checkController.js:L87-90\\\" value=\\\"Return Check Data - checkController.js:L87-90\\\" id=\\\"14df9f01-1358-442d-96f5-eab9a4c4abbf\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"d983e54f-2fbe-496a-932d-a827e1124804\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"maintenanceWindowController.js\\\" value=\\\"maintenanceWindowController.js\\\" id=\\\"a0cae18c-3c0e-40d3-ab03-eef7eace65d6\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#ead5d5\\\" vertex=\\\"1\\\" parent=\\\"fc591f7a-d4ac-4565-949d-a87a58a79bbc\\\">\\n            <mxGeometry x=\\\"425\\\" y=\\\"1519.9999999999998\\\" width=\\\"320\\\" height=\\\"360\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Flow: Create Maintenance Window - Controller Logic - maintenanceWindowController.js:L27-41\\\" value=\\\"Flow: Create Maintenance Window - Controller Logic - maintenanceWindowController.js:L27-41\\\" id=\\\"0fae6e75-38ea-444d-a1bf-0f820ba443b9\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"a0cae18c-3c0e-40d3-ab03-eef7eace65d6\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Flow: View Maintenance Windows - Controller and Service - maintenanceWindowController.js:L75\\\" value=\\\"Flow: View Maintenance Windows - Controller and Service - maintenanceWindowController.js:L75\\\" id=\\\"c35a065c-2808-402c-877e-9055d956ce0d\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"a0cae18c-3c0e-40d3-ab03-eef7eace65d6\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"200\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"inviteController.js\\\" value=\\\"inviteController.js\\\" id=\\\"6a186805-9d50-4bc3-9d56-e627a7ec2eb8\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=14;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"fc591f7a-d4ac-4565-949d-a87a58a79bbc\\\">\\n            <mxGeometry x=\\\"495\\\" y=\\\"339.9999999999999\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"settingsController.js\\\" value=\\\"settingsController.js\\\" id=\\\"a1fea5b0-fb7c-4189-9484-9d3312660767\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#ead5d5\\\" vertex=\\\"1\\\" parent=\\\"fc591f7a-d4ac-4565-949d-a87a58a79bbc\\\">\\n            <mxGeometry x=\\\"425\\\" y=\\\"2594.7713082929035\\\" width=\\\"320\\\" height=\\\"360\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Backend: Retrieve Settings from Database - settingsController.js:L40-49\\\" value=\\\"Backend: Retrieve Settings from Database - settingsController.js:L40-49\\\" id=\\\"83596bd1-dfca-4196-b52e-955f6824fafb\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"a1fea5b0-fb7c-4189-9484-9d3312660767\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Backend: Persist Updated Settings - settingsController.js:L54-64\\\" value=\\\"Backend: Persist Updated Settings - settingsController.js:L54-64\\\" id=\\\"cce3b9c8-f3b7-434b-b3c6-d8d164714f86\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"a1fea5b0-fb7c-4189-9484-9d3312660767\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"200\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"diagnosticController.js\\\" value=\\\"diagnosticController.js\\\" id=\\\"5882419e-8a92-4edd-a71a-1252983f9af7\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"fc591f7a-d4ac-4565-949d-a87a58a79bbc\\\">\\n            <mxGeometry x=\\\"495\\\" y=\\\"1390\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"service\\\" value=\\\"service\\\" id=\\\"99e9b746-7809-41f4-a433-1de7cc90574b\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#f4e9e9\\\" vertex=\\\"1\\\" parent=\\\"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\\\">\\n            <mxGeometry x=\\\"4835\\\" y=\\\"3072.0802430260387\\\" width=\\\"3965\\\" height=\\\"3896.797033318495\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"v1\\\" value=\\\"v1\\\" id=\\\"bbbe53d6-f595-498a-ae45-e08611f39c3d\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#efdfdf\\\" vertex=\\\"1\\\" parent=\\\"99e9b746-7809-41f4-a433-1de7cc90574b\\\">\\n            <mxGeometry x=\\\"175\\\" y=\\\"890.0000000000002\\\" width=\\\"3615\\\" height=\\\"2936.797033318495\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"business\\\" value=\\\"business\\\" id=\\\"87d3b101-9443-4ed4-9c4f-f759d41677eb\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#ead5d5\\\" vertex=\\\"1\\\" parent=\\\"bbbe53d6-f595-498a-ae45-e08611f39c3d\\\">\\n            <mxGeometry x=\\\"1231.1538461538462\\\" y=\\\"70\\\" width=\\\"1000\\\" height=\\\"1713.9996160245596\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"monitorService.js\\\" value=\\\"monitorService.js\\\" id=\\\"b4e479df-9b21-4430-9383-84831f503c2e\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e5cbcb\\\" vertex=\\\"1\\\" parent=\\\"87d3b101-9443-4ed4-9c4f-f759d41677eb\\\">\\n            <mxGeometry x=\\\"265\\\" y=\\\"880.7789018663125\\\" width=\\\"480\\\" height=\\\"490\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Flow 1: CSV Import - Service Parses CSV - monitorService.js:L85-134\\\" value=\\\"Flow 1: CSV Import - Service Parses CSV - monitorService.js:L85-134\\\" id=\\\"6139e487-1dd5-405a-ba7d-ededec4b282e\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"b4e479df-9b21-4430-9383-84831f503c2e\\\">\\n            <mxGeometry x=\\\"150\\\" y=\\\"70\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Flow 1: CSV Import - Enqueue Monitor Jobs - monitorService.js:L128-132\\\" value=\\\"Flow 1: CSV Import - Enqueue Monitor Jobs - monitorService.js:L128-132\\\" id=\\\"1e1d975f-7f0f-4132-bd71-2563b35e99b3\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"b4e479df-9b21-4430-9383-84831f503c2e\\\">\\n            <mxGeometry x=\\\"150\\\" y=\\\"330\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Flow 2: CSV Export - Generate CSV - monitorService.js:L245-266\\\" value=\\\"Flow 2: CSV Export - Generate CSV - monitorService.js:L245-266\\\" id=\\\"ab9cb862-0ac7-45a3-9888-f64e87bdda54\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"b4e479df-9b21-4430-9383-84831f503c2e\\\">\\n            <mxGeometry x=\\\"150\\\" y=\\\"200\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"checkService.js\\\" value=\\\"checkService.js\\\" id=\\\"f90db867-e1e7-4554-b446-fa78fc6a8578\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e5cbcb\\\" vertex=\\\"1\\\" parent=\\\"87d3b101-9443-4ed4-9c4f-f759d41677eb\\\">\\n            <mxGeometry x=\\\"345\\\" y=\\\"610.7789018663126\\\" width=\\\"320\\\" height=\\\"230\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Fetch Checks from Database - checkService.js:L36-45\\\" value=\\\"Fetch Checks from Database - checkService.js:L36-45\\\" id=\\\"499b46a2-f2a2-4ccd-aecd-012eade2bd23\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"f90db867-e1e7-4554-b446-fa78fc6a8578\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"maintenanceWindowService.js\\\" value=\\\"maintenanceWindowService.js\\\" id=\\\"26b8daff-aa48-4baa-9d6c-05f771bf0990\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e5cbcb\\\" vertex=\\\"1\\\" parent=\\\"87d3b101-9443-4ed4-9c4f-f759d41677eb\\\">\\n            <mxGeometry x=\\\"345\\\" y=\\\"1413.9996160245596\\\" width=\\\"320\\\" height=\\\"230\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Flow: Create Maintenance Window - Business Logic Execution - maintenanceWindowService.js:L18-39\\\" value=\\\"Flow: Create Maintenance Window - Business Logic Execution - maintenanceWindowService.js:L18-39\\\" id=\\\"560d268b-ef0f-4cd2-bcfe-9dc0a0e2ce6f\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"26b8daff-aa48-4baa-9d6c-05f771bf0990\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"inviteService.js\\\" value=\\\"inviteService.js\\\" id=\\\"570278b7-9b72-4299-9fd9-46b253b48e9b\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e5cbcb\\\" vertex=\\\"1\\\" parent=\\\"87d3b101-9443-4ed4-9c4f-f759d41677eb\\\">\\n            <mxGeometry x=\\\"185\\\" y=\\\"70\\\" width=\\\"640\\\" height=\\\"230.7789018663125\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Server: Process Invitation in Service Layer - inviteService.js:L24-28\\\" value=\\\"Server: Process Invitation in Service Layer - inviteService.js:L24-28\\\" id=\\\"ae858158-8db6-4917-8fda-0966a953f6ed\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"570278b7-9b72-4299-9fd9-46b253b48e9b\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Server: Dispatch Invitation Email - inviteService.js:L26-28\\\" value=\\\"Server: Dispatch Invitation Email - inviteService.js:L26-28\\\" id=\\\"a7be2d0b-0227-4228-a0a6-074f7324fd89\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"570278b7-9b72-4299-9fd9-46b253b48e9b\\\">\\n            <mxGeometry x=\\\"390\\\" y=\\\"70.77890186631251\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <mxCell id=\\\"bdd52e6f-ddf7-4966-b3af-957f9553082f\\\" value=\\\"Database Query:&#xa;Create and&#xa;Store Invite&#xa;Token\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=11;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"570278b7-9b72-4299-9fd9-46b253b48e9b\\\" source=\\\"ae858158-8db6-4917-8fda-0966a953f6ed\\\" target=\\\"a7be2d0b-0227-4228-a0a6-074f7324fd89\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"290\\\" y=\\\"115\\\" />\\n              <mxPoint x=\\\"290\\\" y=\\\"115.77890186631251\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <UserObject label=\\\"diagnosticService.js\\\" value=\\\"diagnosticService.js\\\" id=\\\"643b26c1-3bfb-4c41-8179-96dfc237d99e\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e5cbcb\\\" vertex=\\\"1\\\" parent=\\\"87d3b101-9443-4ed4-9c4f-f759d41677eb\\\">\\n            <mxGeometry x=\\\"185\\\" y=\\\"340.7789018663125\\\" width=\\\"320\\\" height=\\\"230\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Backend: Gather System Statistics - diagnosticService.js:L39-95\\\" value=\\\"Backend: Gather System Statistics - diagnosticService.js:L39-95\\\" id=\\\"09f07e80-185e-4547-aab4-edaf8ae7501e\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"643b26c1-3bfb-4c41-8179-96dfc237d99e\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"infrastructure\\\" value=\\\"infrastructure\\\" id=\\\"1670815f-860d-4ea4-92e1-b238a799d3dc\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#ead5d5\\\" vertex=\\\"1\\\" parent=\\\"bbbe53d6-f595-498a-ae45-e08611f39c3d\\\">\\n            <mxGeometry x=\\\"195\\\" y=\\\"1845.4635994752946\\\" width=\\\"3245\\\" height=\\\"1021.3334338432\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"SuperSimpleQueue\\\" value=\\\"SuperSimpleQueue\\\" id=\\\"dda70a36-2d1d-4e46-8bcc-52d0d474bf7b\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e5cbcb\\\" vertex=\\\"1\\\" parent=\\\"1670815f-860d-4ea4-92e1-b238a799d3dc\\\">\\n            <mxGeometry x=\\\"95\\\" y=\\\"121.00000000000001\\\" width=\\\"1525\\\" height=\\\"770.3334338432\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"SuperSimpleQueue.js\\\" value=\\\"SuperSimpleQueue.js\\\" id=\\\"d9c0127e-31aa-4509-b5c9-f7017d10d69a\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e0c1c1\\\" vertex=\\\"1\\\" parent=\\\"dda70a36-2d1d-4e46-8bcc-52d0d474bf7b\\\">\\n            <mxGeometry x=\\\"175\\\" y=\\\"70\\\" width=\\\"320\\\" height=\\\"230\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Uptime Monitor Creation: Schedule Job - SuperSimpleQueue.js:L50-57\\\" value=\\\"Uptime Monitor Creation: Schedule Job - SuperSimpleQueue.js:L50-57\\\" id=\\\"51e8db5f-2fdd-4ddc-9605-43981db9d940\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"d9c0127e-31aa-4509-b5c9-f7017d10d69a\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"SuperSimpleQueueHelper.js\\\" value=\\\"SuperSimpleQueueHelper.js\\\" id=\\\"04c12e9a-e025-457c-a634-5f7472a42985\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e0c1c1\\\" vertex=\\\"1\\\" parent=\\\"dda70a36-2d1d-4e46-8bcc-52d0d474bf7b\\\">\\n            <mxGeometry x=\\\"150\\\" y=\\\"340.33343384320005\\\" width=\\\"1280\\\" height=\\\"360\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Service Monitoring: Job Execution - SuperSimpleQueueHelper.js:L27-73\\\" value=\\\"Service Monitoring: Job Execution - SuperSimpleQueueHelper.js:L27-73\\\" id=\\\"18c13391-0cf7-4303-8180-0a40cfd64b58\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"04c12e9a-e025-457c-a634-5f7472a42985\\\">\\n            <mxGeometry x=\\\"1030\\\" y=\\\"200\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Flow: Monitor Suppression - Job Execution Start - SuperSimpleQueueHelper.js:L30-45\\\" value=\\\"Flow: Monitor Suppression - Job Execution Start - SuperSimpleQueueHelper.js:L30-45\\\" id=\\\"23630a1f-7452-4373-a864-7ec7821137f2\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"04c12e9a-e025-457c-a634-5f7472a42985\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"93.00716143795759\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Flow: Monitor Suppression - Fetching Maintenance Windows - SuperSimpleQueueHelper.js:L80-83\\\" value=\\\"Flow: Monitor Suppression - Fetching Maintenance Windows - SuperSimpleQueueHelper.js:L80-83\\\" id=\\\"fc78b5b6-7fad-4f8f-a5a3-c7c38931daba\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"04c12e9a-e025-457c-a634-5f7472a42985\\\">\\n            <mxGeometry x=\\\"390\\\" y=\\\"93.00716143795759\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Flow: Monitor Suppression - Time Evaluation - SuperSimpleQueueHelper.js:L85-113\\\" value=\\\"Flow: Monitor Suppression - Time Evaluation - SuperSimpleQueueHelper.js:L85-113\\\" id=\\\"0fe32416-db43-49b9-9438-3796ba1a0add\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"04c12e9a-e025-457c-a634-5f7472a42985\\\">\\n            <mxGeometry x=\\\"710\\\" y=\\\"93.00716143795759\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Flow: Monitor Suppression - Conditional Job Termination - SuperSimpleQueueHelper.js:L37-44\\\" value=\\\"Flow: Monitor Suppression - Conditional Job Termination - SuperSimpleQueueHelper.js:L37-44\\\" id=\\\"01e042c3-40b4-416a-8d9e-6d6fd323d60b\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"04c12e9a-e025-457c-a634-5f7472a42985\\\">\\n            <mxGeometry x=\\\"1030\\\" y=\\\"70\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <mxCell id=\\\"c99291bb-7316-440e-9a7f-323ee39e26b8\\\" value=\\\"Flow: Monitor&#xa;Suppression -&#xa;Maintenance Check&#xa;Call\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=11;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"04c12e9a-e025-457c-a634-5f7472a42985\\\" source=\\\"23630a1f-7452-4373-a864-7ec7821137f2\\\" target=\\\"fc78b5b6-7fad-4f8f-a5a3-c7c38931daba\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\" />\\n          </mxGeometry>\\n        </mxCell>\\n        <mxCell id=\\\"8a13e585-2310-420b-9e92-211b6d65f201\\\" value=\\\"Flow: Monitor&#xa;Suppression -&#xa;Database Result&#xa;Return\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=11;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"04c12e9a-e025-457c-a634-5f7472a42985\\\" source=\\\"fc78b5b6-7fad-4f8f-a5a3-c7c38931daba\\\" target=\\\"0fe32416-db43-49b9-9438-3796ba1a0add\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\" />\\n          </mxGeometry>\\n        </mxCell>\\n        <mxCell id=\\\"40f4d9df-4c0f-4384-901c-8d7117e3b538\\\" value=\\\"Flow: Monitor&#xa;Suppression -&#xa;Return Suppression&#xa;Flag\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=11;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"04c12e9a-e025-457c-a634-5f7472a42985\\\" source=\\\"0fe32416-db43-49b9-9438-3796ba1a0add\\\" target=\\\"01e042c3-40b4-416a-8d9e-6d6fd323d60b\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"930\\\" y=\\\"138.0071614379576\\\" />\\n              <mxPoint x=\\\"930\\\" y=\\\"115\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <UserObject label=\\\"networkService.js\\\" value=\\\"networkService.js\\\" id=\\\"00406786-9663-440a-96b6-919d544732c0\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e5cbcb\\\" vertex=\\\"1\\\" parent=\\\"1670815f-860d-4ea4-92e1-b238a799d3dc\\\">\\n            <mxGeometry x=\\\"1810\\\" y=\\\"591.3334338432\\\" width=\\\"320\\\" height=\\\"360\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Service Monitoring: Perform Network Check - networkService.js:L44-59\\\" value=\\\"Service Monitoring: Perform Network Check - networkService.js:L44-59\\\" id=\\\"5c900373-e6ba-44d5-b341-676a32d659c8\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"00406786-9663-440a-96b6-919d544732c0\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Automated Check: Backend Fetches Hardware Data - networkService.js:L7-14\\\" value=\\\"Automated Check: Backend Fetches Hardware Data - networkService.js:L7-14\\\" id=\\\"4c47b5f2-5363-4816-9745-30e61d184c7a\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"00406786-9663-440a-96b6-919d544732c0\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"200\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"statusService.js\\\" value=\\\"statusService.js\\\" id=\\\"fbd7d244-2f37-453c-8c83-a23a260b26cc\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e5cbcb\\\" vertex=\\\"1\\\" parent=\\\"1670815f-860d-4ea4-92e1-b238a799d3dc\\\">\\n            <mxGeometry x=\\\"2320\\\" y=\\\"381.7244518190359\\\" width=\\\"320\\\" height=\\\"360\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Service Monitoring: Update Monitor Status - statusService.js:L108-183\\\" value=\\\"Service Monitoring: Update Monitor Status - statusService.js:L108-183\\\" id=\\\"45e38f3a-a7c3-4de7-b3dc-589361d793fd\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"fbd7d244-2f37-453c-8c83-a23a260b26cc\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Automated Check: Process and Store Hardware Data - statusService.js:L265-274\\\" value=\\\"Automated Check: Process and Store Hardware Data - statusService.js:L265-274\\\" id=\\\"c1bf10c9-8c1a-44f4-8e23-39708f0301e8\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"fbd7d244-2f37-453c-8c83-a23a260b26cc\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"200\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"notificationService.js\\\" value=\\\"notificationService.js\\\" id=\\\"2ff1f030-2080-48da-bbbe-90302fdfc2f7\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e5cbcb\\\" vertex=\\\"1\\\" parent=\\\"1670815f-860d-4ea4-92e1-b238a799d3dc\\\">\\n            <mxGeometry x=\\\"2830\\\" y=\\\"110.40446897297748\\\" width=\\\"320\\\" height=\\\"360\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Service Monitoring: Handle Notifications (Conditional) - notificationService.js:L76-92\\\" value=\\\"Service Monitoring: Handle Notifications (Conditional) - notificationService.js:L76-92\\\" id=\\\"9f3ea7fc-16d3-4d36-97eb-66f8808425cc\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"2ff1f030-2080-48da-bbbe-90302fdfc2f7\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"199.99999999999997\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Flow 1: Send Test Notification - notificationService.js:L120-123\\\" value=\\\"Flow 1: Send Test Notification - notificationService.js:L120-123\\\" id=\\\"1cc01e08-4a6c-4526-b8a7-5ee8a06c1709\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"2ff1f030-2080-48da-bbbe-90302fdfc2f7\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <mxCell id=\\\"38ba9b22-5b26-432d-a856-0eceb792c737\\\" value=\\\"Service Monitoring:&#xa;Request Service&#xa;Status\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=13;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"1670815f-860d-4ea4-92e1-b238a799d3dc\\\" source=\\\"18c13391-0cf7-4303-8180-0a40cfd64b58\\\" target=\\\"5c900373-e6ba-44d5-b341-676a32d659c8\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\" />\\n          </mxGeometry>\\n        </mxCell>\\n        <mxCell id=\\\"5e80734c-7b72-41be-9068-30cda3ffb425\\\" value=\\\"Service Monitoring:&#xa;Propagate Network&#xa;Response\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=20;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"1670815f-860d-4ea4-92e1-b238a799d3dc\\\" source=\\\"5c900373-e6ba-44d5-b341-676a32d659c8\\\" target=\\\"45e38f3a-a7c3-4de7-b3dc-589361d793fd\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"2195\\\" y=\\\"706.3334338431989\\\" />\\n              <mxPoint x=\\\"2195\\\" y=\\\"496.72445181903475\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <mxCell id=\\\"0a7e4a72-b644-4bd8-afa1-ae8a1d6c111c\\\" value=\\\"Service Monitoring:&#xa;Check for&#xa;Status Change\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=20;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"1670815f-860d-4ea4-92e1-b238a799d3dc\\\" source=\\\"45e38f3a-a7c3-4de7-b3dc-589361d793fd\\\" target=\\\"9f3ea7fc-16d3-4d36-97eb-66f8808425cc\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"2705\\\" y=\\\"496.72445181903566\\\" />\\n              <mxPoint x=\\\"2705\\\" y=\\\"355.4044689729772\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <UserObject label=\\\"notificationUtils.js\\\" value=\\\"notificationUtils.js\\\" id=\\\"4940977f-933d-4bbc-b19e-749647b44d25\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e5cbcb\\\" vertex=\\\"1\\\" parent=\\\"1670815f-860d-4ea4-92e1-b238a799d3dc\\\">\\n            <mxGeometry x=\\\"2830\\\" y=\\\"511.7244518190359\\\" width=\\\"320\\\" height=\\\"230\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Automated Check: Evaluate Data Against Thresholds - notificationUtils.js:L95-109\\\" value=\\\"Automated Check: Evaluate Data Against Thresholds - notificationUtils.js:L95-109\\\" id=\\\"d4f48f1a-61de-4cde-87d2-4b5215464899\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"4940977f-933d-4bbc-b19e-749647b44d25\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <mxCell id=\\\"a64547c9-d9e6-4941-8e5e-f49add06516b\\\" value=\\\"Automated Check:&#xa;Data Received&#xa;from Capture&#xa;Agent\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=20;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"1670815f-860d-4ea4-92e1-b238a799d3dc\\\" source=\\\"4c47b5f2-5363-4816-9745-30e61d184c7a\\\" target=\\\"c1bf10c9-8c1a-44f4-8e23-39708f0301e8\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"2205\\\" y=\\\"836.3334338431989\\\" />\\n              <mxPoint x=\\\"2205\\\" y=\\\"626.7244518190348\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <mxCell id=\\\"7a250d09-50c6-4935-b10c-626b0ebe1fba\\\" value=\\\"Automated Check:&#xa;Pass Data&#xa;for Alert&#xa;Evaluation\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=10;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"1670815f-860d-4ea4-92e1-b238a799d3dc\\\" source=\\\"c1bf10c9-8c1a-44f4-8e23-39708f0301e8\\\" target=\\\"d4f48f1a-61de-4cde-87d2-4b5215464899\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\" />\\n          </mxGeometry>\\n        </mxCell>\\n        <UserObject label=\\\"v2\\\" value=\\\"v2\\\" id=\\\"feefae96-61b8-4ac5-a37c-592ed4b2330e\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#efdfdf\\\" vertex=\\\"1\\\" parent=\\\"99e9b746-7809-41f4-a433-1de7cc90574b\\\">\\n            <mxGeometry x=\\\"637.5\\\" y=\\\"70\\\" width=\\\"2690\\\" height=\\\"780\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"infrastructure\\\" value=\\\"infrastructure\\\" id=\\\"3f8ff792-40c8-4ae6-9af5-ff8b90da2f9f\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#ead5d5\\\" vertex=\\\"1\\\" parent=\\\"feefae96-61b8-4ac5-a37c-592ed4b2330e\\\">\\n            <mxGeometry x=\\\"95\\\" y=\\\"70\\\" width=\\\"1290\\\" height=\\\"640\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"JobGenerator.ts\\\" value=\\\"JobGenerator.ts\\\" id=\\\"159e569d-31d8-4883-b443-4ec08b21a044\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e5cbcb\\\" vertex=\\\"1\\\" parent=\\\"3f8ff792-40c8-4ae6-9af5-ff8b90da2f9f\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"640\\\" height=\\\"230\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Flow 2: Job Execution and Status Update - JobGenerator.ts:L43-66\\\" value=\\\"Flow 2: Job Execution and Status Update - JobGenerator.ts:L43-66\\\" id=\\\"28f1eabb-4f24-4944-8a0a-04f41ceb8589\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"159e569d-31d8-4883-b443-4ec08b21a044\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Flow 2: Initiate Notification Handling - JobGenerator.ts:L61\\\" value=\\\"Flow 2: Initiate Notification Handling - JobGenerator.ts:L61\\\" id=\\\"31fe5a28-0640-4b52-841b-dd02e2ae646e\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"159e569d-31d8-4883-b443-4ec08b21a044\\\">\\n            <mxGeometry x=\\\"390\\\" y=\\\"70\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <mxCell id=\\\"50797935-1447-47a4-891b-9e886e5601fa\\\" value=\\\"Flow 2:&#xa;Status Change&#xa;Detected\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=11;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"159e569d-31d8-4883-b443-4ec08b21a044\\\" source=\\\"28f1eabb-4f24-4944-8a0a-04f41ceb8589\\\" target=\\\"31fe5a28-0640-4b52-841b-dd02e2ae646e\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\" />\\n          </mxGeometry>\\n        </mxCell>\\n        <UserObject label=\\\"NotificationService.ts\\\" value=\\\"NotificationService.ts\\\" id=\\\"c6d9907f-0a05-4153-a27f-47c3a1c4c0aa\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e5cbcb\\\" vertex=\\\"1\\\" parent=\\\"3f8ff792-40c8-4ae6-9af5-ff8b90da2f9f\\\">\\n            <mxGeometry x=\\\"900\\\" y=\\\"72.47267784570195\\\" width=\\\"320\\\" height=\\\"230\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Flow 2: Dispatch Alerts - NotificationService.ts:L28-57\\\" value=\\\"Flow 2: Dispatch Alerts - NotificationService.ts:L28-57\\\" id=\\\"78e5cb9f-6a97-4d31-a487-fe7dbce5d7d1\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"c6d9907f-0a05-4153-a27f-47c3a1c4c0aa\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <mxCell id=\\\"c778c6b9-c12e-45c0-8682-2c9e892867b0\\\" value=\\\"Flow 2:&#xa;Monitor Data&#xa;Passed to&#xa;Notification Service\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=13;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"3f8ff792-40c8-4ae6-9af5-ff8b90da2f9f\\\" source=\\\"31fe5a28-0640-4b52-841b-dd02e2ae646e\\\" target=\\\"78e5cb9f-6a97-4d31-a487-fe7dbce5d7d1\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"775\\\" y=\\\"184.99999999999955\\\" />\\n              <mxPoint x=\\\"775\\\" y=\\\"187.4726778457015\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <UserObject label=\\\"NetworkService.ts\\\" value=\\\"NetworkService.ts\\\" id=\\\"50aeed0b-bc13-43f7-bb15-cb1b12b2caa7\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e5cbcb\\\" vertex=\\\"1\\\" parent=\\\"3f8ff792-40c8-4ae6-9af5-ff8b90da2f9f\\\">\\n            <mxGeometry x=\\\"242.5\\\" y=\\\"340\\\" width=\\\"320\\\" height=\\\"230\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Backend Requests PageSpeed Analysis - NetworkService.ts:L129-162\\\" value=\\\"Backend Requests PageSpeed Analysis - NetworkService.ts:L129-162\\\" id=\\\"6527fb47-157e-4bba-9aed-adde061c5689\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"50aeed0b-bc13-43f7-bb15-cb1b12b2caa7\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"business\\\" value=\\\"business\\\" id=\\\"7ef79284-534a-466f-a1f1-4e3a2f56be9d\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#ead5d5\\\" vertex=\\\"1\\\" parent=\\\"feefae96-61b8-4ac5-a37c-592ed4b2330e\\\">\\n            <mxGeometry x=\\\"1575\\\" y=\\\"320.89208395118175\\\" width=\\\"1020\\\" height=\\\"371.82353877857975\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"CheckService.ts\\\" value=\\\"CheckService.ts\\\" id=\\\"f0ebd5da-21bb-4d96-8ff9-ca10409acc80\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e5cbcb\\\" vertex=\\\"1\\\" parent=\\\"7ef79284-534a-466f-a1f1-4e3a2f56be9d\\\">\\n            <mxGeometry x=\\\"95\\\" y=\\\"70\\\" width=\\\"320\\\" height=\\\"230\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Backend Processes Lighthouse Data - CheckService.ts:L82-102\\\" value=\\\"Backend Processes Lighthouse Data - CheckService.ts:L82-102\\\" id=\\\"f89cbd87-c961-4f8b-92b6-714da57718d5\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"f0ebd5da-21bb-4d96-8ff9-ca10409acc80\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"MonitorService.ts\\\" value=\\\"MonitorService.ts\\\" id=\\\"7a3824cd-24c8-4b32-8b1d-e0bf357262c4\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e5cbcb\\\" vertex=\\\"1\\\" parent=\\\"7ef79284-534a-466f-a1f1-4e3a2f56be9d\\\">\\n            <mxGeometry x=\\\"605\\\" y=\\\"71.82353877857976\\\" width=\\\"320\\\" height=\\\"230\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Backend Aggregates Performance Data - MonitorService.ts:L106-120\\\" value=\\\"Backend Aggregates Performance Data - MonitorService.ts:L106-120\\\" id=\\\"ca6ee27b-1fbf-49de-978a-d6de259cc3d5\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"7a3824cd-24c8-4b32-8b1d-e0bf357262c4\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <mxCell id=\\\"27c7191b-80a2-475b-9371-e106108aff1c\\\" value=\\\"Store Processed&#xa;Check Data\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=12;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"7ef79284-534a-466f-a1f1-4e3a2f56be9d\\\" source=\\\"f89cbd87-c961-4f8b-92b6-714da57718d5\\\" target=\\\"ca6ee27b-1fbf-49de-978a-d6de259cc3d5\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"480\\\" y=\\\"184.9999999999996\\\" />\\n              <mxPoint x=\\\"480\\\" y=\\\"186.82353877857938\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <mxCell id=\\\"0d3c8091-3d91-4e42-9b46-7e35ed726a7a\\\" value=\\\"Google PageSpeed&#xa;API Response\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=19;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"feefae96-61b8-4ac5-a37c-592ed4b2330e\\\" source=\\\"6527fb47-157e-4bba-9aed-adde061c5689\\\" target=\\\"f89cbd87-c961-4f8b-92b6-714da57718d5\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"870\\\" y=\\\"525.0000000000007\\\" />\\n              <mxPoint x=\\\"870\\\" y=\\\"514.7492296053547\\\" />\\n              <mxPoint x=\\\"1450\\\" y=\\\"514.7492296053547\\\" />\\n              <mxPoint x=\\\"1450\\\" y=\\\"505.8920839511823\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <UserObject label=\\\"db\\\" value=\\\"db\\\" id=\\\"15ee5d81-a0cf-4614-80b8-7a1123ab20b8\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#f4e9e9\\\" vertex=\\\"1\\\" parent=\\\"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\\\">\\n            <mxGeometry x=\\\"3155\\\" y=\\\"7169.877276344534\\\" width=\\\"1470\\\" height=\\\"2919.9964800702883\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"v1\\\" value=\\\"v1\\\" id=\\\"58c5a3fd-1e69-4ca4-a64e-314f5644bdaf\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#efdfdf\\\" vertex=\\\"1\\\" parent=\\\"15ee5d81-a0cf-4614-80b8-7a1123ab20b8\\\">\\n            <mxGeometry x=\\\"175\\\" y=\\\"619.9964800702883\\\" width=\\\"1120\\\" height=\\\"2230\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"modules\\\" value=\\\"modules\\\" id=\\\"82cb3dbe-c922-438a-a912-255376f4b380\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#ead5d5\\\" vertex=\\\"1\\\" parent=\\\"58c5a3fd-1e69-4ca4-a64e-314f5644bdaf\\\">\\n            <mxGeometry x=\\\"175\\\" y=\\\"70\\\" width=\\\"770\\\" height=\\\"2090\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"monitorModule.js\\\" value=\\\"monitorModule.js\\\" id=\\\"630b3ece-2648-48d5-99b5-ef9611de2ad5\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e5cbcb\\\" vertex=\\\"1\\\" parent=\\\"82cb3dbe-c922-438a-a912-255376f4b380\\\">\\n            <mxGeometry x=\\\"195\\\" y=\\\"740\\\" width=\\\"480\\\" height=\\\"490\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Uptime Monitor Creation: Save Monitor to Database - monitorModule.js:L454-455\\\" value=\\\"Uptime Monitor Creation: Save Monitor to Database - monitorModule.js:L454-455\\\" id=\\\"2d407bfd-e4b0-46b8-99e7-121c507d525f\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"630b3ece-2648-48d5-99b5-ef9611de2ad5\\\">\\n            <mxGeometry x=\\\"150\\\" y=\\\"200\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Backend: Aggregate Historical Data - monitorModule.js:L312-322\\\" value=\\\"Backend: Aggregate Historical Data - monitorModule.js:L312-322\\\" id=\\\"9ef7c423-f4fc-4caf-9bf5-c1aa3002ca03\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"630b3ece-2648-48d5-99b5-ef9611de2ad5\\\">\\n            <mxGeometry x=\\\"150\\\" y=\\\"330\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Flow 1: CSV Import - Database Bulk Save - monitorModule.js:L465-468\\\" value=\\\"Flow 1: CSV Import - Database Bulk Save - monitorModule.js:L465-468\\\" id=\\\"d9d519af-5c4d-4494-929e-a869581c1dc4\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"630b3ece-2648-48d5-99b5-ef9611de2ad5\\\">\\n            <mxGeometry x=\\\"150\\\" y=\\\"70\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"monitorModuleQueries.js\\\" value=\\\"monitorModuleQueries.js\\\" id=\\\"a0b22a5a-59e1-47e3-8218-a4ad083b1b71\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"82cb3dbe-c922-438a-a912-255376f4b380\\\">\\n            <mxGeometry x=\\\"345\\\" y=\\\"1270\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"notificationModule.js\\\" value=\\\"notificationModule.js\\\" id=\\\"62daeac4-9402-448a-972c-cb8cb760671c\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e5cbcb\\\" vertex=\\\"1\\\" parent=\\\"82cb3dbe-c922-438a-a912-255376f4b380\\\">\\n            <mxGeometry x=\\\"275\\\" y=\\\"70\\\" width=\\\"320\\\" height=\\\"230\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Flow 1: Database Insertion - notificationModule.js:L10-13\\\" value=\\\"Flow 1: Database Insertion - notificationModule.js:L10-13\\\" id=\\\"4a796ccf-40a9-4446-a109-6a6eed52e898\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"62daeac4-9402-448a-972c-cb8cb760671c\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"statusPageModule.js\\\" value=\\\"statusPageModule.js\\\" id=\\\"f8541fe3-4bcf-4833-a226-66b5301adf58\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e5cbcb\\\" vertex=\\\"1\\\" parent=\\\"82cb3dbe-c922-438a-a912-255376f4b380\\\">\\n            <mxGeometry x=\\\"275\\\" y=\\\"1660.0000000000002\\\" width=\\\"320\\\" height=\\\"360\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Create Status Page: Database Record Creation - statusPageModule.js:L14-34\\\" value=\\\"Create Status Page: Database Record Creation - statusPageModule.js:L14-34\\\" id=\\\"e234917e-a950-48f5-b864-cd957b2216e1\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"f8541fe3-4bcf-4833-a226-66b5301adf58\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"200\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"View Status Page: Database Record Retrieval - statusPageModule.js:L89-299\\\" value=\\\"View Status Page: Database Record Retrieval - statusPageModule.js:L89-299\\\" id=\\\"26da60f9-dde4-44ec-be89-91858cc14f90\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"f8541fe3-4bcf-4833-a226-66b5301adf58\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"checkModule.js\\\" value=\\\"checkModule.js\\\" id=\\\"860b5eec-a1ce-4e1f-a316-e1586f03af96\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=16;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"82cb3dbe-c922-438a-a912-255376f4b380\\\">\\n            <mxGeometry x=\\\"345\\\" y=\\\"1400\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"maintenanceWindowModule.js\\\" value=\\\"maintenanceWindowModule.js\\\" id=\\\"95ed6c41-ebeb-4c08-98c3-bab8b426789e\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e5cbcb\\\" vertex=\\\"1\\\" parent=\\\"82cb3dbe-c922-438a-a912-255376f4b380\\\">\\n            <mxGeometry x=\\\"275\\\" y=\\\"340.0000000000001\\\" width=\\\"320\\\" height=\\\"360\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Flow: Create Maintenance Window - Database Record Creation - maintenanceWindowModule.js:L7-22\\\" value=\\\"Flow: Create Maintenance Window - Database Record Creation - maintenanceWindowModule.js:L7-22\\\" id=\\\"3890b98d-a133-4279-a961-5d2facc6a17a\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"95ed6c41-ebeb-4c08-98c3-bab8b426789e\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Flow: View Maintenance Windows - Data Retrieval - maintenanceWindowModule.js:L37-66\\\" value=\\\"Flow: View Maintenance Windows - Data Retrieval - maintenanceWindowModule.js:L37-66\\\" id=\\\"27d9160a-4f8d-4dff-a09b-1678bc28cf2c\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"95ed6c41-ebeb-4c08-98c3-bab8b426789e\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"200\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"inviteModule.js\\\" value=\\\"inviteModule.js\\\" id=\\\"08853f8a-f596-4df0-9190-dad04f54caef\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=16;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"82cb3dbe-c922-438a-a912-255376f4b380\\\">\\n            <mxGeometry x=\\\"345\\\" y=\\\"1530.0000000000002\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"v2\\\" value=\\\"v2\\\" id=\\\"e2f99143-54b7-44dc-b566-1c2fb901bd16\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#efdfdf\\\" vertex=\\\"1\\\" parent=\\\"15ee5d81-a0cf-4614-80b8-7a1123ab20b8\\\">\\n            <mxGeometry x=\\\"435\\\" y=\\\"70\\\" width=\\\"600\\\" height=\\\"510\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"models\\\" value=\\\"models\\\" id=\\\"b53384d7-b989-4ac7-bd68-1c3621174ef4\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#ead5d5\\\" vertex=\\\"1\\\" parent=\\\"e2f99143-54b7-44dc-b566-1c2fb901bd16\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"460\\\" height=\\\"370\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"checks\\\" value=\\\"checks\\\" id=\\\"64e3bb0a-67f5-4269-9e7d-94fe91ac78fc\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#e5cbcb\\\" vertex=\\\"1\\\" parent=\\\"b53384d7-b989-4ac7-bd68-1c3621174ef4\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"320\\\" height=\\\"230\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Check.ts\\\" value=\\\"Check.ts\\\" id=\\\"1425ec43-f0f4-4c8b-a140-176c079219d6\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=16;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"64e3bb0a-67f5-4269-9e7d-94fe91ac78fc\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <mxCell id=\\\"a6bccd1d-4272-4df7-a7c8-b3979e37b8d7\\\" value=\\\"Uptime Monitor&#xa;Creation: Service&#xa;to DB&#xa;Module\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=20;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\\\" source=\\\"f0409948-75dc-457f-a02d-6b9774258e48\\\" target=\\\"2d407bfd-e4b0-46b8-99e7-121c507d525f\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"2235\\\" y=\\\"4524.569505991416\\\" />\\n              <mxPoint x=\\\"2235\\\" y=\\\"4531.485617898687\\\" />\\n              <mxPoint x=\\\"3060\\\" y=\\\"4531.485617898688\\\" />\\n              <mxPoint x=\\\"3060\\\" y=\\\"8628.807803864096\\\" />\\n              <mxPoint x=\\\"3615\\\" y=\\\"8628.807803864096\\\" />\\n              <mxPoint x=\\\"3615\\\" y=\\\"8844.873756414821\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <mxCell id=\\\"de320ac1-0949-4297-be7c-b9d7a14e0fec\\\" value=\\\"Uptime Monitor&#xa;Creation: Service&#xa;to Job&#xa;Queue\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=20;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\\\" source=\\\"2d407bfd-e4b0-46b8-99e7-121c507d525f\\\" target=\\\"51e8db5f-2fdd-4ddc-9605-43981db9d940\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"4710\\\" y=\\\"8844.873756414821\\\" />\\n              <mxPoint x=\\\"4710\\\" y=\\\"6114.195094447705\\\" />\\n              <mxPoint x=\\\"5410\\\" y=\\\"6114.195094447705\\\" />\\n              <mxPoint x=\\\"5410\\\" y=\\\"6113.543842501334\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <mxCell id=\\\"7b9ebb0e-a6b2-438c-bfed-9c851a1bccbc\\\" value=\\\"Flow 1:&#xa;Controller to&#xa;Database Module\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=20;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\\\" source=\\\"d0a4737f-715f-4f50-b6d5-5e4b31f86f93\\\" target=\\\"4a796ccf-40a9-4446-a109-6a6eed52e898\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"3070\\\" y=\\\"2382.080243026038\\\" />\\n              <mxPoint x=\\\"3070\\\" y=\\\"8374.927415709848\\\" />\\n              <mxPoint x=\\\"3440\\\" y=\\\"8374.927415709852\\\" />\\n              <mxPoint x=\\\"3440\\\" y=\\\"8374.72873228434\\\" />\\n              <mxPoint x=\\\"3615\\\" y=\\\"8374.728732284339\\\" />\\n              <mxPoint x=\\\"3615\\\" y=\\\"8044.873756414823\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <mxCell id=\\\"279155cd-ff31-41a2-8f5f-a538f01bfa66\\\" value=\\\"Flow 1:&#xa;User Clicks&#xa;Test Notification&#xa;Button\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=20;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\\\" source=\\\"4a796ccf-40a9-4446-a109-6a6eed52e898\\\" target=\\\"29c2c56e-9dc0-4304-bfbf-e0c0f8915a39\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"4340\\\" y=\\\"8044.873756414824\\\" />\\n              <mxPoint x=\\\"4340\\\" y=\\\"8045.348182370847\\\" />\\n              <mxPoint x=\\\"4515\\\" y=\\\"8045.348182370847\\\" />\\n              <mxPoint x=\\\"4515\\\" y=\\\"8045.856372136517\\\" />\\n              <mxPoint x=\\\"4690\\\" y=\\\"8045.856372136516\\\" />\\n              <mxPoint x=\\\"4690\\\" y=\\\"2817.080243026039\\\" />\\n              <mxPoint x=\\\"150\\\" y=\\\"2817.080243026039\\\" />\\n              <mxPoint x=\\\"150\\\" y=\\\"2512.080243026039\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <mxCell id=\\\"57018b30-e2f4-4eb2-a1da-fe75afbb8c2f\\\" value=\\\"Flow 1:&#xa;Controller to&#xa;Notification Service\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=20;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\\\" source=\\\"29c2c56e-9dc0-4304-bfbf-e0c0f8915a39\\\" target=\\\"1cc01e08-4a6c-4526-b8a7-5ee8a06c1709\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"4730\\\" y=\\\"2512.0802430260383\\\" />\\n              <mxPoint x=\\\"4730\\\" y=\\\"5359.75177111986\\\" />\\n              <mxPoint x=\\\"4945\\\" y=\\\"5359.75177111986\\\" />\\n              <mxPoint x=\\\"4945\\\" y=\\\"5360.025735259062\\\" />\\n              <mxPoint x=\\\"5140\\\" y=\\\"5360.0257352590625\\\" />\\n              <mxPoint x=\\\"5140\\\" y=\\\"5877.543842501334\\\" />\\n              <mxPoint x=\\\"7910\\\" y=\\\"5877.543842501334\\\" />\\n              <mxPoint x=\\\"7910\\\" y=\\\"6032.948311474312\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <mxCell id=\\\"a3f28fa6-8268-4c13-95a0-83e3b1abdcb0\\\" value=\\\"Create Status&#xa;Page: Data&#xa;Passed to&#xa;Controller\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=20;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\\\" source=\\\"3efddcad-588f-4492-9808-b0c81c823c96\\\" target=\\\"f15ef77e-380f-4768-98cb-7f0dd4113841\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"1360\\\" y=\\\"1168.0000000000002\\\" />\\n              <mxPoint x=\\\"1360\\\" y=\\\"5260.158205581436\\\" />\\n              <mxPoint x=\\\"1575\\\" y=\\\"5260.158205581437\\\" />\\n              <mxPoint x=\\\"1575\\\" y=\\\"5260.184142035576\\\" />\\n              <mxPoint x=\\\"1750\\\" y=\\\"5260.184142035575\\\" />\\n              <mxPoint x=\\\"1750\\\" y=\\\"5844.569505991417\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <mxCell id=\\\"9735611c-924b-49aa-92e8-10d8a86ac288\\\" value=\\\"Create Status&#xa;Page: Data&#xa;Sent to&#xa;DB Module\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=20;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\\\" source=\\\"f15ef77e-380f-4768-98cb-7f0dd4113841\\\" target=\\\"e234917e-a950-48f5-b864-cd957b2216e1\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"3030\\\" y=\\\"5844.569505991416\\\" />\\n              <mxPoint x=\\\"3030\\\" y=\\\"9444.519537302771\\\" />\\n              <mxPoint x=\\\"3265\\\" y=\\\"9444.519537302771\\\" />\\n              <mxPoint x=\\\"3265\\\" y=\\\"9444.930291378314\\\" />\\n              <mxPoint x=\\\"3440\\\" y=\\\"9444.930291378314\\\" />\\n              <mxPoint x=\\\"3440\\\" y=\\\"9445.307233312164\\\" />\\n              <mxPoint x=\\\"3615\\\" y=\\\"9445.307233312164\\\" />\\n              <mxPoint x=\\\"3615\\\" y=\\\"9764.873756414821\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <mxCell id=\\\"40cb7d7b-2888-44de-bb7d-7735af70ba34\\\" value=\\\"Create Status&#xa;Page: Database&#xa;Result Returned\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=20;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\\\" source=\\\"e234917e-a950-48f5-b864-cd957b2216e1\\\" target=\\\"058ded1f-83ce-40a7-a99d-d178c81fe557\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"4700\\\" y=\\\"9764.873756414821\\\" />\\n              <mxPoint x=\\\"4700\\\" y=\\\"10393.873756414825\\\" />\\n              <mxPoint x=\\\"1320\\\" y=\\\"10393.873756414825\\\" />\\n              <mxPoint x=\\\"1320\\\" y=\\\"5961.8495281381365\\\" />\\n              <mxPoint x=\\\"1575\\\" y=\\\"5961.8495281381365\\\" />\\n              <mxPoint x=\\\"1575\\\" y=\\\"5962.048397924002\\\" />\\n              <mxPoint x=\\\"1790\\\" y=\\\"5962.048397924001\\\" />\\n              <mxPoint x=\\\"1790\\\" y=\\\"5974.569505991414\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <mxCell id=\\\"5735f30c-b55f-444a-9236-f3d75f68ed27\\\" value=\\\"View Status&#xa;Page: Data&#xa;Passed to&#xa;Controller\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=20;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\\\" source=\\\"2e26cd2f-1413-4c16-8e63-ea7808ab6c52\\\" target=\\\"9f217674-4cd7-4ef8-b088-d5620042a7ba\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"960\\\" y=\\\"1038.0000000000005\\\" />\\n              <mxPoint x=\\\"960\\\" y=\\\"1038.6171567592999\\\" />\\n              <mxPoint x=\\\"1135\\\" y=\\\"1038.6171567593005\\\" />\\n              <mxPoint x=\\\"1135\\\" y=\\\"1039.2589018709534\\\" />\\n              <mxPoint x=\\\"1370\\\" y=\\\"1039.2589018709525\\\" />\\n              <mxPoint x=\\\"1370\\\" y=\\\"5250.158205581436\\\" />\\n              <mxPoint x=\\\"1575\\\" y=\\\"5250.158205581437\\\" />\\n              <mxPoint x=\\\"1575\\\" y=\\\"5250.184142035576\\\" />\\n              <mxPoint x=\\\"1790\\\" y=\\\"5250.184142035575\\\" />\\n              <mxPoint x=\\\"1790\\\" y=\\\"5715.094156731092\\\" />\\n              <mxPoint x=\\\"2095\\\" y=\\\"5715.094156731093\\\" />\\n              <mxPoint x=\\\"2095\\\" y=\\\"5714.569505991418\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <mxCell id=\\\"dace45d6-fb25-4dae-b940-49ef7d77bbed\\\" value=\\\"View Status&#xa;Page: URL&#xa;Sent to&#xa;DB Module\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=20;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\\\" source=\\\"9f217674-4cd7-4ef8-b088-d5620042a7ba\\\" target=\\\"26da60f9-dde4-44ec-be89-91858cc14f90\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"2355\\\" y=\\\"5714.569505991416\\\" />\\n              <mxPoint x=\\\"2355\\\" y=\\\"5715.2411107154\\\" />\\n              <mxPoint x=\\\"3040\\\" y=\\\"5715.2411107154\\\" />\\n              <mxPoint x=\\\"3040\\\" y=\\\"9434.519537302771\\\" />\\n              <mxPoint x=\\\"3265\\\" y=\\\"9434.519537302771\\\" />\\n              <mxPoint x=\\\"3265\\\" y=\\\"9434.930291378314\\\" />\\n              <mxPoint x=\\\"3440\\\" y=\\\"9434.930291378314\\\" />\\n              <mxPoint x=\\\"3440\\\" y=\\\"9435.307233312164\\\" />\\n              <mxPoint x=\\\"3635\\\" y=\\\"9435.307233312164\\\" />\\n              <mxPoint x=\\\"3635\\\" y=\\\"9634.873756414821\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <mxCell id=\\\"137a5ab7-1e49-42ec-869d-58f7f2380cb3\\\" value=\\\"View Status&#xa;Page: Database&#xa;Result Returned\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=20;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\\\" source=\\\"26da60f9-dde4-44ec-be89-91858cc14f90\\\" target=\\\"d76e70e0-41f9-46cc-b775-b2027c5a0d5b\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"4690\\\" y=\\\"9634.873756414821\\\" />\\n              <mxPoint x=\\\"4690\\\" y=\\\"10292.873756414823\\\" />\\n              <mxPoint x=\\\"1400\\\" y=\\\"10292.873756414823\\\" />\\n              <mxPoint x=\\\"1400\\\" y=\\\"6104.569505991416\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <mxCell id=\\\"839ba9f6-8a34-4919-a04a-13fba1795c61\\\" value=\\\"Forward Request&#xa;to Service&#xa;Layer\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=20;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\\\" source=\\\"cdd090be-0b62-45b4-baa0-fec01fc3ffd1\\\" target=\\\"499b46a2-f2a2-4ccd-aecd-012eade2bd23\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"4740\\\" y=\\\"2103.7525647938664\\\" />\\n              <mxPoint x=\\\"4740\\\" y=\\\"4757.859144892351\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <mxCell id=\\\"42d3bc70-701a-4be0-96b4-d6c2f0519b49\\\" value=\\\"Execute Database&#xa;Query\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=20;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\\\" source=\\\"499b46a2-f2a2-4ccd-aecd-012eade2bd23\\\" target=\\\"14df9f01-1358-442d-96f5-eab9a4c4abbf\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"8865\\\" y=\\\"4757.859144892351\\\" />\\n              <mxPoint x=\\\"8865\\\" y=\\\"2919.0802430260383\\\" />\\n              <mxPoint x=\\\"1400\\\" y=\\\"2919.0802430260383\\\" />\\n              <mxPoint x=\\\"1400\\\" y=\\\"3881.4628483747547\\\" />\\n              <mxPoint x=\\\"1575\\\" y=\\\"3881.4628483747556\\\" />\\n              <mxPoint x=\\\"1575\\\" y=\\\"3881.1223003767236\\\" />\\n              <mxPoint x=\\\"1750\\\" y=\\\"3881.1223003767227\\\" />\\n              <mxPoint x=\\\"1750\\\" y=\\\"3864.569505991416\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <UserObject label=\\\"config\\\" value=\\\"config\\\" id=\\\"fe47576c-c186-4950-82a5-b2fd24eb2561\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#f4e9e9\\\" vertex=\\\"1\\\" parent=\\\"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\\\">\\n            <mxGeometry x=\\\"475\\\" y=\\\"2867.0802430260387\\\" width=\\\"510\\\" height=\\\"370\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"routes.js\\\" value=\\\"routes.js\\\" id=\\\"cb53d612-9b89-47da-911c-165d0382a7d8\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#efdfdf\\\" vertex=\\\"1\\\" parent=\\\"fe47576c-c186-4950-82a5-b2fd24eb2561\\\">\\n            <mxGeometry x=\\\"95\\\" y=\\\"70\\\" width=\\\"320\\\" height=\\\"230\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Flow: Create Maintenance Window - API Routing - routes.js:L43\\\" value=\\\"Flow: Create Maintenance Window - API Routing - routes.js:L43\\\" id=\\\"a391e8ea-9dbe-4fe4-90df-bf475d8b7ef8\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"cb53d612-9b89-47da-911c-165d0382a7d8\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <mxCell id=\\\"e2588541-3ffc-47c6-8f8a-41d30ea7fc72\\\" value=\\\"Flow: Create&#xa;Maintenance Window&#xa;- Controller&#xa;Invocation\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=20;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\\\" source=\\\"a391e8ea-9dbe-4fe4-90df-bf475d8b7ef8\\\" target=\\\"0fae6e75-38ea-444d-a1bf-0f820ba443b9\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"1330\\\" y=\\\"3052.0802430260387\\\" />\\n              <mxPoint x=\\\"1330\\\" y=\\\"5314.569505991416\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <mxCell id=\\\"e1d59cf6-0d96-4e0a-ad17-2a7984a9157f\\\" value=\\\"Flow: Create&#xa;Maintenance Window&#xa;- Service&#xa;Layer Call\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=20;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\\\" source=\\\"0fae6e75-38ea-444d-a1bf-0f820ba443b9\\\" target=\\\"560d268b-ef0f-4cd2-bcfe-9dc0a0e2ce6f\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"4700\\\" y=\\\"5314.569505991416\\\" />\\n              <mxPoint x=\\\"4700\\\" y=\\\"5421.087017132046\\\" />\\n              <mxPoint x=\\\"6361.153846153846\\\" y=\\\"5421.0870171320485\\\" />\\n              <mxPoint x=\\\"6361.153846153846\\\" y=\\\"5561.0798590506\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <mxCell id=\\\"12d0ab8a-392f-48fa-9efa-06ffe1f3a252\\\" value=\\\"Flow: Create&#xa;Maintenance Window&#xa;- Database&#xa;Module Call\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=20;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\\\" source=\\\"560d268b-ef0f-4cd2-bcfe-9dc0a0e2ce6f\\\" target=\\\"3890b98d-a133-4279-a961-5d2facc6a17a\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"8865\\\" y=\\\"5561.0798590505965\\\" />\\n              <mxPoint x=\\\"8865\\\" y=\\\"7119.877276344532\\\" />\\n              <mxPoint x=\\\"3090\\\" y=\\\"7119.877276344532\\\" />\\n              <mxPoint x=\\\"3090\\\" y=\\\"8315.094700672267\\\" />\\n              <mxPoint x=\\\"3440\\\" y=\\\"8315.094700672269\\\" />\\n              <mxPoint x=\\\"3440\\\" y=\\\"8314.873756414821\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <mxCell id=\\\"c3127c74-43f1-42d7-8da6-b0a494c3658f\\\" value=\\\"Flow: View&#xa;Maintenance Windows&#xa;- Database&#xa;Query\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=20;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\\\" source=\\\"c35a065c-2808-402c-877e-9055d956ce0d\\\" target=\\\"27d9160a-4f8d-4dff-a09b-1678bc28cf2c\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"3050\\\" y=\\\"5444.569505991416\\\" />\\n              <mxPoint x=\\\"3050\\\" y=\\\"8638.807803864096\\\" />\\n              <mxPoint x=\\\"3625\\\" y=\\\"8638.807803864096\\\" />\\n              <mxPoint x=\\\"3625\\\" y=\\\"8444.873756414823\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <UserObject label=\\\"middleware\\\" value=\\\"middleware\\\" id=\\\"a968db5d-8f6d-4fd7-9df0-8b332b521703\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#f4e9e9\\\" vertex=\\\"1\\\" parent=\\\"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\\\">\\n            <mxGeometry x=\\\"3540\\\" y=\\\"121\\\" width=\\\"700\\\" height=\\\"510\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"v1\\\" value=\\\"v1\\\" id=\\\"09082f73-e215-465f-9206-0a963fb4c7cb\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#efdfdf\\\" vertex=\\\"1\\\" parent=\\\"a968db5d-8f6d-4fd7-9df0-8b332b521703\\\">\\n            <mxGeometry x=\\\"95\\\" y=\\\"70\\\" width=\\\"510\\\" height=\\\"370\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"isAllowed.js\\\" value=\\\"isAllowed.js\\\" id=\\\"001fa2e4-eadd-4474-b2ec-79d7ea43465f\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=9;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;align=left;verticalAlign=bottom;spacing=0;spacingTop=-14;spacingLeft=15;arcSize=4;labelPosition=center;verticalLabelPosition=top;;fillColor=#ead5d5\\\" vertex=\\\"1\\\" parent=\\\"09082f73-e215-465f-9206-0a963fb4c7cb\\\">\\n            <mxGeometry x=\\\"95\\\" y=\\\"70\\\" width=\\\"320\\\" height=\\\"230\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <UserObject label=\\\"Server: Role-Based Access Control Middleware - isAllowed.js:L39-44\\\" value=\\\"Server: Role-Based Access Control Middleware - isAllowed.js:L39-44\\\" id=\\\"8b3cb6c2-ed57-4510-be15-decb8e3c89e1\\\">\\n          <mxCell style=\\\"rounded=1;whiteSpace=wrap;html=1;container=1;glass=0;comic=0;fontSize=12;fontColor=#615B5B;strokeWidth=0.7;strokeColor=#999190;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontStyle=0;\\\" vertex=\\\"1\\\" parent=\\\"001fa2e4-eadd-4474-b2ec-79d7ea43465f\\\">\\n            <mxGeometry x=\\\"70\\\" y=\\\"70\\\" width=\\\"180\\\" height=\\\"90\\\" as=\\\"geometry\\\" />\\n          </mxCell>\\n        </UserObject>\\n        <mxCell id=\\\"2ee1c4e8-90fb-4470-ad9f-6ffed5420853\\\" value=\\\"Server: Forward&#xa;Request to&#xa;Controller\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=20;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\\\" source=\\\"8b3cb6c2-ed57-4510-be15-decb8e3c89e1\\\" target=\\\"ae858158-8db6-4917-8fda-0966a953f6ed\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"4760\\\" y=\\\"376.0000000000003\\\" />\\n              <mxPoint x=\\\"4760\\\" y=\\\"4246.375688501626\\\" />\\n              <mxPoint x=\\\"5120\\\" y=\\\"4246.375688501627\\\" />\\n              <mxPoint x=\\\"5120\\\" y=\\\"4222.985178140004\\\" />\\n              <mxPoint x=\\\"6351.153846153846\\\" y=\\\"4222.985178140003\\\" />\\n              <mxPoint x=\\\"6351.153846153846\\\" y=\\\"4217.08024302604\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <mxCell id=\\\"20d0e690-a569-4c6f-8238-916cac920553\\\" value=\\\"Flow 1:&#xa;CSV Import&#xa;- Route&#xa;to Controller\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=20;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\\\" source=\\\"c1ac3c26-996a-43ef-9c34-4c2776188784\\\" target=\\\"0e520a6d-34bf-467b-a894-e73979364478\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"1350\\\" y=\\\"1567.9999999999998\\\" />\\n              <mxPoint x=\\\"1350\\\" y=\\\"5270.158205581435\\\" />\\n              <mxPoint x=\\\"1575\\\" y=\\\"5270.158205581436\\\" />\\n              <mxPoint x=\\\"1575\\\" y=\\\"5270.184142035575\\\" />\\n              <mxPoint x=\\\"1760\\\" y=\\\"5270.184142035574\\\" />\\n              <mxPoint x=\\\"1760\\\" y=\\\"4654.569505991416\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <mxCell id=\\\"7292bf6e-431d-4a9d-94ce-2bcfabcaa79d\\\" value=\\\"Flow 1:&#xa;CSV Import&#xa;- Controller&#xa;to Service\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=20;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\\\" source=\\\"0e520a6d-34bf-467b-a894-e73979364478\\\" target=\\\"6139e487-1dd5-405a-ba7d-ededec4b282e\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"2235\\\" y=\\\"4654.569505991416\\\" />\\n              <mxPoint x=\\\"2235\\\" y=\\\"4647.937701543181\\\" />\\n              <mxPoint x=\\\"4720\\\" y=\\\"4647.937701543182\\\" />\\n              <mxPoint x=\\\"4720\\\" y=\\\"5369.751771119861\\\" />\\n              <mxPoint x=\\\"4945\\\" y=\\\"5369.751771119862\\\" />\\n              <mxPoint x=\\\"4945\\\" y=\\\"5370.025735259063\\\" />\\n              <mxPoint x=\\\"5120\\\" y=\\\"5370.025735259062\\\" />\\n              <mxPoint x=\\\"5120\\\" y=\\\"5028.562749012175\\\" />\\n              <mxPoint x=\\\"6616.153846153846\\\" y=\\\"5028.562749012175\\\" />\\n              <mxPoint x=\\\"6616.153846153846\\\" y=\\\"5027.859144892352\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <mxCell id=\\\"b55a0dc6-f596-4e5f-9265-63588b46b519\\\" value=\\\"Flow 1:&#xa;CSV Import&#xa;- Service&#xa;to Database&#xa;Module\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=20;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\\\" source=\\\"6139e487-1dd5-405a-ba7d-ededec4b282e\\\" target=\\\"d9d519af-5c4d-4494-929e-a869581c1dc4\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"6876.153846153846\\\" y=\\\"5027.859144892352\\\" />\\n              <mxPoint x=\\\"6876.153846153846\\\" y=\\\"5028.782680145156\\\" />\\n              <mxPoint x=\\\"8885\\\" y=\\\"5028.782680145156\\\" />\\n              <mxPoint x=\\\"8885\\\" y=\\\"7069.877276344534\\\" />\\n              <mxPoint x=\\\"3080\\\" y=\\\"7069.877276344534\\\" />\\n              <mxPoint x=\\\"3080\\\" y=\\\"8364.728732284337\\\" />\\n              <mxPoint x=\\\"3635\\\" y=\\\"8364.728732284335\\\" />\\n              <mxPoint x=\\\"3635\\\" y=\\\"8715.577360534644\\\" />\\n              <mxPoint x=\\\"3810\\\" y=\\\"8715.577360534648\\\" />\\n              <mxPoint x=\\\"3810\\\" y=\\\"8714.873756414825\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <mxCell id=\\\"f27c60ef-fb40-43e2-9750-c2617bdeaf43\\\" value=\\\"Flow 1:&#xa;CSV Import&#xa;- Database&#xa;to Service\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=20;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\\\" source=\\\"d9d519af-5c4d-4494-929e-a869581c1dc4\\\" target=\\\"1e1d975f-7f0f-4132-bd71-2563b35e99b3\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"4070\\\" y=\\\"8714.873756414823\\\" />\\n              <mxPoint x=\\\"4070\\\" y=\\\"8715.797291667628\\\" />\\n              <mxPoint x=\\\"4700\\\" y=\\\"8715.797291667626\\\" />\\n              <mxPoint x=\\\"4700\\\" y=\\\"5453.569410243563\\\" />\\n              <mxPoint x=\\\"5120\\\" y=\\\"5453.569410243565\\\" />\\n              <mxPoint x=\\\"5120\\\" y=\\\"5431.087017132048\\\" />\\n              <mxPoint x=\\\"6351.153846153846\\\" y=\\\"5431.087017132049\\\" />\\n              <mxPoint x=\\\"6351.153846153846\\\" y=\\\"5287.8591448923535\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <mxCell id=\\\"c449f81a-d6af-4f7a-b2d8-050a9a9ee0f9\\\" value=\\\"Flow 1:&#xa;CSV Import&#xa;- Service&#xa;to Controller\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=20;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\\\" source=\\\"1e1d975f-7f0f-4132-bd71-2563b35e99b3\\\" target=\\\"72b55fa1-d944-4e46-ac98-f6a6cb201afa\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"8895\\\" y=\\\"5287.859144892352\\\" />\\n              <mxPoint x=\\\"8895\\\" y=\\\"2868.080243026039\\\" />\\n              <mxPoint x=\\\"1390\\\" y=\\\"2868.080243026039\\\" />\\n              <mxPoint x=\\\"1390\\\" y=\\\"4394.600243246443\\\" />\\n              <mxPoint x=\\\"1975\\\" y=\\\"4394.600243246443\\\" />\\n              <mxPoint x=\\\"1975\\\" y=\\\"4394.569505991416\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <mxCell id=\\\"febea87e-5033-479c-ba7a-eb35d98db899\\\" value=\\\"Flow 2:&#xa;CSV Export&#xa;- Transmit&#xa;Request to&#xa;Server\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=20;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\\\" source=\\\"26d76516-fd7e-4ae8-956a-d077de4257fa\\\" target=\\\"a3106388-6a3d-4b68-a3fc-3761a0d54f98\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"1340\\\" y=\\\"1698.2471015249996\\\" />\\n              <mxPoint x=\\\"1340\\\" y=\\\"5280.184142035574\\\" />\\n              <mxPoint x=\\\"1770\\\" y=\\\"5280.184142035574\\\" />\\n              <mxPoint x=\\\"1770\\\" y=\\\"4784.569505991416\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <mxCell id=\\\"3e0f0966-5c2f-41af-9bcc-e8f615e03a00\\\" value=\\\"Flow 2:&#xa;CSV Export&#xa;- Controller&#xa;to Service\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=20;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\\\" source=\\\"a3106388-6a3d-4b68-a3fc-3761a0d54f98\\\" target=\\\"ab9cb862-0ac7-45a3-9888-f64e87bdda54\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"2235\\\" y=\\\"4784.569505991416\\\" />\\n              <mxPoint x=\\\"2235\\\" y=\\\"4764.389785187675\\\" />\\n              <mxPoint x=\\\"4710\\\" y=\\\"4764.389785187675\\\" />\\n              <mxPoint x=\\\"4710\\\" y=\\\"5380.0257352590625\\\" />\\n              <mxPoint x=\\\"5130\\\" y=\\\"5380.025735259062\\\" />\\n              <mxPoint x=\\\"5130\\\" y=\\\"5157.859144892351\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <mxCell id=\\\"ad300b1c-6748-40f9-a7c9-5895e0915991\\\" value=\\\"Flow 2:&#xa;CSV Export&#xa;- Service&#xa;to Controller\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=20;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\\\" source=\\\"ab9cb862-0ac7-45a3-9888-f64e87bdda54\\\" target=\\\"f151f89d-6399-48f0-aecd-5eb1572b48cc\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"8875\\\" y=\\\"5157.859144892352\\\" />\\n              <mxPoint x=\\\"8875\\\" y=\\\"10342.873756414825\\\" />\\n              <mxPoint x=\\\"1330\\\" y=\\\"10342.873756414825\\\" />\\n              <mxPoint x=\\\"1330\\\" y=\\\"5972.0483979240025\\\" />\\n              <mxPoint x=\\\"1780\\\" y=\\\"5972.0483979240025\\\" />\\n              <mxPoint x=\\\"1780\\\" y=\\\"4914.569505991417\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <mxCell id=\\\"b6d963d5-c613-407a-9ce9-60a04048dea7\\\" value=\\\"Uptime Monitor&#xa;Creation: API&#xa;Route to&#xa;Controller\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=20;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"1\\\" source=\\\"a30ac765-c546-4993-988e-8c8cfdb7532f\\\" target=\\\"f0409948-75dc-457f-a02d-6b9774258e48\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"5210\\\" y=\\\"5351.542220848844\\\" />\\n              <mxPoint x=\\\"5210\\\" y=\\\"1179.324416712935\\\" />\\n              <mxPoint x=\\\"5455\\\" y=\\\"1179.3244167129315\\\" />\\n              <mxPoint x=\\\"5455\\\" y=\\\"1179.0720525414708\\\" />\\n              <mxPoint x=\\\"5660\\\" y=\\\"1179.0720525414708\\\" />\\n              <mxPoint x=\\\"5660\\\" y=\\\"871.9999999999991\\\" />\\n              <mxPoint x=\\\"6900\\\" y=\\\"871.9999999999991\\\" />\\n              <mxPoint x=\\\"6900\\\" y=\\\"4664.569505991416\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <mxCell id=\\\"1c5c9857-bf32-40e4-921b-957c252dac2a\\\" value=\\\"API Call:&#xa;Submit Monitor&#xa;Configuration\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=20;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"1\\\" source=\\\"9651d084-5c16-4417-89c1-f52ae6572a95\\\" target=\\\"4c47b5f2-5363-4816-9745-30e61d184c7a\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"2937.5\\\" y=\\\"9353.865179846309\\\" />\\n              <mxPoint x=\\\"2937.5\\\" y=\\\"9354.70857742003\\\" />\\n              <mxPoint x=\\\"3690\\\" y=\\\"9354.708577420031\\\" />\\n              <mxPoint x=\\\"3690\\\" y=\\\"7888.852064767872\\\" />\\n              <mxPoint x=\\\"5260\\\" y=\\\"7888.8520647678715\\\" />\\n              <mxPoint x=\\\"5260\\\" y=\\\"5354.5219742643585\\\" />\\n              <mxPoint x=\\\"5455\\\" y=\\\"5354.5219742643585\\\" />\\n              <mxPoint x=\\\"5455\\\" y=\\\"5354.540704383867\\\" />\\n              <mxPoint x=\\\"5650\\\" y=\\\"5354.540704383866\\\" />\\n              <mxPoint x=\\\"5650\\\" y=\\\"10583.873756414823\\\" />\\n              <mxPoint x=\\\"10240\\\" y=\\\"10583.873756414823\\\" />\\n              <mxPoint x=\\\"10240\\\" y=\\\"6888.877276344531\\\" />\\n              <mxPoint x=\\\"12410\\\" y=\\\"6888.877276344533\\\" />\\n              <mxPoint x=\\\"12410\\\" y=\\\"6783.877276344533\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <mxCell id=\\\"3d357de8-9fd2-4d0b-9623-f36fce4cf1de\\\" value=\\\"Automated Check:&#xa;Generate Alert&#xa;Notification Content\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=20;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"1\\\" source=\\\"d4f48f1a-61de-4cde-87d2-4b5215464899\\\" target=\\\"801fe70a-1a19-406c-8f0d-770b0cb74409\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"14735\\\" y=\\\"6574.26829432037\\\" />\\n              <mxPoint x=\\\"14735\\\" y=\\\"11272.865179846314\\\" />\\n              <mxPoint x=\\\"170\\\" y=\\\"11272.865179846314\\\" />\\n              <mxPoint x=\\\"170\\\" y=\\\"10980.865179846314\\\" />\\n              <mxPoint x=\\\"1180\\\" y=\\\"10980.865179846314\\\" />\\n              <mxPoint x=\\\"1180\\\" y=\\\"8668.81532244953\\\" />\\n              <mxPoint x=\\\"1405\\\" y=\\\"8668.81532244953\\\" />\\n              <mxPoint x=\\\"1405\\\" y=\\\"8669.135157943725\\\" />\\n              <mxPoint x=\\\"1580\\\" y=\\\"8669.135157943725\\\" />\\n              <mxPoint x=\\\"1580\\\" y=\\\"10383.86517984631\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <mxCell id=\\\"00921831-b1d9-4a5a-ae6f-5ddee7cfc1e4\\\" value=\\\"API Call:&#xa;Request for&#xa;Historical Hardware&#xa;Data\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=20;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"1\\\" source=\\\"801fe70a-1a19-406c-8f0d-770b0cb74409\\\" target=\\\"9ef7c423-f4fc-4caf-9bf5-c1aa3002ca03\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"5160\\\" y=\\\"10383.86517984631\\\" />\\n              <mxPoint x=\\\"5160\\\" y=\\\"10685.873756414825\\\" />\\n              <mxPoint x=\\\"8550\\\" y=\\\"10685.873756414823\\\" />\\n              <mxPoint x=\\\"8550\\\" y=\\\"9595.307233312162\\\" />\\n              <mxPoint x=\\\"9145\\\" y=\\\"9595.307233312164\\\" />\\n              <mxPoint x=\\\"9145\\\" y=\\\"9114.873756414821\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <mxCell id=\\\"60308696-6f8a-43c8-b9a1-da199ef500cd\\\" value=\\\"API Response:&#xa;Send Aggregated&#xa;Data to&#xa;Frontend\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=20;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"1\\\" source=\\\"9ef7c423-f4fc-4caf-9bf5-c1aa3002ca03\\\" target=\\\"9ea2e32d-1ea8-42f2-9a17-613844723ae6\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"10250\\\" y=\\\"9114.873756414821\\\" />\\n              <mxPoint x=\\\"10250\\\" y=\\\"9430.294055596476\\\" />\\n              <mxPoint x=\\\"14715\\\" y=\\\"9430.294055596476\\\" />\\n              <mxPoint x=\\\"14715\\\" y=\\\"11422.865179846314\\\" />\\n              <mxPoint x=\\\"140\\\" y=\\\"11422.865179846314\\\" />\\n              <mxPoint x=\\\"140\\\" y=\\\"8650.390059635938\\\" />\\n              <mxPoint x=\\\"1170\\\" y=\\\"8650.390059635938\\\" />\\n              <mxPoint x=\\\"1170\\\" y=\\\"8648.815322449533\\\" />\\n              <mxPoint x=\\\"1405\\\" y=\\\"8648.815322449533\\\" />\\n              <mxPoint x=\\\"1405\\\" y=\\\"8649.135157943725\\\" />\\n              <mxPoint x=\\\"1620\\\" y=\\\"8649.135157943727\\\" />\\n              <mxPoint x=\\\"1620\\\" y=\\\"9974.729941001768\\\" />\\n              <mxPoint x=\\\"2087.5\\\" y=\\\"9974.729941001766\\\" />\\n              <mxPoint x=\\\"2087.5\\\" y=\\\"9973.86517984631\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <mxCell id=\\\"dc135d8d-0515-403d-ae58-f3c04647b2ae\\\" value=\\\"Flow 1:&#xa;HTTP POST&#xa;Request\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=20;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"1\\\" source=\\\"a07b805e-e55f-46cb-b54b-765b7813b0ca\\\" target=\\\"d0a4737f-715f-4f50-b6d5-5e4b31f86f93\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"4635\\\" y=\\\"8197.246623286177\\\" />\\n              <mxPoint x=\\\"4635\\\" y=\\\"8198.132006130314\\\" />\\n              <mxPoint x=\\\"5270\\\" y=\\\"8198.132006130312\\\" />\\n              <mxPoint x=\\\"5270\\\" y=\\\"5364.521974264361\\\" />\\n              <mxPoint x=\\\"5455\\\" y=\\\"5364.52197426436\\\" />\\n              <mxPoint x=\\\"5455\\\" y=\\\"5364.540704383869\\\" />\\n              <mxPoint x=\\\"5630\\\" y=\\\"5364.540704383868\\\" />\\n              <mxPoint x=\\\"5630\\\" y=\\\"2372.8227048507842\\\" />\\n              <mxPoint x=\\\"5845\\\" y=\\\"2372.822704850786\\\" />\\n              <mxPoint x=\\\"5845\\\" y=\\\"2373.254397966465\\\" />\\n              <mxPoint x=\\\"6030\\\" y=\\\"2373.2543979664642\\\" />\\n              <mxPoint x=\\\"6030\\\" y=\\\"2522.080243026039\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <mxCell id=\\\"d7faa713-4204-4a97-a172-d621da36c287\\\" value=\\\"Create Status&#xa;Page: API&#xa;Call to&#xa;Backend\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=20;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"1\\\" source=\\\"aa5d6d07-05f0-45f3-b19a-199af50e35f1\\\" target=\\\"3efddcad-588f-4492-9808-b0c81c823c96\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"3070\\\" y=\\\"1779.6070338202878\\\" />\\n              <mxPoint x=\\\"3070\\\" y=\\\"1780.2783715213561\\\" />\\n              <mxPoint x=\\\"3495\\\" y=\\\"1780.278371521355\\\" />\\n              <mxPoint x=\\\"3495\\\" y=\\\"2195.324558788448\\\" />\\n              <mxPoint x=\\\"3670\\\" y=\\\"2195.324558788448\\\" />\\n              <mxPoint x=\\\"3670\\\" y=\\\"2245.8755477247787\\\" />\\n              <mxPoint x=\\\"5180\\\" y=\\\"2245.8755477247814\\\" />\\n              <mxPoint x=\\\"5180\\\" y=\\\"1149.324416712933\\\" />\\n              <mxPoint x=\\\"5455\\\" y=\\\"1149.3244167129305\\\" />\\n              <mxPoint x=\\\"5455\\\" y=\\\"1149.0720525414697\\\" />\\n              <mxPoint x=\\\"5630\\\" y=\\\"1149.0720525414692\\\" />\\n              <mxPoint x=\\\"5630\\\" y=\\\"1307.9999999999984\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <mxCell id=\\\"c3f83811-8674-4dbb-9f84-79499f97fb1f\\\" value=\\\"Create Status&#xa;Page: UI&#xa;Receives Response&#xa;and Redirects\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=20;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"1\\\" source=\\\"058ded1f-83ce-40a7-a99d-d178c81fe557\\\" target=\\\"30aaee38-f509-4e19-a917-e6d2f4bba61c\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"8600\\\" y=\\\"6114.569505991415\\\" />\\n              <mxPoint x=\\\"8600\\\" y=\\\"7158.877276344534\\\" />\\n              <mxPoint x=\\\"14725\\\" y=\\\"7158.877276344533\\\" />\\n              <mxPoint x=\\\"14725\\\" y=\\\"11472.865179846314\\\" />\\n              <mxPoint x=\\\"130\\\" y=\\\"11472.865179846314\\\" />\\n              <mxPoint x=\\\"130\\\" y=\\\"5145.325785083434\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <mxCell id=\\\"ae1c9341-0e39-4d91-a9ac-5cc8a627c247\\\" value=\\\"View Status&#xa;Page: API&#xa;Call to&#xa;Backend\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=20;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"1\\\" source=\\\"ecfb2d04-2681-4f16-af75-632f69e1a868\\\" target=\\\"2e26cd2f-1413-4c16-8e63-ea7808ab6c52\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"3485\\\" y=\\\"2599.607033820288\\\" />\\n              <mxPoint x=\\\"3485\\\" y=\\\"2185.3245587884494\\\" />\\n              <mxPoint x=\\\"5170\\\" y=\\\"2185.3245587884485\\\" />\\n              <mxPoint x=\\\"5170\\\" y=\\\"1139.072052541469\\\" />\\n              <mxPoint x=\\\"5670\\\" y=\\\"1139.0720525414704\\\" />\\n              <mxPoint x=\\\"5670\\\" y=\\\"1178.8447807586938\\\" />\\n              <mxPoint x=\\\"5845\\\" y=\\\"1178.8447807586947\\\" />\\n              <mxPoint x=\\\"5845\\\" y=\\\"1178.3469678356034\\\" />\\n              <mxPoint x=\\\"6020\\\" y=\\\"1178.3469678356028\\\" />\\n              <mxPoint x=\\\"6020\\\" y=\\\"1177.9999999999998\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <mxCell id=\\\"04a33e4f-1dfe-4c5a-8b30-01ed0591c380\\\" value=\\\"View Status&#xa;Page: UI&#xa;Receives Data\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=20;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"1\\\" source=\\\"d76e70e0-41f9-46cc-b775-b2027c5a0d5b\\\" target=\\\"f59b91de-5196-4a43-9d57-3f28402c0672\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"8540\\\" y=\\\"6244.569505991416\\\" />\\n              <mxPoint x=\\\"8540\\\" y=\\\"10279.873756414823\\\" />\\n              <mxPoint x=\\\"14765\\\" y=\\\"10279.873756414821\\\" />\\n              <mxPoint x=\\\"14765\\\" y=\\\"11672.865179846314\\\" />\\n              <mxPoint x=\\\"90\\\" y=\\\"11672.865179846314\\\" />\\n              <mxPoint x=\\\"90\\\" y=\\\"311.9999999999991\\\" />\\n              <mxPoint x=\\\"1170\\\" y=\\\"312\\\" />\\n              <mxPoint x=\\\"1170\\\" y=\\\"2260.6612048679117\\\" />\\n              <mxPoint x=\\\"2081.666666666666\\\" y=\\\"2260.661204867912\\\" />\\n              <mxPoint x=\\\"2081.666666666666\\\" y=\\\"2259.6070338202894\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <mxCell id=\\\"2b8ae59e-ed8d-4837-9a9b-64eb480f982c\\\" value=\\\"API Request&#xa;for Check&#xa;History\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=20;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"1\\\" source=\\\"4a5847d0-91a0-4b4c-8517-2f4ff9a7e8d4\\\" target=\\\"cdd090be-0b62-45b4-baa0-fec01fc3ffd1\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"5280\\\" y=\\\"8597.246623286175\\\" />\\n              <mxPoint x=\\\"5280\\\" y=\\\"5374.540704383869\\\" />\\n              <mxPoint x=\\\"5640\\\" y=\\\"5374.540704383868\\\" />\\n              <mxPoint x=\\\"5640\\\" y=\\\"2383.2543979664624\\\" />\\n              <mxPoint x=\\\"6020\\\" y=\\\"2383.2543979664633\\\" />\\n              <mxPoint x=\\\"6020\\\" y=\\\"2243.7525647938674\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <mxCell id=\\\"6c5b028c-356c-43c8-a35a-b47448cd8695\\\" value=\\\"API Response&#xa;with Check&#xa;History\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=20;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"1\\\" source=\\\"14df9f01-1358-442d-96f5-eab9a4c4abbf\\\" target=\\\"ceb9cda3-968d-44aa-b223-49902adb93b4\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"8170\\\" y=\\\"4004.569505991415\\\" />\\n              <mxPoint x=\\\"8170\\\" y=\\\"4021.3515793950187\\\" />\\n              <mxPoint x=\\\"8345\\\" y=\\\"4021.3515793950196\\\" />\\n              <mxPoint x=\\\"8345\\\" y=\\\"4021.776772020986\\\" />\\n              <mxPoint x=\\\"8520\\\" y=\\\"4021.776772020985\\\" />\\n              <mxPoint x=\\\"8520\\\" y=\\\"3110.0802430260374\\\" />\\n              <mxPoint x=\\\"14405\\\" y=\\\"3110.0802430260374\\\" />\\n              <mxPoint x=\\\"14405\\\" y=\\\"3374.3449744748764\\\" />\\n              <mxPoint x=\\\"14795\\\" y=\\\"3374.3449744748805\\\" />\\n              <mxPoint x=\\\"14795\\\" y=\\\"11722.865179846318\\\" />\\n              <mxPoint x=\\\"80\\\" y=\\\"11722.865179846318\\\" />\\n              <mxPoint x=\\\"80\\\" y=\\\"261.00000000000273\\\" />\\n              <mxPoint x=\\\"3720\\\" y=\\\"261\\\" />\\n              <mxPoint x=\\\"3720\\\" y=\\\"8322.650474325575\\\" />\\n              <mxPoint x=\\\"3905\\\" y=\\\"8322.650474325575\\\" />\\n              <mxPoint x=\\\"3905\\\" y=\\\"8322.124804485018\\\" />\\n              <mxPoint x=\\\"4090\\\" y=\\\"8322.124804485018\\\" />\\n              <mxPoint x=\\\"4090\\\" y=\\\"8467.246623286177\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <mxCell id=\\\"b8e83b0a-69ff-4c34-a7fe-cb8c9ba85438\\\" value=\\\"API Call:&#xa;Create Monitor\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=20;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"1\\\" source=\\\"0622b212-3a4a-484d-9b7a-125864d785cd\\\" target=\\\"6527fb47-157e-4bba-9aed-adde061c5689\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"3310\\\" y=\\\"1117.0101953920014\\\" />\\n              <mxPoint x=\\\"3310\\\" y=\\\"1117.1301485528222\\\" />\\n              <mxPoint x=\\\"3485\\\" y=\\\"1117.1301485528222\\\" />\\n              <mxPoint x=\\\"3485\\\" y=\\\"1117.6113066159762\\\" />\\n              <mxPoint x=\\\"3670\\\" y=\\\"1117.6113066159762\\\" />\\n              <mxPoint x=\\\"3670\\\" y=\\\"1152.3222101959743\\\" />\\n              <mxPoint x=\\\"4985\\\" y=\\\"1152.3222101959743\\\" />\\n              <mxPoint x=\\\"4985\\\" y=\\\"1152.6734369657354\\\" />\\n              <mxPoint x=\\\"5160\\\" y=\\\"1152.6734369657354\\\" />\\n              <mxPoint x=\\\"5160\\\" y=\\\"484.2750730511509\\\" />\\n              <mxPoint x=\\\"5455\\\" y=\\\"484.2750730511518\\\" />\\n              <mxPoint x=\\\"5455\\\" y=\\\"483.9803183778979\\\" />\\n              <mxPoint x=\\\"5630\\\" y=\\\"483.98031837789745\\\" />\\n              <mxPoint x=\\\"5630\\\" y=\\\"209.99999999999977\\\" />\\n              <mxPoint x=\\\"10290\\\" y=\\\"209.99999999999977\\\" />\\n              <mxPoint x=\\\"10290\\\" y=\\\"3807.258669362275\\\" />\\n              <mxPoint x=\\\"10465\\\" y=\\\"3807.258669362275\\\" />\\n              <mxPoint x=\\\"10465\\\" y=\\\"3807.080243026039\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <mxCell id=\\\"7be432cd-2587-4eab-abdc-f7b9c1923597\\\" value=\\\"Aggregated Data&#xa;Transmitted to&#xa;Frontend\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=20;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"1\\\" source=\\\"ca6ee27b-1fbf-49de-978a-d6de259cc3d5\\\" target=\\\"9ef9e218-4742-487a-9a88-5c70e788ccdc\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"14210\\\" y=\\\"3789.795865755802\\\" />\\n              <mxPoint x=\\\"14210\\\" y=\\\"3789.9991158387165\\\" />\\n              <mxPoint x=\\\"14785\\\" y=\\\"3789.9991158387147\\\" />\\n              <mxPoint x=\\\"14785\\\" y=\\\"11772.865179846314\\\" />\\n              <mxPoint x=\\\"70\\\" y=\\\"11772.865179846314\\\" />\\n              <mxPoint x=\\\"70\\\" y=\\\"213.21247231364578\\\" />\\n              <mxPoint x=\\\"355\\\" y=\\\"213.21247231364669\\\" />\\n              <mxPoint x=\\\"355\\\" y=\\\"212.8750987614867\\\" />\\n              <mxPoint x=\\\"530\\\" y=\\\"212.8750987614867\\\" />\\n              <mxPoint x=\\\"530\\\" y=\\\"210.0000000000009\\\" />\\n              <mxPoint x=\\\"1180\\\" y=\\\"210.0000000000009\\\" />\\n              <mxPoint x=\\\"1180\\\" y=\\\"707.4191596459113\\\" />\\n              <mxPoint x=\\\"1405\\\" y=\\\"707.4191596459113\\\" />\\n              <mxPoint x=\\\"1405\\\" y=\\\"707.0000000000009\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <mxCell id=\\\"fd5e4447-123b-4b2d-8bce-1d1ae7cb00af\\\" value=\\\"Flow: Create&#xa;Maintenance Window&#xa;- API&#xa;Call\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=20;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"1\\\" source=\\\"5bdfdfa4-5d93-49fa-b05c-905813e6cf9d\\\" target=\\\"a391e8ea-9dbe-4fe4-90df-bf475d8b7ef8\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"3135\\\" y=\\\"7303.858021594766\\\" />\\n              <mxPoint x=\\\"3135\\\" y=\\\"7304.691438451378\\\" />\\n              <mxPoint x=\\\"3710\\\" y=\\\"7304.691438451378\\\" />\\n              <mxPoint x=\\\"3710\\\" y=\\\"7312.922962115302\\\" />\\n              <mxPoint x=\\\"5230\\\" y=\\\"7312.922962115303\\\" />\\n              <mxPoint x=\\\"5230\\\" y=\\\"3192.080243026041\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <mxCell id=\\\"fcf4eef4-394c-4872-9124-f7a0b32cdc3b\\\" value=\\\"Flow: Create&#xa;Maintenance Window&#xa;- API&#xa;Response\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=20;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"1\\\" source=\\\"3890b98d-a133-4279-a961-5d2facc6a17a\\\" target=\\\"a5a84b08-8c70-4023-8d08-b74e23aab4d7\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"10250\\\" y=\\\"8454.873756414821\\\" />\\n              <mxPoint x=\\\"10250\\\" y=\\\"8860.401538369915\\\" />\\n              <mxPoint x=\\\"14745\\\" y=\\\"8860.401538369915\\\" />\\n              <mxPoint x=\\\"14745\\\" y=\\\"11572.865179846314\\\" />\\n              <mxPoint x=\\\"110\\\" y=\\\"11572.865179846314\\\" />\\n              <mxPoint x=\\\"110\\\" y=\\\"4716.554233649437\\\" />\\n              <mxPoint x=\\\"1180\\\" y=\\\"4716.554233649436\\\" />\\n              <mxPoint x=\\\"1180\\\" y=\\\"4810.621306201957\\\" />\\n              <mxPoint x=\\\"1405\\\" y=\\\"4810.621306201957\\\" />\\n              <mxPoint x=\\\"1405\\\" y=\\\"4810.584553505044\\\" />\\n              <mxPoint x=\\\"1580\\\" y=\\\"4810.584553505044\\\" />\\n              <mxPoint x=\\\"1580\\\" y=\\\"7197.841352716525\\\" />\\n              <mxPoint x=\\\"1795\\\" y=\\\"7197.841352716524\\\" />\\n              <mxPoint x=\\\"1795\\\" y=\\\"7197.080193689382\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <mxCell id=\\\"7f921125-500f-4902-abc3-936ecac033d8\\\" value=\\\"Flow: View&#xa;Maintenance Windows&#xa;- API&#xa;Call\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=20;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"1\\\" source=\\\"d145bb4c-e1e0-473a-b6bc-decc932b738b\\\" target=\\\"c35a065c-2808-402c-877e-9055d956ce0d\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"3710\\\" y=\\\"7713.858021594765\\\" />\\n              <mxPoint x=\\\"3710\\\" y=\\\"7720.4820160745785\\\" />\\n              <mxPoint x=\\\"5240\\\" y=\\\"7720.482016074578\\\" />\\n              <mxPoint x=\\\"5240\\\" y=\\\"3427.0802430260383\\\" />\\n              <mxPoint x=\\\"6840\\\" y=\\\"3427.0802430260374\\\" />\\n              <mxPoint x=\\\"6840\\\" y=\\\"5584.569505991414\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <mxCell id=\\\"6c9979cd-1cc1-4227-b535-2ec3a10ca27e\\\" value=\\\"Flow: View&#xa;Maintenance Windows&#xa;- Data&#xa;Return to&#xa;Frontend\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=20;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"1\\\" source=\\\"27d9160a-4f8d-4dff-a09b-1678bc28cf2c\\\" target=\\\"970e2002-7c0e-40ef-80d8-e5e6d0a60735\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"10210\\\" y=\\\"8584.873756414821\\\" />\\n              <mxPoint x=\\\"10210\\\" y=\\\"8975.970303983748\\\" />\\n              <mxPoint x=\\\"14685\\\" y=\\\"8975.97030398375\\\" />\\n              <mxPoint x=\\\"14685\\\" y=\\\"11222.865179846314\\\" />\\n              <mxPoint x=\\\"180\\\" y=\\\"11222.865179846314\\\" />\\n              <mxPoint x=\\\"180\\\" y=\\\"11031.865179846314\\\" />\\n              <mxPoint x=\\\"1190\\\" y=\\\"11031.865179846312\\\" />\\n              <mxPoint x=\\\"1190\\\" y=\\\"8678.815322449529\\\" />\\n              <mxPoint x=\\\"1405\\\" y=\\\"8678.815322449529\\\" />\\n              <mxPoint x=\\\"1405\\\" y=\\\"8679.135157943725\\\" />\\n              <mxPoint x=\\\"1600\\\" y=\\\"8679.135157943725\\\" />\\n              <mxPoint x=\\\"1600\\\" y=\\\"8053.865179846313\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <mxCell id=\\\"3530244f-2689-444e-bcbf-611db2e3c000\\\" value=\\\"API Call:&#xa;Send Invitation&#xa;Request\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=20;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"1\\\" source=\\\"b27f1bba-c655-40c6-a1dc-71e78c590c92\\\" target=\\\"8b3cb6c2-ed57-4510-be15-decb8e3c89e1\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"3670\\\" y=\\\"3349.6070338202903\\\" />\\n              <mxPoint x=\\\"3670\\\" y=\\\"3374.6051963566842\\\" />\\n              <mxPoint x=\\\"5190\\\" y=\\\"3374.605196356683\\\" />\\n              <mxPoint x=\\\"5190\\\" y=\\\"1159.3244167129328\\\" />\\n              <mxPoint x=\\\"5455\\\" y=\\\"1159.3244167129324\\\" />\\n              <mxPoint x=\\\"5455\\\" y=\\\"1159.0720525414715\\\" />\\n              <mxPoint x=\\\"5640\\\" y=\\\"1159.072052541471\\\" />\\n              <mxPoint x=\\\"5640\\\" y=\\\"516\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <mxCell id=\\\"52732a37-82b8-40a7-b12d-dc1b82380b2d\\\" value=\\\"API Response:&#xa;Send Confirmation&#xa;to Client\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=20;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"1\\\" source=\\\"a7be2d0b-0227-4228-a0a6-074f7324fd89\\\" target=\\\"02d87257-883c-4822-a421-823c983532ec\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"12651.153846153846\\\" y=\\\"4357.859144892352\\\" />\\n              <mxPoint x=\\\"12651.153846153846\\\" y=\\\"4364.080792681034\\\" />\\n              <mxPoint x=\\\"14035\\\" y=\\\"4364.080792681034\\\" />\\n              <mxPoint x=\\\"14035\\\" y=\\\"4387.418850485591\\\" />\\n              <mxPoint x=\\\"14755\\\" y=\\\"4387.41885048559\\\" />\\n              <mxPoint x=\\\"14755\\\" y=\\\"11522.865179846314\\\" />\\n              <mxPoint x=\\\"120\\\" y=\\\"11522.865179846314\\\" />\\n              <mxPoint x=\\\"120\\\" y=\\\"4767.554233649437\\\" />\\n              <mxPoint x=\\\"1170\\\" y=\\\"4767.554233649438\\\" />\\n              <mxPoint x=\\\"1170\\\" y=\\\"4820.621306201959\\\" />\\n              <mxPoint x=\\\"1405\\\" y=\\\"4820.621306201959\\\" />\\n              <mxPoint x=\\\"1405\\\" y=\\\"4820.584553505046\\\" />\\n              <mxPoint x=\\\"1610\\\" y=\\\"4820.584553505046\\\" />\\n              <mxPoint x=\\\"1610\\\" y=\\\"3197.8251006423625\\\" />\\n              <mxPoint x=\\\"2327.5\\\" y=\\\"3197.825100642361\\\" />\\n              <mxPoint x=\\\"2327.5\\\" y=\\\"3219.607033820288\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <mxCell id=\\\"23715cce-c83a-44c0-9853-4c95b85e5ecd\\\" value=\\\"Flow 1:&#xa;CSV Import&#xa;- Transmit&#xa;Data to&#xa;Server\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=20;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"1\\\" source=\\\"5967e576-f542-4c0b-a3f4-9446ae992721\\\" target=\\\"c1ac3c26-996a-43ef-9c34-4c2776188784\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"5220\\\" y=\\\"5481.542220848844\\\" />\\n              <mxPoint x=\\\"5220\\\" y=\\\"1708.0000000000027\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <mxCell id=\\\"926a330c-a9c5-4983-a4b5-70359813e49a\\\" value=\\\"Flow 1:&#xa;CSV Import&#xa;- Transmit&#xa;Success to&#xa;Client\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=20;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"1\\\" source=\\\"72b55fa1-d944-4e46-ac98-f6a6cb201afa\\\" target=\\\"ae3b7e23-ed64-40aa-9760-389f0a869f8d\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"7755\\\" y=\\\"4534.569505991416\\\" />\\n              <mxPoint x=\\\"7755\\\" y=\\\"4555.033534254194\\\" />\\n              <mxPoint x=\\\"8600\\\" y=\\\"4555.033534254195\\\" />\\n              <mxPoint x=\\\"8600\\\" y=\\\"3161.080243026039\\\" />\\n              <mxPoint x=\\\"14395\\\" y=\\\"3161.080243026039\\\" />\\n              <mxPoint x=\\\"14395\\\" y=\\\"3425.2087194595433\\\" />\\n              <mxPoint x=\\\"14775\\\" y=\\\"3425.2087194595433\\\" />\\n              <mxPoint x=\\\"14775\\\" y=\\\"11622.865179846314\\\" />\\n              <mxPoint x=\\\"100\\\" y=\\\"11622.865179846314\\\" />\\n              <mxPoint x=\\\"100\\\" y=\\\"4665.554233649438\\\" />\\n              <mxPoint x=\\\"1190\\\" y=\\\"4665.554233649437\\\" />\\n              <mxPoint x=\\\"1190\\\" y=\\\"4800.584553505045\\\" />\\n              <mxPoint x=\\\"1620\\\" y=\\\"4800.584553505045\\\" />\\n              <mxPoint x=\\\"1620\\\" y=\\\"5520.870240113548\\\" />\\n              <mxPoint x=\\\"2395\\\" y=\\\"5520.870240113547\\\" />\\n              <mxPoint x=\\\"2395\\\" y=\\\"5539.607033820288\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <mxCell id=\\\"f6d80f09-ae83-4c95-aba0-4efffeda38e0\\\" value=\\\"API Call:&#xa;Fetch Application&#xa;Settings\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=20;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"1\\\" source=\\\"97908daf-d071-4df5-8366-1f5f4d8d534a\\\" target=\\\"83596bd1-dfca-4196-b52e-955f6824fafb\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"2811.6666666666665\\\" y=\\\"8533.865179846309\\\" />\\n              <mxPoint x=\\\"2811.6666666666665\\\" y=\\\"8534.901370641881\\\" />\\n              <mxPoint x=\\\"3680\\\" y=\\\"8534.901370641885\\\" />\\n              <mxPoint x=\\\"3680\\\" y=\\\"7837.852064767872\\\" />\\n              <mxPoint x=\\\"5250\\\" y=\\\"7837.8520647678715\\\" />\\n              <mxPoint x=\\\"5250\\\" y=\\\"3478.0802430260374\\\" />\\n              <mxPoint x=\\\"6830\\\" y=\\\"3478.0802430260364\\\" />\\n              <mxPoint x=\\\"6830\\\" y=\\\"6081.849528138135\\\" />\\n              <mxPoint x=\\\"7095\\\" y=\\\"6081.8495281381365\\\" />\\n              <mxPoint x=\\\"7095\\\" y=\\\"6082.048397924002\\\" />\\n              <mxPoint x=\\\"7320\\\" y=\\\"6082.048397924001\\\" />\\n              <mxPoint x=\\\"7320\\\" y=\\\"6529.340814284318\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <mxCell id=\\\"195ad532-9858-493e-876a-6ec457811d1d\\\" value=\\\"API Response:&#xa;Send Settings&#xa;to Client\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=20;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"1\\\" source=\\\"83596bd1-dfca-4196-b52e-955f6824fafb\\\" target=\\\"09cb194a-0ea4-46e2-b32b-36b62fa87f40\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"8530\\\" y=\\\"6529.340814284319\\\" />\\n              <mxPoint x=\\\"8530\\\" y=\\\"10330.873756414823\\\" />\\n              <mxPoint x=\\\"14695\\\" y=\\\"10330.873756414825\\\" />\\n              <mxPoint x=\\\"14695\\\" y=\\\"11322.865179846314\\\" />\\n              <mxPoint x=\\\"160\\\" y=\\\"11322.865179846314\\\" />\\n              <mxPoint x=\\\"160\\\" y=\\\"10929.865179846314\\\" />\\n              <mxPoint x=\\\"1170\\\" y=\\\"10929.865179846314\\\" />\\n              <mxPoint x=\\\"1170\\\" y=\\\"8658.81532244953\\\" />\\n              <mxPoint x=\\\"1405\\\" y=\\\"8658.81532244953\\\" />\\n              <mxPoint x=\\\"1405\\\" y=\\\"8659.135157943725\\\" />\\n              <mxPoint x=\\\"1610\\\" y=\\\"8659.135157943725\\\" />\\n              <mxPoint x=\\\"1610\\\" y=\\\"8803.86517984631\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <mxCell id=\\\"ce3ed3ba-a35b-4881-8dfd-f8425b9bf812\\\" value=\\\"Data Transmission:&#xa;Send Updated&#xa;Settings to&#xa;Server\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=20;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"1\\\" source=\\\"1b2cf182-9ee3-4218-a7ec-b74e427ccddf\\\" target=\\\"cce3b9c8-f3b7-434b-b3c6-d8d164714f86\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"5170\\\" y=\\\"8997.246623286175\\\" />\\n              <mxPoint x=\\\"5170\\\" y=\\\"10634.873756414825\\\" />\\n              <mxPoint x=\\\"6830\\\" y=\\\"10634.873756414825\\\" />\\n              <mxPoint x=\\\"6830\\\" y=\\\"6091.8495281381365\\\" />\\n              <mxPoint x=\\\"7095\\\" y=\\\"6091.849528138137\\\" />\\n              <mxPoint x=\\\"7095\\\" y=\\\"6092.048397924003\\\" />\\n              <mxPoint x=\\\"7270\\\" y=\\\"6092.0483979240025\\\" />\\n              <mxPoint x=\\\"7270\\\" y=\\\"6659.34081428432\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <mxCell id=\\\"fbe9b160-307e-4f51-8f72-713fda5373c8\\\" value=\\\"API Response:&#xa;Confirm Settings&#xa;Update\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=20;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"1\\\" source=\\\"cce3b9c8-f3b7-434b-b3c6-d8d164714f86\\\" target=\\\"fff5dde4-8eb8-4c21-9c6d-0845a9749ff3\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"8520\\\" y=\\\"6659.340814284319\\\" />\\n              <mxPoint x=\\\"8520\\\" y=\\\"10381.873756414823\\\" />\\n              <mxPoint x=\\\"14705\\\" y=\\\"10381.873756414825\\\" />\\n              <mxPoint x=\\\"14705\\\" y=\\\"11372.865179846314\\\" />\\n              <mxPoint x=\\\"150\\\" y=\\\"11372.865179846314\\\" />\\n              <mxPoint x=\\\"150\\\" y=\\\"10878.865179846314\\\" />\\n              <mxPoint x=\\\"3700\\\" y=\\\"10878.865179846314\\\" />\\n              <mxPoint x=\\\"3700\\\" y=\\\"9127.246623286175\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <mxCell id=\\\"499dfe1f-77d4-4b26-a12c-45240691109e\\\" value=\\\"API Call:&#xa;Fetch System&#xa;Diagnostics\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=20;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"1\\\" source=\\\"704e2ec8-9f2f-47e5-852f-c6ada67a02e0\\\" target=\\\"09f07e80-185e-4547-aab4-edaf8ae7501e\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\">\\n            <Array as=\\\"points\\\">\\n              <mxPoint x=\\\"3670\\\" y=\\\"4029.60703382029\\\" />\\n              <mxPoint x=\\\"3670\\\" y=\\\"4051.6580863779977\\\" />\\n              <mxPoint x=\\\"5200\\\" y=\\\"4051.6580863779964\\\" />\\n              <mxPoint x=\\\"5200\\\" y=\\\"1169.3244167129324\\\" />\\n              <mxPoint x=\\\"5455\\\" y=\\\"1169.324416712932\\\" />\\n              <mxPoint x=\\\"5455\\\" y=\\\"1169.0720525414708\\\" />\\n              <mxPoint x=\\\"5650\\\" y=\\\"1169.0720525414708\\\" />\\n              <mxPoint x=\\\"5650\\\" y=\\\"820.9999999999995\\\" />\\n              <mxPoint x=\\\"10270\\\" y=\\\"820.9999999999995\\\" />\\n              <mxPoint x=\\\"10270\\\" y=\\\"4627.859144892351\\\" />\\n            </Array>\\n          </mxGeometry>\\n        </mxCell>\\n        <mxCell id=\\\"d0f92604-a6fa-4d85-9716-ea8f32db78e0\\\" value=\\\"API Response:&#xa;Send Diagnostics&#xa;Data to&#xa;Client\\\" style=\\\"edgeStyle=orthogonalEdgeStyle;shape=connector;rounded=1;sketch=0;jumpStyle=arc;jumpSize=17;orthogonalLoop=1;jettySize=auto;html=0;shadow=0;labelBackgroundColor=none;fontFamily=Poppins;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DPoppins;fontSize=37;fontColor=#5C5C5C;endArrow=block;endFill=1;endSize=5;sourcePerimeterSpacing=0;targetPerimeterSpacing=0;strokeColor=#A1A1A1;strokeWidth=2;arcSize=50;labelPosition=center;verticalLabelPosition=top;align=center;verticalAlign=bottom;container=1;\\\" edge=\\\"1\\\" parent=\\\"1\\\" source=\\\"09f07e80-185e-4547-aab4-edaf8ae7501e\\\" target=\\\"4b418736-6b72-47e0-917a-d86d4bed9ecd\\\">\\n          <mxGeometry relative=\\\"1\\\" as=\\\"geometry\\\" />\\n        </mxCell>\\n      </root>\\n    </mxGraphModel>\\n  </diagram>\\n</mxfile>\\n\",\n\t\"fileName\": \"Checkmate.CodeCanvas\",\n\t\"fileURL\": \"github\",\n\t\"diagramTemplateVersion\": 0.2,\n\t\"filePath\": \"Checkmate.CodeCanvas\",\n\t\"repoData\": {\n\t\t\"client\": {\n\t\t\t\"path\": \"client\",\n\t\t\t\"fileName\": \"client\",\n\t\t\t\"cellName\": \"client\",\n\t\t\t\"cellId\": \"0b23ea66-3e37-4643-b3b9-acb87ea02bae\",\n\t\t\t\"visible\": true,\n\t\t\t\"children\": [\n\t\t\t\t\"client/src\"\n\t\t\t]\n\t\t},\n\t\t\"client/src\": {\n\t\t\t\"path\": \"client/src\",\n\t\t\t\"fileName\": \"src\",\n\t\t\t\"cellName\": \"src\",\n\t\t\t\"cellId\": \"d3264577-10f0-42fe-9411-7e9df0754d1e\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"0b23ea66-3e37-4643-b3b9-acb87ea02bae\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Pages\",\n\t\t\t\t\"client/src/Hooks\",\n\t\t\t\t\"client/src/Utils\",\n\t\t\t\t\"client/src/Routes\"\n\t\t\t]\n\t\t},\n\t\t\"client/src/Hooks\": {\n\t\t\t\"path\": \"client/src/Hooks\",\n\t\t\t\"fileName\": \"Hooks\",\n\t\t\t\"cellName\": \"Hooks\",\n\t\t\t\"cellId\": \"4295a047-076f-4c07-95dd-b3123b6614f7\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"d3264577-10f0-42fe-9411-7e9df0754d1e\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Hooks/v1\"\n\t\t\t]\n\t\t},\n\t\t\"client/src/Hooks/v1\": {\n\t\t\t\"path\": \"client/src/Hooks/v1\",\n\t\t\t\"fileName\": \"v1\",\n\t\t\t\"cellName\": \"v1\",\n\t\t\t\"cellId\": \"3bf0c0f9-cbb0-4f0c-8cb3-6e2a4abc0961\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"4295a047-076f-4c07-95dd-b3123b6614f7\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Hooks/v1/monitorHooks.js\",\n\t\t\t\t\"client/src/Hooks/v1/useNotifications.js\",\n\t\t\t\t\"client/src/Hooks/v1/checkHooks.js\",\n\t\t\t\t\"client/src/Hooks/v1/settingsHooks.js\"\n\t\t\t]\n\t\t},\n\t\t\"client/src/Hooks/v1/checkHooks.js\": {\n\t\t\t\"path\": \"client/src/Hooks/v1/checkHooks.js\",\n\t\t\t\"fileName\": \"checkHooks.js\",\n\t\t\t\"cellName\": \"checkHooks.js\",\n\t\t\t\"cellId\": \"933a6cdc-349c-4725-b7ae-14cf780bfde8\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"3bf0c0f9-cbb0-4f0c-8cb3-6e2a4abc0961\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Hooks/v1/checkHooks.js-simstep-8dc4347c-3e9e-40d7-ae6f-54684f2e6956\",\n\t\t\t\t\"client/src/Hooks/v1/checkHooks.js-simstep-faba07f3-7460-47ae-924d-f92f5b2e821d\"\n\t\t\t]\n\t\t},\n\t\t\"client/src/Hooks/v1/monitorHooks.js\": {\n\t\t\t\"path\": \"client/src/Hooks/v1/monitorHooks.js\",\n\t\t\t\"fileName\": \"monitorHooks.js\",\n\t\t\t\"cellName\": \"monitorHooks.js\",\n\t\t\t\"cellId\": \"595cf0e8-2f86-4543-b51c-b2aeac307f4b\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"3bf0c0f9-cbb0-4f0c-8cb3-6e2a4abc0961\"\n\t\t},\n\t\t\"client/src/Hooks/v1/settingsHooks.js\": {\n\t\t\t\"path\": \"client/src/Hooks/v1/settingsHooks.js\",\n\t\t\t\"fileName\": \"settingsHooks.js\",\n\t\t\t\"cellName\": \"settingsHooks.js\",\n\t\t\t\"cellId\": \"8ee5d524-e61d-4e39-a729-babf54929def\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"3bf0c0f9-cbb0-4f0c-8cb3-6e2a4abc0961\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Hooks/v1/settingsHooks.js-simstep-d7098072-9a83-4369-8176-9646ba34e186\",\n\t\t\t\t\"client/src/Hooks/v1/settingsHooks.js-simstep-a157bd07-b969-44f8-914c-3d8393c1605a\"\n\t\t\t]\n\t\t},\n\t\t\"client/src/Hooks/v1/useNotifications.js\": {\n\t\t\t\"path\": \"client/src/Hooks/v1/useNotifications.js\",\n\t\t\t\"fileName\": \"useNotifications.js\",\n\t\t\t\"cellName\": \"useNotifications.js\",\n\t\t\t\"cellId\": \"cd2428fd-6545-48dd-b685-5261311b7532\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"3bf0c0f9-cbb0-4f0c-8cb3-6e2a4abc0961\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Hooks/v1/useNotifications.js-simstep-383c6be8-aa51-4398-9ae3-21035413f73a\"\n\t\t\t]\n\t\t},\n\t\t\"client/src/Pages\": {\n\t\t\t\"path\": \"client/src/Pages\",\n\t\t\t\"fileName\": \"Pages\",\n\t\t\t\"cellName\": \"Pages\",\n\t\t\t\"cellId\": \"f0feab85-316a-41b5-a2f1-629220018846\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"d3264577-10f0-42fe-9411-7e9df0754d1e\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Pages/v1\"\n\t\t\t]\n\t\t},\n\t\t\"client/src/Pages/v1\": {\n\t\t\t\"path\": \"client/src/Pages/v1\",\n\t\t\t\"fileName\": \"v1\",\n\t\t\t\"cellName\": \"v1\",\n\t\t\t\"cellId\": \"1a083b4a-787c-4eb4-8029-6700de987679\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"f0feab85-316a-41b5-a2f1-629220018846\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Pages/v1/Uptime\",\n\t\t\t\t\"client/src/Pages/v1/Infrastructure\",\n\t\t\t\t\"client/src/Pages/v1/Notifications\",\n\t\t\t\t\"client/src/Pages/v1/StatusPage\",\n\t\t\t\t\"client/src/Pages/v1/PageSpeed\",\n\t\t\t\t\"client/src/Pages/v1/Maintenance\",\n\t\t\t\t\"client/src/Pages/v1/Account\",\n\t\t\t\t\"client/src/Pages/v1/Settings\",\n\t\t\t\t\"client/src/Pages/v1/Logs\"\n\t\t\t]\n\t\t},\n\t\t\"client/src/Pages/v1/Account\": {\n\t\t\t\"path\": \"client/src/Pages/v1/Account\",\n\t\t\t\"fileName\": \"Account\",\n\t\t\t\"cellName\": \"Account\",\n\t\t\t\"cellId\": \"3cad7666-0d1a-4e31-b6ca-70d9c3a46b19\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"1a083b4a-787c-4eb4-8029-6700de987679\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Pages/v1/Account/index.jsx\",\n\t\t\t\t\"client/src/Pages/v1/Account/components\"\n\t\t\t]\n\t\t},\n\t\t\"client/src/Pages/v1/Account/components\": {\n\t\t\t\"path\": \"client/src/Pages/v1/Account/components\",\n\t\t\t\"fileName\": \"components\",\n\t\t\t\"cellName\": \"components\",\n\t\t\t\"cellId\": \"425a4c15-043f-4d05-8832-da00e18f97b9\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"3cad7666-0d1a-4e31-b6ca-70d9c3a46b19\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Pages/v1/Account/components/TeamPanel.jsx\"\n\t\t\t]\n\t\t},\n\t\t\"client/src/Pages/v1/Account/components/TeamPanel.jsx\": {\n\t\t\t\"path\": \"client/src/Pages/v1/Account/components/TeamPanel.jsx\",\n\t\t\t\"fileName\": \"TeamPanel.jsx\",\n\t\t\t\"cellName\": \"TeamPanel.jsx\",\n\t\t\t\"cellId\": \"1145f351-2257-411d-86f7-30bf8c26ad68\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"425a4c15-043f-4d05-8832-da00e18f97b9\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Pages/v1/Account/components/TeamPanel.jsx-simstep-eebaca25-d588-49c4-a35c-9abc82fde580\",\n\t\t\t\t\"client/src/Pages/v1/Account/components/TeamPanel.jsx-simstep-700f35e0-b39d-417c-b0a8-0612feade977\"\n\t\t\t]\n\t\t},\n\t\t\"client/src/Pages/v1/Account/index.jsx\": {\n\t\t\t\"path\": \"client/src/Pages/v1/Account/index.jsx\",\n\t\t\t\"fileName\": \"index.jsx\",\n\t\t\t\"cellName\": \"index.jsx\",\n\t\t\t\"cellId\": \"33960806-1b9e-4d61-a163-e4bebf82d87a\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"3cad7666-0d1a-4e31-b6ca-70d9c3a46b19\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Pages/v1/Account/index.jsx-simstep-2d5a952a-ce62-4948-9309-96b28ad74e59\"\n\t\t\t]\n\t\t},\n\t\t\"client/src/Pages/v1/Infrastructure\": {\n\t\t\t\"path\": \"client/src/Pages/v1/Infrastructure\",\n\t\t\t\"fileName\": \"Infrastructure\",\n\t\t\t\"cellName\": \"Infrastructure\",\n\t\t\t\"cellId\": \"3f26b33e-477f-41df-a78a-3e3e4f4209ae\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"1a083b4a-787c-4eb4-8029-6700de987679\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Pages/v1/Infrastructure/Create\",\n\t\t\t\t\"client/src/Pages/v1/Infrastructure/Details\"\n\t\t\t]\n\t\t},\n\t\t\"client/src/Pages/v1/Infrastructure/Create\": {\n\t\t\t\"path\": \"client/src/Pages/v1/Infrastructure/Create\",\n\t\t\t\"fileName\": \"Create\",\n\t\t\t\"cellName\": \"Create\",\n\t\t\t\"cellId\": \"74019e8a-3148-4a32-aae2-5afd16f3eb9b\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"3f26b33e-477f-41df-a78a-3e3e4f4209ae\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Pages/v1/Infrastructure/Create/Components\"\n\t\t\t]\n\t\t},\n\t\t\"client/src/Pages/v1/Infrastructure/Create/Components\": {\n\t\t\t\"path\": \"client/src/Pages/v1/Infrastructure/Create/Components\",\n\t\t\t\"fileName\": \"Components\",\n\t\t\t\"cellName\": \"Components\",\n\t\t\t\"cellId\": \"ceded1fc-87a9-43c8-a756-746be3d4ad8d\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"74019e8a-3148-4a32-aae2-5afd16f3eb9b\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Pages/v1/Infrastructure/Create/Components/CustomAlertsSection.jsx\"\n\t\t\t]\n\t\t},\n\t\t\"client/src/Pages/v1/Infrastructure/Create/Components/CustomAlertsSection.jsx\": {\n\t\t\t\"path\": \"client/src/Pages/v1/Infrastructure/Create/Components/CustomAlertsSection.jsx\",\n\t\t\t\"fileName\": \"CustomAlertsSection.jsx\",\n\t\t\t\"cellName\": \"CustomAlertsSection.jsx\",\n\t\t\t\"cellId\": \"83800be3-2a0e-4419-b379-3f995f4050e7\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"ceded1fc-87a9-43c8-a756-746be3d4ad8d\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Pages/v1/Infrastructure/Create/Components/CustomAlertsSection.jsx-simstep-80dd889a-1fc9-4d56-b9cf-5b45bf1110b1\"\n\t\t\t]\n\t\t},\n\t\t\"client/src/Pages/v1/Infrastructure/Details\": {\n\t\t\t\"path\": \"client/src/Pages/v1/Infrastructure/Details\",\n\t\t\t\"fileName\": \"Details\",\n\t\t\t\"cellName\": \"Details\",\n\t\t\t\"cellId\": \"591128f9-0994-4e01-a1ab-f23357f97aff\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"3f26b33e-477f-41df-a78a-3e3e4f4209ae\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Pages/v1/Infrastructure/Details/index.jsx\",\n\t\t\t\t\"client/src/Pages/v1/Infrastructure/Details/Components\"\n\t\t\t]\n\t\t},\n\t\t\"client/src/Pages/v1/Infrastructure/Details/Components\": {\n\t\t\t\"path\": \"client/src/Pages/v1/Infrastructure/Details/Components\",\n\t\t\t\"fileName\": \"Components\",\n\t\t\t\"cellName\": \"Components\",\n\t\t\t\"cellId\": \"e97d4e61-483e-4ac5-85a1-0ff72fcdd449\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"591128f9-0994-4e01-a1ab-f23357f97aff\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Pages/v1/Infrastructure/Details/Components/GaugeBoxes\"\n\t\t\t]\n\t\t},\n\t\t\"client/src/Pages/v1/Infrastructure/Details/Components/GaugeBoxes\": {\n\t\t\t\"path\": \"client/src/Pages/v1/Infrastructure/Details/Components/GaugeBoxes\",\n\t\t\t\"fileName\": \"GaugeBoxes\",\n\t\t\t\"cellName\": \"GaugeBoxes\",\n\t\t\t\"cellId\": \"6a7c7720-a399-4d4d-8225-36e0b2f59731\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"e97d4e61-483e-4ac5-85a1-0ff72fcdd449\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Pages/v1/Infrastructure/Details/Components/GaugeBoxes/index.jsx\"\n\t\t\t]\n\t\t},\n\t\t\"client/src/Pages/v1/Infrastructure/Details/Components/GaugeBoxes/index.jsx\": {\n\t\t\t\"path\": \"client/src/Pages/v1/Infrastructure/Details/Components/GaugeBoxes/index.jsx\",\n\t\t\t\"fileName\": \"index.jsx\",\n\t\t\t\"cellName\": \"index.jsx\",\n\t\t\t\"cellId\": \"8fe3d890-3605-407d-b06c-1d890a354e46\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"6a7c7720-a399-4d4d-8225-36e0b2f59731\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Pages/v1/Infrastructure/Details/Components/GaugeBoxes/index.jsx-simstep-6eedce82-b9c8-4022-95e5-3a6e00628105\"\n\t\t\t]\n\t\t},\n\t\t\"client/src/Pages/v1/Infrastructure/Details/index.jsx\": {\n\t\t\t\"path\": \"client/src/Pages/v1/Infrastructure/Details/index.jsx\",\n\t\t\t\"fileName\": \"index.jsx\",\n\t\t\t\"cellName\": \"index.jsx\",\n\t\t\t\"cellId\": \"e292c552-b3df-4bac-bd9a-8f44c260a5aa\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"591128f9-0994-4e01-a1ab-f23357f97aff\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Pages/v1/Infrastructure/Details/index.jsx-simstep-c27365db-9db6-4cc9-96f0-4f046fd38562\"\n\t\t\t]\n\t\t},\n\t\t\"client/src/Pages/v1/Logs\": {\n\t\t\t\"path\": \"client/src/Pages/v1/Logs\",\n\t\t\t\"fileName\": \"Logs\",\n\t\t\t\"cellName\": \"Logs\",\n\t\t\t\"cellId\": \"1716ec41-8b42-4386-9850-55b8a607638e\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"1a083b4a-787c-4eb4-8029-6700de987679\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Pages/v1/Logs/Diagnostics\"\n\t\t\t]\n\t\t},\n\t\t\"client/src/Pages/v1/Logs/Diagnostics\": {\n\t\t\t\"path\": \"client/src/Pages/v1/Logs/Diagnostics\",\n\t\t\t\"fileName\": \"Diagnostics\",\n\t\t\t\"cellName\": \"Diagnostics\",\n\t\t\t\"cellId\": \"e0cb598c-e300-4fd3-8554-db7ffd6201f1\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"1716ec41-8b42-4386-9850-55b8a607638e\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Pages/v1/Logs/Diagnostics/index.jsx\"\n\t\t\t]\n\t\t},\n\t\t\"client/src/Pages/v1/Logs/Diagnostics/index.jsx\": {\n\t\t\t\"path\": \"client/src/Pages/v1/Logs/Diagnostics/index.jsx\",\n\t\t\t\"fileName\": \"index.jsx\",\n\t\t\t\"cellName\": \"index.jsx\",\n\t\t\t\"cellId\": \"87e0e2ea-4a6d-460d-95bc-31e2efd9c9cf\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"e0cb598c-e300-4fd3-8554-db7ffd6201f1\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Pages/v1/Logs/Diagnostics/index.jsx-simstep-a9b24b5f-534b-4baf-a185-bac7c32a1c42\",\n\t\t\t\t\"client/src/Pages/v1/Logs/Diagnostics/index.jsx-simstep-e6c94f52-a599-4568-a06f-2db18f963817\"\n\t\t\t]\n\t\t},\n\t\t\"client/src/Pages/v1/Maintenance\": {\n\t\t\t\"path\": \"client/src/Pages/v1/Maintenance\",\n\t\t\t\"fileName\": \"Maintenance\",\n\t\t\t\"cellName\": \"Maintenance\",\n\t\t\t\"cellId\": \"8021b55d-2d3a-4416-b598-e134e76c9434\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"1a083b4a-787c-4eb4-8029-6700de987679\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Pages/v1/Maintenance/CreateMaintenance\",\n\t\t\t\t\"client/src/Pages/v1/Maintenance/index.jsx\",\n\t\t\t\t\"client/src/Pages/v1/Maintenance/MaintenanceTable\"\n\t\t\t]\n\t\t},\n\t\t\"client/src/Pages/v1/Maintenance/CreateMaintenance\": {\n\t\t\t\"path\": \"client/src/Pages/v1/Maintenance/CreateMaintenance\",\n\t\t\t\"fileName\": \"CreateMaintenance\",\n\t\t\t\"cellName\": \"CreateMaintenance\",\n\t\t\t\"cellId\": \"6f7119ac-d65a-4fdf-a6f2-31052e0f5549\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"8021b55d-2d3a-4416-b598-e134e76c9434\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Pages/v1/Maintenance/CreateMaintenance/index.jsx\",\n\t\t\t\t\"client/src/Pages/v1/Maintenance/CreateMaintenance/hooks\"\n\t\t\t]\n\t\t},\n\t\t\"client/src/Pages/v1/Maintenance/CreateMaintenance/hooks\": {\n\t\t\t\"path\": \"client/src/Pages/v1/Maintenance/CreateMaintenance/hooks\",\n\t\t\t\"fileName\": \"hooks\",\n\t\t\t\"cellName\": \"hooks\",\n\t\t\t\"cellId\": \"015a17fc-3fcf-45e0-8936-19f5e2ca86a3\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"6f7119ac-d65a-4fdf-a6f2-31052e0f5549\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Pages/v1/Maintenance/CreateMaintenance/hooks/useMaintenanceActions.jsx\"\n\t\t\t]\n\t\t},\n\t\t\"client/src/Pages/v1/Maintenance/CreateMaintenance/hooks/useMaintenanceActions.jsx\": {\n\t\t\t\"path\": \"client/src/Pages/v1/Maintenance/CreateMaintenance/hooks/useMaintenanceActions.jsx\",\n\t\t\t\"fileName\": \"useMaintenanceActions.jsx\",\n\t\t\t\"cellName\": \"useMaintenanceActions.jsx\",\n\t\t\t\"cellId\": \"6ad0396e-9b38-4f5d-9ad9-6c9fcb4434f4\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"015a17fc-3fcf-45e0-8936-19f5e2ca86a3\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Pages/v1/Maintenance/CreateMaintenance/hooks/useMaintenanceActions.jsx-simstep-5e0d7085-099b-478a-afaa-47ad4dd07043\"\n\t\t\t]\n\t\t},\n\t\t\"client/src/Pages/v1/Maintenance/CreateMaintenance/index.jsx\": {\n\t\t\t\"path\": \"client/src/Pages/v1/Maintenance/CreateMaintenance/index.jsx\",\n\t\t\t\"fileName\": \"index.jsx\",\n\t\t\t\"cellName\": \"index.jsx\",\n\t\t\t\"cellId\": \"92c244d2-e6a7-4804-a643-1e8d36baf9c6\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"6f7119ac-d65a-4fdf-a6f2-31052e0f5549\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Pages/v1/Maintenance/CreateMaintenance/index.jsx-simstep-2401ef7a-8d8e-4056-868a-547ab213daf1\",\n\t\t\t\t\"client/src/Pages/v1/Maintenance/CreateMaintenance/index.jsx-simstep-ebe8fd52-f2a1-4a98-a71b-b04d6f4cdadc\"\n\t\t\t]\n\t\t},\n\t\t\"client/src/Pages/v1/Maintenance/MaintenanceTable\": {\n\t\t\t\"path\": \"client/src/Pages/v1/Maintenance/MaintenanceTable\",\n\t\t\t\"fileName\": \"MaintenanceTable\",\n\t\t\t\"cellName\": \"MaintenanceTable\",\n\t\t\t\"cellId\": \"5ad4d33f-0932-479c-bb57-22ce6405758f\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"8021b55d-2d3a-4416-b598-e134e76c9434\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Pages/v1/Maintenance/MaintenanceTable/index.jsx\"\n\t\t\t]\n\t\t},\n\t\t\"client/src/Pages/v1/Maintenance/MaintenanceTable/index.jsx\": {\n\t\t\t\"path\": \"client/src/Pages/v1/Maintenance/MaintenanceTable/index.jsx\",\n\t\t\t\"fileName\": \"index.jsx\",\n\t\t\t\"cellName\": \"index.jsx\",\n\t\t\t\"cellId\": \"e7ec5ca9-6d25-4bf2-9695-639556f7d141\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"5ad4d33f-0932-479c-bb57-22ce6405758f\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Pages/v1/Maintenance/MaintenanceTable/index.jsx-simstep-acf97639-e291-4ca6-81a6-d0487397f42a\"\n\t\t\t]\n\t\t},\n\t\t\"client/src/Pages/v1/Maintenance/index.jsx\": {\n\t\t\t\"path\": \"client/src/Pages/v1/Maintenance/index.jsx\",\n\t\t\t\"fileName\": \"index.jsx\",\n\t\t\t\"cellName\": \"index.jsx\",\n\t\t\t\"cellId\": \"1eae6263-aaa2-4206-b92e-1e67f529c1c9\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"8021b55d-2d3a-4416-b598-e134e76c9434\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Pages/v1/Maintenance/index.jsx-simstep-82b5ea14-bb00-4511-aba4-76196029fd81\"\n\t\t\t]\n\t\t},\n\t\t\"client/src/Pages/v1/Notifications\": {\n\t\t\t\"path\": \"client/src/Pages/v1/Notifications\",\n\t\t\t\"fileName\": \"Notifications\",\n\t\t\t\"cellName\": \"Notifications\",\n\t\t\t\"cellId\": \"b3575a92-df07-4cf7-810f-8e5e0672d666\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"1a083b4a-787c-4eb4-8029-6700de987679\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Pages/v1/Notifications/create\"\n\t\t\t]\n\t\t},\n\t\t\"client/src/Pages/v1/Notifications/create\": {\n\t\t\t\"path\": \"client/src/Pages/v1/Notifications/create\",\n\t\t\t\"fileName\": \"create\",\n\t\t\t\"cellName\": \"create\",\n\t\t\t\"cellId\": \"a6fb23f0-73bc-40ee-bb3c-ed93605a2bcb\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"b3575a92-df07-4cf7-810f-8e5e0672d666\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Pages/v1/Notifications/create/index.jsx\"\n\t\t\t]\n\t\t},\n\t\t\"client/src/Pages/v1/Notifications/create/index.jsx\": {\n\t\t\t\"path\": \"client/src/Pages/v1/Notifications/create/index.jsx\",\n\t\t\t\"fileName\": \"index.jsx\",\n\t\t\t\"cellName\": \"index.jsx\",\n\t\t\t\"cellId\": \"b71b02fb-d08e-4fcf-b959-de1b9547d9c2\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"a6fb23f0-73bc-40ee-bb3c-ed93605a2bcb\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Pages/v1/Notifications/create/index.jsx-simstep-e924ec15-1bea-4e3b-befb-a8bf30cbf740\"\n\t\t\t]\n\t\t},\n\t\t\"client/src/Pages/v1/PageSpeed\": {\n\t\t\t\"path\": \"client/src/Pages/v1/PageSpeed\",\n\t\t\t\"fileName\": \"PageSpeed\",\n\t\t\t\"cellName\": \"PageSpeed\",\n\t\t\t\"cellId\": \"043d3dac-d4bb-449b-a3a7-270d53b66dac\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"1a083b4a-787c-4eb4-8029-6700de987679\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Pages/v1/PageSpeed/Create\",\n\t\t\t\t\"client/src/Pages/v1/PageSpeed/Details\"\n\t\t\t]\n\t\t},\n\t\t\"client/src/Pages/v1/PageSpeed/Create\": {\n\t\t\t\"path\": \"client/src/Pages/v1/PageSpeed/Create\",\n\t\t\t\"fileName\": \"Create\",\n\t\t\t\"cellName\": \"Create\",\n\t\t\t\"cellId\": \"414c500b-7b68-42ba-8110-e855efbee750\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"043d3dac-d4bb-449b-a3a7-270d53b66dac\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Pages/v1/PageSpeed/Create/index.jsx\"\n\t\t\t]\n\t\t},\n\t\t\"client/src/Pages/v1/PageSpeed/Create/index.jsx\": {\n\t\t\t\"path\": \"client/src/Pages/v1/PageSpeed/Create/index.jsx\",\n\t\t\t\"fileName\": \"index.jsx\",\n\t\t\t\"cellName\": \"index.jsx\",\n\t\t\t\"cellId\": \"5ffe0baa-054a-4e5b-8b29-1254f07ea975\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"414c500b-7b68-42ba-8110-e855efbee750\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Pages/v1/PageSpeed/Create/index.jsx-simstep-b0cc6e6a-961e-4ea9-aa8a-6bfa44d6ba12\"\n\t\t\t]\n\t\t},\n\t\t\"client/src/Pages/v1/PageSpeed/Details\": {\n\t\t\t\"path\": \"client/src/Pages/v1/PageSpeed/Details\",\n\t\t\t\"fileName\": \"Details\",\n\t\t\t\"cellName\": \"Details\",\n\t\t\t\"cellId\": \"581b4919-8b0c-4f0d-ae67-ad6de11d8c8b\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"043d3dac-d4bb-449b-a3a7-270d53b66dac\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Pages/v1/PageSpeed/Details/index.jsx\"\n\t\t\t]\n\t\t},\n\t\t\"client/src/Pages/v1/PageSpeed/Details/index.jsx\": {\n\t\t\t\"path\": \"client/src/Pages/v1/PageSpeed/Details/index.jsx\",\n\t\t\t\"fileName\": \"index.jsx\",\n\t\t\t\"cellName\": \"index.jsx\",\n\t\t\t\"cellId\": \"c4a7bb58-1d9c-4690-b6b8-460c1cc33702\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"581b4919-8b0c-4f0d-ae67-ad6de11d8c8b\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Pages/v1/PageSpeed/Details/index.jsx-simstep-0ec0eb06-05eb-4204-b077-9e47eb2cc316\"\n\t\t\t]\n\t\t},\n\t\t\"client/src/Pages/v1/Settings\": {\n\t\t\t\"path\": \"client/src/Pages/v1/Settings\",\n\t\t\t\"fileName\": \"Settings\",\n\t\t\t\"cellName\": \"Settings\",\n\t\t\t\"cellId\": \"50f77798-f41b-4f5b-b096-7afc921a0419\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"1a083b4a-787c-4eb4-8029-6700de987679\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Pages/v1/Settings/index.jsx\",\n\t\t\t\t\"client/src/Pages/v1/Settings/SettingsEmail.jsx\"\n\t\t\t]\n\t\t},\n\t\t\"client/src/Pages/v1/Settings/SettingsEmail.jsx\": {\n\t\t\t\"path\": \"client/src/Pages/v1/Settings/SettingsEmail.jsx\",\n\t\t\t\"fileName\": \"SettingsEmail.jsx\",\n\t\t\t\"cellName\": \"SettingsEmail.jsx\",\n\t\t\t\"cellId\": \"d8aa5b9e-f2a7-44c8-8813-d79c3f3238ee\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"50f77798-f41b-4f5b-b096-7afc921a0419\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Pages/v1/Settings/SettingsEmail.jsx-simstep-ae5c5146-4dbb-4612-9d23-086e57f72474\"\n\t\t\t]\n\t\t},\n\t\t\"client/src/Pages/v1/Settings/index.jsx\": {\n\t\t\t\"path\": \"client/src/Pages/v1/Settings/index.jsx\",\n\t\t\t\"fileName\": \"index.jsx\",\n\t\t\t\"cellName\": \"index.jsx\",\n\t\t\t\"cellId\": \"d4b34195-7e1e-47a0-9303-603987c81f95\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"50f77798-f41b-4f5b-b096-7afc921a0419\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Pages/v1/Settings/index.jsx-simstep-64e9f1af-13b7-4361-a2a9-3f45760e316d\"\n\t\t\t]\n\t\t},\n\t\t\"client/src/Pages/v1/StatusPage\": {\n\t\t\t\"path\": \"client/src/Pages/v1/StatusPage\",\n\t\t\t\"fileName\": \"StatusPage\",\n\t\t\t\"cellName\": \"StatusPage\",\n\t\t\t\"cellId\": \"9d662180-8b65-4426-ad37-cfed4bc01fb4\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"1a083b4a-787c-4eb4-8029-6700de987679\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Pages/v1/StatusPage/Create\",\n\t\t\t\t\"client/src/Pages/v1/StatusPage/Status\"\n\t\t\t]\n\t\t},\n\t\t\"client/src/Pages/v1/StatusPage/Create\": {\n\t\t\t\"path\": \"client/src/Pages/v1/StatusPage/Create\",\n\t\t\t\"fileName\": \"Create\",\n\t\t\t\"cellName\": \"Create\",\n\t\t\t\"cellId\": \"08602a28-f073-484e-9403-7eb798126dd4\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"9d662180-8b65-4426-ad37-cfed4bc01fb4\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Pages/v1/StatusPage/Create/index.jsx\",\n\t\t\t\t\"client/src/Pages/v1/StatusPage/Create/Hooks\"\n\t\t\t]\n\t\t},\n\t\t\"client/src/Pages/v1/StatusPage/Create/Hooks\": {\n\t\t\t\"path\": \"client/src/Pages/v1/StatusPage/Create/Hooks\",\n\t\t\t\"fileName\": \"Hooks\",\n\t\t\t\"cellName\": \"Hooks\",\n\t\t\t\"cellId\": \"56f6775e-9843-4ca2-bc8c-1c263b6c35e9\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"08602a28-f073-484e-9403-7eb798126dd4\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Pages/v1/StatusPage/Create/Hooks/useCreateStatusPage.jsx\"\n\t\t\t]\n\t\t},\n\t\t\"client/src/Pages/v1/StatusPage/Create/Hooks/useCreateStatusPage.jsx\": {\n\t\t\t\"path\": \"client/src/Pages/v1/StatusPage/Create/Hooks/useCreateStatusPage.jsx\",\n\t\t\t\"fileName\": \"useCreateStatusPage.jsx\",\n\t\t\t\"cellName\": \"useCreateStatusPage.jsx\",\n\t\t\t\"cellId\": \"3945e05f-2d99-4d6d-9a3e-b6c75ea3c45a\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"56f6775e-9843-4ca2-bc8c-1c263b6c35e9\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Pages/v1/StatusPage/Create/Hooks/useCreateStatusPage.jsx-simstep-3c99ae6a-b671-4f47-bed0-ddccd8ff5d35\"\n\t\t\t]\n\t\t},\n\t\t\"client/src/Pages/v1/StatusPage/Create/index.jsx\": {\n\t\t\t\"path\": \"client/src/Pages/v1/StatusPage/Create/index.jsx\",\n\t\t\t\"fileName\": \"index.jsx\",\n\t\t\t\"cellName\": \"index.jsx\",\n\t\t\t\"cellId\": \"e2d2bbf6-dffd-4edf-8c5d-34088d9d4745\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"08602a28-f073-484e-9403-7eb798126dd4\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Pages/v1/StatusPage/Create/index.jsx-simstep-de7b5d1f-b370-42a4-a410-4178f1e2d3a6\"\n\t\t\t]\n\t\t},\n\t\t\"client/src/Pages/v1/StatusPage/Status\": {\n\t\t\t\"path\": \"client/src/Pages/v1/StatusPage/Status\",\n\t\t\t\"fileName\": \"Status\",\n\t\t\t\"cellName\": \"Status\",\n\t\t\t\"cellId\": \"8ef70566-37d9-48fb-b5e8-37e5b68768a2\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"9d662180-8b65-4426-ad37-cfed4bc01fb4\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Pages/v1/StatusPage/Status/index.jsx\",\n\t\t\t\t\"client/src/Pages/v1/StatusPage/Status/Hooks\"\n\t\t\t]\n\t\t},\n\t\t\"client/src/Pages/v1/StatusPage/Status/Hooks\": {\n\t\t\t\"path\": \"client/src/Pages/v1/StatusPage/Status/Hooks\",\n\t\t\t\"fileName\": \"Hooks\",\n\t\t\t\"cellName\": \"Hooks\",\n\t\t\t\"cellId\": \"79da0721-d810-4f7f-9cf9-3ea462bf0bff\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"8ef70566-37d9-48fb-b5e8-37e5b68768a2\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Pages/v1/StatusPage/Status/Hooks/useStatusPageFetch.jsx\"\n\t\t\t]\n\t\t},\n\t\t\"client/src/Pages/v1/StatusPage/Status/Hooks/useStatusPageFetch.jsx\": {\n\t\t\t\"path\": \"client/src/Pages/v1/StatusPage/Status/Hooks/useStatusPageFetch.jsx\",\n\t\t\t\"fileName\": \"useStatusPageFetch.jsx\",\n\t\t\t\"cellName\": \"useStatusPageFetch.jsx\",\n\t\t\t\"cellId\": \"5b2cdab8-66f1-40a1-9621-0efaf54e04ae\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"79da0721-d810-4f7f-9cf9-3ea462bf0bff\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Pages/v1/StatusPage/Status/Hooks/useStatusPageFetch.jsx-simstep-b57bb249-9066-454e-aa8c-89108fdfcc2e\"\n\t\t\t]\n\t\t},\n\t\t\"client/src/Pages/v1/StatusPage/Status/index.jsx\": {\n\t\t\t\"path\": \"client/src/Pages/v1/StatusPage/Status/index.jsx\",\n\t\t\t\"fileName\": \"index.jsx\",\n\t\t\t\"cellName\": \"index.jsx\",\n\t\t\t\"cellId\": \"e1e6f5e0-fd8c-4260-aa4f-cdb096c6b1c3\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"8ef70566-37d9-48fb-b5e8-37e5b68768a2\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Pages/v1/StatusPage/Status/index.jsx-simstep-3d51e811-a659-442e-97e0-00798cd15647\"\n\t\t\t]\n\t\t},\n\t\t\"client/src/Pages/v1/Uptime\": {\n\t\t\t\"path\": \"client/src/Pages/v1/Uptime\",\n\t\t\t\"fileName\": \"Uptime\",\n\t\t\t\"cellName\": \"Uptime\",\n\t\t\t\"cellId\": \"7090fcdb-09be-4c85-86fd-e73553bbb2ff\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"1a083b4a-787c-4eb4-8029-6700de987679\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Pages/v1/Uptime/Create\",\n\t\t\t\t\"client/src/Pages/v1/Uptime/Details\",\n\t\t\t\t\"client/src/Pages/v1/Uptime/BulkImport\"\n\t\t\t]\n\t\t},\n\t\t\"client/src/Pages/v1/Uptime/BulkImport\": {\n\t\t\t\"path\": \"client/src/Pages/v1/Uptime/BulkImport\",\n\t\t\t\"fileName\": \"BulkImport\",\n\t\t\t\"cellName\": \"BulkImport\",\n\t\t\t\"cellId\": \"56dae13e-5735-4089-a9a4-e18be315aff7\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"7090fcdb-09be-4c85-86fd-e73553bbb2ff\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Pages/v1/Uptime/BulkImport/index.jsx\",\n\t\t\t\t\"client/src/Pages/v1/Uptime/BulkImport/Upload.jsx\"\n\t\t\t]\n\t\t},\n\t\t\"client/src/Pages/v1/Uptime/BulkImport/Upload.jsx\": {\n\t\t\t\"path\": \"client/src/Pages/v1/Uptime/BulkImport/Upload.jsx\",\n\t\t\t\"fileName\": \"Upload.jsx\",\n\t\t\t\"cellName\": \"Upload.jsx\",\n\t\t\t\"cellId\": \"cd84476a-1c8b-4781-811f-58fb9944365b\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"56dae13e-5735-4089-a9a4-e18be315aff7\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Pages/v1/Uptime/BulkImport/Upload.jsx-simstep-bbd04d55-fc6a-4ba8-bcde-5a4dc263d6eb\"\n\t\t\t]\n\t\t},\n\t\t\"client/src/Pages/v1/Uptime/BulkImport/index.jsx\": {\n\t\t\t\"path\": \"client/src/Pages/v1/Uptime/BulkImport/index.jsx\",\n\t\t\t\"fileName\": \"index.jsx\",\n\t\t\t\"cellName\": \"index.jsx\",\n\t\t\t\"cellId\": \"29b6ad3c-9538-47bc-8796-aab942dc4b71\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"56dae13e-5735-4089-a9a4-e18be315aff7\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Pages/v1/Uptime/BulkImport/index.jsx-simstep-0139fcaa-eb46-4176-b7bd-1cb15e7f1f4c\",\n\t\t\t\t\"client/src/Pages/v1/Uptime/BulkImport/index.jsx-simstep-72b3f16d-290d-4a61-8748-2ad90d63ec68\"\n\t\t\t]\n\t\t},\n\t\t\"client/src/Pages/v1/Uptime/Create\": {\n\t\t\t\"path\": \"client/src/Pages/v1/Uptime/Create\",\n\t\t\t\"fileName\": \"Create\",\n\t\t\t\"cellName\": \"Create\",\n\t\t\t\"cellId\": \"3dba5acc-cf25-40b7-ad21-9cd715454cd5\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"7090fcdb-09be-4c85-86fd-e73553bbb2ff\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Pages/v1/Uptime/Create/index.jsx\"\n\t\t\t]\n\t\t},\n\t\t\"client/src/Pages/v1/Uptime/Create/index.jsx\": {\n\t\t\t\"path\": \"client/src/Pages/v1/Uptime/Create/index.jsx\",\n\t\t\t\"fileName\": \"index.jsx\",\n\t\t\t\"cellName\": \"index.jsx\",\n\t\t\t\"cellId\": \"391ad99e-3114-4f54-a6ca-fd89b33c7e06\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"3dba5acc-cf25-40b7-ad21-9cd715454cd5\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Pages/v1/Uptime/Create/index.jsx-simstep-ab5de0b9-c70d-492c-98d9-8ddee66284ad\",\n\t\t\t\t\"client/src/Pages/v1/Uptime/Create/index.jsx-simstep-e02ddf57-270e-4f71-b4c4-d5183bb7879a\"\n\t\t\t]\n\t\t},\n\t\t\"client/src/Pages/v1/Uptime/Details\": {\n\t\t\t\"path\": \"client/src/Pages/v1/Uptime/Details\",\n\t\t\t\"fileName\": \"Details\",\n\t\t\t\"cellName\": \"Details\",\n\t\t\t\"cellId\": \"273f3009-69d0-46fe-af57-3cd94a24b55b\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"7090fcdb-09be-4c85-86fd-e73553bbb2ff\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Pages/v1/Uptime/Details/index.jsx\",\n\t\t\t\t\"client/src/Pages/v1/Uptime/Details/Components\"\n\t\t\t]\n\t\t},\n\t\t\"client/src/Pages/v1/Uptime/Details/Components\": {\n\t\t\t\"path\": \"client/src/Pages/v1/Uptime/Details/Components\",\n\t\t\t\"fileName\": \"Components\",\n\t\t\t\"cellName\": \"Components\",\n\t\t\t\"cellId\": \"6aed78bb-62f1-4ac1-9b9a-9d5977e87404\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"273f3009-69d0-46fe-af57-3cd94a24b55b\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Pages/v1/Uptime/Details/Components/ResponseTable\"\n\t\t\t]\n\t\t},\n\t\t\"client/src/Pages/v1/Uptime/Details/Components/ResponseTable\": {\n\t\t\t\"path\": \"client/src/Pages/v1/Uptime/Details/Components/ResponseTable\",\n\t\t\t\"fileName\": \"ResponseTable\",\n\t\t\t\"cellName\": \"ResponseTable\",\n\t\t\t\"cellId\": \"5ac0878f-d238-4763-8464-a85b4885a40f\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"6aed78bb-62f1-4ac1-9b9a-9d5977e87404\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Pages/v1/Uptime/Details/Components/ResponseTable/index.jsx\"\n\t\t\t]\n\t\t},\n\t\t\"client/src/Pages/v1/Uptime/Details/Components/ResponseTable/index.jsx\": {\n\t\t\t\"path\": \"client/src/Pages/v1/Uptime/Details/Components/ResponseTable/index.jsx\",\n\t\t\t\"fileName\": \"index.jsx\",\n\t\t\t\"cellName\": \"index.jsx\",\n\t\t\t\"cellId\": \"d3f74ac7-3b9a-4cae-8d77-a0d5d605bb27\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"5ac0878f-d238-4763-8464-a85b4885a40f\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Pages/v1/Uptime/Details/Components/ResponseTable/index.jsx-simstep-2b1651cd-2e70-4cc6-b2bb-23f94fa73d66\"\n\t\t\t]\n\t\t},\n\t\t\"client/src/Pages/v1/Uptime/Details/index.jsx\": {\n\t\t\t\"path\": \"client/src/Pages/v1/Uptime/Details/index.jsx\",\n\t\t\t\"fileName\": \"index.jsx\",\n\t\t\t\"cellName\": \"index.jsx\",\n\t\t\t\"cellId\": \"1807d5b9-54be-430b-8997-cada4dd9b521\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"273f3009-69d0-46fe-af57-3cd94a24b55b\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Pages/v1/Uptime/Details/index.jsx-simstep-35195328-9847-4678-b014-9331553f0d19\"\n\t\t\t]\n\t\t},\n\t\t\"client/src/Routes\": {\n\t\t\t\"path\": \"client/src/Routes\",\n\t\t\t\"fileName\": \"Routes\",\n\t\t\t\"cellName\": \"Routes\",\n\t\t\t\"cellId\": \"987f145b-5df6-4c30-bf1c-2a2d2b0e5cdc\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"d3264577-10f0-42fe-9411-7e9df0754d1e\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Routes/index.jsx\"\n\t\t\t]\n\t\t},\n\t\t\"client/src/Routes/index.jsx\": {\n\t\t\t\"path\": \"client/src/Routes/index.jsx\",\n\t\t\t\"fileName\": \"index.jsx\",\n\t\t\t\"cellName\": \"index.jsx\",\n\t\t\t\"cellId\": \"c4d7e7dd-75b1-44f1-a34a-6ed290a8e562\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"987f145b-5df6-4c30-bf1c-2a2d2b0e5cdc\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Routes/index.jsx-simstep-132354d7-df7a-4e03-9d00-16d54f836a1b\",\n\t\t\t\t\"client/src/Routes/index.jsx-simstep-a29da01e-8c5a-4e6d-8d3c-e49af528e4fa\"\n\t\t\t]\n\t\t},\n\t\t\"client/src/Utils\": {\n\t\t\t\"path\": \"client/src/Utils\",\n\t\t\t\"fileName\": \"Utils\",\n\t\t\t\"cellName\": \"Utils\",\n\t\t\t\"cellId\": \"02b07589-ec21-4366-b7d2-9071e8f3bad8\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"d3264577-10f0-42fe-9411-7e9df0754d1e\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Utils/NetworkService.js\"\n\t\t\t]\n\t\t},\n\t\t\"client/src/Utils/NetworkService.js\": {\n\t\t\t\"path\": \"client/src/Utils/NetworkService.js\",\n\t\t\t\"fileName\": \"NetworkService.js\",\n\t\t\t\"cellName\": \"NetworkService.js\",\n\t\t\t\"cellId\": \"16731e9d-3f73-4055-9d79-5ca9be679f68\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"02b07589-ec21-4366-b7d2-9071e8f3bad8\",\n\t\t\t\"children\": [\n\t\t\t\t\"client/src/Utils/NetworkService.js-simstep-14e9986b-c6ce-475e-97ed-da1fa2b6968d\",\n\t\t\t\t\"client/src/Utils/NetworkService.js-simstep-2fc087b3-033d-4cf5-81f2-e35b99a14bce\"\n\t\t\t]\n\t\t},\n\t\t\"server\": {\n\t\t\t\"path\": \"server\",\n\t\t\t\"fileName\": \"server\",\n\t\t\t\"cellName\": \"server\",\n\t\t\t\"cellId\": \"98af25c7-efc2-43d2-a273-c8da4e1038ad\",\n\t\t\t\"visible\": true,\n\t\t\t\"children\": [\n\t\t\t\t\"server/src\"\n\t\t\t]\n\t\t},\n\t\t\"server/src\": {\n\t\t\t\"path\": \"server/src\",\n\t\t\t\"fileName\": \"src\",\n\t\t\t\"cellName\": \"src\",\n\t\t\t\"cellId\": \"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"98af25c7-efc2-43d2-a273-c8da4e1038ad\",\n\t\t\t\"children\": [\n\t\t\t\t\"server/src/routes\",\n\t\t\t\t\"server/src/controllers\",\n\t\t\t\t\"server/src/service\",\n\t\t\t\t\"server/src/db\",\n\t\t\t\t\"server/src/config\",\n\t\t\t\t\"server/src/middleware\"\n\t\t\t]\n\t\t},\n\t\t\"server/src/config\": {\n\t\t\t\"path\": \"server/src/config\",\n\t\t\t\"fileName\": \"config\",\n\t\t\t\"cellName\": \"config\",\n\t\t\t\"cellId\": \"fe47576c-c186-4950-82a5-b2fd24eb2561\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\",\n\t\t\t\"children\": [\n\t\t\t\t\"server/src/config/routes.js\"\n\t\t\t]\n\t\t},\n\t\t\"server/src/config/routes.js\": {\n\t\t\t\"path\": \"server/src/config/routes.js\",\n\t\t\t\"fileName\": \"routes.js\",\n\t\t\t\"cellName\": \"routes.js\",\n\t\t\t\"cellId\": \"cb53d612-9b89-47da-911c-165d0382a7d8\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"fe47576c-c186-4950-82a5-b2fd24eb2561\",\n\t\t\t\"children\": [\n\t\t\t\t\"server/src/config/routes.js-simstep-3e93ef65-8e2c-405b-8dc1-56d8e93937b3\"\n\t\t\t]\n\t\t},\n\t\t\"server/src/controllers\": {\n\t\t\t\"path\": \"server/src/controllers\",\n\t\t\t\"fileName\": \"controllers\",\n\t\t\t\"cellName\": \"controllers\",\n\t\t\t\"cellId\": \"478e649c-1d1b-41d2-9b7b-6927e1dec7e1\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\",\n\t\t\t\"children\": [\n\t\t\t\t\"server/src/controllers/v1\"\n\t\t\t]\n\t\t},\n\t\t\"server/src/controllers/v1\": {\n\t\t\t\"path\": \"server/src/controllers/v1\",\n\t\t\t\"fileName\": \"v1\",\n\t\t\t\"cellName\": \"v1\",\n\t\t\t\"cellId\": \"fc591f7a-d4ac-4565-949d-a87a58a79bbc\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"478e649c-1d1b-41d2-9b7b-6927e1dec7e1\",\n\t\t\t\"children\": [\n\t\t\t\t\"server/src/controllers/v1/monitorController.js\",\n\t\t\t\t\"server/src/controllers/v1/notificationController.js\",\n\t\t\t\t\"server/src/controllers/v1/statusPageController.js\",\n\t\t\t\t\"server/src/controllers/v1/checkController.js\",\n\t\t\t\t\"server/src/controllers/v1/maintenanceWindowController.js\",\n\t\t\t\t\"server/src/controllers/v1/inviteController.js\",\n\t\t\t\t\"server/src/controllers/v1/settingsController.js\",\n\t\t\t\t\"server/src/controllers/v1/diagnosticController.js\"\n\t\t\t]\n\t\t},\n\t\t\"server/src/controllers/v1/checkController.js\": {\n\t\t\t\"path\": \"server/src/controllers/v1/checkController.js\",\n\t\t\t\"fileName\": \"checkController.js\",\n\t\t\t\"cellName\": \"checkController.js\",\n\t\t\t\"cellId\": \"d983e54f-2fbe-496a-932d-a827e1124804\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"fc591f7a-d4ac-4565-949d-a87a58a79bbc\",\n\t\t\t\"children\": [\n\t\t\t\t\"server/src/controllers/v1/checkController.js-simstep-5768fdc5-045c-48ef-b0c9-79769403648f\"\n\t\t\t]\n\t\t},\n\t\t\"server/src/controllers/v1/diagnosticController.js\": {\n\t\t\t\"path\": \"server/src/controllers/v1/diagnosticController.js\",\n\t\t\t\"fileName\": \"diagnosticController.js\",\n\t\t\t\"cellName\": \"diagnosticController.js\",\n\t\t\t\"cellId\": \"5882419e-8a92-4edd-a71a-1252983f9af7\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"fc591f7a-d4ac-4565-949d-a87a58a79bbc\"\n\t\t},\n\t\t\"server/src/controllers/v1/inviteController.js\": {\n\t\t\t\"path\": \"server/src/controllers/v1/inviteController.js\",\n\t\t\t\"fileName\": \"inviteController.js\",\n\t\t\t\"cellName\": \"inviteController.js\",\n\t\t\t\"cellId\": \"6a186805-9d50-4bc3-9d56-e627a7ec2eb8\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"fc591f7a-d4ac-4565-949d-a87a58a79bbc\"\n\t\t},\n\t\t\"server/src/controllers/v1/maintenanceWindowController.js\": {\n\t\t\t\"path\": \"server/src/controllers/v1/maintenanceWindowController.js\",\n\t\t\t\"fileName\": \"maintenanceWindowController.js\",\n\t\t\t\"cellName\": \"maintenanceWindowController.js\",\n\t\t\t\"cellId\": \"a0cae18c-3c0e-40d3-ab03-eef7eace65d6\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"fc591f7a-d4ac-4565-949d-a87a58a79bbc\",\n\t\t\t\"children\": [\n\t\t\t\t\"server/src/controllers/v1/maintenanceWindowController.js-simstep-95fc1919-339d-4659-98cb-3dc50f662075\",\n\t\t\t\t\"server/src/controllers/v1/maintenanceWindowController.js-simstep-1251da83-5949-4e24-a1d2-fc74ff785aa9\"\n\t\t\t]\n\t\t},\n\t\t\"server/src/controllers/v1/monitorController.js\": {\n\t\t\t\"path\": \"server/src/controllers/v1/monitorController.js\",\n\t\t\t\"fileName\": \"monitorController.js\",\n\t\t\t\"cellName\": \"monitorController.js\",\n\t\t\t\"cellId\": \"341f2784-67ee-4477-9445-a8c240ee6261\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"fc591f7a-d4ac-4565-949d-a87a58a79bbc\",\n\t\t\t\"children\": [\n\t\t\t\t\"server/src/controllers/v1/monitorController.js-simstep-38fd069d-9c44-4078-954b-3a0899e9acf4\",\n\t\t\t\t\"server/src/controllers/v1/monitorController.js-simstep-a3799570-64bf-481e-9ffe-31dbad8a36e4\",\n\t\t\t\t\"server/src/controllers/v1/monitorController.js-simstep-f5377571-156f-4c5c-8bab-b6dacdf0fea6\",\n\t\t\t\t\"server/src/controllers/v1/monitorController.js-simstep-d9db3f40-8add-4551-9323-274348b9800f\",\n\t\t\t\t\"server/src/controllers/v1/monitorController.js-simstep-256095b8-5e3a-4c20-abd9-be9e6a9d0bad\",\n\t\t\t\t\"server/src/controllers/v1/monitorController.js-simstep-60abdb27-4078-4678-a010-0f6938d4be48\"\n\t\t\t]\n\t\t},\n\t\t\"server/src/controllers/v1/notificationController.js\": {\n\t\t\t\"path\": \"server/src/controllers/v1/notificationController.js\",\n\t\t\t\"fileName\": \"notificationController.js\",\n\t\t\t\"cellName\": \"notificationController.js\",\n\t\t\t\"cellId\": \"8e5941e1-e577-455f-bbf2-83a418ad5908\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"fc591f7a-d4ac-4565-949d-a87a58a79bbc\"\n\t\t},\n\t\t\"server/src/controllers/v1/settingsController.js\": {\n\t\t\t\"path\": \"server/src/controllers/v1/settingsController.js\",\n\t\t\t\"fileName\": \"settingsController.js\",\n\t\t\t\"cellName\": \"settingsController.js\",\n\t\t\t\"cellId\": \"a1fea5b0-fb7c-4189-9484-9d3312660767\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"fc591f7a-d4ac-4565-949d-a87a58a79bbc\",\n\t\t\t\"children\": [\n\t\t\t\t\"server/src/controllers/v1/settingsController.js-simstep-441b0c45-5f27-478d-8ca8-58fbd5f460ea\",\n\t\t\t\t\"server/src/controllers/v1/settingsController.js-simstep-7632e8d2-4086-4169-ae3f-bfbf8d657987\"\n\t\t\t]\n\t\t},\n\t\t\"server/src/controllers/v1/statusPageController.js\": {\n\t\t\t\"path\": \"server/src/controllers/v1/statusPageController.js\",\n\t\t\t\"fileName\": \"statusPageController.js\",\n\t\t\t\"cellName\": \"statusPageController.js\",\n\t\t\t\"cellId\": \"17a4f435-5a8e-4433-84a6-9ac17362709a\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"fc591f7a-d4ac-4565-949d-a87a58a79bbc\",\n\t\t\t\"children\": [\n\t\t\t\t\"server/src/controllers/v1/statusPageController.js-simstep-01694730-8a75-4949-8815-bb4d6e3e2b42\",\n\t\t\t\t\"server/src/controllers/v1/statusPageController.js-simstep-2a115421-5175-4c8f-8cdd-62f3fe148af5\",\n\t\t\t\t\"server/src/controllers/v1/statusPageController.js-simstep-5bdbd179-ce8f-4171-a073-af72a99b4468\",\n\t\t\t\t\"server/src/controllers/v1/statusPageController.js-simstep-83224406-2f1d-4030-9beb-d65c2baf544d\"\n\t\t\t]\n\t\t},\n\t\t\"server/src/db\": {\n\t\t\t\"path\": \"server/src/db\",\n\t\t\t\"fileName\": \"db\",\n\t\t\t\"cellName\": \"db\",\n\t\t\t\"cellId\": \"15ee5d81-a0cf-4614-80b8-7a1123ab20b8\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\",\n\t\t\t\"children\": [\n\t\t\t\t\"server/src/db/v1\",\n\t\t\t\t\"server/src/db/v2\"\n\t\t\t]\n\t\t},\n\t\t\"server/src/db/v1\": {\n\t\t\t\"path\": \"server/src/db/v1\",\n\t\t\t\"fileName\": \"v1\",\n\t\t\t\"cellName\": \"v1\",\n\t\t\t\"cellId\": \"58c5a3fd-1e69-4ca4-a64e-314f5644bdaf\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"15ee5d81-a0cf-4614-80b8-7a1123ab20b8\",\n\t\t\t\"children\": [\n\t\t\t\t\"server/src/db/v1/modules\"\n\t\t\t]\n\t\t},\n\t\t\"server/src/db/v1/modules\": {\n\t\t\t\"path\": \"server/src/db/v1/modules\",\n\t\t\t\"fileName\": \"modules\",\n\t\t\t\"cellName\": \"modules\",\n\t\t\t\"cellId\": \"82cb3dbe-c922-438a-a912-255376f4b380\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"58c5a3fd-1e69-4ca4-a64e-314f5644bdaf\",\n\t\t\t\"children\": [\n\t\t\t\t\"server/src/db/v1/modules/monitorModule.js\",\n\t\t\t\t\"server/src/db/v1/modules/monitorModuleQueries.js\",\n\t\t\t\t\"server/src/db/v1/modules/notificationModule.js\",\n\t\t\t\t\"server/src/db/v1/modules/statusPageModule.js\",\n\t\t\t\t\"server/src/db/v1/modules/checkModule.js\",\n\t\t\t\t\"server/src/db/v1/modules/maintenanceWindowModule.js\",\n\t\t\t\t\"server/src/db/v1/modules/inviteModule.js\"\n\t\t\t]\n\t\t},\n\t\t\"server/src/db/v1/modules/checkModule.js\": {\n\t\t\t\"path\": \"server/src/db/v1/modules/checkModule.js\",\n\t\t\t\"fileName\": \"checkModule.js\",\n\t\t\t\"cellName\": \"checkModule.js\",\n\t\t\t\"cellId\": \"860b5eec-a1ce-4e1f-a316-e1586f03af96\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"82cb3dbe-c922-438a-a912-255376f4b380\"\n\t\t},\n\t\t\"server/src/db/v1/modules/inviteModule.js\": {\n\t\t\t\"path\": \"server/src/db/v1/modules/inviteModule.js\",\n\t\t\t\"fileName\": \"inviteModule.js\",\n\t\t\t\"cellName\": \"inviteModule.js\",\n\t\t\t\"cellId\": \"08853f8a-f596-4df0-9190-dad04f54caef\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"82cb3dbe-c922-438a-a912-255376f4b380\"\n\t\t},\n\t\t\"server/src/db/v1/modules/maintenanceWindowModule.js\": {\n\t\t\t\"path\": \"server/src/db/v1/modules/maintenanceWindowModule.js\",\n\t\t\t\"fileName\": \"maintenanceWindowModule.js\",\n\t\t\t\"cellName\": \"maintenanceWindowModule.js\",\n\t\t\t\"cellId\": \"95ed6c41-ebeb-4c08-98c3-bab8b426789e\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"82cb3dbe-c922-438a-a912-255376f4b380\",\n\t\t\t\"children\": [\n\t\t\t\t\"server/src/db/v1/modules/maintenanceWindowModule.js-simstep-a3c47fd4-c701-46c2-9aff-94a667b3e368\",\n\t\t\t\t\"server/src/db/v1/modules/maintenanceWindowModule.js-simstep-9bfbae5a-f487-40ef-86f5-04a1cc3c7662\"\n\t\t\t]\n\t\t},\n\t\t\"server/src/db/v1/modules/monitorModule.js\": {\n\t\t\t\"path\": \"server/src/db/v1/modules/monitorModule.js\",\n\t\t\t\"fileName\": \"monitorModule.js\",\n\t\t\t\"cellName\": \"monitorModule.js\",\n\t\t\t\"cellId\": \"630b3ece-2648-48d5-99b5-ef9611de2ad5\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"82cb3dbe-c922-438a-a912-255376f4b380\",\n\t\t\t\"children\": [\n\t\t\t\t\"server/src/db/v1/modules/monitorModule.js-simstep-ca3ad309-323a-418d-a171-c16f56fae23c\",\n\t\t\t\t\"server/src/db/v1/modules/monitorModule.js-simstep-8502ae1f-f029-446e-9dde-59c2aba87a8a\",\n\t\t\t\t\"server/src/db/v1/modules/monitorModule.js-simstep-70f18c21-2918-402e-9c35-1bdce8bc82d4\"\n\t\t\t]\n\t\t},\n\t\t\"server/src/db/v1/modules/monitorModuleQueries.js\": {\n\t\t\t\"path\": \"server/src/db/v1/modules/monitorModuleQueries.js\",\n\t\t\t\"fileName\": \"monitorModuleQueries.js\",\n\t\t\t\"cellName\": \"monitorModuleQueries.js\",\n\t\t\t\"cellId\": \"a0b22a5a-59e1-47e3-8218-a4ad083b1b71\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"82cb3dbe-c922-438a-a912-255376f4b380\"\n\t\t},\n\t\t\"server/src/db/v1/modules/notificationModule.js\": {\n\t\t\t\"path\": \"server/src/db/v1/modules/notificationModule.js\",\n\t\t\t\"fileName\": \"notificationModule.js\",\n\t\t\t\"cellName\": \"notificationModule.js\",\n\t\t\t\"cellId\": \"62daeac4-9402-448a-972c-cb8cb760671c\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"82cb3dbe-c922-438a-a912-255376f4b380\",\n\t\t\t\"children\": [\n\t\t\t\t\"server/src/db/v1/modules/notificationModule.js-simstep-d29ab4ab-be50-4f17-af6e-2c61cec9d0ab\"\n\t\t\t]\n\t\t},\n\t\t\"server/src/db/v1/modules/statusPageModule.js\": {\n\t\t\t\"path\": \"server/src/db/v1/modules/statusPageModule.js\",\n\t\t\t\"fileName\": \"statusPageModule.js\",\n\t\t\t\"cellName\": \"statusPageModule.js\",\n\t\t\t\"cellId\": \"f8541fe3-4bcf-4833-a226-66b5301adf58\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"82cb3dbe-c922-438a-a912-255376f4b380\",\n\t\t\t\"children\": [\n\t\t\t\t\"server/src/db/v1/modules/statusPageModule.js-simstep-b6fa93cd-6fca-4d9e-969a-5400e2437ee8\",\n\t\t\t\t\"server/src/db/v1/modules/statusPageModule.js-simstep-ceb044e9-6545-4d04-bf79-ec8146eb8ec9\"\n\t\t\t]\n\t\t},\n\t\t\"server/src/db/v2\": {\n\t\t\t\"path\": \"server/src/db/v2\",\n\t\t\t\"fileName\": \"v2\",\n\t\t\t\"cellName\": \"v2\",\n\t\t\t\"cellId\": \"e2f99143-54b7-44dc-b566-1c2fb901bd16\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"15ee5d81-a0cf-4614-80b8-7a1123ab20b8\",\n\t\t\t\"children\": [\n\t\t\t\t\"server/src/db/v2/models\"\n\t\t\t]\n\t\t},\n\t\t\"server/src/db/v2/models\": {\n\t\t\t\"path\": \"server/src/db/v2/models\",\n\t\t\t\"fileName\": \"models\",\n\t\t\t\"cellName\": \"models\",\n\t\t\t\"cellId\": \"b53384d7-b989-4ac7-bd68-1c3621174ef4\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"e2f99143-54b7-44dc-b566-1c2fb901bd16\",\n\t\t\t\"children\": [\n\t\t\t\t\"server/src/db/v2/models/checks\"\n\t\t\t]\n\t\t},\n\t\t\"server/src/db/v2/models/checks\": {\n\t\t\t\"path\": \"server/src/db/v2/models/checks\",\n\t\t\t\"fileName\": \"checks\",\n\t\t\t\"cellName\": \"checks\",\n\t\t\t\"cellId\": \"64e3bb0a-67f5-4269-9e7d-94fe91ac78fc\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"b53384d7-b989-4ac7-bd68-1c3621174ef4\",\n\t\t\t\"children\": [\n\t\t\t\t\"server/src/db/v2/models/checks/Check.ts\"\n\t\t\t]\n\t\t},\n\t\t\"server/src/db/v2/models/checks/Check.ts\": {\n\t\t\t\"path\": \"server/src/db/v2/models/checks/Check.ts\",\n\t\t\t\"fileName\": \"Check.ts\",\n\t\t\t\"cellName\": \"Check.ts\",\n\t\t\t\"cellId\": \"1425ec43-f0f4-4c8b-a140-176c079219d6\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"64e3bb0a-67f5-4269-9e7d-94fe91ac78fc\"\n\t\t},\n\t\t\"server/src/middleware\": {\n\t\t\t\"path\": \"server/src/middleware\",\n\t\t\t\"fileName\": \"middleware\",\n\t\t\t\"cellName\": \"middleware\",\n\t\t\t\"cellId\": \"a968db5d-8f6d-4fd7-9df0-8b332b521703\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\",\n\t\t\t\"children\": [\n\t\t\t\t\"server/src/middleware/v1\"\n\t\t\t]\n\t\t},\n\t\t\"server/src/middleware/v1\": {\n\t\t\t\"path\": \"server/src/middleware/v1\",\n\t\t\t\"fileName\": \"v1\",\n\t\t\t\"cellName\": \"v1\",\n\t\t\t\"cellId\": \"09082f73-e215-465f-9206-0a963fb4c7cb\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"a968db5d-8f6d-4fd7-9df0-8b332b521703\",\n\t\t\t\"children\": [\n\t\t\t\t\"server/src/middleware/v1/isAllowed.js\"\n\t\t\t]\n\t\t},\n\t\t\"server/src/middleware/v1/isAllowed.js\": {\n\t\t\t\"path\": \"server/src/middleware/v1/isAllowed.js\",\n\t\t\t\"fileName\": \"isAllowed.js\",\n\t\t\t\"cellName\": \"isAllowed.js\",\n\t\t\t\"cellId\": \"001fa2e4-eadd-4474-b2ec-79d7ea43465f\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"09082f73-e215-465f-9206-0a963fb4c7cb\",\n\t\t\t\"children\": [\n\t\t\t\t\"server/src/middleware/v1/isAllowed.js-simstep-50dd7316-7d01-43f7-9036-d97d51a9c178\"\n\t\t\t]\n\t\t},\n\t\t\"server/src/routes\": {\n\t\t\t\"path\": \"server/src/routes\",\n\t\t\t\"fileName\": \"routes\",\n\t\t\t\"cellName\": \"routes\",\n\t\t\t\"cellId\": \"ffaaf471-ac3c-4ea3-a5a9-d5255169e54b\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\",\n\t\t\t\"children\": [\n\t\t\t\t\"server/src/routes/v1\"\n\t\t\t]\n\t\t},\n\t\t\"server/src/routes/v1\": {\n\t\t\t\"path\": \"server/src/routes/v1\",\n\t\t\t\"fileName\": \"v1\",\n\t\t\t\"cellName\": \"v1\",\n\t\t\t\"cellId\": \"d3375a20-2776-4771-b806-649bbeb541bd\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"ffaaf471-ac3c-4ea3-a5a9-d5255169e54b\",\n\t\t\t\"children\": [\n\t\t\t\t\"server/src/routes/v1/monitorRoute.js\",\n\t\t\t\t\"server/src/routes/v1/notificationRoute.js\",\n\t\t\t\t\"server/src/routes/v1/statusPageRoute.js\",\n\t\t\t\t\"server/src/routes/v1/checkRoute.js\",\n\t\t\t\t\"server/src/routes/v1/maintenanceWindowRoute.js\",\n\t\t\t\t\"server/src/routes/v1/inviteRoute.js\"\n\t\t\t]\n\t\t},\n\t\t\"server/src/routes/v1/checkRoute.js\": {\n\t\t\t\"path\": \"server/src/routes/v1/checkRoute.js\",\n\t\t\t\"fileName\": \"checkRoute.js\",\n\t\t\t\"cellName\": \"checkRoute.js\",\n\t\t\t\"cellId\": \"d18dbe1d-2f2c-4336-bd21-47c1670f7bab\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"d3375a20-2776-4771-b806-649bbeb541bd\",\n\t\t\t\"children\": [\n\t\t\t\t\"server/src/routes/v1/checkRoute.js-simstep-c5fd192f-ea28-48a0-b3e7-5bc04f521192\"\n\t\t\t]\n\t\t},\n\t\t\"server/src/routes/v1/inviteRoute.js\": {\n\t\t\t\"path\": \"server/src/routes/v1/inviteRoute.js\",\n\t\t\t\"fileName\": \"inviteRoute.js\",\n\t\t\t\"cellName\": \"inviteRoute.js\",\n\t\t\t\"cellId\": \"9edafb8a-3661-4a7e-8510-a47f3cbc7564\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"d3375a20-2776-4771-b806-649bbeb541bd\"\n\t\t},\n\t\t\"server/src/routes/v1/maintenanceWindowRoute.js\": {\n\t\t\t\"path\": \"server/src/routes/v1/maintenanceWindowRoute.js\",\n\t\t\t\"fileName\": \"maintenanceWindowRoute.js\",\n\t\t\t\"cellName\": \"maintenanceWindowRoute.js\",\n\t\t\t\"cellId\": \"5f21f109-1967-416f-a649-9b48e78b90f6\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"d3375a20-2776-4771-b806-649bbeb541bd\"\n\t\t},\n\t\t\"server/src/routes/v1/monitorRoute.js\": {\n\t\t\t\"path\": \"server/src/routes/v1/monitorRoute.js\",\n\t\t\t\"fileName\": \"monitorRoute.js\",\n\t\t\t\"cellName\": \"monitorRoute.js\",\n\t\t\t\"cellId\": \"10611636-ec73-4a26-87a5-654ae64a4843\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"d3375a20-2776-4771-b806-649bbeb541bd\",\n\t\t\t\"children\": [\n\t\t\t\t\"server/src/routes/v1/monitorRoute.js-simstep-07bf3d83-047d-4e51-9f96-8c9c64848500\",\n\t\t\t\t\"server/src/routes/v1/monitorRoute.js-simstep-63d8d81f-f436-4594-a6eb-8c0fd2110bc1\"\n\t\t\t]\n\t\t},\n\t\t\"server/src/routes/v1/notificationRoute.js\": {\n\t\t\t\"path\": \"server/src/routes/v1/notificationRoute.js\",\n\t\t\t\"fileName\": \"notificationRoute.js\",\n\t\t\t\"cellName\": \"notificationRoute.js\",\n\t\t\t\"cellId\": \"96250197-23af-4059-9904-fd6751f70ad5\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"d3375a20-2776-4771-b806-649bbeb541bd\",\n\t\t\t\"children\": [\n\t\t\t\t\"server/src/routes/v1/notificationRoute.js-simstep-2f9266c9-4cbc-4b50-a280-cf8b5800d540\",\n\t\t\t\t\"server/src/routes/v1/notificationRoute.js-simstep-c1b17b64-90e9-48bc-8927-25d7ebfc3036\"\n\t\t\t]\n\t\t},\n\t\t\"server/src/routes/v1/statusPageRoute.js\": {\n\t\t\t\"path\": \"server/src/routes/v1/statusPageRoute.js\",\n\t\t\t\"fileName\": \"statusPageRoute.js\",\n\t\t\t\"cellName\": \"statusPageRoute.js\",\n\t\t\t\"cellId\": \"773e1065-b0a5-46a9-b0cc-6b963f69f5cc\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"d3375a20-2776-4771-b806-649bbeb541bd\",\n\t\t\t\"children\": [\n\t\t\t\t\"server/src/routes/v1/statusPageRoute.js-simstep-84f11567-b3c4-42a2-aa7f-d78c1412099a\",\n\t\t\t\t\"server/src/routes/v1/statusPageRoute.js-simstep-477c6821-b29b-4b38-8930-ced21b8a75e5\"\n\t\t\t]\n\t\t},\n\t\t\"server/src/service\": {\n\t\t\t\"path\": \"server/src/service\",\n\t\t\t\"fileName\": \"service\",\n\t\t\t\"cellName\": \"service\",\n\t\t\t\"cellId\": \"99e9b746-7809-41f4-a433-1de7cc90574b\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\",\n\t\t\t\"children\": [\n\t\t\t\t\"server/src/service/v1\",\n\t\t\t\t\"server/src/service/v2\"\n\t\t\t]\n\t\t},\n\t\t\"server/src/service/v1\": {\n\t\t\t\"path\": \"server/src/service/v1\",\n\t\t\t\"fileName\": \"v1\",\n\t\t\t\"cellName\": \"v1\",\n\t\t\t\"cellId\": \"bbbe53d6-f595-498a-ae45-e08611f39c3d\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"99e9b746-7809-41f4-a433-1de7cc90574b\",\n\t\t\t\"children\": [\n\t\t\t\t\"server/src/service/v1/business\",\n\t\t\t\t\"server/src/service/v1/infrastructure\"\n\t\t\t]\n\t\t},\n\t\t\"server/src/service/v1/business\": {\n\t\t\t\"path\": \"server/src/service/v1/business\",\n\t\t\t\"fileName\": \"business\",\n\t\t\t\"cellName\": \"business\",\n\t\t\t\"cellId\": \"87d3b101-9443-4ed4-9c4f-f759d41677eb\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"bbbe53d6-f595-498a-ae45-e08611f39c3d\",\n\t\t\t\"children\": [\n\t\t\t\t\"server/src/service/v1/business/monitorService.js\",\n\t\t\t\t\"server/src/service/v1/business/checkService.js\",\n\t\t\t\t\"server/src/service/v1/business/maintenanceWindowService.js\",\n\t\t\t\t\"server/src/service/v1/business/inviteService.js\",\n\t\t\t\t\"server/src/service/v1/business/diagnosticService.js\"\n\t\t\t]\n\t\t},\n\t\t\"server/src/service/v1/business/checkService.js\": {\n\t\t\t\"path\": \"server/src/service/v1/business/checkService.js\",\n\t\t\t\"fileName\": \"checkService.js\",\n\t\t\t\"cellName\": \"checkService.js\",\n\t\t\t\"cellId\": \"f90db867-e1e7-4554-b446-fa78fc6a8578\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"87d3b101-9443-4ed4-9c4f-f759d41677eb\",\n\t\t\t\"children\": [\n\t\t\t\t\"server/src/service/v1/business/checkService.js-simstep-83fea05d-8306-4a73-a43f-882cdd14f50f\"\n\t\t\t]\n\t\t},\n\t\t\"server/src/service/v1/business/diagnosticService.js\": {\n\t\t\t\"path\": \"server/src/service/v1/business/diagnosticService.js\",\n\t\t\t\"fileName\": \"diagnosticService.js\",\n\t\t\t\"cellName\": \"diagnosticService.js\",\n\t\t\t\"cellId\": \"643b26c1-3bfb-4c41-8179-96dfc237d99e\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"87d3b101-9443-4ed4-9c4f-f759d41677eb\",\n\t\t\t\"children\": [\n\t\t\t\t\"server/src/service/v1/business/diagnosticService.js-simstep-8fb704ca-67d9-437c-90d8-01302634d568\"\n\t\t\t]\n\t\t},\n\t\t\"server/src/service/v1/business/inviteService.js\": {\n\t\t\t\"path\": \"server/src/service/v1/business/inviteService.js\",\n\t\t\t\"fileName\": \"inviteService.js\",\n\t\t\t\"cellName\": \"inviteService.js\",\n\t\t\t\"cellId\": \"570278b7-9b72-4299-9fd9-46b253b48e9b\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"87d3b101-9443-4ed4-9c4f-f759d41677eb\",\n\t\t\t\"children\": [\n\t\t\t\t\"server/src/service/v1/business/inviteService.js-simstep-55fe9963-30d2-47f8-859f-b485a77064c4\",\n\t\t\t\t\"server/src/service/v1/business/inviteService.js-simstep-7d1f86f2-c8d5-48fb-a8c1-b337dc56271f\"\n\t\t\t]\n\t\t},\n\t\t\"server/src/service/v1/business/maintenanceWindowService.js\": {\n\t\t\t\"path\": \"server/src/service/v1/business/maintenanceWindowService.js\",\n\t\t\t\"fileName\": \"maintenanceWindowService.js\",\n\t\t\t\"cellName\": \"maintenanceWindowService.js\",\n\t\t\t\"cellId\": \"26b8daff-aa48-4baa-9d6c-05f771bf0990\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"87d3b101-9443-4ed4-9c4f-f759d41677eb\",\n\t\t\t\"children\": [\n\t\t\t\t\"server/src/service/v1/business/maintenanceWindowService.js-simstep-6e2cf739-1514-4c37-9874-10b68a47010e\"\n\t\t\t]\n\t\t},\n\t\t\"server/src/service/v1/business/monitorService.js\": {\n\t\t\t\"path\": \"server/src/service/v1/business/monitorService.js\",\n\t\t\t\"fileName\": \"monitorService.js\",\n\t\t\t\"cellName\": \"monitorService.js\",\n\t\t\t\"cellId\": \"b4e479df-9b21-4430-9383-84831f503c2e\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"87d3b101-9443-4ed4-9c4f-f759d41677eb\",\n\t\t\t\"children\": [\n\t\t\t\t\"server/src/service/v1/business/monitorService.js-simstep-2c7c3082-e4b6-4525-860f-2ffcd9e86db1\",\n\t\t\t\t\"server/src/service/v1/business/monitorService.js-simstep-66fbf913-e662-4bd9-ada6-077be9e37f07\",\n\t\t\t\t\"server/src/service/v1/business/monitorService.js-simstep-85cd1d5d-7ffb-49c5-aacb-907048003fc5\"\n\t\t\t]\n\t\t},\n\t\t\"server/src/service/v1/infrastructure\": {\n\t\t\t\"path\": \"server/src/service/v1/infrastructure\",\n\t\t\t\"fileName\": \"infrastructure\",\n\t\t\t\"cellName\": \"infrastructure\",\n\t\t\t\"cellId\": \"1670815f-860d-4ea4-92e1-b238a799d3dc\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"bbbe53d6-f595-498a-ae45-e08611f39c3d\",\n\t\t\t\"children\": [\n\t\t\t\t\"server/src/service/v1/infrastructure/SuperSimpleQueue\",\n\t\t\t\t\"server/src/service/v1/infrastructure/networkService.js\",\n\t\t\t\t\"server/src/service/v1/infrastructure/statusService.js\",\n\t\t\t\t\"server/src/service/v1/infrastructure/notificationService.js\",\n\t\t\t\t\"server/src/service/v1/infrastructure/notificationUtils.js\"\n\t\t\t]\n\t\t},\n\t\t\"server/src/service/v1/infrastructure/SuperSimpleQueue\": {\n\t\t\t\"path\": \"server/src/service/v1/infrastructure/SuperSimpleQueue\",\n\t\t\t\"fileName\": \"SuperSimpleQueue\",\n\t\t\t\"cellName\": \"SuperSimpleQueue\",\n\t\t\t\"cellId\": \"dda70a36-2d1d-4e46-8bcc-52d0d474bf7b\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"1670815f-860d-4ea4-92e1-b238a799d3dc\",\n\t\t\t\"children\": [\n\t\t\t\t\"server/src/service/v1/infrastructure/SuperSimpleQueue/SuperSimpleQueue.js\",\n\t\t\t\t\"server/src/service/v1/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.js\"\n\t\t\t]\n\t\t},\n\t\t\"server/src/service/v1/infrastructure/SuperSimpleQueue/SuperSimpleQueue.js\": {\n\t\t\t\"path\": \"server/src/service/v1/infrastructure/SuperSimpleQueue/SuperSimpleQueue.js\",\n\t\t\t\"fileName\": \"SuperSimpleQueue.js\",\n\t\t\t\"cellName\": \"SuperSimpleQueue.js\",\n\t\t\t\"cellId\": \"d9c0127e-31aa-4509-b5c9-f7017d10d69a\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"dda70a36-2d1d-4e46-8bcc-52d0d474bf7b\",\n\t\t\t\"children\": [\n\t\t\t\t\"server/src/service/v1/infrastructure/SuperSimpleQueue/SuperSimpleQueue.js-simstep-2702bfca-7611-4562-8d3e-a05af8257871\"\n\t\t\t]\n\t\t},\n\t\t\"server/src/service/v1/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.js\": {\n\t\t\t\"path\": \"server/src/service/v1/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.js\",\n\t\t\t\"fileName\": \"SuperSimpleQueueHelper.js\",\n\t\t\t\"cellName\": \"SuperSimpleQueueHelper.js\",\n\t\t\t\"cellId\": \"04c12e9a-e025-457c-a634-5f7472a42985\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"dda70a36-2d1d-4e46-8bcc-52d0d474bf7b\",\n\t\t\t\"children\": [\n\t\t\t\t\"server/src/service/v1/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.js-simstep-e22a708a-a348-4775-8ee3-f32a35446e24\",\n\t\t\t\t\"server/src/service/v1/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.js-simstep-a47affaf-b952-46d6-9709-6120a77690e1\",\n\t\t\t\t\"server/src/service/v1/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.js-simstep-2127e749-80b4-499a-ae14-8dc2dcc9db9b\",\n\t\t\t\t\"server/src/service/v1/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.js-simstep-6ba6b9d1-5fc3-454e-8744-2022b5192ed9\",\n\t\t\t\t\"server/src/service/v1/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.js-simstep-e59fe64e-f06b-4855-b631-923bb5a68540\"\n\t\t\t]\n\t\t},\n\t\t\"server/src/service/v1/infrastructure/networkService.js\": {\n\t\t\t\"path\": \"server/src/service/v1/infrastructure/networkService.js\",\n\t\t\t\"fileName\": \"networkService.js\",\n\t\t\t\"cellName\": \"networkService.js\",\n\t\t\t\"cellId\": \"00406786-9663-440a-96b6-919d544732c0\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"1670815f-860d-4ea4-92e1-b238a799d3dc\",\n\t\t\t\"children\": [\n\t\t\t\t\"server/src/service/v1/infrastructure/networkService.js-simstep-84f82fea-e306-4e0b-8222-e9705803d51a\",\n\t\t\t\t\"server/src/service/v1/infrastructure/networkService.js-simstep-ed6e7faf-69dd-4d0b-bda8-137739ed288b\"\n\t\t\t]\n\t\t},\n\t\t\"server/src/service/v1/infrastructure/notificationService.js\": {\n\t\t\t\"path\": \"server/src/service/v1/infrastructure/notificationService.js\",\n\t\t\t\"fileName\": \"notificationService.js\",\n\t\t\t\"cellName\": \"notificationService.js\",\n\t\t\t\"cellId\": \"2ff1f030-2080-48da-bbbe-90302fdfc2f7\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"1670815f-860d-4ea4-92e1-b238a799d3dc\",\n\t\t\t\"children\": [\n\t\t\t\t\"server/src/service/v1/infrastructure/notificationService.js-simstep-1a260a75-cf50-4f7a-90b0-c280b512a5cb\",\n\t\t\t\t\"server/src/service/v1/infrastructure/notificationService.js-simstep-f29f9be1-a0cd-43a3-b259-e5105a25ce41\"\n\t\t\t]\n\t\t},\n\t\t\"server/src/service/v1/infrastructure/notificationUtils.js\": {\n\t\t\t\"path\": \"server/src/service/v1/infrastructure/notificationUtils.js\",\n\t\t\t\"fileName\": \"notificationUtils.js\",\n\t\t\t\"cellName\": \"notificationUtils.js\",\n\t\t\t\"cellId\": \"4940977f-933d-4bbc-b19e-749647b44d25\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"1670815f-860d-4ea4-92e1-b238a799d3dc\",\n\t\t\t\"children\": [\n\t\t\t\t\"server/src/service/v1/infrastructure/notificationUtils.js-simstep-07fe8489-1d94-4afb-83f8-7cebb0dff49a\"\n\t\t\t]\n\t\t},\n\t\t\"server/src/service/v1/infrastructure/statusService.js\": {\n\t\t\t\"path\": \"server/src/service/v1/infrastructure/statusService.js\",\n\t\t\t\"fileName\": \"statusService.js\",\n\t\t\t\"cellName\": \"statusService.js\",\n\t\t\t\"cellId\": \"fbd7d244-2f37-453c-8c83-a23a260b26cc\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"1670815f-860d-4ea4-92e1-b238a799d3dc\",\n\t\t\t\"children\": [\n\t\t\t\t\"server/src/service/v1/infrastructure/statusService.js-simstep-c66a04c6-113e-4391-ab71-93fc612279ef\",\n\t\t\t\t\"server/src/service/v1/infrastructure/statusService.js-simstep-e5b90cf2-9369-4741-9803-c835a81c009b\"\n\t\t\t]\n\t\t},\n\t\t\"server/src/service/v2\": {\n\t\t\t\"path\": \"server/src/service/v2\",\n\t\t\t\"fileName\": \"v2\",\n\t\t\t\"cellName\": \"v2\",\n\t\t\t\"cellId\": \"feefae96-61b8-4ac5-a37c-592ed4b2330e\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"99e9b746-7809-41f4-a433-1de7cc90574b\",\n\t\t\t\"children\": [\n\t\t\t\t\"server/src/service/v2/infrastructure\",\n\t\t\t\t\"server/src/service/v2/business\"\n\t\t\t]\n\t\t},\n\t\t\"server/src/service/v2/business\": {\n\t\t\t\"path\": \"server/src/service/v2/business\",\n\t\t\t\"fileName\": \"business\",\n\t\t\t\"cellName\": \"business\",\n\t\t\t\"cellId\": \"7ef79284-534a-466f-a1f1-4e3a2f56be9d\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"feefae96-61b8-4ac5-a37c-592ed4b2330e\",\n\t\t\t\"children\": [\n\t\t\t\t\"server/src/service/v2/business/CheckService.ts\",\n\t\t\t\t\"server/src/service/v2/business/MonitorService.ts\"\n\t\t\t]\n\t\t},\n\t\t\"server/src/service/v2/business/CheckService.ts\": {\n\t\t\t\"path\": \"server/src/service/v2/business/CheckService.ts\",\n\t\t\t\"fileName\": \"CheckService.ts\",\n\t\t\t\"cellName\": \"CheckService.ts\",\n\t\t\t\"cellId\": \"f0ebd5da-21bb-4d96-8ff9-ca10409acc80\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"7ef79284-534a-466f-a1f1-4e3a2f56be9d\",\n\t\t\t\"children\": [\n\t\t\t\t\"server/src/service/v2/business/CheckService.ts-simstep-01206383-2db8-4b18-84d0-be2a0289c196\"\n\t\t\t]\n\t\t},\n\t\t\"server/src/service/v2/business/MonitorService.ts\": {\n\t\t\t\"path\": \"server/src/service/v2/business/MonitorService.ts\",\n\t\t\t\"fileName\": \"MonitorService.ts\",\n\t\t\t\"cellName\": \"MonitorService.ts\",\n\t\t\t\"cellId\": \"7a3824cd-24c8-4b32-8b1d-e0bf357262c4\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"7ef79284-534a-466f-a1f1-4e3a2f56be9d\",\n\t\t\t\"children\": [\n\t\t\t\t\"server/src/service/v2/business/MonitorService.ts-simstep-5616ac6d-c281-4879-82f1-6590c721c8f7\"\n\t\t\t]\n\t\t},\n\t\t\"server/src/service/v2/infrastructure\": {\n\t\t\t\"path\": \"server/src/service/v2/infrastructure\",\n\t\t\t\"fileName\": \"infrastructure\",\n\t\t\t\"cellName\": \"infrastructure\",\n\t\t\t\"cellId\": \"3f8ff792-40c8-4ae6-9af5-ff8b90da2f9f\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"feefae96-61b8-4ac5-a37c-592ed4b2330e\",\n\t\t\t\"children\": [\n\t\t\t\t\"server/src/service/v2/infrastructure/JobGenerator.ts\",\n\t\t\t\t\"server/src/service/v2/infrastructure/NotificationService.ts\",\n\t\t\t\t\"server/src/service/v2/infrastructure/NetworkService.ts\"\n\t\t\t]\n\t\t},\n\t\t\"server/src/service/v2/infrastructure/JobGenerator.ts\": {\n\t\t\t\"path\": \"server/src/service/v2/infrastructure/JobGenerator.ts\",\n\t\t\t\"fileName\": \"JobGenerator.ts\",\n\t\t\t\"cellName\": \"JobGenerator.ts\",\n\t\t\t\"cellId\": \"159e569d-31d8-4883-b443-4ec08b21a044\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"3f8ff792-40c8-4ae6-9af5-ff8b90da2f9f\",\n\t\t\t\"children\": [\n\t\t\t\t\"server/src/service/v2/infrastructure/JobGenerator.ts-simstep-157cec87-9b76-4a1c-9d85-0a6d3decbaa3\",\n\t\t\t\t\"server/src/service/v2/infrastructure/JobGenerator.ts-simstep-55ad645b-118a-478e-a00c-09ef82357008\"\n\t\t\t]\n\t\t},\n\t\t\"server/src/service/v2/infrastructure/NetworkService.ts\": {\n\t\t\t\"path\": \"server/src/service/v2/infrastructure/NetworkService.ts\",\n\t\t\t\"fileName\": \"NetworkService.ts\",\n\t\t\t\"cellName\": \"NetworkService.ts\",\n\t\t\t\"cellId\": \"50aeed0b-bc13-43f7-bb15-cb1b12b2caa7\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"3f8ff792-40c8-4ae6-9af5-ff8b90da2f9f\",\n\t\t\t\"children\": [\n\t\t\t\t\"server/src/service/v2/infrastructure/NetworkService.ts-simstep-53968267-0c6e-42f4-88b3-cd90f44532ae\"\n\t\t\t]\n\t\t},\n\t\t\"server/src/service/v2/infrastructure/NotificationService.ts\": {\n\t\t\t\"path\": \"server/src/service/v2/infrastructure/NotificationService.ts\",\n\t\t\t\"fileName\": \"NotificationService.ts\",\n\t\t\t\"cellName\": \"NotificationService.ts\",\n\t\t\t\"cellId\": \"c6d9907f-0a05-4153-a27f-47c3a1c4c0aa\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"3f8ff792-40c8-4ae6-9af5-ff8b90da2f9f\",\n\t\t\t\"children\": [\n\t\t\t\t\"server/src/service/v2/infrastructure/NotificationService.ts-simstep-8d1176f3-c755-401d-9ca8-234689b4b837\"\n\t\t\t]\n\t\t},\n\t\t\"0b23ea66-3e37-4643-b3b9-acb87ea02bae\": {\n\t\t\t\"path\": \"0b23ea66-3e37-4643-b3b9-acb87ea02bae\",\n\t\t\t\"cellName\": \"client\",\n\t\t\t\"cellId\": \"0b23ea66-3e37-4643-b3b9-acb87ea02bae\",\n\t\t\t\"visible\": true\n\t\t},\n\t\t\"98af25c7-efc2-43d2-a273-c8da4e1038ad\": {\n\t\t\t\"path\": \"98af25c7-efc2-43d2-a273-c8da4e1038ad\",\n\t\t\t\"cellName\": \"server\",\n\t\t\t\"cellId\": \"98af25c7-efc2-43d2-a273-c8da4e1038ad\",\n\t\t\t\"visible\": true\n\t\t},\n\t\t\"d3264577-10f0-42fe-9411-7e9df0754d1e\": {\n\t\t\t\"path\": \"d3264577-10f0-42fe-9411-7e9df0754d1e\",\n\t\t\t\"cellName\": \"src\",\n\t\t\t\"cellId\": \"d3264577-10f0-42fe-9411-7e9df0754d1e\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"0b23ea66-3e37-4643-b3b9-acb87ea02bae\"\n\t\t},\n\t\t\"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\": {\n\t\t\t\"path\": \"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\",\n\t\t\t\"cellName\": \"src\",\n\t\t\t\"cellId\": \"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"98af25c7-efc2-43d2-a273-c8da4e1038ad\"\n\t\t},\n\t\t\"f0feab85-316a-41b5-a2f1-629220018846\": {\n\t\t\t\"path\": \"f0feab85-316a-41b5-a2f1-629220018846\",\n\t\t\t\"cellName\": \"Pages\",\n\t\t\t\"cellId\": \"f0feab85-316a-41b5-a2f1-629220018846\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"d3264577-10f0-42fe-9411-7e9df0754d1e\"\n\t\t},\n\t\t\"4295a047-076f-4c07-95dd-b3123b6614f7\": {\n\t\t\t\"path\": \"4295a047-076f-4c07-95dd-b3123b6614f7\",\n\t\t\t\"cellName\": \"Hooks\",\n\t\t\t\"cellId\": \"4295a047-076f-4c07-95dd-b3123b6614f7\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"d3264577-10f0-42fe-9411-7e9df0754d1e\"\n\t\t},\n\t\t\"02b07589-ec21-4366-b7d2-9071e8f3bad8\": {\n\t\t\t\"path\": \"02b07589-ec21-4366-b7d2-9071e8f3bad8\",\n\t\t\t\"cellName\": \"Utils\",\n\t\t\t\"cellId\": \"02b07589-ec21-4366-b7d2-9071e8f3bad8\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"d3264577-10f0-42fe-9411-7e9df0754d1e\"\n\t\t},\n\t\t\"ffaaf471-ac3c-4ea3-a5a9-d5255169e54b\": {\n\t\t\t\"path\": \"ffaaf471-ac3c-4ea3-a5a9-d5255169e54b\",\n\t\t\t\"cellName\": \"routes\",\n\t\t\t\"cellId\": \"ffaaf471-ac3c-4ea3-a5a9-d5255169e54b\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\"\n\t\t},\n\t\t\"478e649c-1d1b-41d2-9b7b-6927e1dec7e1\": {\n\t\t\t\"path\": \"478e649c-1d1b-41d2-9b7b-6927e1dec7e1\",\n\t\t\t\"cellName\": \"controllers\",\n\t\t\t\"cellId\": \"478e649c-1d1b-41d2-9b7b-6927e1dec7e1\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\"\n\t\t},\n\t\t\"99e9b746-7809-41f4-a433-1de7cc90574b\": {\n\t\t\t\"path\": \"99e9b746-7809-41f4-a433-1de7cc90574b\",\n\t\t\t\"cellName\": \"service\",\n\t\t\t\"cellId\": \"99e9b746-7809-41f4-a433-1de7cc90574b\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\"\n\t\t},\n\t\t\"15ee5d81-a0cf-4614-80b8-7a1123ab20b8\": {\n\t\t\t\"path\": \"15ee5d81-a0cf-4614-80b8-7a1123ab20b8\",\n\t\t\t\"cellName\": \"db\",\n\t\t\t\"cellId\": \"15ee5d81-a0cf-4614-80b8-7a1123ab20b8\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\"\n\t\t},\n\t\t\"1a083b4a-787c-4eb4-8029-6700de987679\": {\n\t\t\t\"path\": \"1a083b4a-787c-4eb4-8029-6700de987679\",\n\t\t\t\"cellName\": \"v1\",\n\t\t\t\"cellId\": \"1a083b4a-787c-4eb4-8029-6700de987679\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"f0feab85-316a-41b5-a2f1-629220018846\"\n\t\t},\n\t\t\"3bf0c0f9-cbb0-4f0c-8cb3-6e2a4abc0961\": {\n\t\t\t\"path\": \"3bf0c0f9-cbb0-4f0c-8cb3-6e2a4abc0961\",\n\t\t\t\"cellName\": \"v1\",\n\t\t\t\"cellId\": \"3bf0c0f9-cbb0-4f0c-8cb3-6e2a4abc0961\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"4295a047-076f-4c07-95dd-b3123b6614f7\"\n\t\t},\n\t\t\"16731e9d-3f73-4055-9d79-5ca9be679f68\": {\n\t\t\t\"path\": \"16731e9d-3f73-4055-9d79-5ca9be679f68\",\n\t\t\t\"cellName\": \"NetworkService.js\",\n\t\t\t\"cellId\": \"16731e9d-3f73-4055-9d79-5ca9be679f68\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"02b07589-ec21-4366-b7d2-9071e8f3bad8\"\n\t\t},\n\t\t\"d3375a20-2776-4771-b806-649bbeb541bd\": {\n\t\t\t\"path\": \"d3375a20-2776-4771-b806-649bbeb541bd\",\n\t\t\t\"cellName\": \"v1\",\n\t\t\t\"cellId\": \"d3375a20-2776-4771-b806-649bbeb541bd\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"ffaaf471-ac3c-4ea3-a5a9-d5255169e54b\"\n\t\t},\n\t\t\"fc591f7a-d4ac-4565-949d-a87a58a79bbc\": {\n\t\t\t\"path\": \"fc591f7a-d4ac-4565-949d-a87a58a79bbc\",\n\t\t\t\"cellName\": \"v1\",\n\t\t\t\"cellId\": \"fc591f7a-d4ac-4565-949d-a87a58a79bbc\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"478e649c-1d1b-41d2-9b7b-6927e1dec7e1\"\n\t\t},\n\t\t\"bbbe53d6-f595-498a-ae45-e08611f39c3d\": {\n\t\t\t\"path\": \"bbbe53d6-f595-498a-ae45-e08611f39c3d\",\n\t\t\t\"cellName\": \"v1\",\n\t\t\t\"cellId\": \"bbbe53d6-f595-498a-ae45-e08611f39c3d\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"99e9b746-7809-41f4-a433-1de7cc90574b\"\n\t\t},\n\t\t\"58c5a3fd-1e69-4ca4-a64e-314f5644bdaf\": {\n\t\t\t\"path\": \"58c5a3fd-1e69-4ca4-a64e-314f5644bdaf\",\n\t\t\t\"cellName\": \"v1\",\n\t\t\t\"cellId\": \"58c5a3fd-1e69-4ca4-a64e-314f5644bdaf\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"15ee5d81-a0cf-4614-80b8-7a1123ab20b8\"\n\t\t},\n\t\t\"7090fcdb-09be-4c85-86fd-e73553bbb2ff\": {\n\t\t\t\"path\": \"7090fcdb-09be-4c85-86fd-e73553bbb2ff\",\n\t\t\t\"cellName\": \"Uptime\",\n\t\t\t\"cellId\": \"7090fcdb-09be-4c85-86fd-e73553bbb2ff\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"1a083b4a-787c-4eb4-8029-6700de987679\"\n\t\t},\n\t\t\"595cf0e8-2f86-4543-b51c-b2aeac307f4b\": {\n\t\t\t\"path\": \"595cf0e8-2f86-4543-b51c-b2aeac307f4b\",\n\t\t\t\"cellName\": \"monitorHooks.js\",\n\t\t\t\"cellId\": \"595cf0e8-2f86-4543-b51c-b2aeac307f4b\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"3bf0c0f9-cbb0-4f0c-8cb3-6e2a4abc0961\"\n\t\t},\n\t\t\"10611636-ec73-4a26-87a5-654ae64a4843\": {\n\t\t\t\"path\": \"10611636-ec73-4a26-87a5-654ae64a4843\",\n\t\t\t\"cellName\": \"monitorRoute.js\",\n\t\t\t\"cellId\": \"10611636-ec73-4a26-87a5-654ae64a4843\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"d3375a20-2776-4771-b806-649bbeb541bd\"\n\t\t},\n\t\t\"341f2784-67ee-4477-9445-a8c240ee6261\": {\n\t\t\t\"path\": \"341f2784-67ee-4477-9445-a8c240ee6261\",\n\t\t\t\"cellName\": \"monitorController.js\",\n\t\t\t\"cellId\": \"341f2784-67ee-4477-9445-a8c240ee6261\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"fc591f7a-d4ac-4565-949d-a87a58a79bbc\"\n\t\t},\n\t\t\"87d3b101-9443-4ed4-9c4f-f759d41677eb\": {\n\t\t\t\"path\": \"87d3b101-9443-4ed4-9c4f-f759d41677eb\",\n\t\t\t\"cellName\": \"business\",\n\t\t\t\"cellId\": \"87d3b101-9443-4ed4-9c4f-f759d41677eb\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"bbbe53d6-f595-498a-ae45-e08611f39c3d\"\n\t\t},\n\t\t\"1670815f-860d-4ea4-92e1-b238a799d3dc\": {\n\t\t\t\"path\": \"1670815f-860d-4ea4-92e1-b238a799d3dc\",\n\t\t\t\"cellName\": \"infrastructure\",\n\t\t\t\"cellId\": \"1670815f-860d-4ea4-92e1-b238a799d3dc\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"bbbe53d6-f595-498a-ae45-e08611f39c3d\"\n\t\t},\n\t\t\"82cb3dbe-c922-438a-a912-255376f4b380\": {\n\t\t\t\"path\": \"82cb3dbe-c922-438a-a912-255376f4b380\",\n\t\t\t\"cellName\": \"modules\",\n\t\t\t\"cellId\": \"82cb3dbe-c922-438a-a912-255376f4b380\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"58c5a3fd-1e69-4ca4-a64e-314f5644bdaf\"\n\t\t},\n\t\t\"3dba5acc-cf25-40b7-ad21-9cd715454cd5\": {\n\t\t\t\"path\": \"3dba5acc-cf25-40b7-ad21-9cd715454cd5\",\n\t\t\t\"cellName\": \"Create\",\n\t\t\t\"cellId\": \"3dba5acc-cf25-40b7-ad21-9cd715454cd5\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"7090fcdb-09be-4c85-86fd-e73553bbb2ff\"\n\t\t},\n\t\t\"b4e479df-9b21-4430-9383-84831f503c2e\": {\n\t\t\t\"path\": \"b4e479df-9b21-4430-9383-84831f503c2e\",\n\t\t\t\"cellName\": \"monitorService.js\",\n\t\t\t\"cellId\": \"b4e479df-9b21-4430-9383-84831f503c2e\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"87d3b101-9443-4ed4-9c4f-f759d41677eb\"\n\t\t},\n\t\t\"dda70a36-2d1d-4e46-8bcc-52d0d474bf7b\": {\n\t\t\t\"path\": \"dda70a36-2d1d-4e46-8bcc-52d0d474bf7b\",\n\t\t\t\"cellName\": \"SuperSimpleQueue\",\n\t\t\t\"cellId\": \"dda70a36-2d1d-4e46-8bcc-52d0d474bf7b\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"1670815f-860d-4ea4-92e1-b238a799d3dc\"\n\t\t},\n\t\t\"00406786-9663-440a-96b6-919d544732c0\": {\n\t\t\t\"path\": \"00406786-9663-440a-96b6-919d544732c0\",\n\t\t\t\"cellName\": \"networkService.js\",\n\t\t\t\"cellId\": \"00406786-9663-440a-96b6-919d544732c0\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"1670815f-860d-4ea4-92e1-b238a799d3dc\"\n\t\t},\n\t\t\"fbd7d244-2f37-453c-8c83-a23a260b26cc\": {\n\t\t\t\"path\": \"fbd7d244-2f37-453c-8c83-a23a260b26cc\",\n\t\t\t\"cellName\": \"statusService.js\",\n\t\t\t\"cellId\": \"fbd7d244-2f37-453c-8c83-a23a260b26cc\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"1670815f-860d-4ea4-92e1-b238a799d3dc\"\n\t\t},\n\t\t\"2ff1f030-2080-48da-bbbe-90302fdfc2f7\": {\n\t\t\t\"path\": \"2ff1f030-2080-48da-bbbe-90302fdfc2f7\",\n\t\t\t\"cellName\": \"notificationService.js\",\n\t\t\t\"cellId\": \"2ff1f030-2080-48da-bbbe-90302fdfc2f7\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"1670815f-860d-4ea4-92e1-b238a799d3dc\"\n\t\t},\n\t\t\"630b3ece-2648-48d5-99b5-ef9611de2ad5\": {\n\t\t\t\"path\": \"630b3ece-2648-48d5-99b5-ef9611de2ad5\",\n\t\t\t\"cellName\": \"monitorModule.js\",\n\t\t\t\"cellId\": \"630b3ece-2648-48d5-99b5-ef9611de2ad5\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"82cb3dbe-c922-438a-a912-255376f4b380\"\n\t\t},\n\t\t\"391ad99e-3114-4f54-a6ca-fd89b33c7e06\": {\n\t\t\t\"path\": \"391ad99e-3114-4f54-a6ca-fd89b33c7e06\",\n\t\t\t\"cellName\": \"index.jsx\",\n\t\t\t\"cellId\": \"391ad99e-3114-4f54-a6ca-fd89b33c7e06\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"3dba5acc-cf25-40b7-ad21-9cd715454cd5\"\n\t\t},\n\t\t\"d9c0127e-31aa-4509-b5c9-f7017d10d69a\": {\n\t\t\t\"path\": \"d9c0127e-31aa-4509-b5c9-f7017d10d69a\",\n\t\t\t\"cellName\": \"SuperSimpleQueue.js\",\n\t\t\t\"cellId\": \"d9c0127e-31aa-4509-b5c9-f7017d10d69a\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"dda70a36-2d1d-4e46-8bcc-52d0d474bf7b\"\n\t\t},\n\t\t\"04c12e9a-e025-457c-a634-5f7472a42985\": {\n\t\t\t\"path\": \"04c12e9a-e025-457c-a634-5f7472a42985\",\n\t\t\t\"cellName\": \"SuperSimpleQueueHelper.js\",\n\t\t\t\"cellId\": \"04c12e9a-e025-457c-a634-5f7472a42985\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"dda70a36-2d1d-4e46-8bcc-52d0d474bf7b\"\n\t\t},\n\t\t\"7a2da928-a65c-49d8-b0a3-c159a6df2bc5\": {\n\t\t\t\"path\": \"7a2da928-a65c-49d8-b0a3-c159a6df2bc5\",\n\t\t\t\"cellName\": \"Uptime Monitor Creation: Display Form - index.jsx:L315-802\",\n\t\t\t\"cellId\": \"7a2da928-a65c-49d8-b0a3-c159a6df2bc5\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"391ad99e-3114-4f54-a6ca-fd89b33c7e06\"\n\t\t},\n\t\t\"client/src/Pages/v1/Uptime/Create/index.jsx-simstep-ab5de0b9-c70d-492c-98d9-8ddee66284ad\": {\n\t\t\t\"path\": \"client/src/Pages/v1/Uptime/Create/index.jsx-simstep-ab5de0b9-c70d-492c-98d9-8ddee66284ad\",\n\t\t\t\"fileName\": \"index.jsx\",\n\t\t\t\"wiki\": \"The user navigates to the 'Create Uptime Monitor' page. The `UptimeCreate` React component renders the form, allowing the user to select the monitor type (HTTP, Ping, Docker, etc.) and input details like URL, name, and check interval.\",\n\t\t\t\"cellName\": \"Uptime Monitor Creation: Display Form - index.jsx:L315-802\",\n\t\t\t\"cellId\": \"7a2da928-a65c-49d8-b0a3-c159a6df2bc5\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 315,\n\t\t\t\"endLine\": 802,\n\t\t\t\"parentCellId\": \"391ad99e-3114-4f54-a6ca-fd89b33c7e06\",\n\t\t\t\"parentPath\": \"client/src/Pages/v1/Uptime/Create/index.jsx\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Comprehensive Uptime Monitoring for Various Services\",\n\t\t\t\t\t\"simStepId\": \"ab5de0b9-c70d-492c-98d9-8ddee66284ad\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"a81f4ae8-41fe-4d1b-95ce-86abcc67b53c\": {\n\t\t\t\"path\": \"a81f4ae8-41fe-4d1b-95ce-86abcc67b53c\",\n\t\t\t\"cellName\": \"Uptime Monitor Creation: Handle Form Submission and Validation - index.jsx:L170-248\",\n\t\t\t\"cellId\": \"a81f4ae8-41fe-4d1b-95ce-86abcc67b53c\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"391ad99e-3114-4f54-a6ca-fd89b33c7e06\"\n\t\t},\n\t\t\"client/src/Pages/v1/Uptime/Create/index.jsx-simstep-e02ddf57-270e-4f71-b4c4-d5183bb7879a\": {\n\t\t\t\"path\": \"client/src/Pages/v1/Uptime/Create/index.jsx-simstep-e02ddf57-270e-4f71-b4c4-d5183bb7879a\",\n\t\t\t\"fileName\": \"index.jsx\",\n\t\t\t\"wiki\": \"The `onSubmit` function in `UptimeCreate.jsx` is executed. It prevents the default form submission, constructs a `form` object with monitor data, validates it using `monitorValidation`, and then calls the `createMonitor` function from the `useCreateMonitor` hook.\",\n\t\t\t\"cellName\": \"Uptime Monitor Creation: Handle Form Submission and Validation - index.jsx:L170-248\",\n\t\t\t\"cellId\": \"a81f4ae8-41fe-4d1b-95ce-86abcc67b53c\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 170,\n\t\t\t\"endLine\": 248,\n\t\t\t\"parentCellId\": \"391ad99e-3114-4f54-a6ca-fd89b33c7e06\",\n\t\t\t\"parentPath\": \"client/src/Pages/v1/Uptime/Create/index.jsx\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Comprehensive Uptime Monitoring for Various Services\",\n\t\t\t\t\t\"simStepId\": \"e02ddf57-270e-4f71-b4c4-d5183bb7879a\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"a30ac765-c546-4993-988e-8c8cfdb7532f\": {\n\t\t\t\"path\": \"a30ac765-c546-4993-988e-8c8cfdb7532f\",\n\t\t\t\"cellName\": \"Uptime Monitor Creation: Send API Request - NetworkService.js:L119-121\",\n\t\t\t\"cellId\": \"a30ac765-c546-4993-988e-8c8cfdb7532f\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"16731e9d-3f73-4055-9d79-5ca9be679f68\"\n\t\t},\n\t\t\"client/src/Utils/NetworkService.js-simstep-14e9986b-c6ce-475e-97ed-da1fa2b6968d\": {\n\t\t\t\"path\": \"client/src/Utils/NetworkService.js-simstep-14e9986b-c6ce-475e-97ed-da1fa2b6968d\",\n\t\t\t\"fileName\": \"NetworkService.js\",\n\t\t\t\"wiki\": \"The `createMonitor` method in `NetworkService.js` makes an HTTP POST request to the `/monitors` endpoint on the server, sending the new monitor's data in the request body.\",\n\t\t\t\"cellName\": \"Uptime Monitor Creation: Send API Request - NetworkService.js:L119-121\",\n\t\t\t\"cellId\": \"a30ac765-c546-4993-988e-8c8cfdb7532f\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 119,\n\t\t\t\"endLine\": 121,\n\t\t\t\"parentCellId\": \"16731e9d-3f73-4055-9d79-5ca9be679f68\",\n\t\t\t\"parentPath\": \"client/src/Utils/NetworkService.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Comprehensive Uptime Monitoring for Various Services\",\n\t\t\t\t\t\"simStepId\": \"14e9986b-c6ce-475e-97ed-da1fa2b6968d\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"f0409948-75dc-457f-a02d-6b9774258e48\": {\n\t\t\t\"path\": \"f0409948-75dc-457f-a02d-6b9774258e48\",\n\t\t\t\"cellName\": \"Uptime Monitor Creation: Controller to Service - monitorController.js:L195\",\n\t\t\t\"cellId\": \"f0409948-75dc-457f-a02d-6b9774258e48\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"341f2784-67ee-4477-9445-a8c240ee6261\"\n\t\t},\n\t\t\"server/src/controllers/v1/monitorController.js-simstep-38fd069d-9c44-4078-954b-3a0899e9acf4\": {\n\t\t\t\"path\": \"server/src/controllers/v1/monitorController.js-simstep-38fd069d-9c44-4078-954b-3a0899e9acf4\",\n\t\t\t\"fileName\": \"monitorController.js\",\n\t\t\t\"wiki\": \"The `MonitorController` extracts the user and team ID from the request and calls the `createMonitor` method in the `MonitorService`, passing along the monitor data from the request body.\",\n\t\t\t\"cellName\": \"Uptime Monitor Creation: Controller to Service - monitorController.js:L195\",\n\t\t\t\"cellId\": \"f0409948-75dc-457f-a02d-6b9774258e48\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 195,\n\t\t\t\"endLine\": 195,\n\t\t\t\"parentCellId\": \"341f2784-67ee-4477-9445-a8c240ee6261\",\n\t\t\t\"parentPath\": \"server/src/controllers/v1/monitorController.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Comprehensive Uptime Monitoring for Various Services\",\n\t\t\t\t\t\"simStepId\": \"38fd069d-9c44-4078-954b-3a0899e9acf4\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"2d407bfd-e4b0-46b8-99e7-121c507d525f\": {\n\t\t\t\"path\": \"2d407bfd-e4b0-46b8-99e7-121c507d525f\",\n\t\t\t\"cellName\": \"Uptime Monitor Creation: Save Monitor to Database - monitorModule.js:L454-455\",\n\t\t\t\"cellId\": \"2d407bfd-e4b0-46b8-99e7-121c507d525f\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"630b3ece-2648-48d5-99b5-ef9611de2ad5\"\n\t\t},\n\t\t\"server/src/db/v1/modules/monitorModule.js-simstep-ca3ad309-323a-418d-a171-c16f56fae23c\": {\n\t\t\t\"path\": \"server/src/db/v1/modules/monitorModule.js-simstep-ca3ad309-323a-418d-a171-c16f56fae23c\",\n\t\t\t\"fileName\": \"monitorModule.js\",\n\t\t\t\"wiki\": \"The `monitorModule` creates a new `Monitor` model instance with the provided data and saves it to the MongoDB database. The newly created document, including its generated `_id`, is returned.\",\n\t\t\t\"cellName\": \"Uptime Monitor Creation: Save Monitor to Database - monitorModule.js:L454-455\",\n\t\t\t\"cellId\": \"2d407bfd-e4b0-46b8-99e7-121c507d525f\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 454,\n\t\t\t\"endLine\": 455,\n\t\t\t\"parentCellId\": \"630b3ece-2648-48d5-99b5-ef9611de2ad5\",\n\t\t\t\"parentPath\": \"server/src/db/v1/modules/monitorModule.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Comprehensive Uptime Monitoring for Various Services\",\n\t\t\t\t\t\"simStepId\": \"ca3ad309-323a-418d-a171-c16f56fae23c\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"51e8db5f-2fdd-4ddc-9605-43981db9d940\": {\n\t\t\t\"path\": \"51e8db5f-2fdd-4ddc-9605-43981db9d940\",\n\t\t\t\"cellName\": \"Uptime Monitor Creation: Schedule Job - SuperSimpleQueue.js:L50-57\",\n\t\t\t\"cellId\": \"51e8db5f-2fdd-4ddc-9605-43981db9d940\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"d9c0127e-31aa-4509-b5c9-f7017d10d69a\"\n\t\t},\n\t\t\"server/src/service/v1/infrastructure/SuperSimpleQueue/SuperSimpleQueue.js-simstep-2702bfca-7611-4562-8d3e-a05af8257871\": {\n\t\t\t\"path\": \"server/src/service/v1/infrastructure/SuperSimpleQueue/SuperSimpleQueue.js-simstep-2702bfca-7611-4562-8d3e-a05af8257871\",\n\t\t\t\"fileName\": \"SuperSimpleQueue.js\",\n\t\t\t\"wiki\": \"The `SuperSimpleQueue` receives the new monitor and uses its `scheduler.addJob` method to create a recurring job based on the monitor's interval. The monitor object itself is stored as data for the job.\",\n\t\t\t\"cellName\": \"Uptime Monitor Creation: Schedule Job - SuperSimpleQueue.js:L50-57\",\n\t\t\t\"cellId\": \"51e8db5f-2fdd-4ddc-9605-43981db9d940\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 50,\n\t\t\t\"endLine\": 57,\n\t\t\t\"parentCellId\": \"d9c0127e-31aa-4509-b5c9-f7017d10d69a\",\n\t\t\t\"parentPath\": \"server/src/service/v1/infrastructure/SuperSimpleQueue/SuperSimpleQueue.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Comprehensive Uptime Monitoring for Various Services\",\n\t\t\t\t\t\"simStepId\": \"2702bfca-7611-4562-8d3e-a05af8257871\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"18c13391-0cf7-4303-8180-0a40cfd64b58\": {\n\t\t\t\"path\": \"18c13391-0cf7-4303-8180-0a40cfd64b58\",\n\t\t\t\"cellName\": \"Service Monitoring: Job Execution - SuperSimpleQueueHelper.js:L27-73\",\n\t\t\t\"cellId\": \"18c13391-0cf7-4303-8180-0a40cfd64b58\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"04c12e9a-e025-457c-a634-5f7472a42985\"\n\t\t},\n\t\t\"server/src/service/v1/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.js-simstep-e22a708a-a348-4775-8ee3-f32a35446e24\": {\n\t\t\t\"path\": \"server/src/service/v1/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.js-simstep-e22a708a-a348-4775-8ee3-f32a35446e24\",\n\t\t\t\"fileName\": \"SuperSimpleQueueHelper.js\",\n\t\t\t\"wiki\": \"The scheduler triggers a monitor job at the specified interval. The `getMonitorJob` function in `SuperSimpleQueueHelper` is executed, which first checks if the monitor is in a maintenance window.\",\n\t\t\t\"cellName\": \"Service Monitoring: Job Execution - SuperSimpleQueueHelper.js:L27-73\",\n\t\t\t\"cellId\": \"18c13391-0cf7-4303-8180-0a40cfd64b58\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 27,\n\t\t\t\"endLine\": 73,\n\t\t\t\"parentCellId\": \"04c12e9a-e025-457c-a634-5f7472a42985\",\n\t\t\t\"parentPath\": \"server/src/service/v1/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Comprehensive Uptime Monitoring for Various Services\",\n\t\t\t\t\t\"simStepId\": \"e22a708a-a348-4775-8ee3-f32a35446e24\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"5c900373-e6ba-44d5-b341-676a32d659c8\": {\n\t\t\t\"path\": \"5c900373-e6ba-44d5-b341-676a32d659c8\",\n\t\t\t\"cellName\": \"Service Monitoring: Perform Network Check - networkService.js:L44-59\",\n\t\t\t\"cellId\": \"5c900373-e6ba-44d5-b341-676a32d659c8\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"00406786-9663-440a-96b6-919d544732c0\"\n\t\t},\n\t\t\"server/src/service/v1/infrastructure/networkService.js-simstep-84f82fea-e306-4e0b-8222-e9705803d51a\": {\n\t\t\t\"path\": \"server/src/service/v1/infrastructure/networkService.js-simstep-84f82fea-e306-4e0b-8222-e9705803d51a\",\n\t\t\t\"fileName\": \"networkService.js\",\n\t\t\t\"wiki\": \"The `requestStatus` method in the network service acts as a router. Based on the monitor's `type` (e.g., 'http', 'ping', 'docker'), it calls the corresponding specialized request function (e.g., `requestHttp`) to perform the check and constructs a standardized response object.\",\n\t\t\t\"cellName\": \"Service Monitoring: Perform Network Check - networkService.js:L44-59\",\n\t\t\t\"cellId\": \"5c900373-e6ba-44d5-b341-676a32d659c8\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 44,\n\t\t\t\"endLine\": 59,\n\t\t\t\"parentCellId\": \"00406786-9663-440a-96b6-919d544732c0\",\n\t\t\t\"parentPath\": \"server/src/service/v1/infrastructure/networkService.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Comprehensive Uptime Monitoring for Various Services\",\n\t\t\t\t\t\"simStepId\": \"84f82fea-e306-4e0b-8222-e9705803d51a\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"45e38f3a-a7c3-4de7-b3dc-589361d793fd\": {\n\t\t\t\"path\": \"45e38f3a-a7c3-4de7-b3dc-589361d793fd\",\n\t\t\t\"cellName\": \"Service Monitoring: Update Monitor Status - statusService.js:L108-183\",\n\t\t\t\"cellId\": \"45e38f3a-a7c3-4de7-b3dc-589361d793fd\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"fbd7d244-2f37-453c-8c83-a23a260b26cc\"\n\t\t},\n\t\t\"server/src/service/v1/infrastructure/statusService.js-simstep-c66a04c6-113e-4391-ab71-93fc612279ef\": {\n\t\t\t\"path\": \"server/src/service/v1/infrastructure/statusService.js-simstep-c66a04c6-113e-4391-ab71-93fc612279ef\",\n\t\t\t\"fileName\": \"statusService.js\",\n\t\t\t\"wiki\": \"The job handler passes the network response to `statusService.updateStatus`. This service creates a new `Check` document in the database, updates the monitor's status based on a sliding window and threshold, and calculates running statistics.\",\n\t\t\t\"cellName\": \"Service Monitoring: Update Monitor Status - statusService.js:L108-183\",\n\t\t\t\"cellId\": \"45e38f3a-a7c3-4de7-b3dc-589361d793fd\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 108,\n\t\t\t\"endLine\": 183,\n\t\t\t\"parentCellId\": \"fbd7d244-2f37-453c-8c83-a23a260b26cc\",\n\t\t\t\"parentPath\": \"server/src/service/v1/infrastructure/statusService.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Comprehensive Uptime Monitoring for Various Services\",\n\t\t\t\t\t\"simStepId\": \"c66a04c6-113e-4391-ab71-93fc612279ef\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"9f3ea7fc-16d3-4d36-97eb-66f8808425cc\": {\n\t\t\t\"path\": \"9f3ea7fc-16d3-4d36-97eb-66f8808425cc\",\n\t\t\t\"cellName\": \"Service Monitoring: Handle Notifications (Conditional) - notificationService.js:L76-92\",\n\t\t\t\"cellId\": \"9f3ea7fc-16d3-4d36-97eb-66f8808425cc\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"2ff1f030-2080-48da-bbbe-90302fdfc2f7\"\n\t\t},\n\t\t\"server/src/service/v1/infrastructure/notificationService.js-simstep-1a260a75-cf50-4f7a-90b0-c280b512a5cb\": {\n\t\t\t\"path\": \"server/src/service/v1/infrastructure/notificationService.js-simstep-1a260a75-cf50-4f7a-90b0-c280b512a5cb\",\n\t\t\t\"fileName\": \"notificationService.js\",\n\t\t\t\"wiki\": \"If `statusChanged` is true, the job handler calls `notificationService.handleNotifications`. The service identifies the notification channels associated with the monitor and sends out alerts (e.g., email, webhook, Discord) with details about the status change.\",\n\t\t\t\"cellName\": \"Service Monitoring: Handle Notifications (Conditional) - notificationService.js:L76-92\",\n\t\t\t\"cellId\": \"9f3ea7fc-16d3-4d36-97eb-66f8808425cc\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 76,\n\t\t\t\"endLine\": 92,\n\t\t\t\"parentCellId\": \"2ff1f030-2080-48da-bbbe-90302fdfc2f7\",\n\t\t\t\"parentPath\": \"server/src/service/v1/infrastructure/notificationService.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Comprehensive Uptime Monitoring for Various Services\",\n\t\t\t\t\t\"simStepId\": \"1a260a75-cf50-4f7a-90b0-c280b512a5cb\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"0e09aa33-d7c7-4c89-9da8-f0937658f4d3\": {\n\t\t\t\"path\": \"0e09aa33-d7c7-4c89-9da8-f0937658f4d3\",\n\t\t\t\"cellName\": \"Uptime Monitor\\nCreation: Form\\nSubmission\",\n\t\t\t\"cellId\": \"0e09aa33-d7c7-4c89-9da8-f0937658f4d3\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"391ad99e-3114-4f54-a6ca-fd89b33c7e06\"\n\t\t},\n\t\t\"generated-edge-simstep-888df086-41bb-469d-9c0a-daf74bdecb9f-0e09aa33-d7c7-4c89-9da8-f0937658f4d3\": {\n\t\t\t\"path\": \"generated-edge-simstep-888df086-41bb-469d-9c0a-daf74bdecb9f-0e09aa33-d7c7-4c89-9da8-f0937658f4d3\",\n\t\t\t\"fileName\": \"index.jsx\",\n\t\t\t\"cellName\": \"Uptime Monitor Creation: Form Submission\",\n\t\t\t\"cellId\": \"0e09aa33-d7c7-4c89-9da8-f0937658f4d3\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 435,\n\t\t\t\"endLine\": 443,\n\t\t\t\"parentPath\": \"client/src/Pages/v1/Uptime/Create/index.jsx\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Comprehensive Uptime Monitoring for Various Services\",\n\t\t\t\t\t\"simStepId\": \"888df086-41bb-469d-9c0a-daf74bdecb9f\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"1f6f04a9-0123-4729-b06a-8f3da6d1b58c\": {\n\t\t\t\"path\": \"1f6f04a9-0123-4729-b06a-8f3da6d1b58c\",\n\t\t\t\"cellName\": \"Uptime Monitor\\nCreation: Call\\nNetwork Service\",\n\t\t\t\"cellId\": \"1f6f04a9-0123-4729-b06a-8f3da6d1b58c\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"d3264577-10f0-42fe-9411-7e9df0754d1e\"\n\t\t},\n\t\t\"generated-edge-simstep-3fe0afaa-c673-4b52-a0c4-02a3ffd3a075-1f6f04a9-0123-4729-b06a-8f3da6d1b58c\": {\n\t\t\t\"path\": \"generated-edge-simstep-3fe0afaa-c673-4b52-a0c4-02a3ffd3a075-1f6f04a9-0123-4729-b06a-8f3da6d1b58c\",\n\t\t\t\"fileName\": \"index.jsx\",\n\t\t\t\"cellName\": \"Uptime Monitor Creation: Call Network Service\",\n\t\t\t\"cellId\": \"1f6f04a9-0123-4729-b06a-8f3da6d1b58c\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 306,\n\t\t\t\"endLine\": 306,\n\t\t\t\"parentPath\": \"client/src/Pages/v1/Uptime/Create/index.jsx\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Comprehensive Uptime Monitoring for Various Services\",\n\t\t\t\t\t\"simStepId\": \"3fe0afaa-c673-4b52-a0c4-02a3ffd3a075\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"b6d963d5-c613-407a-9ce9-60a04048dea7\": {\n\t\t\t\"path\": \"b6d963d5-c613-407a-9ce9-60a04048dea7\",\n\t\t\t\"cellName\": \"Uptime Monitor\\nCreation: API\\nRoute to\\nController\",\n\t\t\t\"cellId\": \"b6d963d5-c613-407a-9ce9-60a04048dea7\",\n\t\t\t\"visible\": true\n\t\t},\n\t\t\"generated-edge-simstep-13dd0564-44a5-43ea-a163-ce1148cc48e7-b6d963d5-c613-407a-9ce9-60a04048dea7\": {\n\t\t\t\"path\": \"generated-edge-simstep-13dd0564-44a5-43ea-a163-ce1148cc48e7-b6d963d5-c613-407a-9ce9-60a04048dea7\",\n\t\t\t\"fileName\": \"NetworkService.js\",\n\t\t\t\"cellName\": \"Uptime Monitor Creation: API Route to Controller\",\n\t\t\t\"cellId\": \"b6d963d5-c613-407a-9ce9-60a04048dea7\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 35,\n\t\t\t\"endLine\": 35,\n\t\t\t\"parentPath\": \"client/src/Utils/NetworkService.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Comprehensive Uptime Monitoring for Various Services\",\n\t\t\t\t\t\"simStepId\": \"13dd0564-44a5-43ea-a163-ce1148cc48e7\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"a6bccd1d-4272-4df7-a7c8-b3979e37b8d7\": {\n\t\t\t\"path\": \"a6bccd1d-4272-4df7-a7c8-b3979e37b8d7\",\n\t\t\t\"cellName\": \"Uptime Monitor\\nCreation: Service\\nto DB\\nModule\",\n\t\t\t\"cellId\": \"a6bccd1d-4272-4df7-a7c8-b3979e37b8d7\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\"\n\t\t},\n\t\t\"generated-edge-simstep-a6f4c967-b1a8-4804-bc2e-67f47a7b68f9-a6bccd1d-4272-4df7-a7c8-b3979e37b8d7\": {\n\t\t\t\"path\": \"generated-edge-simstep-a6f4c967-b1a8-4804-bc2e-67f47a7b68f9-a6bccd1d-4272-4df7-a7c8-b3979e37b8d7\",\n\t\t\t\"fileName\": \"monitorController.js\",\n\t\t\t\"cellName\": \"Uptime Monitor Creation: Service to DB Module\",\n\t\t\t\"cellId\": \"a6bccd1d-4272-4df7-a7c8-b3979e37b8d7\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 74,\n\t\t\t\"endLine\": 78,\n\t\t\t\"parentPath\": \"server/src/controllers/v1/monitorController.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Comprehensive Uptime Monitoring for Various Services\",\n\t\t\t\t\t\"simStepId\": \"a6f4c967-b1a8-4804-bc2e-67f47a7b68f9\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"de320ac1-0949-4297-be7c-b9d7a14e0fec\": {\n\t\t\t\"path\": \"de320ac1-0949-4297-be7c-b9d7a14e0fec\",\n\t\t\t\"cellName\": \"Uptime Monitor\\nCreation: Service\\nto Job\\nQueue\",\n\t\t\t\"cellId\": \"de320ac1-0949-4297-be7c-b9d7a14e0fec\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\"\n\t\t},\n\t\t\"generated-edge-simstep-71ec03b6-1166-4c5d-9ada-0875a0866e30-de320ac1-0949-4297-be7c-b9d7a14e0fec\": {\n\t\t\t\"path\": \"generated-edge-simstep-71ec03b6-1166-4c5d-9ada-0875a0866e30-de320ac1-0949-4297-be7c-b9d7a14e0fec\",\n\t\t\t\"fileName\": \"monitorModule.js\",\n\t\t\t\"cellName\": \"Uptime Monitor Creation: Service to Job Queue\",\n\t\t\t\"cellId\": \"de320ac1-0949-4297-be7c-b9d7a14e0fec\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 80,\n\t\t\t\"endLine\": 80,\n\t\t\t\"parentPath\": \"server/src/db/v1/modules/monitorModule.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Comprehensive Uptime Monitoring for Various Services\",\n\t\t\t\t\t\"simStepId\": \"71ec03b6-1166-4c5d-9ada-0875a0866e30\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"38ba9b22-5b26-432d-a856-0eceb792c737\": {\n\t\t\t\"path\": \"38ba9b22-5b26-432d-a856-0eceb792c737\",\n\t\t\t\"cellName\": \"Service Monitoring:\\nRequest Service\\nStatus\",\n\t\t\t\"cellId\": \"38ba9b22-5b26-432d-a856-0eceb792c737\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"1670815f-860d-4ea4-92e1-b238a799d3dc\"\n\t\t},\n\t\t\"generated-edge-simstep-1d7580f2-f107-4008-a207-b8ec07998721-38ba9b22-5b26-432d-a856-0eceb792c737\": {\n\t\t\t\"path\": \"generated-edge-simstep-1d7580f2-f107-4008-a207-b8ec07998721-38ba9b22-5b26-432d-a856-0eceb792c737\",\n\t\t\t\"fileName\": \"SuperSimpleQueueHelper.js\",\n\t\t\t\"cellName\": \"Service Monitoring: Request Service Status\",\n\t\t\t\"cellId\": \"38ba9b22-5b26-432d-a856-0eceb792c737\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 45,\n\t\t\t\"endLine\": 45,\n\t\t\t\"parentPath\": \"server/src/service/v1/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Comprehensive Uptime Monitoring for Various Services\",\n\t\t\t\t\t\"simStepId\": \"1d7580f2-f107-4008-a207-b8ec07998721\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"5e80734c-7b72-41be-9068-30cda3ffb425\": {\n\t\t\t\"path\": \"5e80734c-7b72-41be-9068-30cda3ffb425\",\n\t\t\t\"cellName\": \"Service Monitoring:\\nPropagate Network\\nResponse\",\n\t\t\t\"cellId\": \"5e80734c-7b72-41be-9068-30cda3ffb425\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"1670815f-860d-4ea4-92e1-b238a799d3dc\"\n\t\t},\n\t\t\"generated-edge-simstep-9b0ada30-d3e6-4b2c-b3ff-f50615139588-5e80734c-7b72-41be-9068-30cda3ffb425\": {\n\t\t\t\"path\": \"generated-edge-simstep-9b0ada30-d3e6-4b2c-b3ff-f50615139588-5e80734c-7b72-41be-9068-30cda3ffb425\",\n\t\t\t\"fileName\": \"networkService.js\",\n\t\t\t\"cellName\": \"Service Monitoring: Propagate Network Response\",\n\t\t\t\"cellId\": \"5e80734c-7b72-41be-9068-30cda3ffb425\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 45,\n\t\t\t\"endLine\": 45,\n\t\t\t\"parentPath\": \"server/src/service/v1/infrastructure/networkService.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Comprehensive Uptime Monitoring for Various Services\",\n\t\t\t\t\t\"simStepId\": \"9b0ada30-d3e6-4b2c-b3ff-f50615139588\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"0a7e4a72-b644-4bd8-afa1-ae8a1d6c111c\": {\n\t\t\t\"path\": \"0a7e4a72-b644-4bd8-afa1-ae8a1d6c111c\",\n\t\t\t\"cellName\": \"Service Monitoring:\\nCheck for\\nStatus Change\",\n\t\t\t\"cellId\": \"0a7e4a72-b644-4bd8-afa1-ae8a1d6c111c\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"1670815f-860d-4ea4-92e1-b238a799d3dc\"\n\t\t},\n\t\t\"generated-edge-simstep-9896c387-4fca-47ad-82eb-7301286decb7-0a7e4a72-b644-4bd8-afa1-ae8a1d6c111c\": {\n\t\t\t\"path\": \"generated-edge-simstep-9896c387-4fca-47ad-82eb-7301286decb7-0a7e4a72-b644-4bd8-afa1-ae8a1d6c111c\",\n\t\t\t\"fileName\": \"statusService.js\",\n\t\t\t\"cellName\": \"Service Monitoring: Check for Status Change\",\n\t\t\t\"cellId\": \"0a7e4a72-b644-4bd8-afa1-ae8a1d6c111c\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 51,\n\t\t\t\"endLine\": 51,\n\t\t\t\"parentPath\": \"server/src/service/v1/infrastructure/statusService.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Comprehensive Uptime Monitoring for Various Services\",\n\t\t\t\t\t\"simStepId\": \"9896c387-4fca-47ad-82eb-7301286decb7\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"3f26b33e-477f-41df-a78a-3e3e4f4209ae\": {\n\t\t\t\"path\": \"3f26b33e-477f-41df-a78a-3e3e4f4209ae\",\n\t\t\t\"cellName\": \"Infrastructure\",\n\t\t\t\"cellId\": \"3f26b33e-477f-41df-a78a-3e3e4f4209ae\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"1a083b4a-787c-4eb4-8029-6700de987679\"\n\t\t},\n\t\t\"74019e8a-3148-4a32-aae2-5afd16f3eb9b\": {\n\t\t\t\"path\": \"74019e8a-3148-4a32-aae2-5afd16f3eb9b\",\n\t\t\t\"cellName\": \"Create\",\n\t\t\t\"cellId\": \"74019e8a-3148-4a32-aae2-5afd16f3eb9b\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"3f26b33e-477f-41df-a78a-3e3e4f4209ae\"\n\t\t},\n\t\t\"591128f9-0994-4e01-a1ab-f23357f97aff\": {\n\t\t\t\"path\": \"591128f9-0994-4e01-a1ab-f23357f97aff\",\n\t\t\t\"cellName\": \"Details\",\n\t\t\t\"cellId\": \"591128f9-0994-4e01-a1ab-f23357f97aff\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"3f26b33e-477f-41df-a78a-3e3e4f4209ae\"\n\t\t},\n\t\t\"4940977f-933d-4bbc-b19e-749647b44d25\": {\n\t\t\t\"path\": \"4940977f-933d-4bbc-b19e-749647b44d25\",\n\t\t\t\"cellName\": \"notificationUtils.js\",\n\t\t\t\"cellId\": \"4940977f-933d-4bbc-b19e-749647b44d25\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"1670815f-860d-4ea4-92e1-b238a799d3dc\"\n\t\t},\n\t\t\"a0b22a5a-59e1-47e3-8218-a4ad083b1b71\": {\n\t\t\t\"path\": \"a0b22a5a-59e1-47e3-8218-a4ad083b1b71\",\n\t\t\t\"cellName\": \"monitorModuleQueries.js\",\n\t\t\t\"cellId\": \"a0b22a5a-59e1-47e3-8218-a4ad083b1b71\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"82cb3dbe-c922-438a-a912-255376f4b380\"\n\t\t},\n\t\t\"ceded1fc-87a9-43c8-a756-746be3d4ad8d\": {\n\t\t\t\"path\": \"ceded1fc-87a9-43c8-a756-746be3d4ad8d\",\n\t\t\t\"cellName\": \"Components\",\n\t\t\t\"cellId\": \"ceded1fc-87a9-43c8-a756-746be3d4ad8d\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"74019e8a-3148-4a32-aae2-5afd16f3eb9b\"\n\t\t},\n\t\t\"e292c552-b3df-4bac-bd9a-8f44c260a5aa\": {\n\t\t\t\"path\": \"e292c552-b3df-4bac-bd9a-8f44c260a5aa\",\n\t\t\t\"cellName\": \"index.jsx\",\n\t\t\t\"cellId\": \"e292c552-b3df-4bac-bd9a-8f44c260a5aa\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"591128f9-0994-4e01-a1ab-f23357f97aff\"\n\t\t},\n\t\t\"e97d4e61-483e-4ac5-85a1-0ff72fcdd449\": {\n\t\t\t\"path\": \"e97d4e61-483e-4ac5-85a1-0ff72fcdd449\",\n\t\t\t\"cellName\": \"Components\",\n\t\t\t\"cellId\": \"e97d4e61-483e-4ac5-85a1-0ff72fcdd449\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"591128f9-0994-4e01-a1ab-f23357f97aff\"\n\t\t},\n\t\t\"83800be3-2a0e-4419-b379-3f995f4050e7\": {\n\t\t\t\"path\": \"83800be3-2a0e-4419-b379-3f995f4050e7\",\n\t\t\t\"cellName\": \"CustomAlertsSection.jsx\",\n\t\t\t\"cellId\": \"83800be3-2a0e-4419-b379-3f995f4050e7\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"ceded1fc-87a9-43c8-a756-746be3d4ad8d\"\n\t\t},\n\t\t\"6a7c7720-a399-4d4d-8225-36e0b2f59731\": {\n\t\t\t\"path\": \"6a7c7720-a399-4d4d-8225-36e0b2f59731\",\n\t\t\t\"cellName\": \"GaugeBoxes\",\n\t\t\t\"cellId\": \"6a7c7720-a399-4d4d-8225-36e0b2f59731\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"e97d4e61-483e-4ac5-85a1-0ff72fcdd449\"\n\t\t},\n\t\t\"8fe3d890-3605-407d-b06c-1d890a354e46\": {\n\t\t\t\"path\": \"8fe3d890-3605-407d-b06c-1d890a354e46\",\n\t\t\t\"cellName\": \"index.jsx\",\n\t\t\t\"cellId\": \"8fe3d890-3605-407d-b06c-1d890a354e46\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"6a7c7720-a399-4d4d-8225-36e0b2f59731\"\n\t\t},\n\t\t\"9651d084-5c16-4417-89c1-f52ae6572a95\": {\n\t\t\t\"path\": \"9651d084-5c16-4417-89c1-f52ae6572a95\",\n\t\t\t\"cellName\": \"Configuration: User Sets Alert Thresholds - CustomAlertsSection.jsx:L45-53\",\n\t\t\t\"cellId\": \"9651d084-5c16-4417-89c1-f52ae6572a95\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"83800be3-2a0e-4419-b379-3f995f4050e7\"\n\t\t},\n\t\t\"client/src/Pages/v1/Infrastructure/Create/Components/CustomAlertsSection.jsx-simstep-80dd889a-1fc9-4d56-b9cf-5b45bf1110b1\": {\n\t\t\t\"path\": \"client/src/Pages/v1/Infrastructure/Create/Components/CustomAlertsSection.jsx-simstep-80dd889a-1fc9-4d56-b9cf-5b45bf1110b1\",\n\t\t\t\"fileName\": \"CustomAlertsSection.jsx\",\n\t\t\t\"wiki\": \"A user navigates to the 'Create Infrastructure Monitor' page to set up monitoring for a new server. They enable alerts for CPU, memory, and disk usage, and define specific thresholds for each metric. For example, an alert is configured to trigger if CPU usage exceeds 80%.\",\n\t\t\t\"cellName\": \"Configuration: User Sets Alert Thresholds - CustomAlertsSection.jsx:L45-53\",\n\t\t\t\"cellId\": \"9651d084-5c16-4417-89c1-f52ae6572a95\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 45,\n\t\t\t\"endLine\": 53,\n\t\t\t\"parentCellId\": \"83800be3-2a0e-4419-b379-3f995f4050e7\",\n\t\t\t\"parentPath\": \"client/src/Pages/v1/Infrastructure/Create/Components/CustomAlertsSection.jsx\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Infrastructure and Hardware Health Monitoring\",\n\t\t\t\t\t\"simStepId\": \"80dd889a-1fc9-4d56-b9cf-5b45bf1110b1\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"4c47b5f2-5363-4816-9745-30e61d184c7a\": {\n\t\t\t\"path\": \"4c47b5f2-5363-4816-9745-30e61d184c7a\",\n\t\t\t\"cellName\": \"Automated Check: Backend Fetches Hardware Data - networkService.js:L7-14\",\n\t\t\t\"cellId\": \"4c47b5f2-5363-4816-9745-30e61d184c7a\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"00406786-9663-440a-96b6-919d544732c0\"\n\t\t},\n\t\t\"server/src/service/v1/infrastructure/networkService.js-simstep-ed6e7faf-69dd-4d0b-bda8-137739ed288b\": {\n\t\t\t\"path\": \"server/src/service/v1/infrastructure/networkService.js-simstep-ed6e7faf-69dd-4d0b-bda8-137739ed288b\",\n\t\t\t\"fileName\": \"networkService.js\",\n\t\t\t\"wiki\": \"The Checkmate server's job queue periodically initiates a check for the newly created hardware monitor. It makes an HTTP request to the monitor's URL, which points to the external 'Capture' agent running on the target server.\",\n\t\t\t\"cellName\": \"Automated Check: Backend Fetches Hardware Data - networkService.js:L7-14\",\n\t\t\t\"cellId\": \"4c47b5f2-5363-4816-9745-30e61d184c7a\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 7,\n\t\t\t\"endLine\": 14,\n\t\t\t\"parentCellId\": \"00406786-9663-440a-96b6-919d544732c0\",\n\t\t\t\"parentPath\": \"server/src/service/v1/infrastructure/networkService.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Infrastructure and Hardware Health Monitoring\",\n\t\t\t\t\t\"simStepId\": \"ed6e7faf-69dd-4d0b-bda8-137739ed288b\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"c1bf10c9-8c1a-44f4-8e23-39708f0301e8\": {\n\t\t\t\"path\": \"c1bf10c9-8c1a-44f4-8e23-39708f0301e8\",\n\t\t\t\"cellName\": \"Automated Check: Process and Store Hardware Data - statusService.js:L265-274\",\n\t\t\t\"cellId\": \"c1bf10c9-8c1a-44f4-8e23-39708f0301e8\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"fbd7d244-2f37-453c-8c83-a23a260b26cc\"\n\t\t},\n\t\t\"server/src/service/v1/infrastructure/statusService.js-simstep-e5b90cf2-9369-4741-9803-c835a81c009b\": {\n\t\t\t\"path\": \"server/src/service/v1/infrastructure/statusService.js-simstep-e5b90cf2-9369-4741-9803-c835a81c009b\",\n\t\t\t\"fileName\": \"statusService.js\",\n\t\t\t\"wiki\": \"The backend's StatusService receives the payload from the Capture agent. It parses the data and constructs a 'check' document. This document, containing the detailed hardware metrics, is then saved to the database for historical tracking and visualization.\",\n\t\t\t\"cellName\": \"Automated Check: Process and Store Hardware Data - statusService.js:L265-274\",\n\t\t\t\"cellId\": \"c1bf10c9-8c1a-44f4-8e23-39708f0301e8\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 265,\n\t\t\t\"endLine\": 274,\n\t\t\t\"parentCellId\": \"fbd7d244-2f37-453c-8c83-a23a260b26cc\",\n\t\t\t\"parentPath\": \"server/src/service/v1/infrastructure/statusService.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Infrastructure and Hardware Health Monitoring\",\n\t\t\t\t\t\"simStepId\": \"e5b90cf2-9369-4741-9803-c835a81c009b\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"d4f48f1a-61de-4cde-87d2-4b5215464899\": {\n\t\t\t\"path\": \"d4f48f1a-61de-4cde-87d2-4b5215464899\",\n\t\t\t\"cellName\": \"Automated Check: Evaluate Data Against Thresholds - notificationUtils.js:L95-109\",\n\t\t\t\"cellId\": \"d4f48f1a-61de-4cde-87d2-4b5215464899\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"4940977f-933d-4bbc-b19e-749647b44d25\"\n\t\t},\n\t\t\"server/src/service/v1/infrastructure/notificationUtils.js-simstep-07fe8489-1d94-4afb-83f8-7cebb0dff49a\": {\n\t\t\t\"path\": \"server/src/service/v1/infrastructure/notificationUtils.js-simstep-07fe8489-1d94-4afb-83f8-7cebb0dff49a\",\n\t\t\t\"fileName\": \"notificationUtils.js\",\n\t\t\t\"wiki\": \"The notification utility function compares the received hardware metrics against the user-defined thresholds stored in the monitor's configuration. In this case, the CPU usage of 85% is greater than the 80% threshold, so an alert condition is met.\",\n\t\t\t\"cellName\": \"Automated Check: Evaluate Data Against Thresholds - notificationUtils.js:L95-109\",\n\t\t\t\"cellId\": \"d4f48f1a-61de-4cde-87d2-4b5215464899\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 95,\n\t\t\t\"endLine\": 109,\n\t\t\t\"parentCellId\": \"4940977f-933d-4bbc-b19e-749647b44d25\",\n\t\t\t\"parentPath\": \"server/src/service/v1/infrastructure/notificationUtils.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Infrastructure and Hardware Health Monitoring\",\n\t\t\t\t\t\"simStepId\": \"07fe8489-1d94-4afb-83f8-7cebb0dff49a\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"801fe70a-1a19-406c-8f0d-770b0cb74409\": {\n\t\t\t\"path\": \"801fe70a-1a19-406c-8f0d-770b0cb74409\",\n\t\t\t\"cellName\": \"Visualization: User Views Monitor Details - index.jsx:L23-31\",\n\t\t\t\"cellId\": \"801fe70a-1a19-406c-8f0d-770b0cb74409\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"e292c552-b3df-4bac-bd9a-8f44c260a5aa\"\n\t\t},\n\t\t\"client/src/Pages/v1/Infrastructure/Details/index.jsx-simstep-c27365db-9db6-4cc9-96f0-4f046fd38562\": {\n\t\t\t\"path\": \"client/src/Pages/v1/Infrastructure/Details/index.jsx-simstep-c27365db-9db6-4cc9-96f0-4f046fd38562\",\n\t\t\t\"fileName\": \"index.jsx\",\n\t\t\t\"wiki\": \"A user navigates to the details page for their 'Production Web Server' monitor in the Checkmate UI to view its performance. The React component for the details page mounts and prepares to fetch data.\",\n\t\t\t\"cellName\": \"Visualization: User Views Monitor Details - index.jsx:L23-31\",\n\t\t\t\"cellId\": \"801fe70a-1a19-406c-8f0d-770b0cb74409\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 23,\n\t\t\t\"endLine\": 31,\n\t\t\t\"parentCellId\": \"e292c552-b3df-4bac-bd9a-8f44c260a5aa\",\n\t\t\t\"parentPath\": \"client/src/Pages/v1/Infrastructure/Details/index.jsx\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Infrastructure and Hardware Health Monitoring\",\n\t\t\t\t\t\"simStepId\": \"c27365db-9db6-4cc9-96f0-4f046fd38562\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"9ef7c423-f4fc-4caf-9bf5-c1aa3002ca03\": {\n\t\t\t\"path\": \"9ef7c423-f4fc-4caf-9bf5-c1aa3002ca03\",\n\t\t\t\"cellName\": \"Backend: Aggregate Historical Data - monitorModule.js:L312-322\",\n\t\t\t\"cellId\": \"9ef7c423-f4fc-4caf-9bf5-c1aa3002ca03\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"630b3ece-2648-48d5-99b5-ef9611de2ad5\"\n\t\t},\n\t\t\"server/src/db/v1/modules/monitorModule.js-simstep-8502ae1f-f029-446e-9dde-59c2aba87a8a\": {\n\t\t\t\"path\": \"server/src/db/v1/modules/monitorModule.js-simstep-8502ae1f-f029-446e-9dde-59c2aba87a8a\",\n\t\t\t\"fileName\": \"monitorModule.js\",\n\t\t\t\"wiki\": \"The backend receives the request and executes a database aggregation pipeline. This query fetches all 'hardware' checks for the monitor within the given date range and calculates metrics like average CPU usage, average memory usage, and average temperatures, grouped by time intervals.\",\n\t\t\t\"cellName\": \"Backend: Aggregate Historical Data - monitorModule.js:L312-322\",\n\t\t\t\"cellId\": \"9ef7c423-f4fc-4caf-9bf5-c1aa3002ca03\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 312,\n\t\t\t\"endLine\": 322,\n\t\t\t\"parentCellId\": \"630b3ece-2648-48d5-99b5-ef9611de2ad5\",\n\t\t\t\"parentPath\": \"server/src/db/v1/modules/monitorModule.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Infrastructure and Hardware Health Monitoring\",\n\t\t\t\t\t\"simStepId\": \"8502ae1f-f029-446e-9dde-59c2aba87a8a\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"9ea2e32d-1ea8-42f2-9a17-613844723ae6\": {\n\t\t\t\"path\": \"9ea2e32d-1ea8-42f2-9a17-613844723ae6\",\n\t\t\t\"cellName\": \"Visualization: Frontend Renders Charts and Gauges - index.jsx:L22-51\",\n\t\t\t\"cellId\": \"9ea2e32d-1ea8-42f2-9a17-613844723ae6\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"8fe3d890-3605-407d-b06c-1d890a354e46\"\n\t\t},\n\t\t\"client/src/Pages/v1/Infrastructure/Details/Components/GaugeBoxes/index.jsx-simstep-6eedce82-b9c8-4022-95e5-3a6e00628105\": {\n\t\t\t\"path\": \"client/src/Pages/v1/Infrastructure/Details/Components/GaugeBoxes/index.jsx-simstep-6eedce82-b9c8-4022-95e5-3a6e00628105\",\n\t\t\t\"fileName\": \"index.jsx\",\n\t\t\t\"wiki\": \"The frontend components on the Infrastructure Details page receive the aggregated data. The 'GaugeBoxes' component uses the 'latestCheck' data to render real-time gauges for current CPU and memory usage, while the 'AreaChartBoxes' component uses the historical 'checks' data to render time-series charts.\",\n\t\t\t\"cellName\": \"Visualization: Frontend Renders Charts and Gauges - index.jsx:L22-51\",\n\t\t\t\"cellId\": \"9ea2e32d-1ea8-42f2-9a17-613844723ae6\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 22,\n\t\t\t\"endLine\": 51,\n\t\t\t\"parentCellId\": \"8fe3d890-3605-407d-b06c-1d890a354e46\",\n\t\t\t\"parentPath\": \"client/src/Pages/v1/Infrastructure/Details/Components/GaugeBoxes/index.jsx\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Infrastructure and Hardware Health Monitoring\",\n\t\t\t\t\t\"simStepId\": \"6eedce82-b9c8-4022-95e5-3a6e00628105\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"1c5c9857-bf32-40e4-921b-957c252dac2a\": {\n\t\t\t\"path\": \"1c5c9857-bf32-40e4-921b-957c252dac2a\",\n\t\t\t\"cellName\": \"API Call:\\nSubmit Monitor\\nConfiguration\",\n\t\t\t\"cellId\": \"1c5c9857-bf32-40e4-921b-957c252dac2a\",\n\t\t\t\"visible\": true\n\t\t},\n\t\t\"generated-edge-simstep-815f96af-c28e-4f80-b4ab-18a6fb23eee0-1c5c9857-bf32-40e4-921b-957c252dac2a\": {\n\t\t\t\"path\": \"generated-edge-simstep-815f96af-c28e-4f80-b4ab-18a6fb23eee0-1c5c9857-bf32-40e4-921b-957c252dac2a\",\n\t\t\t\"fileName\": \"CustomAlertsSection.jsx\",\n\t\t\t\"cellName\": \"API Call: Submit Monitor Configuration\",\n\t\t\t\"cellId\": \"1c5c9857-bf32-40e4-921b-957c252dac2a\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 386,\n\t\t\t\"endLine\": 389,\n\t\t\t\"parentPath\": \"client/src/Pages/v1/Infrastructure/Create/Components/CustomAlertsSection.jsx\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Infrastructure and Hardware Health Monitoring\",\n\t\t\t\t\t\"simStepId\": \"815f96af-c28e-4f80-b4ab-18a6fb23eee0\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"a64547c9-d9e6-4941-8e5e-f49add06516b\": {\n\t\t\t\"path\": \"a64547c9-d9e6-4941-8e5e-f49add06516b\",\n\t\t\t\"cellName\": \"Automated Check:\\nData Received\\nfrom Capture\\nAgent\",\n\t\t\t\"cellId\": \"a64547c9-d9e6-4941-8e5e-f49add06516b\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"1670815f-860d-4ea4-92e1-b238a799d3dc\"\n\t\t},\n\t\t\"generated-edge-simstep-4434dca1-2048-4458-a70b-b70d569e378d-a64547c9-d9e6-4941-8e5e-f49add06516b\": {\n\t\t\t\"path\": \"generated-edge-simstep-4434dca1-2048-4458-a70b-b70d569e378d-a64547c9-d9e6-4941-8e5e-f49add06516b\",\n\t\t\t\"fileName\": \"networkService.js\",\n\t\t\t\"cellName\": \"Automated Check: Data Received from Capture Agent\",\n\t\t\t\"cellId\": \"a64547c9-d9e6-4941-8e5e-f49add06516b\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 266,\n\t\t\t\"endLine\": 273,\n\t\t\t\"parentPath\": \"server/src/service/v1/infrastructure/networkService.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Infrastructure and Hardware Health Monitoring\",\n\t\t\t\t\t\"simStepId\": \"4434dca1-2048-4458-a70b-b70d569e378d\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"7a250d09-50c6-4935-b10c-626b0ebe1fba\": {\n\t\t\t\"path\": \"7a250d09-50c6-4935-b10c-626b0ebe1fba\",\n\t\t\t\"cellName\": \"Automated Check:\\nPass Data\\nfor Alert\\nEvaluation\",\n\t\t\t\"cellId\": \"7a250d09-50c6-4935-b10c-626b0ebe1fba\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"1670815f-860d-4ea4-92e1-b238a799d3dc\"\n\t\t},\n\t\t\"generated-edge-simstep-b019a6d0-a23a-4a1d-bd21-644f01996f14-7a250d09-50c6-4935-b10c-626b0ebe1fba\": {\n\t\t\t\"path\": \"generated-edge-simstep-b019a6d0-a23a-4a1d-bd21-644f01996f14-7a250d09-50c6-4935-b10c-626b0ebe1fba\",\n\t\t\t\"fileName\": \"statusService.js\",\n\t\t\t\"cellName\": \"Automated Check: Pass Data for Alert Evaluation\",\n\t\t\t\"cellId\": \"7a250d09-50c6-4935-b10c-626b0ebe1fba\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 60,\n\t\t\t\"endLine\": 79,\n\t\t\t\"parentPath\": \"server/src/service/v1/infrastructure/statusService.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Infrastructure and Hardware Health Monitoring\",\n\t\t\t\t\t\"simStepId\": \"b019a6d0-a23a-4a1d-bd21-644f01996f14\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"3d357de8-9fd2-4d0b-9623-f36fce4cf1de\": {\n\t\t\t\"path\": \"3d357de8-9fd2-4d0b-9623-f36fce4cf1de\",\n\t\t\t\"cellName\": \"Automated Check:\\nGenerate Alert\\nNotification Content\",\n\t\t\t\"cellId\": \"3d357de8-9fd2-4d0b-9623-f36fce4cf1de\",\n\t\t\t\"visible\": true\n\t\t},\n\t\t\"generated-edge-simstep-c691b3b9-88b3-4c88-a399-ff9fd5866194-3d357de8-9fd2-4d0b-9623-f36fce4cf1de\": {\n\t\t\t\"path\": \"generated-edge-simstep-c691b3b9-88b3-4c88-a399-ff9fd5866194-3d357de8-9fd2-4d0b-9623-f36fce4cf1de\",\n\t\t\t\"fileName\": \"notificationUtils.js\",\n\t\t\t\"cellName\": \"Automated Check: Generate Alert Notification Content\",\n\t\t\t\"cellId\": \"3d357de8-9fd2-4d0b-9623-f36fce4cf1de\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 177,\n\t\t\t\"endLine\": 183,\n\t\t\t\"parentPath\": \"server/src/service/v1/infrastructure/notificationUtils.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Infrastructure and Hardware Health Monitoring\",\n\t\t\t\t\t\"simStepId\": \"c691b3b9-88b3-4c88-a399-ff9fd5866194\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"00921831-b1d9-4a5a-ae6f-5ddee7cfc1e4\": {\n\t\t\t\"path\": \"00921831-b1d9-4a5a-ae6f-5ddee7cfc1e4\",\n\t\t\t\"cellName\": \"API Call:\\nRequest for\\nHistorical Hardware\\nData\",\n\t\t\t\"cellId\": \"00921831-b1d9-4a5a-ae6f-5ddee7cfc1e4\",\n\t\t\t\"visible\": true\n\t\t},\n\t\t\"generated-edge-simstep-a5d20172-1c95-4c9e-af39-f86a498734bb-00921831-b1d9-4a5a-ae6f-5ddee7cfc1e4\": {\n\t\t\t\"path\": \"generated-edge-simstep-a5d20172-1c95-4c9e-af39-f86a498734bb-00921831-b1d9-4a5a-ae6f-5ddee7cfc1e4\",\n\t\t\t\"fileName\": \"index.jsx\",\n\t\t\t\"cellName\": \"API Call: Request for Historical Hardware Data\",\n\t\t\t\"cellId\": \"00921831-b1d9-4a5a-ae6f-5ddee7cfc1e4\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 198,\n\t\t\t\"endLine\": 206,\n\t\t\t\"parentPath\": \"client/src/Pages/v1/Infrastructure/Details/index.jsx\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Infrastructure and Hardware Health Monitoring\",\n\t\t\t\t\t\"simStepId\": \"a5d20172-1c95-4c9e-af39-f86a498734bb\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"60308696-6f8a-43c8-b9a1-da199ef500cd\": {\n\t\t\t\"path\": \"60308696-6f8a-43c8-b9a1-da199ef500cd\",\n\t\t\t\"cellName\": \"API Response:\\nSend Aggregated\\nData to\\nFrontend\",\n\t\t\t\"cellId\": \"60308696-6f8a-43c8-b9a1-da199ef500cd\",\n\t\t\t\"visible\": true\n\t\t},\n\t\t\"generated-edge-simstep-627fcb0c-0282-4b4d-8c55-aceb636e4da0-60308696-6f8a-43c8-b9a1-da199ef500cd\": {\n\t\t\t\"path\": \"generated-edge-simstep-627fcb0c-0282-4b4d-8c55-aceb636e4da0-60308696-6f8a-43c8-b9a1-da199ef500cd\",\n\t\t\t\"fileName\": \"monitorModule.js\",\n\t\t\t\"cellName\": \"API Response: Send Aggregated Data to Frontend\",\n\t\t\t\"cellId\": \"60308696-6f8a-43c8-b9a1-da199ef500cd\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 247,\n\t\t\t\"endLine\": 262,\n\t\t\t\"parentPath\": \"server/src/db/v1/modules/monitorModule.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Infrastructure and Hardware Health Monitoring\",\n\t\t\t\t\t\"simStepId\": \"627fcb0c-0282-4b4d-8c55-aceb636e4da0\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"feefae96-61b8-4ac5-a37c-592ed4b2330e\": {\n\t\t\t\"path\": \"feefae96-61b8-4ac5-a37c-592ed4b2330e\",\n\t\t\t\"cellName\": \"v2\",\n\t\t\t\"cellId\": \"feefae96-61b8-4ac5-a37c-592ed4b2330e\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"99e9b746-7809-41f4-a433-1de7cc90574b\"\n\t\t},\n\t\t\"b3575a92-df07-4cf7-810f-8e5e0672d666\": {\n\t\t\t\"path\": \"b3575a92-df07-4cf7-810f-8e5e0672d666\",\n\t\t\t\"cellName\": \"Notifications\",\n\t\t\t\"cellId\": \"b3575a92-df07-4cf7-810f-8e5e0672d666\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"1a083b4a-787c-4eb4-8029-6700de987679\"\n\t\t},\n\t\t\"cd2428fd-6545-48dd-b685-5261311b7532\": {\n\t\t\t\"path\": \"cd2428fd-6545-48dd-b685-5261311b7532\",\n\t\t\t\"cellName\": \"useNotifications.js\",\n\t\t\t\"cellId\": \"cd2428fd-6545-48dd-b685-5261311b7532\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"3bf0c0f9-cbb0-4f0c-8cb3-6e2a4abc0961\"\n\t\t},\n\t\t\"96250197-23af-4059-9904-fd6751f70ad5\": {\n\t\t\t\"path\": \"96250197-23af-4059-9904-fd6751f70ad5\",\n\t\t\t\"cellName\": \"notificationRoute.js\",\n\t\t\t\"cellId\": \"96250197-23af-4059-9904-fd6751f70ad5\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"d3375a20-2776-4771-b806-649bbeb541bd\"\n\t\t},\n\t\t\"8e5941e1-e577-455f-bbf2-83a418ad5908\": {\n\t\t\t\"path\": \"8e5941e1-e577-455f-bbf2-83a418ad5908\",\n\t\t\t\"cellName\": \"notificationController.js\",\n\t\t\t\"cellId\": \"8e5941e1-e577-455f-bbf2-83a418ad5908\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"fc591f7a-d4ac-4565-949d-a87a58a79bbc\"\n\t\t},\n\t\t\"3f8ff792-40c8-4ae6-9af5-ff8b90da2f9f\": {\n\t\t\t\"path\": \"3f8ff792-40c8-4ae6-9af5-ff8b90da2f9f\",\n\t\t\t\"cellName\": \"infrastructure\",\n\t\t\t\"cellId\": \"3f8ff792-40c8-4ae6-9af5-ff8b90da2f9f\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"feefae96-61b8-4ac5-a37c-592ed4b2330e\"\n\t\t},\n\t\t\"a6fb23f0-73bc-40ee-bb3c-ed93605a2bcb\": {\n\t\t\t\"path\": \"a6fb23f0-73bc-40ee-bb3c-ed93605a2bcb\",\n\t\t\t\"cellName\": \"create\",\n\t\t\t\"cellId\": \"a6fb23f0-73bc-40ee-bb3c-ed93605a2bcb\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"b3575a92-df07-4cf7-810f-8e5e0672d666\"\n\t\t},\n\t\t\"62daeac4-9402-448a-972c-cb8cb760671c\": {\n\t\t\t\"path\": \"62daeac4-9402-448a-972c-cb8cb760671c\",\n\t\t\t\"cellName\": \"notificationModule.js\",\n\t\t\t\"cellId\": \"62daeac4-9402-448a-972c-cb8cb760671c\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"82cb3dbe-c922-438a-a912-255376f4b380\"\n\t\t},\n\t\t\"159e569d-31d8-4883-b443-4ec08b21a044\": {\n\t\t\t\"path\": \"159e569d-31d8-4883-b443-4ec08b21a044\",\n\t\t\t\"cellName\": \"JobGenerator.ts\",\n\t\t\t\"cellId\": \"159e569d-31d8-4883-b443-4ec08b21a044\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"3f8ff792-40c8-4ae6-9af5-ff8b90da2f9f\"\n\t\t},\n\t\t\"c6d9907f-0a05-4153-a27f-47c3a1c4c0aa\": {\n\t\t\t\"path\": \"c6d9907f-0a05-4153-a27f-47c3a1c4c0aa\",\n\t\t\t\"cellName\": \"NotificationService.ts\",\n\t\t\t\"cellId\": \"c6d9907f-0a05-4153-a27f-47c3a1c4c0aa\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"3f8ff792-40c8-4ae6-9af5-ff8b90da2f9f\"\n\t\t},\n\t\t\"b71b02fb-d08e-4fcf-b959-de1b9547d9c2\": {\n\t\t\t\"path\": \"b71b02fb-d08e-4fcf-b959-de1b9547d9c2\",\n\t\t\t\"cellName\": \"index.jsx\",\n\t\t\t\"cellId\": \"b71b02fb-d08e-4fcf-b959-de1b9547d9c2\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"a6fb23f0-73bc-40ee-bb3c-ed93605a2bcb\"\n\t\t},\n\t\t\"15486629-84b3-463a-962b-06083f69e4bf\": {\n\t\t\t\"path\": \"15486629-84b3-463a-962b-06083f69e4bf\",\n\t\t\t\"cellName\": \"Flow 1: Render Notification Creation Form - index.jsx:L157-321\",\n\t\t\t\"cellId\": \"15486629-84b3-463a-962b-06083f69e4bf\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"b71b02fb-d08e-4fcf-b959-de1b9547d9c2\"\n\t\t},\n\t\t\"client/src/Pages/v1/Notifications/create/index.jsx-simstep-e924ec15-1bea-4e3b-befb-a8bf30cbf740\": {\n\t\t\t\"path\": \"client/src/Pages/v1/Notifications/create/index.jsx-simstep-e924ec15-1bea-4e3b-befb-a8bf30cbf740\",\n\t\t\t\"fileName\": \"index.jsx\",\n\t\t\t\"wiki\": \"User accesses the `/notifications/create` route, which renders the `CreateNotifications` component. This component displays a form for setting up a new notification channel, including fields for name, type, and provider-specific details.\",\n\t\t\t\"cellName\": \"Flow 1: Render Notification Creation Form - index.jsx:L157-321\",\n\t\t\t\"cellId\": \"15486629-84b3-463a-962b-06083f69e4bf\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 157,\n\t\t\t\"endLine\": 321,\n\t\t\t\"parentCellId\": \"b71b02fb-d08e-4fcf-b959-de1b9547d9c2\",\n\t\t\t\"parentPath\": \"client/src/Pages/v1/Notifications/create/index.jsx\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Multi-Channel Alerting and Notifications\",\n\t\t\t\t\t\"simStepId\": \"e924ec15-1bea-4e3b-befb-a8bf30cbf740\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"a07b805e-e55f-46cb-b54b-765b7813b0ca\": {\n\t\t\t\"path\": \"a07b805e-e55f-46cb-b54b-765b7813b0ca\",\n\t\t\t\"cellName\": \"Flow 1: Frontend API Call - useNotifications.js:L14-17\",\n\t\t\t\"cellId\": \"a07b805e-e55f-46cb-b54b-765b7813b0ca\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"cd2428fd-6545-48dd-b685-5261311b7532\"\n\t\t},\n\t\t\"client/src/Hooks/v1/useNotifications.js-simstep-383c6be8-aa51-4398-9ae3-21035413f73a\": {\n\t\t\t\"path\": \"client/src/Hooks/v1/useNotifications.js-simstep-383c6be8-aa51-4398-9ae3-21035413f73a\",\n\t\t\t\"fileName\": \"useNotifications.js\",\n\t\t\t\"wiki\": \"The `createNotification` hook executes an asynchronous function that calls `networkService.createNotification` to send the new notification data to the backend API.\",\n\t\t\t\"cellName\": \"Flow 1: Frontend API Call - useNotifications.js:L14-17\",\n\t\t\t\"cellId\": \"a07b805e-e55f-46cb-b54b-765b7813b0ca\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 14,\n\t\t\t\"endLine\": 17,\n\t\t\t\"parentCellId\": \"cd2428fd-6545-48dd-b685-5261311b7532\",\n\t\t\t\"parentPath\": \"client/src/Hooks/v1/useNotifications.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Multi-Channel Alerting and Notifications\",\n\t\t\t\t\t\"simStepId\": \"383c6be8-aa51-4398-9ae3-21035413f73a\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"d0a4737f-715f-4f50-b6d5-5e4b31f86f93\": {\n\t\t\t\"path\": \"d0a4737f-715f-4f50-b6d5-5e4b31f86f93\",\n\t\t\t\"cellName\": \"Flow 1: Backend Route Handling - notificationRoute.js:L10\",\n\t\t\t\"cellId\": \"d0a4737f-715f-4f50-b6d5-5e4b31f86f93\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"96250197-23af-4059-9904-fd6751f70ad5\"\n\t\t},\n\t\t\"server/src/routes/v1/notificationRoute.js-simstep-2f9266c9-4cbc-4b50-a280-cf8b5800d540\": {\n\t\t\t\"path\": \"server/src/routes/v1/notificationRoute.js-simstep-2f9266c9-4cbc-4b50-a280-cf8b5800d540\",\n\t\t\t\"fileName\": \"notificationRoute.js\",\n\t\t\t\"wiki\": \"The backend server receives the POST request. The Express router matches the `/notifications` path and forwards the request to the `createNotification` method of the `NotificationController`.\",\n\t\t\t\"cellName\": \"Flow 1: Backend Route Handling - notificationRoute.js:L10\",\n\t\t\t\"cellId\": \"d0a4737f-715f-4f50-b6d5-5e4b31f86f93\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 10,\n\t\t\t\"endLine\": 10,\n\t\t\t\"parentCellId\": \"96250197-23af-4059-9904-fd6751f70ad5\",\n\t\t\t\"parentPath\": \"server/src/routes/v1/notificationRoute.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Multi-Channel Alerting and Notifications\",\n\t\t\t\t\t\"simStepId\": \"2f9266c9-4cbc-4b50-a280-cf8b5800d540\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"4a796ccf-40a9-4446-a109-6a6eed52e898\": {\n\t\t\t\"path\": \"4a796ccf-40a9-4446-a109-6a6eed52e898\",\n\t\t\t\"cellName\": \"Flow 1: Database Insertion - notificationModule.js:L10-13\",\n\t\t\t\"cellId\": \"4a796ccf-40a9-4446-a109-6a6eed52e898\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"62daeac4-9402-448a-972c-cb8cb760671c\"\n\t\t},\n\t\t\"server/src/db/v1/modules/notificationModule.js-simstep-d29ab4ab-be50-4f17-af6e-2c61cec9d0ab\": {\n\t\t\t\"path\": \"server/src/db/v1/modules/notificationModule.js-simstep-d29ab4ab-be50-4f17-af6e-2c61cec9d0ab\",\n\t\t\t\"fileName\": \"notificationModule.js\",\n\t\t\t\"wiki\": \"The `notificationModule` creates a new instance of the `Notification` model with the provided data and saves it to the MongoDB database.\",\n\t\t\t\"cellName\": \"Flow 1: Database Insertion - notificationModule.js:L10-13\",\n\t\t\t\"cellId\": \"4a796ccf-40a9-4446-a109-6a6eed52e898\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 10,\n\t\t\t\"endLine\": 13,\n\t\t\t\"parentCellId\": \"62daeac4-9402-448a-972c-cb8cb760671c\",\n\t\t\t\"parentPath\": \"server/src/db/v1/modules/notificationModule.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Multi-Channel Alerting and Notifications\",\n\t\t\t\t\t\"simStepId\": \"d29ab4ab-be50-4f17-af6e-2c61cec9d0ab\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"29c2c56e-9dc0-4304-bfbf-e0c0f8915a39\": {\n\t\t\t\"path\": \"29c2c56e-9dc0-4304-bfbf-e0c0f8915a39\",\n\t\t\t\"cellName\": \"Flow 1: Backend Receives Test Request - notificationRoute.js:L13\",\n\t\t\t\"cellId\": \"29c2c56e-9dc0-4304-bfbf-e0c0f8915a39\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"96250197-23af-4059-9904-fd6751f70ad5\"\n\t\t},\n\t\t\"server/src/routes/v1/notificationRoute.js-simstep-c1b17b64-90e9-48bc-8927-25d7ebfc3036\": {\n\t\t\t\"path\": \"server/src/routes/v1/notificationRoute.js-simstep-c1b17b64-90e9-48bc-8927-25d7ebfc3036\",\n\t\t\t\"fileName\": \"notificationRoute.js\",\n\t\t\t\"wiki\": \"The client sends a POST request to `/notifications/test`. The router directs this request to the `testNotification` method in the `NotificationController`.\",\n\t\t\t\"cellName\": \"Flow 1: Backend Receives Test Request - notificationRoute.js:L13\",\n\t\t\t\"cellId\": \"29c2c56e-9dc0-4304-bfbf-e0c0f8915a39\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 13,\n\t\t\t\"endLine\": 13,\n\t\t\t\"parentCellId\": \"96250197-23af-4059-9904-fd6751f70ad5\",\n\t\t\t\"parentPath\": \"server/src/routes/v1/notificationRoute.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Multi-Channel Alerting and Notifications\",\n\t\t\t\t\t\"simStepId\": \"c1b17b64-90e9-48bc-8927-25d7ebfc3036\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"1cc01e08-4a6c-4526-b8a7-5ee8a06c1709\": {\n\t\t\t\"path\": \"1cc01e08-4a6c-4526-b8a7-5ee8a06c1709\",\n\t\t\t\"cellName\": \"Flow 1: Send Test Notification - notificationService.js:L120-123\",\n\t\t\t\"cellId\": \"1cc01e08-4a6c-4526-b8a7-5ee8a06c1709\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"2ff1f030-2080-48da-bbbe-90302fdfc2f7\"\n\t\t},\n\t\t\"server/src/service/v1/infrastructure/notificationService.js-simstep-f29f9be1-a0cd-43a3-b259-e5105a25ce41\": {\n\t\t\t\"path\": \"server/src/service/v1/infrastructure/notificationService.js-simstep-f29f9be1-a0cd-43a3-b259-e5105a25ce41\",\n\t\t\t\"fileName\": \"notificationService.js\",\n\t\t\t\"wiki\": \"The `NotificationService` prepares a standard test message and calls its internal `sendNotification` method. This method identifies the notification type (e.g., email, Slack) and uses the corresponding service (e.g., EmailService, NetworkService for webhooks) to dispatch the test message.\",\n\t\t\t\"cellName\": \"Flow 1: Send Test Notification - notificationService.js:L120-123\",\n\t\t\t\"cellId\": \"1cc01e08-4a6c-4526-b8a7-5ee8a06c1709\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 120,\n\t\t\t\"endLine\": 123,\n\t\t\t\"parentCellId\": \"2ff1f030-2080-48da-bbbe-90302fdfc2f7\",\n\t\t\t\"parentPath\": \"server/src/service/v1/infrastructure/notificationService.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Multi-Channel Alerting and Notifications\",\n\t\t\t\t\t\"simStepId\": \"f29f9be1-a0cd-43a3-b259-e5105a25ce41\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"28f1eabb-4f24-4944-8a0a-04f41ceb8589\": {\n\t\t\t\"path\": \"28f1eabb-4f24-4944-8a0a-04f41ceb8589\",\n\t\t\t\"cellName\": \"Flow 2: Job Execution and Status Update - JobGenerator.ts:L43-66\",\n\t\t\t\"cellId\": \"28f1eabb-4f24-4944-8a0a-04f41ceb8589\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"159e569d-31d8-4883-b443-4ec08b21a044\"\n\t\t},\n\t\t\"server/src/service/v2/infrastructure/JobGenerator.ts-simstep-157cec87-9b76-4a1c-9d85-0a6d3decbaa3\": {\n\t\t\t\"path\": \"server/src/service/v2/infrastructure/JobGenerator.ts-simstep-157cec87-9b76-4a1c-9d85-0a6d3decbaa3\",\n\t\t\t\"fileName\": \"JobGenerator.ts\",\n\t\t\t\"wiki\": \"A background job is generated for a monitor. When executed, it performs a network check, saves the result, and updates the monitor's status via `statusService.updateMonitorStatus`.\",\n\t\t\t\"cellName\": \"Flow 2: Job Execution and Status Update - JobGenerator.ts:L43-66\",\n\t\t\t\"cellId\": \"28f1eabb-4f24-4944-8a0a-04f41ceb8589\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 43,\n\t\t\t\"endLine\": 66,\n\t\t\t\"parentCellId\": \"159e569d-31d8-4883-b443-4ec08b21a044\",\n\t\t\t\"parentPath\": \"server/src/service/v2/infrastructure/JobGenerator.ts\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Multi-Channel Alerting and Notifications\",\n\t\t\t\t\t\"simStepId\": \"157cec87-9b76-4a1c-9d85-0a6d3decbaa3\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"31fe5a28-0640-4b52-841b-dd02e2ae646e\": {\n\t\t\t\"path\": \"31fe5a28-0640-4b52-841b-dd02e2ae646e\",\n\t\t\t\"cellName\": \"Flow 2: Initiate Notification Handling - JobGenerator.ts:L61\",\n\t\t\t\"cellId\": \"31fe5a28-0640-4b52-841b-dd02e2ae646e\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"159e569d-31d8-4883-b443-4ec08b21a044\"\n\t\t},\n\t\t\"server/src/service/v2/infrastructure/JobGenerator.ts-simstep-55ad645b-118a-478e-a00c-09ef82357008\": {\n\t\t\t\"path\": \"server/src/service/v2/infrastructure/JobGenerator.ts-simstep-55ad645b-118a-478e-a00c-09ef82357008\",\n\t\t\t\"fileName\": \"JobGenerator.ts\",\n\t\t\t\"wiki\": \"If the monitor's status has changed, the `handleNotifications` method of the `NotificationService` is invoked with the updated monitor's data.\",\n\t\t\t\"cellName\": \"Flow 2: Initiate Notification Handling - JobGenerator.ts:L61\",\n\t\t\t\"cellId\": \"31fe5a28-0640-4b52-841b-dd02e2ae646e\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 61,\n\t\t\t\"endLine\": 61,\n\t\t\t\"parentCellId\": \"159e569d-31d8-4883-b443-4ec08b21a044\",\n\t\t\t\"parentPath\": \"server/src/service/v2/infrastructure/JobGenerator.ts\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Multi-Channel Alerting and Notifications\",\n\t\t\t\t\t\"simStepId\": \"55ad645b-118a-478e-a00c-09ef82357008\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"78e5cb9f-6a97-4d31-a487-fe7dbce5d7d1\": {\n\t\t\t\"path\": \"78e5cb9f-6a97-4d31-a487-fe7dbce5d7d1\",\n\t\t\t\"cellName\": \"Flow 2: Dispatch Alerts - NotificationService.ts:L28-57\",\n\t\t\t\"cellId\": \"78e5cb9f-6a97-4d31-a487-fe7dbce5d7d1\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"c6d9907f-0a05-4153-a27f-47c3a1c4c0aa\"\n\t\t},\n\t\t\"server/src/service/v2/infrastructure/NotificationService.ts-simstep-8d1176f3-c755-401d-9ca8-234689b4b837\": {\n\t\t\t\"path\": \"server/src/service/v2/infrastructure/NotificationService.ts-simstep-8d1176f3-c755-401d-9ca8-234689b4b837\",\n\t\t\t\"fileName\": \"NotificationService.ts\",\n\t\t\t\"wiki\": \"The `handleNotifications` method retrieves the full details for each associated notification channel. It then iterates through them, using specific provider services (e.g., `SlackService`, `EmailService`) to format and send a tailored alert message for each channel, notifying users that the monitor is down.\",\n\t\t\t\"cellName\": \"Flow 2: Dispatch Alerts - NotificationService.ts:L28-57\",\n\t\t\t\"cellId\": \"78e5cb9f-6a97-4d31-a487-fe7dbce5d7d1\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 28,\n\t\t\t\"endLine\": 57,\n\t\t\t\"parentCellId\": \"c6d9907f-0a05-4153-a27f-47c3a1c4c0aa\",\n\t\t\t\"parentPath\": \"server/src/service/v2/infrastructure/NotificationService.ts\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Multi-Channel Alerting and Notifications\",\n\t\t\t\t\t\"simStepId\": \"8d1176f3-c755-401d-9ca8-234689b4b837\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"54497b9a-4910-4df4-b016-480b9ac250a7\": {\n\t\t\t\"path\": \"54497b9a-4910-4df4-b016-480b9ac250a7\",\n\t\t\t\"cellName\": \"Flow 1:\\nSubmit Form\\nData for\\nCreation\",\n\t\t\t\"cellId\": \"54497b9a-4910-4df4-b016-480b9ac250a7\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"d3264577-10f0-42fe-9411-7e9df0754d1e\"\n\t\t},\n\t\t\"generated-edge-simstep-71dbcd41-c6d4-4514-b5a4-6c966ca7ba6f-54497b9a-4910-4df4-b016-480b9ac250a7\": {\n\t\t\t\"path\": \"generated-edge-simstep-71dbcd41-c6d4-4514-b5a4-6c966ca7ba6f-54497b9a-4910-4df4-b016-480b9ac250a7\",\n\t\t\t\"fileName\": \"index.jsx\",\n\t\t\t\"cellName\": \"Flow 1: Submit Form Data for Creation\",\n\t\t\t\"cellId\": \"54497b9a-4910-4df4-b016-480b9ac250a7\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 96,\n\t\t\t\"endLine\": 101,\n\t\t\t\"parentPath\": \"client/src/Pages/v1/Notifications/create/index.jsx\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Multi-Channel Alerting and Notifications\",\n\t\t\t\t\t\"simStepId\": \"71dbcd41-c6d4-4514-b5a4-6c966ca7ba6f\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"dc135d8d-0515-403d-ae58-f3c04647b2ae\": {\n\t\t\t\"path\": \"dc135d8d-0515-403d-ae58-f3c04647b2ae\",\n\t\t\t\"cellName\": \"Flow 1:\\nHTTP POST\\nRequest\",\n\t\t\t\"cellId\": \"dc135d8d-0515-403d-ae58-f3c04647b2ae\",\n\t\t\t\"visible\": true\n\t\t},\n\t\t\"generated-edge-simstep-162d8d2f-6cd1-45fa-8711-1ee85c5f86ef-dc135d8d-0515-403d-ae58-f3c04647b2ae\": {\n\t\t\t\"path\": \"generated-edge-simstep-162d8d2f-6cd1-45fa-8711-1ee85c5f86ef-dc135d8d-0515-403d-ae58-f3c04647b2ae\",\n\t\t\t\"fileName\": \"useNotifications.js\",\n\t\t\t\"cellName\": \"Flow 1: HTTP POST Request\",\n\t\t\t\"cellId\": \"dc135d8d-0515-403d-ae58-f3c04647b2ae\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 1064,\n\t\t\t\"endLine\": 1066,\n\t\t\t\"parentPath\": \"client/src/Hooks/v1/useNotifications.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Multi-Channel Alerting and Notifications\",\n\t\t\t\t\t\"simStepId\": \"162d8d2f-6cd1-45fa-8711-1ee85c5f86ef\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"7b9ebb0e-a6b2-438c-bfed-9c851a1bccbc\": {\n\t\t\t\"path\": \"7b9ebb0e-a6b2-438c-bfed-9c851a1bccbc\",\n\t\t\t\"cellName\": \"Flow 1:\\nController to\\nDatabase Module\",\n\t\t\t\"cellId\": \"7b9ebb0e-a6b2-438c-bfed-9c851a1bccbc\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\"\n\t\t},\n\t\t\"generated-edge-simstep-73e63d2f-2b43-488d-9e86-170f511673f5-7b9ebb0e-a6b2-438c-bfed-9c851a1bccbc\": {\n\t\t\t\"path\": \"generated-edge-simstep-73e63d2f-2b43-488d-9e86-170f511673f5-7b9ebb0e-a6b2-438c-bfed-9c851a1bccbc\",\n\t\t\t\"fileName\": \"notificationRoute.js\",\n\t\t\t\"cellName\": \"Flow 1: Controller to Database Module\",\n\t\t\t\"cellId\": \"7b9ebb0e-a6b2-438c-bfed-9c851a1bccbc\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 55,\n\t\t\t\"endLine\": 55,\n\t\t\t\"parentPath\": \"server/src/routes/v1/notificationRoute.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Multi-Channel Alerting and Notifications\",\n\t\t\t\t\t\"simStepId\": \"73e63d2f-2b43-488d-9e86-170f511673f5\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"279155cd-ff31-41a2-8f5f-a538f01bfa66\": {\n\t\t\t\"path\": \"279155cd-ff31-41a2-8f5f-a538f01bfa66\",\n\t\t\t\"cellName\": \"Flow 1:\\nUser Clicks\\nTest Notification\\nButton\",\n\t\t\t\"cellId\": \"279155cd-ff31-41a2-8f5f-a538f01bfa66\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\"\n\t\t},\n\t\t\"generated-edge-simstep-d390ef45-f2fe-4806-a45a-cc9c84b48a5a-279155cd-ff31-41a2-8f5f-a538f01bfa66\": {\n\t\t\t\"path\": \"generated-edge-simstep-d390ef45-f2fe-4806-a45a-cc9c84b48a5a-279155cd-ff31-41a2-8f5f-a538f01bfa66\",\n\t\t\t\"fileName\": \"notificationModule.js\",\n\t\t\t\"cellName\": \"Flow 1: User Clicks Test Notification Button\",\n\t\t\t\"cellId\": \"279155cd-ff31-41a2-8f5f-a538f01bfa66\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 281,\n\t\t\t\"endLine\": 285,\n\t\t\t\"parentPath\": \"server/src/db/v1/modules/notificationModule.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Multi-Channel Alerting and Notifications\",\n\t\t\t\t\t\"simStepId\": \"d390ef45-f2fe-4806-a45a-cc9c84b48a5a\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"57018b30-e2f4-4eb2-a1da-fe75afbb8c2f\": {\n\t\t\t\"path\": \"57018b30-e2f4-4eb2-a1da-fe75afbb8c2f\",\n\t\t\t\"cellName\": \"Flow 1:\\nController to\\nNotification Service\",\n\t\t\t\"cellId\": \"57018b30-e2f4-4eb2-a1da-fe75afbb8c2f\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\"\n\t\t},\n\t\t\"generated-edge-simstep-6f2bf027-50d9-472e-9569-808a64fce7cf-57018b30-e2f4-4eb2-a1da-fe75afbb8c2f\": {\n\t\t\t\"path\": \"generated-edge-simstep-6f2bf027-50d9-472e-9569-808a64fce7cf-57018b30-e2f4-4eb2-a1da-fe75afbb8c2f\",\n\t\t\t\"fileName\": \"notificationRoute.js\",\n\t\t\t\"cellName\": \"Flow 1: Controller to Notification Service\",\n\t\t\t\"cellId\": \"57018b30-e2f4-4eb2-a1da-fe75afbb8c2f\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 22,\n\t\t\t\"endLine\": 22,\n\t\t\t\"parentPath\": \"server/src/routes/v1/notificationRoute.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Multi-Channel Alerting and Notifications\",\n\t\t\t\t\t\"simStepId\": \"6f2bf027-50d9-472e-9569-808a64fce7cf\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"50797935-1447-47a4-891b-9e886e5601fa\": {\n\t\t\t\"path\": \"50797935-1447-47a4-891b-9e886e5601fa\",\n\t\t\t\"cellName\": \"Flow 2:\\nStatus Change\\nDetected\",\n\t\t\t\"cellId\": \"50797935-1447-47a4-891b-9e886e5601fa\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"159e569d-31d8-4883-b443-4ec08b21a044\"\n\t\t},\n\t\t\"generated-edge-simstep-b7ec7415-fcae-4077-8c19-302a015b00b5-50797935-1447-47a4-891b-9e886e5601fa\": {\n\t\t\t\"path\": \"generated-edge-simstep-b7ec7415-fcae-4077-8c19-302a015b00b5-50797935-1447-47a4-891b-9e886e5601fa\",\n\t\t\t\"fileName\": \"JobGenerator.ts\",\n\t\t\t\"cellName\": \"Flow 2: Status Change Detected\",\n\t\t\t\"cellId\": \"50797935-1447-47a4-891b-9e886e5601fa\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 60,\n\t\t\t\"endLine\": 60,\n\t\t\t\"parentPath\": \"server/src/service/v2/infrastructure/JobGenerator.ts\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Multi-Channel Alerting and Notifications\",\n\t\t\t\t\t\"simStepId\": \"b7ec7415-fcae-4077-8c19-302a015b00b5\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"c778c6b9-c12e-45c0-8682-2c9e892867b0\": {\n\t\t\t\"path\": \"c778c6b9-c12e-45c0-8682-2c9e892867b0\",\n\t\t\t\"cellName\": \"Flow 2:\\nMonitor Data\\nPassed to\\nNotification Service\",\n\t\t\t\"cellId\": \"c778c6b9-c12e-45c0-8682-2c9e892867b0\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"3f8ff792-40c8-4ae6-9af5-ff8b90da2f9f\"\n\t\t},\n\t\t\"generated-edge-simstep-b7259d77-c8df-4060-ac03-58728ae3eb54-c778c6b9-c12e-45c0-8682-2c9e892867b0\": {\n\t\t\t\"path\": \"generated-edge-simstep-b7259d77-c8df-4060-ac03-58728ae3eb54-c778c6b9-c12e-45c0-8682-2c9e892867b0\",\n\t\t\t\"fileName\": \"JobGenerator.ts\",\n\t\t\t\"cellName\": \"Flow 2: Monitor Data Passed to Notification Service\",\n\t\t\t\"cellId\": \"c778c6b9-c12e-45c0-8682-2c9e892867b0\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 7,\n\t\t\t\"endLine\": 7,\n\t\t\t\"parentPath\": \"server/src/service/v2/infrastructure/JobGenerator.ts\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Multi-Channel Alerting and Notifications\",\n\t\t\t\t\t\"simStepId\": \"b7259d77-c8df-4060-ac03-58728ae3eb54\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"987f145b-5df6-4c30-bf1c-2a2d2b0e5cdc\": {\n\t\t\t\"path\": \"987f145b-5df6-4c30-bf1c-2a2d2b0e5cdc\",\n\t\t\t\"cellName\": \"Routes\",\n\t\t\t\"cellId\": \"987f145b-5df6-4c30-bf1c-2a2d2b0e5cdc\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"d3264577-10f0-42fe-9411-7e9df0754d1e\"\n\t\t},\n\t\t\"c4d7e7dd-75b1-44f1-a34a-6ed290a8e562\": {\n\t\t\t\"path\": \"c4d7e7dd-75b1-44f1-a34a-6ed290a8e562\",\n\t\t\t\"cellName\": \"index.jsx\",\n\t\t\t\"cellId\": \"c4d7e7dd-75b1-44f1-a34a-6ed290a8e562\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"987f145b-5df6-4c30-bf1c-2a2d2b0e5cdc\"\n\t\t},\n\t\t\"9d662180-8b65-4426-ad37-cfed4bc01fb4\": {\n\t\t\t\"path\": \"9d662180-8b65-4426-ad37-cfed4bc01fb4\",\n\t\t\t\"cellName\": \"StatusPage\",\n\t\t\t\"cellId\": \"9d662180-8b65-4426-ad37-cfed4bc01fb4\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"1a083b4a-787c-4eb4-8029-6700de987679\"\n\t\t},\n\t\t\"773e1065-b0a5-46a9-b0cc-6b963f69f5cc\": {\n\t\t\t\"path\": \"773e1065-b0a5-46a9-b0cc-6b963f69f5cc\",\n\t\t\t\"cellName\": \"statusPageRoute.js\",\n\t\t\t\"cellId\": \"773e1065-b0a5-46a9-b0cc-6b963f69f5cc\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"d3375a20-2776-4771-b806-649bbeb541bd\"\n\t\t},\n\t\t\"17a4f435-5a8e-4433-84a6-9ac17362709a\": {\n\t\t\t\"path\": \"17a4f435-5a8e-4433-84a6-9ac17362709a\",\n\t\t\t\"cellName\": \"statusPageController.js\",\n\t\t\t\"cellId\": \"17a4f435-5a8e-4433-84a6-9ac17362709a\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"fc591f7a-d4ac-4565-949d-a87a58a79bbc\"\n\t\t},\n\t\t\"08602a28-f073-484e-9403-7eb798126dd4\": {\n\t\t\t\"path\": \"08602a28-f073-484e-9403-7eb798126dd4\",\n\t\t\t\"cellName\": \"Create\",\n\t\t\t\"cellId\": \"08602a28-f073-484e-9403-7eb798126dd4\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"9d662180-8b65-4426-ad37-cfed4bc01fb4\"\n\t\t},\n\t\t\"8ef70566-37d9-48fb-b5e8-37e5b68768a2\": {\n\t\t\t\"path\": \"8ef70566-37d9-48fb-b5e8-37e5b68768a2\",\n\t\t\t\"cellName\": \"Status\",\n\t\t\t\"cellId\": \"8ef70566-37d9-48fb-b5e8-37e5b68768a2\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"9d662180-8b65-4426-ad37-cfed4bc01fb4\"\n\t\t},\n\t\t\"f8541fe3-4bcf-4833-a226-66b5301adf58\": {\n\t\t\t\"path\": \"f8541fe3-4bcf-4833-a226-66b5301adf58\",\n\t\t\t\"cellName\": \"statusPageModule.js\",\n\t\t\t\"cellId\": \"f8541fe3-4bcf-4833-a226-66b5301adf58\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"82cb3dbe-c922-438a-a912-255376f4b380\"\n\t\t},\n\t\t\"e2d2bbf6-dffd-4edf-8c5d-34088d9d4745\": {\n\t\t\t\"path\": \"e2d2bbf6-dffd-4edf-8c5d-34088d9d4745\",\n\t\t\t\"cellName\": \"index.jsx\",\n\t\t\t\"cellId\": \"e2d2bbf6-dffd-4edf-8c5d-34088d9d4745\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"08602a28-f073-484e-9403-7eb798126dd4\"\n\t\t},\n\t\t\"56f6775e-9843-4ca2-bc8c-1c263b6c35e9\": {\n\t\t\t\"path\": \"56f6775e-9843-4ca2-bc8c-1c263b6c35e9\",\n\t\t\t\"cellName\": \"Hooks\",\n\t\t\t\"cellId\": \"56f6775e-9843-4ca2-bc8c-1c263b6c35e9\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"08602a28-f073-484e-9403-7eb798126dd4\"\n\t\t},\n\t\t\"e1e6f5e0-fd8c-4260-aa4f-cdb096c6b1c3\": {\n\t\t\t\"path\": \"e1e6f5e0-fd8c-4260-aa4f-cdb096c6b1c3\",\n\t\t\t\"cellName\": \"index.jsx\",\n\t\t\t\"cellId\": \"e1e6f5e0-fd8c-4260-aa4f-cdb096c6b1c3\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"8ef70566-37d9-48fb-b5e8-37e5b68768a2\"\n\t\t},\n\t\t\"79da0721-d810-4f7f-9cf9-3ea462bf0bff\": {\n\t\t\t\"path\": \"79da0721-d810-4f7f-9cf9-3ea462bf0bff\",\n\t\t\t\"cellName\": \"Hooks\",\n\t\t\t\"cellId\": \"79da0721-d810-4f7f-9cf9-3ea462bf0bff\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"8ef70566-37d9-48fb-b5e8-37e5b68768a2\"\n\t\t},\n\t\t\"3945e05f-2d99-4d6d-9a3e-b6c75ea3c45a\": {\n\t\t\t\"path\": \"3945e05f-2d99-4d6d-9a3e-b6c75ea3c45a\",\n\t\t\t\"cellName\": \"useCreateStatusPage.jsx\",\n\t\t\t\"cellId\": \"3945e05f-2d99-4d6d-9a3e-b6c75ea3c45a\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"56f6775e-9843-4ca2-bc8c-1c263b6c35e9\"\n\t\t},\n\t\t\"5b2cdab8-66f1-40a1-9621-0efaf54e04ae\": {\n\t\t\t\"path\": \"5b2cdab8-66f1-40a1-9621-0efaf54e04ae\",\n\t\t\t\"cellName\": \"useStatusPageFetch.jsx\",\n\t\t\t\"cellId\": \"5b2cdab8-66f1-40a1-9621-0efaf54e04ae\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"79da0721-d810-4f7f-9cf9-3ea462bf0bff\"\n\t\t},\n\t\t\"00289d11-0015-4b2a-9c5b-dc9fd0f32b80\": {\n\t\t\t\"path\": \"00289d11-0015-4b2a-9c5b-dc9fd0f32b80\",\n\t\t\t\"cellName\": \"Create Status Page: User Initiates Creation - index.jsx:L26-313\",\n\t\t\t\"cellId\": \"00289d11-0015-4b2a-9c5b-dc9fd0f32b80\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"e2d2bbf6-dffd-4edf-8c5d-34088d9d4745\"\n\t\t},\n\t\t\"client/src/Pages/v1/StatusPage/Create/index.jsx-simstep-de7b5d1f-b370-42a4-a410-4178f1e2d3a6\": {\n\t\t\t\"path\": \"client/src/Pages/v1/StatusPage/Create/index.jsx-simstep-de7b5d1f-b370-42a4-a410-4178f1e2d3a6\",\n\t\t\t\"fileName\": \"index.jsx\",\n\t\t\t\"wiki\": \"The user navigates to the 'Create Status Page' screen. The `CreateStatusPage` component renders the UI, including tabs for configuration, and initializes the form state.\",\n\t\t\t\"cellName\": \"Create Status Page: User Initiates Creation - index.jsx:L26-313\",\n\t\t\t\"cellId\": \"00289d11-0015-4b2a-9c5b-dc9fd0f32b80\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 26,\n\t\t\t\"endLine\": 313,\n\t\t\t\"parentCellId\": \"e2d2bbf6-dffd-4edf-8c5d-34088d9d4745\",\n\t\t\t\"parentPath\": \"client/src/Pages/v1/StatusPage/Create/index.jsx\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Customizable Public and Private Status Pages\",\n\t\t\t\t\t\"simStepId\": \"de7b5d1f-b370-42a4-a410-4178f1e2d3a6\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"aa5d6d07-05f0-45f3-b19a-199af50e35f1\": {\n\t\t\t\"path\": \"aa5d6d07-05f0-45f3-b19a-199af50e35f1\",\n\t\t\t\"cellName\": \"Create Status Page: Client Hook Sends API Request - useCreateStatusPage.jsx:L8-11\",\n\t\t\t\"cellId\": \"aa5d6d07-05f0-45f3-b19a-199af50e35f1\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"3945e05f-2d99-4d6d-9a3e-b6c75ea3c45a\"\n\t\t},\n\t\t\"client/src/Pages/v1/StatusPage/Create/Hooks/useCreateStatusPage.jsx-simstep-3c99ae6a-b671-4f47-bed0-ddccd8ff5d35\": {\n\t\t\t\"path\": \"client/src/Pages/v1/StatusPage/Create/Hooks/useCreateStatusPage.jsx-simstep-3c99ae6a-b671-4f47-bed0-ddccd8ff5d35\",\n\t\t\t\"fileName\": \"useCreateStatusPage.jsx\",\n\t\t\t\"wiki\": \"The `useCreateStatusPage` hook receives the form data and uses the `networkService` to send a request to the backend API to create or update the status page.\",\n\t\t\t\"cellName\": \"Create Status Page: Client Hook Sends API Request - useCreateStatusPage.jsx:L8-11\",\n\t\t\t\"cellId\": \"aa5d6d07-05f0-45f3-b19a-199af50e35f1\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 8,\n\t\t\t\"endLine\": 11,\n\t\t\t\"parentCellId\": \"3945e05f-2d99-4d6d-9a3e-b6c75ea3c45a\",\n\t\t\t\"parentPath\": \"client/src/Pages/v1/StatusPage/Create/Hooks/useCreateStatusPage.jsx\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Customizable Public and Private Status Pages\",\n\t\t\t\t\t\"simStepId\": \"3c99ae6a-b671-4f47-bed0-ddccd8ff5d35\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"3efddcad-588f-4492-9808-b0c81c823c96\": {\n\t\t\t\"path\": \"3efddcad-588f-4492-9808-b0c81c823c96\",\n\t\t\t\"cellName\": \"Create Status Page: Backend Route Handling - statusPageRoute.js:L14\",\n\t\t\t\"cellId\": \"3efddcad-588f-4492-9808-b0c81c823c96\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"773e1065-b0a5-46a9-b0cc-6b963f69f5cc\"\n\t\t},\n\t\t\"server/src/routes/v1/statusPageRoute.js-simstep-84f11567-b3c4-42a2-aa7f-d78c1412099a\": {\n\t\t\t\"path\": \"server/src/routes/v1/statusPageRoute.js-simstep-84f11567-b3c4-42a2-aa7f-d78c1412099a\",\n\t\t\t\"fileName\": \"statusPageRoute.js\",\n\t\t\t\"wiki\": \"The backend router receives the POST request on `/api/v1/status-page`. It uses `multer` to handle the file upload and forwards the request to the `createStatusPage` method in the `StatusPageController`.\",\n\t\t\t\"cellName\": \"Create Status Page: Backend Route Handling - statusPageRoute.js:L14\",\n\t\t\t\"cellId\": \"3efddcad-588f-4492-9808-b0c81c823c96\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 14,\n\t\t\t\"endLine\": 14,\n\t\t\t\"parentCellId\": \"773e1065-b0a5-46a9-b0cc-6b963f69f5cc\",\n\t\t\t\"parentPath\": \"server/src/routes/v1/statusPageRoute.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Customizable Public and Private Status Pages\",\n\t\t\t\t\t\"simStepId\": \"84f11567-b3c4-42a2-aa7f-d78c1412099a\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"f15ef77e-380f-4768-98cb-7f0dd4113841\": {\n\t\t\t\"path\": \"f15ef77e-380f-4768-98cb-7f0dd4113841\",\n\t\t\t\"cellName\": \"Create Status Page: Controller Logic - statusPageController.js:L18-24\",\n\t\t\t\"cellId\": \"f15ef77e-380f-4768-98cb-7f0dd4113841\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"17a4f435-5a8e-4433-84a6-9ac17362709a\"\n\t\t},\n\t\t\"server/src/controllers/v1/statusPageController.js-simstep-01694730-8a75-4949-8815-bb4d6e3e2b42\": {\n\t\t\t\"path\": \"server/src/controllers/v1/statusPageController.js-simstep-01694730-8a75-4949-8815-bb4d6e3e2b42\",\n\t\t\t\"fileName\": \"statusPageController.js\",\n\t\t\t\"wiki\": \"The `StatusPageController` validates the incoming request body and file. It then calls the `statusPageModule` to persist the new status page in the database.\",\n\t\t\t\"cellName\": \"Create Status Page: Controller Logic - statusPageController.js:L18-24\",\n\t\t\t\"cellId\": \"f15ef77e-380f-4768-98cb-7f0dd4113841\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 18,\n\t\t\t\"endLine\": 24,\n\t\t\t\"parentCellId\": \"17a4f435-5a8e-4433-84a6-9ac17362709a\",\n\t\t\t\"parentPath\": \"server/src/controllers/v1/statusPageController.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Customizable Public and Private Status Pages\",\n\t\t\t\t\t\"simStepId\": \"01694730-8a75-4949-8815-bb4d6e3e2b42\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"e234917e-a950-48f5-b864-cd957b2216e1\": {\n\t\t\t\"path\": \"e234917e-a950-48f5-b864-cd957b2216e1\",\n\t\t\t\"cellName\": \"Create Status Page: Database Record Creation - statusPageModule.js:L14-34\",\n\t\t\t\"cellId\": \"e234917e-a950-48f5-b864-cd957b2216e1\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"f8541fe3-4bcf-4833-a226-66b5301adf58\"\n\t\t},\n\t\t\"server/src/db/v1/modules/statusPageModule.js-simstep-b6fa93cd-6fca-4d9e-969a-5400e2437ee8\": {\n\t\t\t\"path\": \"server/src/db/v1/modules/statusPageModule.js-simstep-b6fa93cd-6fca-4d9e-969a-5400e2437ee8\",\n\t\t\t\"fileName\": \"statusPageModule.js\",\n\t\t\t\"wiki\": \"The `StatusPageModule` creates a new instance of the `StatusPage` Mongoose model, populates it with the provided data including the image buffer, and saves it to the MongoDB database. It also handles duplicate URL errors.\",\n\t\t\t\"cellName\": \"Create Status Page: Database Record Creation - statusPageModule.js:L14-34\",\n\t\t\t\"cellId\": \"e234917e-a950-48f5-b864-cd957b2216e1\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 14,\n\t\t\t\"endLine\": 34,\n\t\t\t\"parentCellId\": \"f8541fe3-4bcf-4833-a226-66b5301adf58\",\n\t\t\t\"parentPath\": \"server/src/db/v1/modules/statusPageModule.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Customizable Public and Private Status Pages\",\n\t\t\t\t\t\"simStepId\": \"b6fa93cd-6fca-4d9e-969a-5400e2437ee8\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"058ded1f-83ce-40a7-a99d-d178c81fe557\": {\n\t\t\t\"path\": \"058ded1f-83ce-40a7-a99d-d178c81fe557\",\n\t\t\t\"cellName\": \"Create Status Page: Controller Sends Success Response - statusPageController.js:L25-28\",\n\t\t\t\"cellId\": \"058ded1f-83ce-40a7-a99d-d178c81fe557\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"17a4f435-5a8e-4433-84a6-9ac17362709a\"\n\t\t},\n\t\t\"server/src/controllers/v1/statusPageController.js-simstep-2a115421-5175-4c8f-8cdd-62f3fe148af5\": {\n\t\t\t\"path\": \"server/src/controllers/v1/statusPageController.js-simstep-2a115421-5175-4c8f-8cdd-62f3fe148af5\",\n\t\t\t\"fileName\": \"statusPageController.js\",\n\t\t\t\"wiki\": \"The controller receives the newly created status page object from the database module and sends a successful JSON response back to the client, including a success message and the new data.\",\n\t\t\t\"cellName\": \"Create Status Page: Controller Sends Success Response - statusPageController.js:L25-28\",\n\t\t\t\"cellId\": \"058ded1f-83ce-40a7-a99d-d178c81fe557\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 25,\n\t\t\t\"endLine\": 28,\n\t\t\t\"parentCellId\": \"17a4f435-5a8e-4433-84a6-9ac17362709a\",\n\t\t\t\"parentPath\": \"server/src/controllers/v1/statusPageController.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Customizable Public and Private Status Pages\",\n\t\t\t\t\t\"simStepId\": \"2a115421-5175-4c8f-8cdd-62f3fe148af5\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"30aaee38-f509-4e19-a917-e6d2f4bba61c\": {\n\t\t\t\"path\": \"30aaee38-f509-4e19-a917-e6d2f4bba61c\",\n\t\t\t\"cellName\": \"View Status Page: User Navigates to URL - index.jsx:L148-152\",\n\t\t\t\"cellId\": \"30aaee38-f509-4e19-a917-e6d2f4bba61c\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"c4d7e7dd-75b1-44f1-a34a-6ed290a8e562\"\n\t\t},\n\t\t\"client/src/Routes/index.jsx-simstep-132354d7-df7a-4e03-9d00-16d54f836a1b\": {\n\t\t\t\"path\": \"client/src/Routes/index.jsx-simstep-132354d7-df7a-4e03-9d00-16d54f836a1b\",\n\t\t\t\"fileName\": \"index.jsx\",\n\t\t\t\"wiki\": \"A user accesses a status page URL (e.g., /status/uptime/my-awesome-service). The React router matches the path and renders the `Status` component, which is responsible for fetching and displaying the page details.\",\n\t\t\t\"cellName\": \"View Status Page: User Navigates to URL - index.jsx:L148-152\",\n\t\t\t\"cellId\": \"30aaee38-f509-4e19-a917-e6d2f4bba61c\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 148,\n\t\t\t\"endLine\": 152,\n\t\t\t\"parentCellId\": \"c4d7e7dd-75b1-44f1-a34a-6ed290a8e562\",\n\t\t\t\"parentPath\": \"client/src/Routes/index.jsx\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Customizable Public and Private Status Pages\",\n\t\t\t\t\t\"simStepId\": \"132354d7-df7a-4e03-9d00-16d54f836a1b\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"ecfb2d04-2681-4f16-af75-632f69e1a868\": {\n\t\t\t\"path\": \"ecfb2d04-2681-4f16-af75-632f69e1a868\",\n\t\t\t\"cellName\": \"View Status Page: Client Hook Sends API Request - useStatusPageFetch.jsx:L15-18\",\n\t\t\t\"cellId\": \"ecfb2d04-2681-4f16-af75-632f69e1a868\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"5b2cdab8-66f1-40a1-9621-0efaf54e04ae\"\n\t\t},\n\t\t\"client/src/Pages/v1/StatusPage/Status/Hooks/useStatusPageFetch.jsx-simstep-b57bb249-9066-454e-aa8c-89108fdfcc2e\": {\n\t\t\t\"path\": \"client/src/Pages/v1/StatusPage/Status/Hooks/useStatusPageFetch.jsx-simstep-b57bb249-9066-454e-aa8c-89108fdfcc2e\",\n\t\t\t\"fileName\": \"useStatusPageFetch.jsx\",\n\t\t\t\"wiki\": \"The `useStatusPageFetch` hook uses the `networkService` to send a GET request to the backend API to retrieve the status page data based on its URL.\",\n\t\t\t\"cellName\": \"View Status Page: Client Hook Sends API Request - useStatusPageFetch.jsx:L15-18\",\n\t\t\t\"cellId\": \"ecfb2d04-2681-4f16-af75-632f69e1a868\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 15,\n\t\t\t\"endLine\": 18,\n\t\t\t\"parentCellId\": \"5b2cdab8-66f1-40a1-9621-0efaf54e04ae\",\n\t\t\t\"parentPath\": \"client/src/Pages/v1/StatusPage/Status/Hooks/useStatusPageFetch.jsx\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Customizable Public and Private Status Pages\",\n\t\t\t\t\t\"simStepId\": \"b57bb249-9066-454e-aa8c-89108fdfcc2e\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"2e26cd2f-1413-4c16-8e63-ea7808ab6c52\": {\n\t\t\t\"path\": \"2e26cd2f-1413-4c16-8e63-ea7808ab6c52\",\n\t\t\t\"cellName\": \"View Status Page: Backend Route Handling - statusPageRoute.js:L16\",\n\t\t\t\"cellId\": \"2e26cd2f-1413-4c16-8e63-ea7808ab6c52\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"773e1065-b0a5-46a9-b0cc-6b963f69f5cc\"\n\t\t},\n\t\t\"server/src/routes/v1/statusPageRoute.js-simstep-477c6821-b29b-4b38-8930-ced21b8a75e5\": {\n\t\t\t\"path\": \"server/src/routes/v1/statusPageRoute.js-simstep-477c6821-b29b-4b38-8930-ced21b8a75e5\",\n\t\t\t\"fileName\": \"statusPageRoute.js\",\n\t\t\t\"wiki\": \"The backend router receives the GET request on `/api/v1/status-page/:url` and forwards it to the `getStatusPageByUrl` method in the `StatusPageController`.\",\n\t\t\t\"cellName\": \"View Status Page: Backend Route Handling - statusPageRoute.js:L16\",\n\t\t\t\"cellId\": \"2e26cd2f-1413-4c16-8e63-ea7808ab6c52\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 16,\n\t\t\t\"endLine\": 16,\n\t\t\t\"parentCellId\": \"773e1065-b0a5-46a9-b0cc-6b963f69f5cc\",\n\t\t\t\"parentPath\": \"server/src/routes/v1/statusPageRoute.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Customizable Public and Private Status Pages\",\n\t\t\t\t\t\"simStepId\": \"477c6821-b29b-4b38-8930-ced21b8a75e5\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"9f217674-4cd7-4ef8-b088-d5620042a7ba\": {\n\t\t\t\"path\": \"9f217674-4cd7-4ef8-b088-d5620042a7ba\",\n\t\t\t\"cellName\": \"View Status Page: Controller Logic - statusPageController.js:L75-78\",\n\t\t\t\"cellId\": \"9f217674-4cd7-4ef8-b088-d5620042a7ba\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"17a4f435-5a8e-4433-84a6-9ac17362709a\"\n\t\t},\n\t\t\"server/src/controllers/v1/statusPageController.js-simstep-5bdbd179-ce8f-4171-a073-af72a99b4468\": {\n\t\t\t\"path\": \"server/src/controllers/v1/statusPageController.js-simstep-5bdbd179-ce8f-4171-a073-af72a99b4468\",\n\t\t\t\"fileName\": \"statusPageController.js\",\n\t\t\t\"wiki\": \"The `StatusPageController` validates the request parameters and calls the `statusPageModule` to retrieve the status page data from the database.\",\n\t\t\t\"cellName\": \"View Status Page: Controller Logic - statusPageController.js:L75-78\",\n\t\t\t\"cellId\": \"9f217674-4cd7-4ef8-b088-d5620042a7ba\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 75,\n\t\t\t\"endLine\": 78,\n\t\t\t\"parentCellId\": \"17a4f435-5a8e-4433-84a6-9ac17362709a\",\n\t\t\t\"parentPath\": \"server/src/controllers/v1/statusPageController.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Customizable Public and Private Status Pages\",\n\t\t\t\t\t\"simStepId\": \"5bdbd179-ce8f-4171-a073-af72a99b4468\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"26da60f9-dde4-44ec-be89-91858cc14f90\": {\n\t\t\t\"path\": \"26da60f9-dde4-44ec-be89-91858cc14f90\",\n\t\t\t\"cellName\": \"View Status Page: Database Record Retrieval - statusPageModule.js:L89-299\",\n\t\t\t\"cellId\": \"26da60f9-dde4-44ec-be89-91858cc14f90\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"f8541fe3-4bcf-4833-a226-66b5301adf58\"\n\t\t},\n\t\t\"server/src/db/v1/modules/statusPageModule.js-simstep-ceb044e9-6545-4d04-bf79-ec8146eb8ec9\": {\n\t\t\t\"path\": \"server/src/db/v1/modules/statusPageModule.js-simstep-ceb044e9-6545-4d04-bf79-ec8146eb8ec9\",\n\t\t\t\"fileName\": \"statusPageModule.js\",\n\t\t\t\"wiki\": \"The `StatusPageModule` executes a complex MongoDB aggregation pipeline to find the status page by its URL, and then look up and join data for all associated monitors and their recent checks.\",\n\t\t\t\"cellName\": \"View Status Page: Database Record Retrieval - statusPageModule.js:L89-299\",\n\t\t\t\"cellId\": \"26da60f9-dde4-44ec-be89-91858cc14f90\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 89,\n\t\t\t\"endLine\": 299,\n\t\t\t\"parentCellId\": \"f8541fe3-4bcf-4833-a226-66b5301adf58\",\n\t\t\t\"parentPath\": \"server/src/db/v1/modules/statusPageModule.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Customizable Public and Private Status Pages\",\n\t\t\t\t\t\"simStepId\": \"ceb044e9-6545-4d04-bf79-ec8146eb8ec9\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"d76e70e0-41f9-46cc-b775-b2027c5a0d5b\": {\n\t\t\t\"path\": \"d76e70e0-41f9-46cc-b775-b2027c5a0d5b\",\n\t\t\t\"cellName\": \"View Status Page: Controller Sends Success Response - statusPageController.js:L79-82\",\n\t\t\t\"cellId\": \"d76e70e0-41f9-46cc-b775-b2027c5a0d5b\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"17a4f435-5a8e-4433-84a6-9ac17362709a\"\n\t\t},\n\t\t\"server/src/controllers/v1/statusPageController.js-simstep-83224406-2f1d-4030-9beb-d65c2baf544d\": {\n\t\t\t\"path\": \"server/src/controllers/v1/statusPageController.js-simstep-83224406-2f1d-4030-9beb-d65c2baf544d\",\n\t\t\t\"fileName\": \"statusPageController.js\",\n\t\t\t\"wiki\": \"The controller receives the status page data and sends a successful JSON response back to the client.\",\n\t\t\t\"cellName\": \"View Status Page: Controller Sends Success Response - statusPageController.js:L79-82\",\n\t\t\t\"cellId\": \"d76e70e0-41f9-46cc-b775-b2027c5a0d5b\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 79,\n\t\t\t\"endLine\": 82,\n\t\t\t\"parentCellId\": \"17a4f435-5a8e-4433-84a6-9ac17362709a\",\n\t\t\t\"parentPath\": \"server/src/controllers/v1/statusPageController.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Customizable Public and Private Status Pages\",\n\t\t\t\t\t\"simStepId\": \"83224406-2f1d-4030-9beb-d65c2baf544d\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"f59b91de-5196-4a43-9d57-3f28402c0672\": {\n\t\t\t\"path\": \"f59b91de-5196-4a43-9d57-3f28402c0672\",\n\t\t\t\"cellName\": \"View Status Page: Component Renders UI - index.jsx:L145-163\",\n\t\t\t\"cellId\": \"f59b91de-5196-4a43-9d57-3f28402c0672\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"e1e6f5e0-fd8c-4260-aa4f-cdb096c6b1c3\"\n\t\t},\n\t\t\"client/src/Pages/v1/StatusPage/Status/index.jsx-simstep-3d51e811-a659-442e-97e0-00798cd15647\": {\n\t\t\t\"path\": \"client/src/Pages/v1/StatusPage/Status/index.jsx-simstep-3d51e811-a659-442e-97e0-00798cd15647\",\n\t\t\t\"fileName\": \"index.jsx\",\n\t\t\t\"wiki\": \"The `Status` component re-renders with the fetched data. It displays the company name, logo, overall status bar, and a list of monitors with their individual status and historical uptime charts.\",\n\t\t\t\"cellName\": \"View Status Page: Component Renders UI - index.jsx:L145-163\",\n\t\t\t\"cellId\": \"f59b91de-5196-4a43-9d57-3f28402c0672\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 145,\n\t\t\t\"endLine\": 163,\n\t\t\t\"parentCellId\": \"e1e6f5e0-fd8c-4260-aa4f-cdb096c6b1c3\",\n\t\t\t\"parentPath\": \"client/src/Pages/v1/StatusPage/Status/index.jsx\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Customizable Public and Private Status Pages\",\n\t\t\t\t\t\"simStepId\": \"3d51e811-a659-442e-97e0-00798cd15647\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"de23eee2-b60a-4236-a890-3c5b78388bb3\": {\n\t\t\t\"path\": \"de23eee2-b60a-4236-a890-3c5b78388bb3\",\n\t\t\t\"cellName\": \"Create Status\\nPage: Form\\nSubmission\",\n\t\t\t\"cellId\": \"de23eee2-b60a-4236-a890-3c5b78388bb3\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"08602a28-f073-484e-9403-7eb798126dd4\"\n\t\t},\n\t\t\"generated-edge-simstep-d419f7b6-7b9b-4494-9fad-83e3ce208ca4-de23eee2-b60a-4236-a890-3c5b78388bb3\": {\n\t\t\t\"path\": \"generated-edge-simstep-d419f7b6-7b9b-4494-9fad-83e3ce208ca4-de23eee2-b60a-4236-a890-3c5b78388bb3\",\n\t\t\t\"fileName\": \"index.jsx\",\n\t\t\t\"cellName\": \"Create Status Page: Form Submission\",\n\t\t\t\"cellId\": \"de23eee2-b60a-4236-a890-3c5b78388bb3\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 143,\n\t\t\t\"endLine\": 159,\n\t\t\t\"parentPath\": \"client/src/Pages/v1/StatusPage/Create/index.jsx\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Customizable Public and Private Status Pages\",\n\t\t\t\t\t\"simStepId\": \"d419f7b6-7b9b-4494-9fad-83e3ce208ca4\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"d7faa713-4204-4a97-a172-d621da36c287\": {\n\t\t\t\"path\": \"d7faa713-4204-4a97-a172-d621da36c287\",\n\t\t\t\"cellName\": \"Create Status\\nPage: API\\nCall to\\nBackend\",\n\t\t\t\"cellId\": \"d7faa713-4204-4a97-a172-d621da36c287\",\n\t\t\t\"visible\": true\n\t\t},\n\t\t\"generated-edge-simstep-8a2ab372-73db-4b9f-bc0e-6a20f15a4d79-d7faa713-4204-4a97-a172-d621da36c287\": {\n\t\t\t\"path\": \"generated-edge-simstep-8a2ab372-73db-4b9f-bc0e-6a20f15a4d79-d7faa713-4204-4a97-a172-d621da36c287\",\n\t\t\t\"fileName\": \"useCreateStatusPage.jsx\",\n\t\t\t\"cellName\": \"Create Status Page: API Call to Backend\",\n\t\t\t\"cellId\": \"d7faa713-4204-4a97-a172-d621da36c287\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 912,\n\t\t\t\"endLine\": 944,\n\t\t\t\"parentPath\": \"client/src/Pages/v1/StatusPage/Create/Hooks/useCreateStatusPage.jsx\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Customizable Public and Private Status Pages\",\n\t\t\t\t\t\"simStepId\": \"8a2ab372-73db-4b9f-bc0e-6a20f15a4d79\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"a3f28fa6-8268-4c13-95a0-83e3b1abdcb0\": {\n\t\t\t\"path\": \"a3f28fa6-8268-4c13-95a0-83e3b1abdcb0\",\n\t\t\t\"cellName\": \"Create Status\\nPage: Data\\nPassed to\\nController\",\n\t\t\t\"cellId\": \"a3f28fa6-8268-4c13-95a0-83e3b1abdcb0\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\"\n\t\t},\n\t\t\"generated-edge-simstep-0923a533-c572-4da3-ad87-cdfff111f3bb-a3f28fa6-8268-4c13-95a0-83e3b1abdcb0\": {\n\t\t\t\"path\": \"generated-edge-simstep-0923a533-c572-4da3-ad87-cdfff111f3bb-a3f28fa6-8268-4c13-95a0-83e3b1abdcb0\",\n\t\t\t\"fileName\": \"statusPageRoute.js\",\n\t\t\t\"cellName\": \"Create Status Page: Data Passed to Controller\",\n\t\t\t\"cellId\": \"a3f28fa6-8268-4c13-95a0-83e3b1abdcb0\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 14,\n\t\t\t\"endLine\": 14,\n\t\t\t\"parentPath\": \"server/src/routes/v1/statusPageRoute.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Customizable Public and Private Status Pages\",\n\t\t\t\t\t\"simStepId\": \"0923a533-c572-4da3-ad87-cdfff111f3bb\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"9735611c-924b-49aa-92e8-10d8a86ac288\": {\n\t\t\t\"path\": \"9735611c-924b-49aa-92e8-10d8a86ac288\",\n\t\t\t\"cellName\": \"Create Status\\nPage: Data\\nSent to\\nDB Module\",\n\t\t\t\"cellId\": \"9735611c-924b-49aa-92e8-10d8a86ac288\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\"\n\t\t},\n\t\t\"generated-edge-simstep-67603f03-c088-4ed0-9f18-072435134cdd-9735611c-924b-49aa-92e8-10d8a86ac288\": {\n\t\t\t\"path\": \"generated-edge-simstep-67603f03-c088-4ed0-9f18-072435134cdd-9735611c-924b-49aa-92e8-10d8a86ac288\",\n\t\t\t\"fileName\": \"statusPageController.js\",\n\t\t\t\"cellName\": \"Create Status Page: Data Sent to DB Module\",\n\t\t\t\"cellId\": \"9735611c-924b-49aa-92e8-10d8a86ac288\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 21,\n\t\t\t\"endLine\": 21,\n\t\t\t\"parentPath\": \"server/src/controllers/v1/statusPageController.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Customizable Public and Private Status Pages\",\n\t\t\t\t\t\"simStepId\": \"67603f03-c088-4ed0-9f18-072435134cdd\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"40cb7d7b-2888-44de-bb7d-7735af70ba34\": {\n\t\t\t\"path\": \"40cb7d7b-2888-44de-bb7d-7735af70ba34\",\n\t\t\t\"cellName\": \"Create Status\\nPage: Database\\nResult Returned\",\n\t\t\t\"cellId\": \"40cb7d7b-2888-44de-bb7d-7735af70ba34\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\"\n\t\t},\n\t\t\"generated-edge-simstep-ea4b3532-baae-4890-a73e-2ca385d0319e-40cb7d7b-2888-44de-bb7d-7735af70ba34\": {\n\t\t\t\"path\": \"generated-edge-simstep-ea4b3532-baae-4890-a73e-2ca385d0319e-40cb7d7b-2888-44de-bb7d-7735af70ba34\",\n\t\t\t\"fileName\": \"statusPageModule.js\",\n\t\t\t\"cellName\": \"Create Status Page: Database Result Returned\",\n\t\t\t\"cellId\": \"40cb7d7b-2888-44de-bb7d-7735af70ba34\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 27,\n\t\t\t\"endLine\": 27,\n\t\t\t\"parentPath\": \"server/src/db/v1/modules/statusPageModule.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Customizable Public and Private Status Pages\",\n\t\t\t\t\t\"simStepId\": \"ea4b3532-baae-4890-a73e-2ca385d0319e\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"c3f83811-8674-4dbb-9f84-79499f97fb1f\": {\n\t\t\t\"path\": \"c3f83811-8674-4dbb-9f84-79499f97fb1f\",\n\t\t\t\"cellName\": \"Create Status\\nPage: UI\\nReceives Response\\nand Redirects\",\n\t\t\t\"cellId\": \"c3f83811-8674-4dbb-9f84-79499f97fb1f\",\n\t\t\t\"visible\": true\n\t\t},\n\t\t\"generated-edge-simstep-210acc07-81c3-4394-b566-41f6031e8eeb-c3f83811-8674-4dbb-9f84-79499f97fb1f\": {\n\t\t\t\"path\": \"generated-edge-simstep-210acc07-81c3-4394-b566-41f6031e8eeb-c3f83811-8674-4dbb-9f84-79499f97fb1f\",\n\t\t\t\"fileName\": \"statusPageController.js\",\n\t\t\t\"cellName\": \"Create Status Page: UI Receives Response and Redirects\",\n\t\t\t\"cellId\": \"c3f83811-8674-4dbb-9f84-79499f97fb1f\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 151,\n\t\t\t\"endLine\": 156,\n\t\t\t\"parentPath\": \"server/src/controllers/v1/statusPageController.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Customizable Public and Private Status Pages\",\n\t\t\t\t\t\"simStepId\": \"210acc07-81c3-4394-b566-41f6031e8eeb\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"0575bf87-5362-4988-b895-7e514148d420\": {\n\t\t\t\"path\": \"0575bf87-5362-4988-b895-7e514148d420\",\n\t\t\t\"cellName\": \"View Status\\nPage: Component\\nTriggers Data\\nFetch\",\n\t\t\t\"cellId\": \"0575bf87-5362-4988-b895-7e514148d420\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"d3264577-10f0-42fe-9411-7e9df0754d1e\"\n\t\t},\n\t\t\"generated-edge-simstep-2ba49e28-1cac-47f5-9118-ab930788736a-0575bf87-5362-4988-b895-7e514148d420\": {\n\t\t\t\"path\": \"generated-edge-simstep-2ba49e28-1cac-47f5-9118-ab930788736a-0575bf87-5362-4988-b895-7e514148d420\",\n\t\t\t\"fileName\": \"index.jsx\",\n\t\t\t\"cellName\": \"View Status Page: Component Triggers Data Fetch\",\n\t\t\t\"cellId\": \"0575bf87-5362-4988-b895-7e514148d420\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 29,\n\t\t\t\"endLine\": 29,\n\t\t\t\"parentPath\": \"client/src/Routes/index.jsx\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Customizable Public and Private Status Pages\",\n\t\t\t\t\t\"simStepId\": \"2ba49e28-1cac-47f5-9118-ab930788736a\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"ae1c9341-0e39-4d91-a9ac-5cc8a627c247\": {\n\t\t\t\"path\": \"ae1c9341-0e39-4d91-a9ac-5cc8a627c247\",\n\t\t\t\"cellName\": \"View Status\\nPage: API\\nCall to\\nBackend\",\n\t\t\t\"cellId\": \"ae1c9341-0e39-4d91-a9ac-5cc8a627c247\",\n\t\t\t\"visible\": true\n\t\t},\n\t\t\"generated-edge-simstep-de0714d2-bf1e-4a1a-a389-60793de8b772-ae1c9341-0e39-4d91-a9ac-5cc8a627c247\": {\n\t\t\t\"path\": \"generated-edge-simstep-de0714d2-bf1e-4a1a-a389-60793de8b772-ae1c9341-0e39-4d91-a9ac-5cc8a627c247\",\n\t\t\t\"fileName\": \"useStatusPageFetch.jsx\",\n\t\t\t\"cellName\": \"View Status Page: API Call to Backend\",\n\t\t\t\"cellId\": \"ae1c9341-0e39-4d91-a9ac-5cc8a627c247\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 896,\n\t\t\t\"endLine\": 902,\n\t\t\t\"parentPath\": \"client/src/Pages/v1/StatusPage/Status/Hooks/useStatusPageFetch.jsx\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Customizable Public and Private Status Pages\",\n\t\t\t\t\t\"simStepId\": \"de0714d2-bf1e-4a1a-a389-60793de8b772\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"5735f30c-b55f-444a-9236-f3d75f68ed27\": {\n\t\t\t\"path\": \"5735f30c-b55f-444a-9236-f3d75f68ed27\",\n\t\t\t\"cellName\": \"View Status\\nPage: Data\\nPassed to\\nController\",\n\t\t\t\"cellId\": \"5735f30c-b55f-444a-9236-f3d75f68ed27\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\"\n\t\t},\n\t\t\"generated-edge-simstep-b79b8922-4de6-477d-8648-37b4bd9a6767-5735f30c-b55f-444a-9236-f3d75f68ed27\": {\n\t\t\t\"path\": \"generated-edge-simstep-b79b8922-4de6-477d-8648-37b4bd9a6767-5735f30c-b55f-444a-9236-f3d75f68ed27\",\n\t\t\t\"fileName\": \"statusPageRoute.js\",\n\t\t\t\"cellName\": \"View Status Page: Data Passed to Controller\",\n\t\t\t\"cellId\": \"5735f30c-b55f-444a-9236-f3d75f68ed27\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 16,\n\t\t\t\"endLine\": 16,\n\t\t\t\"parentPath\": \"server/src/routes/v1/statusPageRoute.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Customizable Public and Private Status Pages\",\n\t\t\t\t\t\"simStepId\": \"b79b8922-4de6-477d-8648-37b4bd9a6767\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"dace45d6-fb25-4dae-b940-49ef7d77bbed\": {\n\t\t\t\"path\": \"dace45d6-fb25-4dae-b940-49ef7d77bbed\",\n\t\t\t\"cellName\": \"View Status\\nPage: URL\\nSent to\\nDB Module\",\n\t\t\t\"cellId\": \"dace45d6-fb25-4dae-b940-49ef7d77bbed\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\"\n\t\t},\n\t\t\"generated-edge-simstep-788307ef-4cfa-4f5a-b2e9-a0bfc7a378d8-dace45d6-fb25-4dae-b940-49ef7d77bbed\": {\n\t\t\t\"path\": \"generated-edge-simstep-788307ef-4cfa-4f5a-b2e9-a0bfc7a378d8-dace45d6-fb25-4dae-b940-49ef7d77bbed\",\n\t\t\t\"fileName\": \"statusPageController.js\",\n\t\t\t\"cellName\": \"View Status Page: URL Sent to DB Module\",\n\t\t\t\"cellId\": \"dace45d6-fb25-4dae-b940-49ef7d77bbed\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 78,\n\t\t\t\"endLine\": 78,\n\t\t\t\"parentPath\": \"server/src/controllers/v1/statusPageController.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Customizable Public and Private Status Pages\",\n\t\t\t\t\t\"simStepId\": \"788307ef-4cfa-4f5a-b2e9-a0bfc7a378d8\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"137a5ab7-1e49-42ec-869d-58f7f2380cb3\": {\n\t\t\t\"path\": \"137a5ab7-1e49-42ec-869d-58f7f2380cb3\",\n\t\t\t\"cellName\": \"View Status\\nPage: Database\\nResult Returned\",\n\t\t\t\"cellId\": \"137a5ab7-1e49-42ec-869d-58f7f2380cb3\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\"\n\t\t},\n\t\t\"generated-edge-simstep-4d3fad92-8fa9-4a8f-be3b-f09eda2f8dd4-137a5ab7-1e49-42ec-869d-58f7f2380cb3\": {\n\t\t\t\"path\": \"generated-edge-simstep-4d3fad92-8fa9-4a8f-be3b-f09eda2f8dd4-137a5ab7-1e49-42ec-869d-58f7f2380cb3\",\n\t\t\t\"fileName\": \"statusPageModule.js\",\n\t\t\t\"cellName\": \"View Status Page: Database Result Returned\",\n\t\t\t\"cellId\": \"137a5ab7-1e49-42ec-869d-58f7f2380cb3\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 291,\n\t\t\t\"endLine\": 291,\n\t\t\t\"parentPath\": \"server/src/db/v1/modules/statusPageModule.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Customizable Public and Private Status Pages\",\n\t\t\t\t\t\"simStepId\": \"4d3fad92-8fa9-4a8f-be3b-f09eda2f8dd4\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"04a33e4f-1dfe-4c5a-8b30-01ed0591c380\": {\n\t\t\t\"path\": \"04a33e4f-1dfe-4c5a-8b30-01ed0591c380\",\n\t\t\t\"cellName\": \"View Status\\nPage: UI\\nReceives Data\",\n\t\t\t\"cellId\": \"04a33e4f-1dfe-4c5a-8b30-01ed0591c380\",\n\t\t\t\"visible\": true\n\t\t},\n\t\t\"generated-edge-simstep-d5f3c300-9777-4e09-bb05-f1281c2ff29a-04a33e4f-1dfe-4c5a-8b30-01ed0591c380\": {\n\t\t\t\"path\": \"generated-edge-simstep-d5f3c300-9777-4e09-bb05-f1281c2ff29a-04a33e4f-1dfe-4c5a-8b30-01ed0591c380\",\n\t\t\t\"fileName\": \"statusPageController.js\",\n\t\t\t\"cellName\": \"View Status Page: UI Receives Data\",\n\t\t\t\"cellId\": \"04a33e4f-1dfe-4c5a-8b30-01ed0591c380\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 20,\n\t\t\t\"endLine\": 26,\n\t\t\t\"parentPath\": \"server/src/controllers/v1/statusPageController.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Customizable Public and Private Status Pages\",\n\t\t\t\t\t\"simStepId\": \"d5f3c300-9777-4e09-bb05-f1281c2ff29a\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"933a6cdc-349c-4725-b7ae-14cf780bfde8\": {\n\t\t\t\"path\": \"933a6cdc-349c-4725-b7ae-14cf780bfde8\",\n\t\t\t\"cellName\": \"checkHooks.js\",\n\t\t\t\"cellId\": \"933a6cdc-349c-4725-b7ae-14cf780bfde8\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"3bf0c0f9-cbb0-4f0c-8cb3-6e2a4abc0961\"\n\t\t},\n\t\t\"d18dbe1d-2f2c-4336-bd21-47c1670f7bab\": {\n\t\t\t\"path\": \"d18dbe1d-2f2c-4336-bd21-47c1670f7bab\",\n\t\t\t\"cellName\": \"checkRoute.js\",\n\t\t\t\"cellId\": \"d18dbe1d-2f2c-4336-bd21-47c1670f7bab\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"d3375a20-2776-4771-b806-649bbeb541bd\"\n\t\t},\n\t\t\"d983e54f-2fbe-496a-932d-a827e1124804\": {\n\t\t\t\"path\": \"d983e54f-2fbe-496a-932d-a827e1124804\",\n\t\t\t\"cellName\": \"checkController.js\",\n\t\t\t\"cellId\": \"d983e54f-2fbe-496a-932d-a827e1124804\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"fc591f7a-d4ac-4565-949d-a87a58a79bbc\"\n\t\t},\n\t\t\"273f3009-69d0-46fe-af57-3cd94a24b55b\": {\n\t\t\t\"path\": \"273f3009-69d0-46fe-af57-3cd94a24b55b\",\n\t\t\t\"cellName\": \"Details\",\n\t\t\t\"cellId\": \"273f3009-69d0-46fe-af57-3cd94a24b55b\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"7090fcdb-09be-4c85-86fd-e73553bbb2ff\"\n\t\t},\n\t\t\"f90db867-e1e7-4554-b446-fa78fc6a8578\": {\n\t\t\t\"path\": \"f90db867-e1e7-4554-b446-fa78fc6a8578\",\n\t\t\t\"cellName\": \"checkService.js\",\n\t\t\t\"cellId\": \"f90db867-e1e7-4554-b446-fa78fc6a8578\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"87d3b101-9443-4ed4-9c4f-f759d41677eb\"\n\t\t},\n\t\t\"860b5eec-a1ce-4e1f-a316-e1586f03af96\": {\n\t\t\t\"path\": \"860b5eec-a1ce-4e1f-a316-e1586f03af96\",\n\t\t\t\"cellName\": \"checkModule.js\",\n\t\t\t\"cellId\": \"860b5eec-a1ce-4e1f-a316-e1586f03af96\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"82cb3dbe-c922-438a-a912-255376f4b380\"\n\t\t},\n\t\t\"1807d5b9-54be-430b-8997-cada4dd9b521\": {\n\t\t\t\"path\": \"1807d5b9-54be-430b-8997-cada4dd9b521\",\n\t\t\t\"cellName\": \"index.jsx\",\n\t\t\t\"cellId\": \"1807d5b9-54be-430b-8997-cada4dd9b521\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"273f3009-69d0-46fe-af57-3cd94a24b55b\"\n\t\t},\n\t\t\"6aed78bb-62f1-4ac1-9b9a-9d5977e87404\": {\n\t\t\t\"path\": \"6aed78bb-62f1-4ac1-9b9a-9d5977e87404\",\n\t\t\t\"cellName\": \"Components\",\n\t\t\t\"cellId\": \"6aed78bb-62f1-4ac1-9b9a-9d5977e87404\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"273f3009-69d0-46fe-af57-3cd94a24b55b\"\n\t\t},\n\t\t\"5ac0878f-d238-4763-8464-a85b4885a40f\": {\n\t\t\t\"path\": \"5ac0878f-d238-4763-8464-a85b4885a40f\",\n\t\t\t\"cellName\": \"ResponseTable\",\n\t\t\t\"cellId\": \"5ac0878f-d238-4763-8464-a85b4885a40f\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"6aed78bb-62f1-4ac1-9b9a-9d5977e87404\"\n\t\t},\n\t\t\"d3f74ac7-3b9a-4cae-8d77-a0d5d605bb27\": {\n\t\t\t\"path\": \"d3f74ac7-3b9a-4cae-8d77-a0d5d605bb27\",\n\t\t\t\"cellName\": \"index.jsx\",\n\t\t\t\"cellId\": \"d3f74ac7-3b9a-4cae-8d77-a0d5d605bb27\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"5ac0878f-d238-4763-8464-a85b4885a40f\"\n\t\t},\n\t\t\"78a8a7c5-41d3-4453-a7f7-ac632bbef288\": {\n\t\t\t\"path\": \"78a8a7c5-41d3-4453-a7f7-ac632bbef288\",\n\t\t\t\"cellName\": \"Navigate to Monitor Details - index.jsx:L27-188\",\n\t\t\t\"cellId\": \"78a8a7c5-41d3-4453-a7f7-ac632bbef288\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"1807d5b9-54be-430b-8997-cada4dd9b521\"\n\t\t},\n\t\t\"client/src/Pages/v1/Uptime/Details/index.jsx-simstep-35195328-9847-4678-b014-9331553f0d19\": {\n\t\t\t\"path\": \"client/src/Pages/v1/Uptime/Details/index.jsx-simstep-35195328-9847-4678-b014-9331553f0d19\",\n\t\t\t\"fileName\": \"index.jsx\",\n\t\t\t\"wiki\": \"The user navigates to the details page for a specific uptime monitor. The `UptimeDetails` component mounts and initializes its state and hooks.\",\n\t\t\t\"cellName\": \"Navigate to Monitor Details - index.jsx:L27-188\",\n\t\t\t\"cellId\": \"78a8a7c5-41d3-4453-a7f7-ac632bbef288\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 27,\n\t\t\t\"endLine\": 188,\n\t\t\t\"parentCellId\": \"1807d5b9-54be-430b-8997-cada4dd9b521\",\n\t\t\t\"parentPath\": \"client/src/Pages/v1/Uptime/Details/index.jsx\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Incident History, Analysis, and Management\",\n\t\t\t\t\t\"simStepId\": \"35195328-9847-4678-b014-9331553f0d19\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"4a5847d0-91a0-4b4c-8517-2f4ff9a7e8d4\": {\n\t\t\t\"path\": \"4a5847d0-91a0-4b4c-8517-2f4ff9a7e8d4\",\n\t\t\t\"cellName\": \"Fetch Monitor Checks Hook - checkHooks.js:L89-121\",\n\t\t\t\"cellId\": \"4a5847d0-91a0-4b4c-8517-2f4ff9a7e8d4\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"933a6cdc-349c-4725-b7ae-14cf780bfde8\"\n\t\t},\n\t\t\"client/src/Hooks/v1/checkHooks.js-simstep-8dc4347c-3e9e-40d7-ae6f-54684f2e6956\": {\n\t\t\t\"path\": \"client/src/Hooks/v1/checkHooks.js-simstep-8dc4347c-3e9e-40d7-ae6f-54684f2e6956\",\n\t\t\t\"fileName\": \"checkHooks.js\",\n\t\t\t\"wiki\": \"The `useFetchChecksByMonitor` custom hook executes. It sets the loading state and prepares to call the network service to fetch the data from the backend API.\",\n\t\t\t\"cellName\": \"Fetch Monitor Checks Hook - checkHooks.js:L89-121\",\n\t\t\t\"cellId\": \"4a5847d0-91a0-4b4c-8517-2f4ff9a7e8d4\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 89,\n\t\t\t\"endLine\": 121,\n\t\t\t\"parentCellId\": \"933a6cdc-349c-4725-b7ae-14cf780bfde8\",\n\t\t\t\"parentPath\": \"client/src/Hooks/v1/checkHooks.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Incident History, Analysis, and Management\",\n\t\t\t\t\t\"simStepId\": \"8dc4347c-3e9e-40d7-ae6f-54684f2e6956\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"cdd090be-0b62-45b4-baa0-fec01fc3ffd1\": {\n\t\t\t\"path\": \"cdd090be-0b62-45b4-baa0-fec01fc3ffd1\",\n\t\t\t\"cellName\": \"Route Request to Controller - checkRoute.js:L19\",\n\t\t\t\"cellId\": \"cdd090be-0b62-45b4-baa0-fec01fc3ffd1\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"d18dbe1d-2f2c-4336-bd21-47c1670f7bab\"\n\t\t},\n\t\t\"server/src/routes/v1/checkRoute.js-simstep-c5fd192f-ea28-48a0-b3e7-5bc04f521192\": {\n\t\t\t\"path\": \"server/src/routes/v1/checkRoute.js-simstep-c5fd192f-ea28-48a0-b3e7-5bc04f521192\",\n\t\t\t\"fileName\": \"checkRoute.js\",\n\t\t\t\"wiki\": \"The backend Express router receives the incoming GET request and matches it to the appropriate route, forwarding the request to the `getChecksByMonitor` method in the `CheckController`.\",\n\t\t\t\"cellName\": \"Route Request to Controller - checkRoute.js:L19\",\n\t\t\t\"cellId\": \"cdd090be-0b62-45b4-baa0-fec01fc3ffd1\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 19,\n\t\t\t\"endLine\": 19,\n\t\t\t\"parentCellId\": \"d18dbe1d-2f2c-4336-bd21-47c1670f7bab\",\n\t\t\t\"parentPath\": \"server/src/routes/v1/checkRoute.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Incident History, Analysis, and Management\",\n\t\t\t\t\t\"simStepId\": \"c5fd192f-ea28-48a0-b3e7-5bc04f521192\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"499b46a2-f2a2-4ccd-aecd-012eade2bd23\": {\n\t\t\t\"path\": \"499b46a2-f2a2-4ccd-aecd-012eade2bd23\",\n\t\t\t\"cellName\": \"Fetch Checks from Database - checkService.js:L36-45\",\n\t\t\t\"cellId\": \"499b46a2-f2a2-4ccd-aecd-012eade2bd23\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"f90db867-e1e7-4554-b446-fa78fc6a8578\"\n\t\t},\n\t\t\"server/src/service/v1/business/checkService.js-simstep-83fea05d-8306-4a73-a43f-882cdd14f50f\": {\n\t\t\t\"path\": \"server/src/service/v1/business/checkService.js-simstep-83fea05d-8306-4a73-a43f-882cdd14f50f\",\n\t\t\t\"fileName\": \"checkService.js\",\n\t\t\t\"wiki\": \"The `CheckService` calls the `checkModule` to interact with the database. It passes the necessary parameters to query for the check history.\",\n\t\t\t\"cellName\": \"Fetch Checks from Database - checkService.js:L36-45\",\n\t\t\t\"cellId\": \"499b46a2-f2a2-4ccd-aecd-012eade2bd23\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 36,\n\t\t\t\"endLine\": 45,\n\t\t\t\"parentCellId\": \"f90db867-e1e7-4554-b446-fa78fc6a8578\",\n\t\t\t\"parentPath\": \"server/src/service/v1/business/checkService.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Incident History, Analysis, and Management\",\n\t\t\t\t\t\"simStepId\": \"83fea05d-8306-4a73-a43f-882cdd14f50f\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"14df9f01-1358-442d-96f5-eab9a4c4abbf\": {\n\t\t\t\"path\": \"14df9f01-1358-442d-96f5-eab9a4c4abbf\",\n\t\t\t\"cellName\": \"Return Check Data - checkController.js:L87-90\",\n\t\t\t\"cellId\": \"14df9f01-1358-442d-96f5-eab9a4c4abbf\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"d983e54f-2fbe-496a-932d-a827e1124804\"\n\t\t},\n\t\t\"server/src/controllers/v1/checkController.js-simstep-5768fdc5-045c-48ef-b0c9-79769403648f\": {\n\t\t\t\"path\": \"server/src/controllers/v1/checkController.js-simstep-5768fdc5-045c-48ef-b0c9-79769403648f\",\n\t\t\t\"fileName\": \"checkController.js\",\n\t\t\t\"wiki\": \"The database returns the query results, which flow back up through the `checkModule` and `checkService`. The `checkController` then formats a successful JSON response.\",\n\t\t\t\"cellName\": \"Return Check Data - checkController.js:L87-90\",\n\t\t\t\"cellId\": \"14df9f01-1358-442d-96f5-eab9a4c4abbf\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 87,\n\t\t\t\"endLine\": 90,\n\t\t\t\"parentCellId\": \"d983e54f-2fbe-496a-932d-a827e1124804\",\n\t\t\t\"parentPath\": \"server/src/controllers/v1/checkController.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Incident History, Analysis, and Management\",\n\t\t\t\t\t\"simStepId\": \"5768fdc5-045c-48ef-b0c9-79769403648f\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"ceb9cda3-968d-44aa-b223-49902adb93b4\": {\n\t\t\t\"path\": \"ceb9cda3-968d-44aa-b223-49902adb93b4\",\n\t\t\t\"cellName\": \"Update Frontend State - checkHooks.js:L109-110\",\n\t\t\t\"cellId\": \"ceb9cda3-968d-44aa-b223-49902adb93b4\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"933a6cdc-349c-4725-b7ae-14cf780bfde8\"\n\t\t},\n\t\t\"client/src/Hooks/v1/checkHooks.js-simstep-faba07f3-7460-47ae-924d-f92f5b2e821d\": {\n\t\t\t\"path\": \"client/src/Hooks/v1/checkHooks.js-simstep-faba07f3-7460-47ae-924d-f92f5b2e821d\",\n\t\t\t\"fileName\": \"checkHooks.js\",\n\t\t\t\"wiki\": \"The `useFetchChecksByMonitor` hook receives the data from the API call and updates the component's state with the new list of checks and the total count.\",\n\t\t\t\"cellName\": \"Update Frontend State - checkHooks.js:L109-110\",\n\t\t\t\"cellId\": \"ceb9cda3-968d-44aa-b223-49902adb93b4\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 109,\n\t\t\t\"endLine\": 110,\n\t\t\t\"parentCellId\": \"933a6cdc-349c-4725-b7ae-14cf780bfde8\",\n\t\t\t\"parentPath\": \"client/src/Hooks/v1/checkHooks.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Incident History, Analysis, and Management\",\n\t\t\t\t\t\"simStepId\": \"faba07f3-7460-47ae-924d-f92f5b2e821d\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"c996f7ca-9384-4252-b343-7bfc049d14bb\": {\n\t\t\t\"path\": \"c996f7ca-9384-4252-b343-7bfc049d14bb\",\n\t\t\t\"cellName\": \"Render Historical Data Table - index.jsx:L11-92\",\n\t\t\t\"cellId\": \"c996f7ca-9384-4252-b343-7bfc049d14bb\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"d3f74ac7-3b9a-4cae-8d77-a0d5d605bb27\"\n\t\t},\n\t\t\"client/src/Pages/v1/Uptime/Details/Components/ResponseTable/index.jsx-simstep-2b1651cd-2e70-4cc6-b2bb-23f94fa73d66\": {\n\t\t\t\"path\": \"client/src/Pages/v1/Uptime/Details/Components/ResponseTable/index.jsx-simstep-2b1651cd-2e70-4cc6-b2bb-23f94fa73d66\",\n\t\t\t\"fileName\": \"index.jsx\",\n\t\t\t\"wiki\": \"The `ResponseTable` component receives the list of checks and renders them in a data table, allowing the user to view the incident history, including status, response time, and when the check occurred.\",\n\t\t\t\"cellName\": \"Render Historical Data Table - index.jsx:L11-92\",\n\t\t\t\"cellId\": \"c996f7ca-9384-4252-b343-7bfc049d14bb\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 11,\n\t\t\t\"endLine\": 92,\n\t\t\t\"parentCellId\": \"d3f74ac7-3b9a-4cae-8d77-a0d5d605bb27\",\n\t\t\t\"parentPath\": \"client/src/Pages/v1/Uptime/Details/Components/ResponseTable/index.jsx\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Incident History, Analysis, and Management\",\n\t\t\t\t\t\"simStepId\": \"2b1651cd-2e70-4cc6-b2bb-23f94fa73d66\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"e90e4943-6108-46e3-8a2c-a9a1c7361279\": {\n\t\t\t\"path\": \"e90e4943-6108-46e3-8a2c-a9a1c7361279\",\n\t\t\t\"cellName\": \"Trigger Check\\nHistory Fetch\",\n\t\t\t\"cellId\": \"e90e4943-6108-46e3-8a2c-a9a1c7361279\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"d3264577-10f0-42fe-9411-7e9df0754d1e\"\n\t\t},\n\t\t\"generated-edge-simstep-49979250-1a32-4da5-95e0-58652fe218f9-e90e4943-6108-46e3-8a2c-a9a1c7361279\": {\n\t\t\t\"path\": \"generated-edge-simstep-49979250-1a32-4da5-95e0-58652fe218f9-e90e4943-6108-46e3-8a2c-a9a1c7361279\",\n\t\t\t\"fileName\": \"index.jsx\",\n\t\t\t\"cellName\": \"Trigger Check History Fetch\",\n\t\t\t\"cellId\": \"e90e4943-6108-46e3-8a2c-a9a1c7361279\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 69,\n\t\t\t\"endLine\": 77,\n\t\t\t\"parentPath\": \"client/src/Pages/v1/Uptime/Details/index.jsx\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Incident History, Analysis, and Management\",\n\t\t\t\t\t\"simStepId\": \"49979250-1a32-4da5-95e0-58652fe218f9\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"2b8ae59e-ed8d-4837-9a9b-64eb480f982c\": {\n\t\t\t\"path\": \"2b8ae59e-ed8d-4837-9a9b-64eb480f982c\",\n\t\t\t\"cellName\": \"API Request\\nfor Check\\nHistory\",\n\t\t\t\"cellId\": \"2b8ae59e-ed8d-4837-9a9b-64eb480f982c\",\n\t\t\t\"visible\": true\n\t\t},\n\t\t\"generated-edge-simstep-336b534d-8d6a-4639-af8e-889b38f51ab1-2b8ae59e-ed8d-4837-9a9b-64eb480f982c\": {\n\t\t\t\"path\": \"generated-edge-simstep-336b534d-8d6a-4639-af8e-889b38f51ab1-2b8ae59e-ed8d-4837-9a9b-64eb480f982c\",\n\t\t\t\"fileName\": \"checkHooks.js\",\n\t\t\t\"cellName\": \"API Request for Check History\",\n\t\t\t\"cellId\": \"2b8ae59e-ed8d-4837-9a9b-64eb480f982c\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 551,\n\t\t\t\"endLine\": 562,\n\t\t\t\"parentPath\": \"client/src/Hooks/v1/checkHooks.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Incident History, Analysis, and Management\",\n\t\t\t\t\t\"simStepId\": \"336b534d-8d6a-4639-af8e-889b38f51ab1\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"839ba9f6-8a34-4919-a04a-13fba1795c61\": {\n\t\t\t\"path\": \"839ba9f6-8a34-4919-a04a-13fba1795c61\",\n\t\t\t\"cellName\": \"Forward Request\\nto Service\\nLayer\",\n\t\t\t\"cellId\": \"839ba9f6-8a34-4919-a04a-13fba1795c61\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\"\n\t\t},\n\t\t\"generated-edge-simstep-4f73f0fe-b390-4fe1-a354-eb0857835126-839ba9f6-8a34-4919-a04a-13fba1795c61\": {\n\t\t\t\"path\": \"generated-edge-simstep-4f73f0fe-b390-4fe1-a354-eb0857835126-839ba9f6-8a34-4919-a04a-13fba1795c61\",\n\t\t\t\"fileName\": \"checkRoute.js\",\n\t\t\t\"cellName\": \"Forward Request to Service Layer\",\n\t\t\t\"cellId\": \"839ba9f6-8a34-4919-a04a-13fba1795c61\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 81,\n\t\t\t\"endLine\": 85,\n\t\t\t\"parentPath\": \"server/src/routes/v1/checkRoute.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Incident History, Analysis, and Management\",\n\t\t\t\t\t\"simStepId\": \"4f73f0fe-b390-4fe1-a354-eb0857835126\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"42d3bc70-701a-4be0-96b4-d6c2f0519b49\": {\n\t\t\t\"path\": \"42d3bc70-701a-4be0-96b4-d6c2f0519b49\",\n\t\t\t\"cellName\": \"Execute Database\\nQuery\",\n\t\t\t\"cellId\": \"42d3bc70-701a-4be0-96b4-d6c2f0519b49\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\"\n\t\t},\n\t\t\"generated-edge-simstep-65da1a9e-041c-4656-9c5b-0a92b761a9be-42d3bc70-701a-4be0-96b4-d6c2f0519b49\": {\n\t\t\t\"path\": \"generated-edge-simstep-65da1a9e-041c-4656-9c5b-0a92b761a9be-42d3bc70-701a-4be0-96b4-d6c2f0519b49\",\n\t\t\t\"fileName\": \"checkService.js\",\n\t\t\t\"cellName\": \"Execute Database Query\",\n\t\t\t\"cellId\": \"42d3bc70-701a-4be0-96b4-d6c2f0519b49\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 28,\n\t\t\t\"endLine\": 108,\n\t\t\t\"parentPath\": \"server/src/service/v1/business/checkService.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Incident History, Analysis, and Management\",\n\t\t\t\t\t\"simStepId\": \"65da1a9e-041c-4656-9c5b-0a92b761a9be\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"6c5b028c-356c-43c8-a35a-b47448cd8695\": {\n\t\t\t\"path\": \"6c5b028c-356c-43c8-a35a-b47448cd8695\",\n\t\t\t\"cellName\": \"API Response\\nwith Check\\nHistory\",\n\t\t\t\"cellId\": \"6c5b028c-356c-43c8-a35a-b47448cd8695\",\n\t\t\t\"visible\": true\n\t\t},\n\t\t\"generated-edge-simstep-2c1bdec8-d0e6-4163-a99c-f27899b987c5-6c5b028c-356c-43c8-a35a-b47448cd8695\": {\n\t\t\t\"path\": \"generated-edge-simstep-2c1bdec8-d0e6-4163-a99c-f27899b987c5-6c5b028c-356c-43c8-a35a-b47448cd8695\",\n\t\t\t\"fileName\": \"checkController.js\",\n\t\t\t\"cellName\": \"API Response with Check History\",\n\t\t\t\"cellId\": \"6c5b028c-356c-43c8-a35a-b47448cd8695\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 560,\n\t\t\t\"endLine\": 560,\n\t\t\t\"parentPath\": \"server/src/controllers/v1/checkController.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Incident History, Analysis, and Management\",\n\t\t\t\t\t\"simStepId\": \"2c1bdec8-d0e6-4163-a99c-f27899b987c5\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"74b0dd89-9fea-4219-af1f-9571316a9d5a\": {\n\t\t\t\"path\": \"74b0dd89-9fea-4219-af1f-9571316a9d5a\",\n\t\t\t\"cellName\": \"Pass Data\\nto UI\\nComponents\",\n\t\t\t\"cellId\": \"74b0dd89-9fea-4219-af1f-9571316a9d5a\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"d3264577-10f0-42fe-9411-7e9df0754d1e\"\n\t\t},\n\t\t\"generated-edge-simstep-9405dce1-0565-4dfa-9539-a048472acda9-74b0dd89-9fea-4219-af1f-9571316a9d5a\": {\n\t\t\t\"path\": \"generated-edge-simstep-9405dce1-0565-4dfa-9539-a048472acda9-74b0dd89-9fea-4219-af1f-9571316a9d5a\",\n\t\t\t\"fileName\": \"checkHooks.js\",\n\t\t\t\"cellName\": \"Pass Data to UI Components\",\n\t\t\t\"cellId\": \"74b0dd89-9fea-4219-af1f-9571316a9d5a\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 175,\n\t\t\t\"endLine\": 186,\n\t\t\t\"parentPath\": \"client/src/Hooks/v1/checkHooks.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Incident History, Analysis, and Management\",\n\t\t\t\t\t\"simStepId\": \"9405dce1-0565-4dfa-9539-a048472acda9\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"e2f99143-54b7-44dc-b566-1c2fb901bd16\": {\n\t\t\t\"path\": \"e2f99143-54b7-44dc-b566-1c2fb901bd16\",\n\t\t\t\"cellName\": \"v2\",\n\t\t\t\"cellId\": \"e2f99143-54b7-44dc-b566-1c2fb901bd16\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"15ee5d81-a0cf-4614-80b8-7a1123ab20b8\"\n\t\t},\n\t\t\"043d3dac-d4bb-449b-a3a7-270d53b66dac\": {\n\t\t\t\"path\": \"043d3dac-d4bb-449b-a3a7-270d53b66dac\",\n\t\t\t\"cellName\": \"PageSpeed\",\n\t\t\t\"cellId\": \"043d3dac-d4bb-449b-a3a7-270d53b66dac\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"1a083b4a-787c-4eb4-8029-6700de987679\"\n\t\t},\n\t\t\"7ef79284-534a-466f-a1f1-4e3a2f56be9d\": {\n\t\t\t\"path\": \"7ef79284-534a-466f-a1f1-4e3a2f56be9d\",\n\t\t\t\"cellName\": \"business\",\n\t\t\t\"cellId\": \"7ef79284-534a-466f-a1f1-4e3a2f56be9d\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"feefae96-61b8-4ac5-a37c-592ed4b2330e\"\n\t\t},\n\t\t\"b53384d7-b989-4ac7-bd68-1c3621174ef4\": {\n\t\t\t\"path\": \"b53384d7-b989-4ac7-bd68-1c3621174ef4\",\n\t\t\t\"cellName\": \"models\",\n\t\t\t\"cellId\": \"b53384d7-b989-4ac7-bd68-1c3621174ef4\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"e2f99143-54b7-44dc-b566-1c2fb901bd16\"\n\t\t},\n\t\t\"414c500b-7b68-42ba-8110-e855efbee750\": {\n\t\t\t\"path\": \"414c500b-7b68-42ba-8110-e855efbee750\",\n\t\t\t\"cellName\": \"Create\",\n\t\t\t\"cellId\": \"414c500b-7b68-42ba-8110-e855efbee750\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"043d3dac-d4bb-449b-a3a7-270d53b66dac\"\n\t\t},\n\t\t\"581b4919-8b0c-4f0d-ae67-ad6de11d8c8b\": {\n\t\t\t\"path\": \"581b4919-8b0c-4f0d-ae67-ad6de11d8c8b\",\n\t\t\t\"cellName\": \"Details\",\n\t\t\t\"cellId\": \"581b4919-8b0c-4f0d-ae67-ad6de11d8c8b\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"043d3dac-d4bb-449b-a3a7-270d53b66dac\"\n\t\t},\n\t\t\"50aeed0b-bc13-43f7-bb15-cb1b12b2caa7\": {\n\t\t\t\"path\": \"50aeed0b-bc13-43f7-bb15-cb1b12b2caa7\",\n\t\t\t\"cellName\": \"NetworkService.ts\",\n\t\t\t\"cellId\": \"50aeed0b-bc13-43f7-bb15-cb1b12b2caa7\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"3f8ff792-40c8-4ae6-9af5-ff8b90da2f9f\"\n\t\t},\n\t\t\"f0ebd5da-21bb-4d96-8ff9-ca10409acc80\": {\n\t\t\t\"path\": \"f0ebd5da-21bb-4d96-8ff9-ca10409acc80\",\n\t\t\t\"cellName\": \"CheckService.ts\",\n\t\t\t\"cellId\": \"f0ebd5da-21bb-4d96-8ff9-ca10409acc80\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"7ef79284-534a-466f-a1f1-4e3a2f56be9d\"\n\t\t},\n\t\t\"7a3824cd-24c8-4b32-8b1d-e0bf357262c4\": {\n\t\t\t\"path\": \"7a3824cd-24c8-4b32-8b1d-e0bf357262c4\",\n\t\t\t\"cellName\": \"MonitorService.ts\",\n\t\t\t\"cellId\": \"7a3824cd-24c8-4b32-8b1d-e0bf357262c4\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"7ef79284-534a-466f-a1f1-4e3a2f56be9d\"\n\t\t},\n\t\t\"64e3bb0a-67f5-4269-9e7d-94fe91ac78fc\": {\n\t\t\t\"path\": \"64e3bb0a-67f5-4269-9e7d-94fe91ac78fc\",\n\t\t\t\"cellName\": \"checks\",\n\t\t\t\"cellId\": \"64e3bb0a-67f5-4269-9e7d-94fe91ac78fc\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"b53384d7-b989-4ac7-bd68-1c3621174ef4\"\n\t\t},\n\t\t\"5ffe0baa-054a-4e5b-8b29-1254f07ea975\": {\n\t\t\t\"path\": \"5ffe0baa-054a-4e5b-8b29-1254f07ea975\",\n\t\t\t\"cellName\": \"index.jsx\",\n\t\t\t\"cellId\": \"5ffe0baa-054a-4e5b-8b29-1254f07ea975\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"414c500b-7b68-42ba-8110-e855efbee750\"\n\t\t},\n\t\t\"c4a7bb58-1d9c-4690-b6b8-460c1cc33702\": {\n\t\t\t\"path\": \"c4a7bb58-1d9c-4690-b6b8-460c1cc33702\",\n\t\t\t\"cellName\": \"index.jsx\",\n\t\t\t\"cellId\": \"c4a7bb58-1d9c-4690-b6b8-460c1cc33702\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"581b4919-8b0c-4f0d-ae67-ad6de11d8c8b\"\n\t\t},\n\t\t\"1425ec43-f0f4-4c8b-a140-176c079219d6\": {\n\t\t\t\"path\": \"1425ec43-f0f4-4c8b-a140-176c079219d6\",\n\t\t\t\"cellName\": \"Check.ts\",\n\t\t\t\"cellId\": \"1425ec43-f0f4-4c8b-a140-176c079219d6\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"64e3bb0a-67f5-4269-9e7d-94fe91ac78fc\"\n\t\t},\n\t\t\"0622b212-3a4a-484d-9b7a-125864d785cd\": {\n\t\t\t\"path\": \"0622b212-3a4a-484d-9b7a-125864d785cd\",\n\t\t\t\"cellName\": \"Create PageSpeed Monitor - index.jsx:L111-143\",\n\t\t\t\"cellId\": \"0622b212-3a4a-484d-9b7a-125864d785cd\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"5ffe0baa-054a-4e5b-8b29-1254f07ea975\"\n\t\t},\n\t\t\"client/src/Pages/v1/PageSpeed/Create/index.jsx-simstep-b0cc6e6a-961e-4ea9-aa8a-6bfa44d6ba12\": {\n\t\t\t\"path\": \"client/src/Pages/v1/PageSpeed/Create/index.jsx-simstep-b0cc6e6a-961e-4ea9-aa8a-6bfa44d6ba12\",\n\t\t\t\"fileName\": \"index.jsx\",\n\t\t\t\"wiki\": \"The user navigates to the PageSpeed creation page, fills in the details for a new monitor (URL, name, interval), and submits the form. This triggers the `handleSubmit` function, which calls the `createMonitor` hook to send the data to the backend API.\",\n\t\t\t\"cellName\": \"Create PageSpeed Monitor - index.jsx:L111-143\",\n\t\t\t\"cellId\": \"0622b212-3a4a-484d-9b7a-125864d785cd\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 111,\n\t\t\t\"endLine\": 143,\n\t\t\t\"parentCellId\": \"5ffe0baa-054a-4e5b-8b29-1254f07ea975\",\n\t\t\t\"parentPath\": \"client/src/Pages/v1/PageSpeed/Create/index.jsx\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Website Performance and Page Speed Monitoring\",\n\t\t\t\t\t\"simStepId\": \"b0cc6e6a-961e-4ea9-aa8a-6bfa44d6ba12\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"6527fb47-157e-4bba-9aed-adde061c5689\": {\n\t\t\t\"path\": \"6527fb47-157e-4bba-9aed-adde061c5689\",\n\t\t\t\"cellName\": \"Backend Requests PageSpeed Analysis - NetworkService.ts:L129-162\",\n\t\t\t\"cellId\": \"6527fb47-157e-4bba-9aed-adde061c5689\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"50aeed0b-bc13-43f7-bb15-cb1b12b2caa7\"\n\t\t},\n\t\t\"server/src/service/v2/infrastructure/NetworkService.ts-simstep-53968267-0c6e-42f4-88b3-cd90f44532ae\": {\n\t\t\t\"path\": \"server/src/service/v2/infrastructure/NetworkService.ts-simstep-53968267-0c6e-42f4-88b3-cd90f44532ae\",\n\t\t\t\"fileName\": \"NetworkService.ts\",\n\t\t\t\"wiki\": \"A background job for the newly created monitor triggers the `NetworkService` to request a performance analysis from the Google PageSpeed Insights API. It constructs the API URL using the monitor's target URL and the configured PageSpeed API key.\",\n\t\t\t\"cellName\": \"Backend Requests PageSpeed Analysis - NetworkService.ts:L129-162\",\n\t\t\t\"cellId\": \"6527fb47-157e-4bba-9aed-adde061c5689\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 129,\n\t\t\t\"endLine\": 162,\n\t\t\t\"parentCellId\": \"50aeed0b-bc13-43f7-bb15-cb1b12b2caa7\",\n\t\t\t\"parentPath\": \"server/src/service/v2/infrastructure/NetworkService.ts\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Website Performance and Page Speed Monitoring\",\n\t\t\t\t\t\"simStepId\": \"53968267-0c6e-42f4-88b3-cd90f44532ae\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"f89cbd87-c961-4f8b-92b6-714da57718d5\": {\n\t\t\t\"path\": \"f89cbd87-c961-4f8b-92b6-714da57718d5\",\n\t\t\t\"cellName\": \"Backend Processes Lighthouse Data - CheckService.ts:L82-102\",\n\t\t\t\"cellId\": \"f89cbd87-c961-4f8b-92b6-714da57718d5\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"f0ebd5da-21bb-4d96-8ff9-ca10409acc80\"\n\t\t},\n\t\t\"server/src/service/v2/business/CheckService.ts-simstep-01206383-2db8-4b18-84d0-be2a0289c196\": {\n\t\t\t\"path\": \"server/src/service/v2/business/CheckService.ts-simstep-01206383-2db8-4b18-84d0-be2a0289c196\",\n\t\t\t\"fileName\": \"CheckService.ts\",\n\t\t\t\"wiki\": \"The `CheckService` receives the raw data from the Google API. The `buildPagespeedCheck` function extracts and transforms the relevant scores and audit details into a structured `Check` object, preparing it for database storage.\",\n\t\t\t\"cellName\": \"Backend Processes Lighthouse Data - CheckService.ts:L82-102\",\n\t\t\t\"cellId\": \"f89cbd87-c961-4f8b-92b6-714da57718d5\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 82,\n\t\t\t\"endLine\": 102,\n\t\t\t\"parentCellId\": \"f0ebd5da-21bb-4d96-8ff9-ca10409acc80\",\n\t\t\t\"parentPath\": \"server/src/service/v2/business/CheckService.ts\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Website Performance and Page Speed Monitoring\",\n\t\t\t\t\t\"simStepId\": \"01206383-2db8-4b18-84d0-be2a0289c196\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"ca6ee27b-1fbf-49de-978a-d6de259cc3d5\": {\n\t\t\t\"path\": \"ca6ee27b-1fbf-49de-978a-d6de259cc3d5\",\n\t\t\t\"cellName\": \"Backend Aggregates Performance Data - MonitorService.ts:L106-120\",\n\t\t\t\"cellId\": \"ca6ee27b-1fbf-49de-978a-d6de259cc3d5\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"7a3824cd-24c8-4b32-8b1d-e0bf357262c4\"\n\t\t},\n\t\t\"server/src/service/v2/business/MonitorService.ts-simstep-5616ac6d-c281-4879-82f1-6590c721c8f7\": {\n\t\t\t\"path\": \"server/src/service/v2/business/MonitorService.ts-simstep-5616ac6d-c281-4879-82f1-6590c721c8f7\",\n\t\t\t\"fileName\": \"MonitorService.ts\",\n\t\t\t\"wiki\": \"When a user views the details of a PageSpeed monitor, the frontend requests historical data. The `MonitorService` on the backend uses a MongoDB aggregation pipeline to group checks by time intervals and calculate average scores for metrics like performance, SEO, etc. This is defined by helper functions like `getPageSpeedGroup`.\",\n\t\t\t\"cellName\": \"Backend Aggregates Performance Data - MonitorService.ts:L106-120\",\n\t\t\t\"cellId\": \"ca6ee27b-1fbf-49de-978a-d6de259cc3d5\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 106,\n\t\t\t\"endLine\": 120,\n\t\t\t\"parentCellId\": \"7a3824cd-24c8-4b32-8b1d-e0bf357262c4\",\n\t\t\t\"parentPath\": \"server/src/service/v2/business/MonitorService.ts\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Website Performance and Page Speed Monitoring\",\n\t\t\t\t\t\"simStepId\": \"5616ac6d-c281-4879-82f1-6590c721c8f7\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"9ef9e218-4742-487a-9a88-5c70e788ccdc\": {\n\t\t\t\"path\": \"9ef9e218-4742-487a-9a88-5c70e788ccdc\",\n\t\t\t\"cellName\": \"Frontend Renders Performance Charts - index.jsx:L91-126\",\n\t\t\t\"cellId\": \"9ef9e218-4742-487a-9a88-5c70e788ccdc\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"c4a7bb58-1d9c-4690-b6b8-460c1cc33702\"\n\t\t},\n\t\t\"client/src/Pages/v1/PageSpeed/Details/index.jsx-simstep-0ec0eb06-05eb-4204-b077-9e47eb2cc316\": {\n\t\t\t\"path\": \"client/src/Pages/v1/PageSpeed/Details/index.jsx-simstep-0ec0eb06-05eb-4204-b077-9e47eb2cc316\",\n\t\t\t\"fileName\": \"index.jsx\",\n\t\t\t\"wiki\": \"The `PageSpeedDetails` component receives the historical data from the backend. It then passes this data to specialized child components like `PageSpeedAreaChart` and `PerformanceReport` to render visualizations of the website's performance over time.\",\n\t\t\t\"cellName\": \"Frontend Renders Performance Charts - index.jsx:L91-126\",\n\t\t\t\"cellId\": \"9ef9e218-4742-487a-9a88-5c70e788ccdc\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 91,\n\t\t\t\"endLine\": 126,\n\t\t\t\"parentCellId\": \"c4a7bb58-1d9c-4690-b6b8-460c1cc33702\",\n\t\t\t\"parentPath\": \"client/src/Pages/v1/PageSpeed/Details/index.jsx\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Website Performance and Page Speed Monitoring\",\n\t\t\t\t\t\"simStepId\": \"0ec0eb06-05eb-4204-b077-9e47eb2cc316\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"b8e83b0a-69ff-4c34-a7fe-cb8c9ba85438\": {\n\t\t\t\"path\": \"b8e83b0a-69ff-4c34-a7fe-cb8c9ba85438\",\n\t\t\t\"cellName\": \"API Call:\\nCreate Monitor\",\n\t\t\t\"cellId\": \"b8e83b0a-69ff-4c34-a7fe-cb8c9ba85438\",\n\t\t\t\"visible\": true\n\t\t},\n\t\t\"generated-edge-simstep-f8df1cad-6051-466e-a13e-47d710ba1c14-b8e83b0a-69ff-4c34-a7fe-cb8c9ba85438\": {\n\t\t\t\"path\": \"generated-edge-simstep-f8df1cad-6051-466e-a13e-47d710ba1c14-b8e83b0a-69ff-4c34-a7fe-cb8c9ba85438\",\n\t\t\t\"fileName\": \"index.jsx\",\n\t\t\t\"cellName\": \"API Call: Create Monitor\",\n\t\t\t\"cellId\": \"b8e83b0a-69ff-4c34-a7fe-cb8c9ba85438\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 119,\n\t\t\t\"endLine\": 119,\n\t\t\t\"parentPath\": \"client/src/Pages/v1/PageSpeed/Create/index.jsx\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Website Performance and Page Speed Monitoring\",\n\t\t\t\t\t\"simStepId\": \"f8df1cad-6051-466e-a13e-47d710ba1c14\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"0d3c8091-3d91-4e42-9b46-7e35ed726a7a\": {\n\t\t\t\"path\": \"0d3c8091-3d91-4e42-9b46-7e35ed726a7a\",\n\t\t\t\"cellName\": \"Google PageSpeed\\nAPI Response\",\n\t\t\t\"cellId\": \"0d3c8091-3d91-4e42-9b46-7e35ed726a7a\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"feefae96-61b8-4ac5-a37c-592ed4b2330e\"\n\t\t},\n\t\t\"generated-edge-simstep-0b380571-3896-4365-b5dc-187494f02e0d-0d3c8091-3d91-4e42-9b46-7e35ed726a7a\": {\n\t\t\t\"path\": \"generated-edge-simstep-0b380571-3896-4365-b5dc-187494f02e0d-0d3c8091-3d91-4e42-9b46-7e35ed726a7a\",\n\t\t\t\"fileName\": \"NetworkService.ts\",\n\t\t\t\"cellName\": \"Google PageSpeed API Response\",\n\t\t\t\"cellId\": \"0d3c8091-3d91-4e42-9b46-7e35ed726a7a\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 156,\n\t\t\t\"endLine\": 156,\n\t\t\t\"parentPath\": \"server/src/service/v2/infrastructure/NetworkService.ts\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Website Performance and Page Speed Monitoring\",\n\t\t\t\t\t\"simStepId\": \"0b380571-3896-4365-b5dc-187494f02e0d\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"27c7191b-80a2-475b-9371-e106108aff1c\": {\n\t\t\t\"path\": \"27c7191b-80a2-475b-9371-e106108aff1c\",\n\t\t\t\"cellName\": \"Store Processed\\nCheck Data\",\n\t\t\t\"cellId\": \"27c7191b-80a2-475b-9371-e106108aff1c\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"7ef79284-534a-466f-a1f1-4e3a2f56be9d\"\n\t\t},\n\t\t\"generated-edge-simstep-a629a102-0df1-4798-a7a2-45c8f6cdad29-27c7191b-80a2-475b-9371-e106108aff1c\": {\n\t\t\t\"path\": \"generated-edge-simstep-a629a102-0df1-4798-a7a2-45c8f6cdad29-27c7191b-80a2-475b-9371-e106108aff1c\",\n\t\t\t\"fileName\": \"CheckService.ts\",\n\t\t\t\"cellName\": \"Store Processed Check Data\",\n\t\t\t\"cellId\": \"27c7191b-80a2-475b-9371-e106108aff1c\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 237,\n\t\t\t\"endLine\": 268,\n\t\t\t\"parentPath\": \"server/src/service/v2/business/CheckService.ts\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Website Performance and Page Speed Monitoring\",\n\t\t\t\t\t\"simStepId\": \"a629a102-0df1-4798-a7a2-45c8f6cdad29\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"7be432cd-2587-4eab-abdc-f7b9c1923597\": {\n\t\t\t\"path\": \"7be432cd-2587-4eab-abdc-f7b9c1923597\",\n\t\t\t\"cellName\": \"Aggregated Data\\nTransmitted to\\nFrontend\",\n\t\t\t\"cellId\": \"7be432cd-2587-4eab-abdc-f7b9c1923597\",\n\t\t\t\"visible\": true\n\t\t},\n\t\t\"generated-edge-simstep-4ed43eaf-fa8f-4fce-af87-8a5f74dd5c08-7be432cd-2587-4eab-abdc-f7b9c1923597\": {\n\t\t\t\"path\": \"generated-edge-simstep-4ed43eaf-fa8f-4fce-af87-8a5f74dd5c08-7be432cd-2587-4eab-abdc-f7b9c1923597\",\n\t\t\t\"fileName\": \"MonitorService.ts\",\n\t\t\t\"cellName\": \"Aggregated Data Transmitted to Frontend\",\n\t\t\t\"cellId\": \"7be432cd-2587-4eab-abdc-f7b9c1923597\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 368,\n\t\t\t\"endLine\": 372,\n\t\t\t\"parentPath\": \"server/src/service/v2/business/MonitorService.ts\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Website Performance and Page Speed Monitoring\",\n\t\t\t\t\t\"simStepId\": \"4ed43eaf-fa8f-4fce-af87-8a5f74dd5c08\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"fe47576c-c186-4950-82a5-b2fd24eb2561\": {\n\t\t\t\"path\": \"fe47576c-c186-4950-82a5-b2fd24eb2561\",\n\t\t\t\"cellName\": \"config\",\n\t\t\t\"cellId\": \"fe47576c-c186-4950-82a5-b2fd24eb2561\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\"\n\t\t},\n\t\t\"cb53d612-9b89-47da-911c-165d0382a7d8\": {\n\t\t\t\"path\": \"cb53d612-9b89-47da-911c-165d0382a7d8\",\n\t\t\t\"cellName\": \"routes.js\",\n\t\t\t\"cellId\": \"cb53d612-9b89-47da-911c-165d0382a7d8\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"fe47576c-c186-4950-82a5-b2fd24eb2561\"\n\t\t},\n\t\t\"8021b55d-2d3a-4416-b598-e134e76c9434\": {\n\t\t\t\"path\": \"8021b55d-2d3a-4416-b598-e134e76c9434\",\n\t\t\t\"cellName\": \"Maintenance\",\n\t\t\t\"cellId\": \"8021b55d-2d3a-4416-b598-e134e76c9434\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"1a083b4a-787c-4eb4-8029-6700de987679\"\n\t\t},\n\t\t\"5f21f109-1967-416f-a649-9b48e78b90f6\": {\n\t\t\t\"path\": \"5f21f109-1967-416f-a649-9b48e78b90f6\",\n\t\t\t\"cellName\": \"maintenanceWindowRoute.js\",\n\t\t\t\"cellId\": \"5f21f109-1967-416f-a649-9b48e78b90f6\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"d3375a20-2776-4771-b806-649bbeb541bd\"\n\t\t},\n\t\t\"a0cae18c-3c0e-40d3-ab03-eef7eace65d6\": {\n\t\t\t\"path\": \"a0cae18c-3c0e-40d3-ab03-eef7eace65d6\",\n\t\t\t\"cellName\": \"maintenanceWindowController.js\",\n\t\t\t\"cellId\": \"a0cae18c-3c0e-40d3-ab03-eef7eace65d6\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"fc591f7a-d4ac-4565-949d-a87a58a79bbc\"\n\t\t},\n\t\t\"6f7119ac-d65a-4fdf-a6f2-31052e0f5549\": {\n\t\t\t\"path\": \"6f7119ac-d65a-4fdf-a6f2-31052e0f5549\",\n\t\t\t\"cellName\": \"CreateMaintenance\",\n\t\t\t\"cellId\": \"6f7119ac-d65a-4fdf-a6f2-31052e0f5549\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"8021b55d-2d3a-4416-b598-e134e76c9434\"\n\t\t},\n\t\t\"1eae6263-aaa2-4206-b92e-1e67f529c1c9\": {\n\t\t\t\"path\": \"1eae6263-aaa2-4206-b92e-1e67f529c1c9\",\n\t\t\t\"cellName\": \"index.jsx\",\n\t\t\t\"cellId\": \"1eae6263-aaa2-4206-b92e-1e67f529c1c9\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"8021b55d-2d3a-4416-b598-e134e76c9434\"\n\t\t},\n\t\t\"5ad4d33f-0932-479c-bb57-22ce6405758f\": {\n\t\t\t\"path\": \"5ad4d33f-0932-479c-bb57-22ce6405758f\",\n\t\t\t\"cellName\": \"MaintenanceTable\",\n\t\t\t\"cellId\": \"5ad4d33f-0932-479c-bb57-22ce6405758f\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"8021b55d-2d3a-4416-b598-e134e76c9434\"\n\t\t},\n\t\t\"26b8daff-aa48-4baa-9d6c-05f771bf0990\": {\n\t\t\t\"path\": \"26b8daff-aa48-4baa-9d6c-05f771bf0990\",\n\t\t\t\"cellName\": \"maintenanceWindowService.js\",\n\t\t\t\"cellId\": \"26b8daff-aa48-4baa-9d6c-05f771bf0990\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"87d3b101-9443-4ed4-9c4f-f759d41677eb\"\n\t\t},\n\t\t\"95ed6c41-ebeb-4c08-98c3-bab8b426789e\": {\n\t\t\t\"path\": \"95ed6c41-ebeb-4c08-98c3-bab8b426789e\",\n\t\t\t\"cellName\": \"maintenanceWindowModule.js\",\n\t\t\t\"cellId\": \"95ed6c41-ebeb-4c08-98c3-bab8b426789e\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"82cb3dbe-c922-438a-a912-255376f4b380\"\n\t\t},\n\t\t\"92c244d2-e6a7-4804-a643-1e8d36baf9c6\": {\n\t\t\t\"path\": \"92c244d2-e6a7-4804-a643-1e8d36baf9c6\",\n\t\t\t\"cellName\": \"index.jsx\",\n\t\t\t\"cellId\": \"92c244d2-e6a7-4804-a643-1e8d36baf9c6\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"6f7119ac-d65a-4fdf-a6f2-31052e0f5549\"\n\t\t},\n\t\t\"015a17fc-3fcf-45e0-8936-19f5e2ca86a3\": {\n\t\t\t\"path\": \"015a17fc-3fcf-45e0-8936-19f5e2ca86a3\",\n\t\t\t\"cellName\": \"hooks\",\n\t\t\t\"cellId\": \"015a17fc-3fcf-45e0-8936-19f5e2ca86a3\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"6f7119ac-d65a-4fdf-a6f2-31052e0f5549\"\n\t\t},\n\t\t\"e7ec5ca9-6d25-4bf2-9695-639556f7d141\": {\n\t\t\t\"path\": \"e7ec5ca9-6d25-4bf2-9695-639556f7d141\",\n\t\t\t\"cellName\": \"index.jsx\",\n\t\t\t\"cellId\": \"e7ec5ca9-6d25-4bf2-9695-639556f7d141\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"5ad4d33f-0932-479c-bb57-22ce6405758f\"\n\t\t},\n\t\t\"6ad0396e-9b38-4f5d-9ad9-6c9fcb4434f4\": {\n\t\t\t\"path\": \"6ad0396e-9b38-4f5d-9ad9-6c9fcb4434f4\",\n\t\t\t\"cellName\": \"useMaintenanceActions.jsx\",\n\t\t\t\"cellId\": \"6ad0396e-9b38-4f5d-9ad9-6c9fcb4434f4\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"015a17fc-3fcf-45e0-8936-19f5e2ca86a3\"\n\t\t},\n\t\t\"20335f29-a2ac-4e0c-aba6-28707748ecd4\": {\n\t\t\t\"path\": \"20335f29-a2ac-4e0c-aba6-28707748ecd4\",\n\t\t\t\"cellName\": \"Flow: Create Maintenance Window - User Interaction - index.jsx:L46-131\",\n\t\t\t\"cellId\": \"20335f29-a2ac-4e0c-aba6-28707748ecd4\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"92c244d2-e6a7-4804-a643-1e8d36baf9c6\"\n\t\t},\n\t\t\"client/src/Pages/v1/Maintenance/CreateMaintenance/index.jsx-simstep-2401ef7a-8d8e-4056-868a-547ab213daf1\": {\n\t\t\t\"path\": \"client/src/Pages/v1/Maintenance/CreateMaintenance/index.jsx-simstep-2401ef7a-8d8e-4056-868a-547ab213daf1\",\n\t\t\t\"fileName\": \"index.jsx\",\n\t\t\t\"wiki\": \"A user navigates to the 'Create Maintenance Window' page. They fill out a form with details such as a name, start date/time, duration, recurrence, and select the monitors to which this window will apply.\",\n\t\t\t\"cellName\": \"Flow: Create Maintenance Window - User Interaction - index.jsx:L46-131\",\n\t\t\t\"cellId\": \"20335f29-a2ac-4e0c-aba6-28707748ecd4\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 46,\n\t\t\t\"endLine\": 131,\n\t\t\t\"parentCellId\": \"92c244d2-e6a7-4804-a643-1e8d36baf9c6\",\n\t\t\t\"parentPath\": \"client/src/Pages/v1/Maintenance/CreateMaintenance/index.jsx\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Scheduled Maintenance Windows\",\n\t\t\t\t\t\"simStepId\": \"2401ef7a-8d8e-4056-868a-547ab213daf1\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"5bdfdfa4-5d93-49fa-b05c-905813e6cf9d\": {\n\t\t\t\"path\": \"5bdfdfa4-5d93-49fa-b05c-905813e6cf9d\",\n\t\t\t\"cellName\": \"Flow: Create Maintenance Window - Prepare API Request - useMaintenanceActions.jsx:L25-58\",\n\t\t\t\"cellId\": \"5bdfdfa4-5d93-49fa-b05c-905813e6cf9d\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"6ad0396e-9b38-4f5d-9ad9-6c9fcb4434f4\"\n\t\t},\n\t\t\"client/src/Pages/v1/Maintenance/CreateMaintenance/hooks/useMaintenanceActions.jsx-simstep-5e0d7085-099b-478a-afaa-47ad4dd07043\": {\n\t\t\t\"path\": \"client/src/Pages/v1/Maintenance/CreateMaintenance/hooks/useMaintenanceActions.jsx-simstep-5e0d7085-099b-478a-afaa-47ad4dd07043\",\n\t\t\t\"fileName\": \"useMaintenanceActions.jsx\",\n\t\t\t\"wiki\": \"The `handleSubmitForm` hook processes the form data, calculates start and end timestamps, and constructs a request object. It then determines whether to call `createMaintenanceWindow` or `editMaintenanceWindow` on the network service.\",\n\t\t\t\"cellName\": \"Flow: Create Maintenance Window - Prepare API Request - useMaintenanceActions.jsx:L25-58\",\n\t\t\t\"cellId\": \"5bdfdfa4-5d93-49fa-b05c-905813e6cf9d\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 25,\n\t\t\t\"endLine\": 58,\n\t\t\t\"parentCellId\": \"6ad0396e-9b38-4f5d-9ad9-6c9fcb4434f4\",\n\t\t\t\"parentPath\": \"client/src/Pages/v1/Maintenance/CreateMaintenance/hooks/useMaintenanceActions.jsx\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Scheduled Maintenance Windows\",\n\t\t\t\t\t\"simStepId\": \"5e0d7085-099b-478a-afaa-47ad4dd07043\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"a391e8ea-9dbe-4fe4-90df-bf475d8b7ef8\": {\n\t\t\t\"path\": \"a391e8ea-9dbe-4fe4-90df-bf475d8b7ef8\",\n\t\t\t\"cellName\": \"Flow: Create Maintenance Window - API Routing - routes.js:L43\",\n\t\t\t\"cellId\": \"a391e8ea-9dbe-4fe4-90df-bf475d8b7ef8\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"cb53d612-9b89-47da-911c-165d0382a7d8\"\n\t\t},\n\t\t\"server/src/config/routes.js-simstep-3e93ef65-8e2c-405b-8dc1-56d8e93937b3\": {\n\t\t\t\"path\": \"server/src/config/routes.js-simstep-3e93ef65-8e2c-405b-8dc1-56d8e93937b3\",\n\t\t\t\"fileName\": \"routes.js\",\n\t\t\t\"wiki\": \"The backend Express server receives the request. The routing configuration maps the `/api/v1/maintenance-window` path to the `maintenanceWindowRoutes`, which in turn directs the POST request to the `createMaintenanceWindows` method in the controller.\",\n\t\t\t\"cellName\": \"Flow: Create Maintenance Window - API Routing - routes.js:L43\",\n\t\t\t\"cellId\": \"a391e8ea-9dbe-4fe4-90df-bf475d8b7ef8\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 43,\n\t\t\t\"endLine\": 43,\n\t\t\t\"parentCellId\": \"cb53d612-9b89-47da-911c-165d0382a7d8\",\n\t\t\t\"parentPath\": \"server/src/config/routes.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Scheduled Maintenance Windows\",\n\t\t\t\t\t\"simStepId\": \"3e93ef65-8e2c-405b-8dc1-56d8e93937b3\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"0fae6e75-38ea-444d-a1bf-0f820ba443b9\": {\n\t\t\t\"path\": \"0fae6e75-38ea-444d-a1bf-0f820ba443b9\",\n\t\t\t\"cellName\": \"Flow: Create Maintenance Window - Controller Logic - maintenanceWindowController.js:L27-41\",\n\t\t\t\"cellId\": \"0fae6e75-38ea-444d-a1bf-0f820ba443b9\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"a0cae18c-3c0e-40d3-ab03-eef7eace65d6\"\n\t\t},\n\t\t\"server/src/controllers/v1/maintenanceWindowController.js-simstep-95fc1919-339d-4659-98cb-3dc50f662075\": {\n\t\t\t\"path\": \"server/src/controllers/v1/maintenanceWindowController.js-simstep-95fc1919-339d-4659-98cb-3dc50f662075\",\n\t\t\t\"fileName\": \"maintenanceWindowController.js\",\n\t\t\t\"wiki\": \"The `maintenanceWindowController` validates the request body using Joi, ensures a `teamId` exists on the user object, and then calls the `maintenanceWindowService` to handle the business logic of creating the window.\",\n\t\t\t\"cellName\": \"Flow: Create Maintenance Window - Controller Logic - maintenanceWindowController.js:L27-41\",\n\t\t\t\"cellId\": \"0fae6e75-38ea-444d-a1bf-0f820ba443b9\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 27,\n\t\t\t\"endLine\": 41,\n\t\t\t\"parentCellId\": \"a0cae18c-3c0e-40d3-ab03-eef7eace65d6\",\n\t\t\t\"parentPath\": \"server/src/controllers/v1/maintenanceWindowController.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Scheduled Maintenance Windows\",\n\t\t\t\t\t\"simStepId\": \"95fc1919-339d-4659-98cb-3dc50f662075\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"560d268b-ef0f-4cd2-bcfe-9dc0a0e2ce6f\": {\n\t\t\t\"path\": \"560d268b-ef0f-4cd2-bcfe-9dc0a0e2ce6f\",\n\t\t\t\"cellName\": \"Flow: Create Maintenance Window - Business Logic Execution - maintenanceWindowService.js:L18-39\",\n\t\t\t\"cellId\": \"560d268b-ef0f-4cd2-bcfe-9dc0a0e2ce6f\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"26b8daff-aa48-4baa-9d6c-05f771bf0990\"\n\t\t},\n\t\t\"server/src/service/v1/business/maintenanceWindowService.js-simstep-6e2cf739-1514-4c37-9874-10b68a47010e\": {\n\t\t\t\"path\": \"server/src/service/v1/business/maintenanceWindowService.js-simstep-6e2cf739-1514-4c37-9874-10b68a47010e\",\n\t\t\t\"fileName\": \"maintenanceWindowService.js\",\n\t\t\t\"wiki\": \"The `maintenanceWindowService` verifies that all monitors specified in the request belong to the user's team. It then iterates through each monitor ID and prepares a separate database transaction to create a maintenance window record for each one.\",\n\t\t\t\"cellName\": \"Flow: Create Maintenance Window - Business Logic Execution - maintenanceWindowService.js:L18-39\",\n\t\t\t\"cellId\": \"560d268b-ef0f-4cd2-bcfe-9dc0a0e2ce6f\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 18,\n\t\t\t\"endLine\": 39,\n\t\t\t\"parentCellId\": \"26b8daff-aa48-4baa-9d6c-05f771bf0990\",\n\t\t\t\"parentPath\": \"server/src/service/v1/business/maintenanceWindowService.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Scheduled Maintenance Windows\",\n\t\t\t\t\t\"simStepId\": \"6e2cf739-1514-4c37-9874-10b68a47010e\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"3890b98d-a133-4279-a961-5d2facc6a17a\": {\n\t\t\t\"path\": \"3890b98d-a133-4279-a961-5d2facc6a17a\",\n\t\t\t\"cellName\": \"Flow: Create Maintenance Window - Database Record Creation - maintenanceWindowModule.js:L7-22\",\n\t\t\t\"cellId\": \"3890b98d-a133-4279-a961-5d2facc6a17a\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"95ed6c41-ebeb-4c08-98c3-bab8b426789e\"\n\t\t},\n\t\t\"server/src/db/v1/modules/maintenanceWindowModule.js-simstep-a3c47fd4-c701-46c2-9aff-94a667b3e368\": {\n\t\t\t\"path\": \"server/src/db/v1/modules/maintenanceWindowModule.js-simstep-a3c47fd4-c701-46c2-9aff-94a667b3e368\",\n\t\t\t\"fileName\": \"maintenanceWindowModule.js\",\n\t\t\t\"wiki\": \"The `maintenanceWindowModule` instantiates a new `MaintenanceWindow` Mongoose model. If the window is a one-time event, it sets an `expiry` field to the end time for automatic cleanup by MongoDB's TTL index. Finally, it saves the new document to the database.\",\n\t\t\t\"cellName\": \"Flow: Create Maintenance Window - Database Record Creation - maintenanceWindowModule.js:L7-22\",\n\t\t\t\"cellId\": \"3890b98d-a133-4279-a961-5d2facc6a17a\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 7,\n\t\t\t\"endLine\": 22,\n\t\t\t\"parentCellId\": \"95ed6c41-ebeb-4c08-98c3-bab8b426789e\",\n\t\t\t\"parentPath\": \"server/src/db/v1/modules/maintenanceWindowModule.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Scheduled Maintenance Windows\",\n\t\t\t\t\t\"simStepId\": \"a3c47fd4-c701-46c2-9aff-94a667b3e368\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"a5a84b08-8c70-4023-8d08-b74e23aab4d7\": {\n\t\t\t\"path\": \"a5a84b08-8c70-4023-8d08-b74e23aab4d7\",\n\t\t\t\"cellName\": \"Flow: Create Maintenance Window - UI Update - index.jsx:L111-119\",\n\t\t\t\"cellId\": \"a5a84b08-8c70-4023-8d08-b74e23aab4d7\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"92c244d2-e6a7-4804-a643-1e8d36baf9c6\"\n\t\t},\n\t\t\"client/src/Pages/v1/Maintenance/CreateMaintenance/index.jsx-simstep-ebe8fd52-f2a1-4a98-a71b-b04d6f4cdadc\": {\n\t\t\t\"path\": \"client/src/Pages/v1/Maintenance/CreateMaintenance/index.jsx-simstep-ebe8fd52-f2a1-4a98-a71b-b04d6f4cdadc\",\n\t\t\t\"fileName\": \"index.jsx\",\n\t\t\t\"wiki\": \"The frontend receives the success response. A success toast message is displayed, and the user is navigated back to the main maintenance windows table.\",\n\t\t\t\"cellName\": \"Flow: Create Maintenance Window - UI Update - index.jsx:L111-119\",\n\t\t\t\"cellId\": \"a5a84b08-8c70-4023-8d08-b74e23aab4d7\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 111,\n\t\t\t\"endLine\": 119,\n\t\t\t\"parentCellId\": \"92c244d2-e6a7-4804-a643-1e8d36baf9c6\",\n\t\t\t\"parentPath\": \"client/src/Pages/v1/Maintenance/CreateMaintenance/index.jsx\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Scheduled Maintenance Windows\",\n\t\t\t\t\t\"simStepId\": \"ebe8fd52-f2a1-4a98-a71b-b04d6f4cdadc\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"d145bb4c-e1e0-473a-b6bc-decc932b738b\": {\n\t\t\t\"path\": \"d145bb4c-e1e0-473a-b6bc-decc932b738b\",\n\t\t\t\"cellName\": \"Flow: View Maintenance Windows - Page Load - index.jsx:L25-47\",\n\t\t\t\"cellId\": \"d145bb4c-e1e0-473a-b6bc-decc932b738b\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"1eae6263-aaa2-4206-b92e-1e67f529c1c9\"\n\t\t},\n\t\t\"client/src/Pages/v1/Maintenance/index.jsx-simstep-82b5ea14-bb00-4511-aba4-76196029fd81\": {\n\t\t\t\"path\": \"client/src/Pages/v1/Maintenance/index.jsx-simstep-82b5ea14-bb00-4511-aba4-76196029fd81\",\n\t\t\t\"fileName\": \"index.jsx\",\n\t\t\t\"wiki\": \"User navigates to the '/maintenance' page. The `Maintenance` component mounts and triggers a `useEffect` hook to fetch the list of maintenance windows.\",\n\t\t\t\"cellName\": \"Flow: View Maintenance Windows - Page Load - index.jsx:L25-47\",\n\t\t\t\"cellId\": \"d145bb4c-e1e0-473a-b6bc-decc932b738b\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 25,\n\t\t\t\"endLine\": 47,\n\t\t\t\"parentCellId\": \"1eae6263-aaa2-4206-b92e-1e67f529c1c9\",\n\t\t\t\"parentPath\": \"client/src/Pages/v1/Maintenance/index.jsx\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Scheduled Maintenance Windows\",\n\t\t\t\t\t\"simStepId\": \"82b5ea14-bb00-4511-aba4-76196029fd81\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"c35a065c-2808-402c-877e-9055d956ce0d\": {\n\t\t\t\"path\": \"c35a065c-2808-402c-877e-9055d956ce0d\",\n\t\t\t\"cellName\": \"Flow: View Maintenance Windows - Controller and Service - maintenanceWindowController.js:L75\",\n\t\t\t\"cellId\": \"c35a065c-2808-402c-877e-9055d956ce0d\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"a0cae18c-3c0e-40d3-ab03-eef7eace65d6\"\n\t\t},\n\t\t\"server/src/controllers/v1/maintenanceWindowController.js-simstep-1251da83-5949-4e24-a1d2-fc74ff785aa9\": {\n\t\t\t\"path\": \"server/src/controllers/v1/maintenanceWindowController.js-simstep-1251da83-5949-4e24-a1d2-fc74ff785aa9\",\n\t\t\t\"fileName\": \"maintenanceWindowController.js\",\n\t\t\t\"wiki\": \"The backend routes the request to `maintenanceWindowController.getMaintenanceWindowsByTeamId`. This controller calls the corresponding service, which in turn calls the database module to query for the data.\",\n\t\t\t\"cellName\": \"Flow: View Maintenance Windows - Controller and Service - maintenanceWindowController.js:L75\",\n\t\t\t\"cellId\": \"c35a065c-2808-402c-877e-9055d956ce0d\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 75,\n\t\t\t\"endLine\": 75,\n\t\t\t\"parentCellId\": \"a0cae18c-3c0e-40d3-ab03-eef7eace65d6\",\n\t\t\t\"parentPath\": \"server/src/controllers/v1/maintenanceWindowController.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Scheduled Maintenance Windows\",\n\t\t\t\t\t\"simStepId\": \"1251da83-5949-4e24-a1d2-fc74ff785aa9\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"27d9160a-4f8d-4dff-a09b-1678bc28cf2c\": {\n\t\t\t\"path\": \"27d9160a-4f8d-4dff-a09b-1678bc28cf2c\",\n\t\t\t\"cellName\": \"Flow: View Maintenance Windows - Data Retrieval - maintenanceWindowModule.js:L37-66\",\n\t\t\t\"cellId\": \"27d9160a-4f8d-4dff-a09b-1678bc28cf2c\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"95ed6c41-ebeb-4c08-98c3-bab8b426789e\"\n\t\t},\n\t\t\"server/src/db/v1/modules/maintenanceWindowModule.js-simstep-9bfbae5a-f487-40ef-86f5-04a1cc3c7662\": {\n\t\t\t\"path\": \"server/src/db/v1/modules/maintenanceWindowModule.js-simstep-9bfbae5a-f487-40ef-86f5-04a1cc3c7662\",\n\t\t\t\"fileName\": \"maintenanceWindowModule.js\",\n\t\t\t\"wiki\": \"The `maintenanceWindowModule` constructs a MongoDB query to find all maintenance windows for the given `teamId`, applying pagination (skip, limit) and sorting. It executes the query and returns the results along with the total count.\",\n\t\t\t\"cellName\": \"Flow: View Maintenance Windows - Data Retrieval - maintenanceWindowModule.js:L37-66\",\n\t\t\t\"cellId\": \"27d9160a-4f8d-4dff-a09b-1678bc28cf2c\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 37,\n\t\t\t\"endLine\": 66,\n\t\t\t\"parentCellId\": \"95ed6c41-ebeb-4c08-98c3-bab8b426789e\",\n\t\t\t\"parentPath\": \"server/src/db/v1/modules/maintenanceWindowModule.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Scheduled Maintenance Windows\",\n\t\t\t\t\t\"simStepId\": \"9bfbae5a-f487-40ef-86f5-04a1cc3c7662\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"970e2002-7c0e-40ef-80d8-e5e6d0a60735\": {\n\t\t\t\"path\": \"970e2002-7c0e-40ef-80d8-e5e6d0a60735\",\n\t\t\t\"cellName\": \"Flow: View Maintenance Windows - UI Rendering - index.jsx:L195-201\",\n\t\t\t\"cellId\": \"970e2002-7c0e-40ef-80d8-e5e6d0a60735\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"e7ec5ca9-6d25-4bf2-9695-639556f7d141\"\n\t\t},\n\t\t\"client/src/Pages/v1/Maintenance/MaintenanceTable/index.jsx-simstep-acf97639-e291-4ca6-81a6-d0487397f42a\": {\n\t\t\t\"path\": \"client/src/Pages/v1/Maintenance/MaintenanceTable/index.jsx-simstep-acf97639-e291-4ca6-81a6-d0487397f42a\",\n\t\t\t\"fileName\": \"index.jsx\",\n\t\t\t\"wiki\": \"The client receives the data and updates its state. The `MaintenanceTable` component then renders the list of maintenance windows in a table, displaying their names, schedules, and providing actions like edit or delete.\",\n\t\t\t\"cellName\": \"Flow: View Maintenance Windows - UI Rendering - index.jsx:L195-201\",\n\t\t\t\"cellId\": \"970e2002-7c0e-40ef-80d8-e5e6d0a60735\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 195,\n\t\t\t\"endLine\": 201,\n\t\t\t\"parentCellId\": \"e7ec5ca9-6d25-4bf2-9695-639556f7d141\",\n\t\t\t\"parentPath\": \"client/src/Pages/v1/Maintenance/MaintenanceTable/index.jsx\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Scheduled Maintenance Windows\",\n\t\t\t\t\t\"simStepId\": \"acf97639-e291-4ca6-81a6-d0487397f42a\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"23630a1f-7452-4373-a864-7ec7821137f2\": {\n\t\t\t\"path\": \"23630a1f-7452-4373-a864-7ec7821137f2\",\n\t\t\t\"cellName\": \"Flow: Monitor Suppression - Job Execution Start - SuperSimpleQueueHelper.js:L30-45\",\n\t\t\t\"cellId\": \"23630a1f-7452-4373-a864-7ec7821137f2\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"04c12e9a-e025-457c-a634-5f7472a42985\"\n\t\t},\n\t\t\"server/src/service/v1/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.js-simstep-a47affaf-b952-46d6-9709-6120a77690e1\": {\n\t\t\t\"path\": \"server/src/service/v1/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.js-simstep-a47affaf-b952-46d6-9709-6120a77690e1\",\n\t\t\t\"fileName\": \"SuperSimpleQueueHelper.js\",\n\t\t\t\"wiki\": \"The `SuperSimpleQueue` processing system picks up a job to check a specific monitor. The job handler is retrieved from `SuperSimpleQueueHelper`.\",\n\t\t\t\"cellName\": \"Flow: Monitor Suppression - Job Execution Start - SuperSimpleQueueHelper.js:L30-45\",\n\t\t\t\"cellId\": \"23630a1f-7452-4373-a864-7ec7821137f2\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 30,\n\t\t\t\"endLine\": 45,\n\t\t\t\"parentCellId\": \"04c12e9a-e025-457c-a634-5f7472a42985\",\n\t\t\t\"parentPath\": \"server/src/service/v1/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Scheduled Maintenance Windows\",\n\t\t\t\t\t\"simStepId\": \"a47affaf-b952-46d6-9709-6120a77690e1\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"fc78b5b6-7fad-4f8f-a5a3-c7c38931daba\": {\n\t\t\t\"path\": \"fc78b5b6-7fad-4f8f-a5a3-c7c38931daba\",\n\t\t\t\"cellName\": \"Flow: Monitor Suppression - Fetching Maintenance Windows - SuperSimpleQueueHelper.js:L80-83\",\n\t\t\t\"cellId\": \"fc78b5b6-7fad-4f8f-a5a3-c7c38931daba\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"04c12e9a-e025-457c-a634-5f7472a42985\"\n\t\t},\n\t\t\"server/src/service/v1/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.js-simstep-2127e749-80b4-499a-ae14-8dc2dcc9db9b\": {\n\t\t\t\"path\": \"server/src/service/v1/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.js-simstep-2127e749-80b4-499a-ae14-8dc2dcc9db9b\",\n\t\t\t\"fileName\": \"SuperSimpleQueueHelper.js\",\n\t\t\t\"wiki\": \"The `isInMaintenanceWindow` function calls the database module to fetch all maintenance windows associated with the given monitor ID and team ID.\",\n\t\t\t\"cellName\": \"Flow: Monitor Suppression - Fetching Maintenance Windows - SuperSimpleQueueHelper.js:L80-83\",\n\t\t\t\"cellId\": \"fc78b5b6-7fad-4f8f-a5a3-c7c38931daba\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 80,\n\t\t\t\"endLine\": 83,\n\t\t\t\"parentCellId\": \"04c12e9a-e025-457c-a634-5f7472a42985\",\n\t\t\t\"parentPath\": \"server/src/service/v1/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Scheduled Maintenance Windows\",\n\t\t\t\t\t\"simStepId\": \"2127e749-80b4-499a-ae14-8dc2dcc9db9b\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"0fe32416-db43-49b9-9438-3796ba1a0add\": {\n\t\t\t\"path\": \"0fe32416-db43-49b9-9438-3796ba1a0add\",\n\t\t\t\"cellName\": \"Flow: Monitor Suppression - Time Evaluation - SuperSimpleQueueHelper.js:L85-113\",\n\t\t\t\"cellId\": \"0fe32416-db43-49b9-9438-3796ba1a0add\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"04c12e9a-e025-457c-a634-5f7472a42985\"\n\t\t},\n\t\t\"server/src/service/v1/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.js-simstep-6ba6b9d1-5fc3-454e-8744-2022b5192ed9\": {\n\t\t\t\"path\": \"server/src/service/v1/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.js-simstep-6ba6b9d1-5fc3-454e-8744-2022b5192ed9\",\n\t\t\t\"fileName\": \"SuperSimpleQueueHelper.js\",\n\t\t\t\"wiki\": \"The `isInMaintenanceWindow` function iterates through the returned windows. For each active window, it checks if the current time (`new Date()`) is between the `start` and `end` times.\",\n\t\t\t\"cellName\": \"Flow: Monitor Suppression - Time Evaluation - SuperSimpleQueueHelper.js:L85-113\",\n\t\t\t\"cellId\": \"0fe32416-db43-49b9-9438-3796ba1a0add\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 85,\n\t\t\t\"endLine\": 113,\n\t\t\t\"parentCellId\": \"04c12e9a-e025-457c-a634-5f7472a42985\",\n\t\t\t\"parentPath\": \"server/src/service/v1/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Scheduled Maintenance Windows\",\n\t\t\t\t\t\"simStepId\": \"6ba6b9d1-5fc3-454e-8744-2022b5192ed9\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"01e042c3-40b4-416a-8d9e-6d6fd323d60b\": {\n\t\t\t\"path\": \"01e042c3-40b4-416a-8d9e-6d6fd323d60b\",\n\t\t\t\"cellName\": \"Flow: Monitor Suppression - Conditional Job Termination - SuperSimpleQueueHelper.js:L37-44\",\n\t\t\t\"cellId\": \"01e042c3-40b4-416a-8d9e-6d6fd323d60b\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"04c12e9a-e025-457c-a634-5f7472a42985\"\n\t\t},\n\t\t\"server/src/service/v1/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.js-simstep-e59fe64e-f06b-4855-b631-923bb5a68540\": {\n\t\t\t\"path\": \"server/src/service/v1/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.js-simstep-e59fe64e-f06b-4855-b631-923bb5a68540\",\n\t\t\t\"fileName\": \"SuperSimpleQueueHelper.js\",\n\t\t\t\"wiki\": \"If the `isInMaintenanceWindow` function returns true, the `getMonitorJob` logs that the monitor is in a maintenance window and terminates its execution for this cycle, effectively suppressing the check.\",\n\t\t\t\"cellName\": \"Flow: Monitor Suppression - Conditional Job Termination - SuperSimpleQueueHelper.js:L37-44\",\n\t\t\t\"cellId\": \"01e042c3-40b4-416a-8d9e-6d6fd323d60b\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 37,\n\t\t\t\"endLine\": 44,\n\t\t\t\"parentCellId\": \"04c12e9a-e025-457c-a634-5f7472a42985\",\n\t\t\t\"parentPath\": \"server/src/service/v1/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Scheduled Maintenance Windows\",\n\t\t\t\t\t\"simStepId\": \"e59fe64e-f06b-4855-b631-923bb5a68540\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"d3bdc6ff-875e-472e-88c8-eb10b20c526e\": {\n\t\t\t\"path\": \"d3bdc6ff-875e-472e-88c8-eb10b20c526e\",\n\t\t\t\"cellName\": \"Flow: Create\\nMaintenance Window\\n- Form\\nSubmission\",\n\t\t\t\"cellId\": \"d3bdc6ff-875e-472e-88c8-eb10b20c526e\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"6f7119ac-d65a-4fdf-a6f2-31052e0f5549\"\n\t\t},\n\t\t\"generated-edge-simstep-f881435b-3bc2-453d-b6bf-56ad3a12f120-d3bdc6ff-875e-472e-88c8-eb10b20c526e\": {\n\t\t\t\"path\": \"generated-edge-simstep-f881435b-3bc2-453d-b6bf-56ad3a12f120-d3bdc6ff-875e-472e-88c8-eb10b20c526e\",\n\t\t\t\"fileName\": \"index.jsx\",\n\t\t\t\"cellName\": \"Flow: Create Maintenance Window - Form Submission\",\n\t\t\t\"cellId\": \"d3bdc6ff-875e-472e-88c8-eb10b20c526e\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 108,\n\t\t\t\"endLine\": 109,\n\t\t\t\"parentPath\": \"client/src/Pages/v1/Maintenance/CreateMaintenance/index.jsx\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Scheduled Maintenance Windows\",\n\t\t\t\t\t\"simStepId\": \"f881435b-3bc2-453d-b6bf-56ad3a12f120\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"fd5e4447-123b-4b2d-8bce-1d1ae7cb00af\": {\n\t\t\t\"path\": \"fd5e4447-123b-4b2d-8bce-1d1ae7cb00af\",\n\t\t\t\"cellName\": \"Flow: Create\\nMaintenance Window\\n- API\\nCall\",\n\t\t\t\"cellId\": \"fd5e4447-123b-4b2d-8bce-1d1ae7cb00af\",\n\t\t\t\"visible\": true\n\t\t},\n\t\t\"generated-edge-simstep-0660b48b-139f-4ecf-b7d9-f12f544e0ab5-fd5e4447-123b-4b2d-8bce-1d1ae7cb00af\": {\n\t\t\t\"path\": \"generated-edge-simstep-0660b48b-139f-4ecf-b7d9-f12f544e0ab5-fd5e4447-123b-4b2d-8bce-1d1ae7cb00af\",\n\t\t\t\"fileName\": \"useMaintenanceActions.jsx\",\n\t\t\t\"cellName\": \"Flow: Create Maintenance Window - API Call\",\n\t\t\t\"cellId\": \"fd5e4447-123b-4b2d-8bce-1d1ae7cb00af\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 762,\n\t\t\t\"endLine\": 766,\n\t\t\t\"parentPath\": \"client/src/Pages/v1/Maintenance/CreateMaintenance/hooks/useMaintenanceActions.jsx\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Scheduled Maintenance Windows\",\n\t\t\t\t\t\"simStepId\": \"0660b48b-139f-4ecf-b7d9-f12f544e0ab5\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"e2588541-3ffc-47c6-8f8a-41d30ea7fc72\": {\n\t\t\t\"path\": \"e2588541-3ffc-47c6-8f8a-41d30ea7fc72\",\n\t\t\t\"cellName\": \"Flow: Create\\nMaintenance Window\\n- Controller\\nInvocation\",\n\t\t\t\"cellId\": \"e2588541-3ffc-47c6-8f8a-41d30ea7fc72\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\"\n\t\t},\n\t\t\"generated-edge-simstep-e4cc5ce8-6da9-4281-9204-29c061ab13ce-e2588541-3ffc-47c6-8f8a-41d30ea7fc72\": {\n\t\t\t\"path\": \"generated-edge-simstep-e4cc5ce8-6da9-4281-9204-29c061ab13ce-e2588541-3ffc-47c6-8f8a-41d30ea7fc72\",\n\t\t\t\"fileName\": \"routes.js\",\n\t\t\t\"cellName\": \"Flow: Create Maintenance Window - Controller Invocation\",\n\t\t\t\"cellId\": \"e2588541-3ffc-47c6-8f8a-41d30ea7fc72\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 10,\n\t\t\t\"endLine\": 10,\n\t\t\t\"parentPath\": \"server/src/config/routes.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Scheduled Maintenance Windows\",\n\t\t\t\t\t\"simStepId\": \"e4cc5ce8-6da9-4281-9204-29c061ab13ce\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"e1d59cf6-0d96-4e0a-ad17-2a7984a9157f\": {\n\t\t\t\"path\": \"e1d59cf6-0d96-4e0a-ad17-2a7984a9157f\",\n\t\t\t\"cellName\": \"Flow: Create\\nMaintenance Window\\n- Service\\nLayer Call\",\n\t\t\t\"cellId\": \"e1d59cf6-0d96-4e0a-ad17-2a7984a9157f\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\"\n\t\t},\n\t\t\"generated-edge-simstep-c3d1a95c-e93d-499a-8830-a6d870902414-e1d59cf6-0d96-4e0a-ad17-2a7984a9157f\": {\n\t\t\t\"path\": \"generated-edge-simstep-c3d1a95c-e93d-499a-8830-a6d870902414-e1d59cf6-0d96-4e0a-ad17-2a7984a9157f\",\n\t\t\t\"fileName\": \"maintenanceWindowController.js\",\n\t\t\t\"cellName\": \"Flow: Create Maintenance Window - Service Layer Call\",\n\t\t\t\"cellId\": \"e1d59cf6-0d96-4e0a-ad17-2a7984a9157f\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 35,\n\t\t\t\"endLine\": 35,\n\t\t\t\"parentPath\": \"server/src/controllers/v1/maintenanceWindowController.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Scheduled Maintenance Windows\",\n\t\t\t\t\t\"simStepId\": \"c3d1a95c-e93d-499a-8830-a6d870902414\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"12d0ab8a-392f-48fa-9efa-06ffe1f3a252\": {\n\t\t\t\"path\": \"12d0ab8a-392f-48fa-9efa-06ffe1f3a252\",\n\t\t\t\"cellName\": \"Flow: Create\\nMaintenance Window\\n- Database\\nModule Call\",\n\t\t\t\"cellId\": \"12d0ab8a-392f-48fa-9efa-06ffe1f3a252\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\"\n\t\t},\n\t\t\"generated-edge-simstep-80aed28e-68b6-47bf-8bc9-ededb4824066-12d0ab8a-392f-48fa-9efa-06ffe1f3a252\": {\n\t\t\t\"path\": \"generated-edge-simstep-80aed28e-68b6-47bf-8bc9-ededb4824066-12d0ab8a-392f-48fa-9efa-06ffe1f3a252\",\n\t\t\t\"fileName\": \"maintenanceWindowService.js\",\n\t\t\t\"cellName\": \"Flow: Create Maintenance Window - Database Module Call\",\n\t\t\t\"cellId\": \"12d0ab8a-392f-48fa-9efa-06ffe1f3a252\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 28,\n\t\t\t\"endLine\": 37,\n\t\t\t\"parentPath\": \"server/src/service/v1/business/maintenanceWindowService.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Scheduled Maintenance Windows\",\n\t\t\t\t\t\"simStepId\": \"80aed28e-68b6-47bf-8bc9-ededb4824066\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"fcf4eef4-394c-4872-9124-f7a0b32cdc3b\": {\n\t\t\t\"path\": \"fcf4eef4-394c-4872-9124-f7a0b32cdc3b\",\n\t\t\t\"cellName\": \"Flow: Create\\nMaintenance Window\\n- API\\nResponse\",\n\t\t\t\"cellId\": \"fcf4eef4-394c-4872-9124-f7a0b32cdc3b\",\n\t\t\t\"visible\": true\n\t\t},\n\t\t\"generated-edge-simstep-69fdc2a9-837f-466c-9562-a12319019580-fcf4eef4-394c-4872-9124-f7a0b32cdc3b\": {\n\t\t\t\"path\": \"generated-edge-simstep-69fdc2a9-837f-466c-9562-a12319019580-fcf4eef4-394c-4872-9124-f7a0b32cdc3b\",\n\t\t\t\"fileName\": \"maintenanceWindowModule.js\",\n\t\t\t\"cellName\": \"Flow: Create Maintenance Window - API Response\",\n\t\t\t\"cellId\": \"fcf4eef4-394c-4872-9124-f7a0b32cdc3b\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 37,\n\t\t\t\"endLine\": 39,\n\t\t\t\"parentPath\": \"server/src/db/v1/modules/maintenanceWindowModule.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Scheduled Maintenance Windows\",\n\t\t\t\t\t\"simStepId\": \"69fdc2a9-837f-466c-9562-a12319019580\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"7f921125-500f-4902-abc3-936ecac033d8\": {\n\t\t\t\"path\": \"7f921125-500f-4902-abc3-936ecac033d8\",\n\t\t\t\"cellName\": \"Flow: View\\nMaintenance Windows\\n- API\\nCall\",\n\t\t\t\"cellId\": \"7f921125-500f-4902-abc3-936ecac033d8\",\n\t\t\t\"visible\": true\n\t\t},\n\t\t\"generated-edge-simstep-7e20cd6c-d24e-4540-86d6-d6a9fa087314-7f921125-500f-4902-abc3-936ecac033d8\": {\n\t\t\t\"path\": \"generated-edge-simstep-7e20cd6c-d24e-4540-86d6-d6a9fa087314-7f921125-500f-4902-abc3-936ecac033d8\",\n\t\t\t\"fileName\": \"index.jsx\",\n\t\t\t\"cellName\": \"Flow: View Maintenance Windows - API Call\",\n\t\t\t\"cellId\": \"7f921125-500f-4902-abc3-936ecac033d8\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 824,\n\t\t\t\"endLine\": 824,\n\t\t\t\"parentPath\": \"client/src/Pages/v1/Maintenance/index.jsx\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Scheduled Maintenance Windows\",\n\t\t\t\t\t\"simStepId\": \"7e20cd6c-d24e-4540-86d6-d6a9fa087314\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"c3127c74-43f1-42d7-8da6-b0a494c3658f\": {\n\t\t\t\"path\": \"c3127c74-43f1-42d7-8da6-b0a494c3658f\",\n\t\t\t\"cellName\": \"Flow: View\\nMaintenance Windows\\n- Database\\nQuery\",\n\t\t\t\"cellId\": \"c3127c74-43f1-42d7-8da6-b0a494c3658f\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\"\n\t\t},\n\t\t\"generated-edge-simstep-feb8bd4f-339f-4132-a709-89c63c4efa9c-c3127c74-43f1-42d7-8da6-b0a494c3658f\": {\n\t\t\t\"path\": \"generated-edge-simstep-feb8bd4f-339f-4132-a709-89c63c4efa9c-c3127c74-43f1-42d7-8da6-b0a494c3658f\",\n\t\t\t\"fileName\": \"maintenanceWindowController.js\",\n\t\t\t\"cellName\": \"Flow: View Maintenance Windows - Database Query\",\n\t\t\t\"cellId\": \"c3127c74-43f1-42d7-8da6-b0a494c3658f\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 48,\n\t\t\t\"endLine\": 48,\n\t\t\t\"parentPath\": \"server/src/controllers/v1/maintenanceWindowController.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Scheduled Maintenance Windows\",\n\t\t\t\t\t\"simStepId\": \"feb8bd4f-339f-4132-a709-89c63c4efa9c\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"6c9979cd-1cc1-4227-b535-2ec3a10ca27e\": {\n\t\t\t\"path\": \"6c9979cd-1cc1-4227-b535-2ec3a10ca27e\",\n\t\t\t\"cellName\": \"Flow: View\\nMaintenance Windows\\n- Data\\nReturn to\\nFrontend\",\n\t\t\t\"cellId\": \"6c9979cd-1cc1-4227-b535-2ec3a10ca27e\",\n\t\t\t\"visible\": true\n\t\t},\n\t\t\"generated-edge-simstep-eda86dca-dea6-4671-a079-7d212f4f18c4-6c9979cd-1cc1-4227-b535-2ec3a10ca27e\": {\n\t\t\t\"path\": \"generated-edge-simstep-eda86dca-dea6-4671-a079-7d212f4f18c4-6c9979cd-1cc1-4227-b535-2ec3a10ca27e\",\n\t\t\t\"fileName\": \"maintenanceWindowModule.js\",\n\t\t\t\"cellName\": \"Flow: View Maintenance Windows - Data Return to Frontend\",\n\t\t\t\"cellId\": \"6c9979cd-1cc1-4227-b535-2ec3a10ca27e\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 77,\n\t\t\t\"endLine\": 80,\n\t\t\t\"parentPath\": \"server/src/db/v1/modules/maintenanceWindowModule.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Scheduled Maintenance Windows\",\n\t\t\t\t\t\"simStepId\": \"eda86dca-dea6-4671-a079-7d212f4f18c4\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"c99291bb-7316-440e-9a7f-323ee39e26b8\": {\n\t\t\t\"path\": \"c99291bb-7316-440e-9a7f-323ee39e26b8\",\n\t\t\t\"cellName\": \"Flow: Monitor\\nSuppression -\\nMaintenance Check\\nCall\",\n\t\t\t\"cellId\": \"c99291bb-7316-440e-9a7f-323ee39e26b8\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"04c12e9a-e025-457c-a634-5f7472a42985\"\n\t\t},\n\t\t\"generated-edge-simstep-87583096-f1ec-4160-ae52-5238f32ed0ab-c99291bb-7316-440e-9a7f-323ee39e26b8\": {\n\t\t\t\"path\": \"generated-edge-simstep-87583096-f1ec-4160-ae52-5238f32ed0ab-c99291bb-7316-440e-9a7f-323ee39e26b8\",\n\t\t\t\"fileName\": \"SuperSimpleQueueHelper.js\",\n\t\t\t\"cellName\": \"Flow: Monitor Suppression - Maintenance Check Call\",\n\t\t\t\"cellId\": \"c99291bb-7316-440e-9a7f-323ee39e26b8\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 36,\n\t\t\t\"endLine\": 36,\n\t\t\t\"parentPath\": \"server/src/service/v1/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Scheduled Maintenance Windows\",\n\t\t\t\t\t\"simStepId\": \"87583096-f1ec-4160-ae52-5238f32ed0ab\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"8a13e585-2310-420b-9e92-211b6d65f201\": {\n\t\t\t\"path\": \"8a13e585-2310-420b-9e92-211b6d65f201\",\n\t\t\t\"cellName\": \"Flow: Monitor\\nSuppression -\\nDatabase Result\\nReturn\",\n\t\t\t\"cellId\": \"8a13e585-2310-420b-9e92-211b6d65f201\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"04c12e9a-e025-457c-a634-5f7472a42985\"\n\t\t},\n\t\t\"generated-edge-simstep-e6542e14-556d-482a-8c35-f7b03997be49-8a13e585-2310-420b-9e92-211b6d65f201\": {\n\t\t\t\"path\": \"generated-edge-simstep-e6542e14-556d-482a-8c35-f7b03997be49-8a13e585-2310-420b-9e92-211b6d65f201\",\n\t\t\t\"fileName\": \"SuperSimpleQueueHelper.js\",\n\t\t\t\"cellName\": \"Flow: Monitor Suppression - Database Result Return\",\n\t\t\t\"cellId\": \"8a13e585-2310-420b-9e92-211b6d65f201\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 69,\n\t\t\t\"endLine\": 76,\n\t\t\t\"parentPath\": \"server/src/service/v1/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Scheduled Maintenance Windows\",\n\t\t\t\t\t\"simStepId\": \"e6542e14-556d-482a-8c35-f7b03997be49\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"40f4d9df-4c0f-4384-901c-8d7117e3b538\": {\n\t\t\t\"path\": \"40f4d9df-4c0f-4384-901c-8d7117e3b538\",\n\t\t\t\"cellName\": \"Flow: Monitor\\nSuppression -\\nReturn Suppression\\nFlag\",\n\t\t\t\"cellId\": \"40f4d9df-4c0f-4384-901c-8d7117e3b538\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"04c12e9a-e025-457c-a634-5f7472a42985\"\n\t\t},\n\t\t\"generated-edge-simstep-a715d98f-60bf-4f32-aae6-21ee4e09f4da-40f4d9df-4c0f-4384-901c-8d7117e3b538\": {\n\t\t\t\"path\": \"generated-edge-simstep-a715d98f-60bf-4f32-aae6-21ee4e09f4da-40f4d9df-4c0f-4384-901c-8d7117e3b538\",\n\t\t\t\"fileName\": \"SuperSimpleQueueHelper.js\",\n\t\t\t\"cellName\": \"Flow: Monitor Suppression - Return Suppression Flag\",\n\t\t\t\"cellId\": \"40f4d9df-4c0f-4384-901c-8d7117e3b538\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 114,\n\t\t\t\"endLine\": 114,\n\t\t\t\"parentPath\": \"server/src/service/v1/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Scheduled Maintenance Windows\",\n\t\t\t\t\t\"simStepId\": \"a715d98f-60bf-4f32-aae6-21ee4e09f4da\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"a968db5d-8f6d-4fd7-9df0-8b332b521703\": {\n\t\t\t\"path\": \"a968db5d-8f6d-4fd7-9df0-8b332b521703\",\n\t\t\t\"cellName\": \"middleware\",\n\t\t\t\"cellId\": \"a968db5d-8f6d-4fd7-9df0-8b332b521703\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\"\n\t\t},\n\t\t\"09082f73-e215-465f-9206-0a963fb4c7cb\": {\n\t\t\t\"path\": \"09082f73-e215-465f-9206-0a963fb4c7cb\",\n\t\t\t\"cellName\": \"v1\",\n\t\t\t\"cellId\": \"09082f73-e215-465f-9206-0a963fb4c7cb\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"a968db5d-8f6d-4fd7-9df0-8b332b521703\"\n\t\t},\n\t\t\"3cad7666-0d1a-4e31-b6ca-70d9c3a46b19\": {\n\t\t\t\"path\": \"3cad7666-0d1a-4e31-b6ca-70d9c3a46b19\",\n\t\t\t\"cellName\": \"Account\",\n\t\t\t\"cellId\": \"3cad7666-0d1a-4e31-b6ca-70d9c3a46b19\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"1a083b4a-787c-4eb4-8029-6700de987679\"\n\t\t},\n\t\t\"9edafb8a-3661-4a7e-8510-a47f3cbc7564\": {\n\t\t\t\"path\": \"9edafb8a-3661-4a7e-8510-a47f3cbc7564\",\n\t\t\t\"cellName\": \"inviteRoute.js\",\n\t\t\t\"cellId\": \"9edafb8a-3661-4a7e-8510-a47f3cbc7564\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"d3375a20-2776-4771-b806-649bbeb541bd\"\n\t\t},\n\t\t\"001fa2e4-eadd-4474-b2ec-79d7ea43465f\": {\n\t\t\t\"path\": \"001fa2e4-eadd-4474-b2ec-79d7ea43465f\",\n\t\t\t\"cellName\": \"isAllowed.js\",\n\t\t\t\"cellId\": \"001fa2e4-eadd-4474-b2ec-79d7ea43465f\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"09082f73-e215-465f-9206-0a963fb4c7cb\"\n\t\t},\n\t\t\"6a186805-9d50-4bc3-9d56-e627a7ec2eb8\": {\n\t\t\t\"path\": \"6a186805-9d50-4bc3-9d56-e627a7ec2eb8\",\n\t\t\t\"cellName\": \"inviteController.js\",\n\t\t\t\"cellId\": \"6a186805-9d50-4bc3-9d56-e627a7ec2eb8\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"fc591f7a-d4ac-4565-949d-a87a58a79bbc\"\n\t\t},\n\t\t\"33960806-1b9e-4d61-a163-e4bebf82d87a\": {\n\t\t\t\"path\": \"33960806-1b9e-4d61-a163-e4bebf82d87a\",\n\t\t\t\"cellName\": \"index.jsx\",\n\t\t\t\"cellId\": \"33960806-1b9e-4d61-a163-e4bebf82d87a\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"3cad7666-0d1a-4e31-b6ca-70d9c3a46b19\"\n\t\t},\n\t\t\"425a4c15-043f-4d05-8832-da00e18f97b9\": {\n\t\t\t\"path\": \"425a4c15-043f-4d05-8832-da00e18f97b9\",\n\t\t\t\"cellName\": \"components\",\n\t\t\t\"cellId\": \"425a4c15-043f-4d05-8832-da00e18f97b9\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"3cad7666-0d1a-4e31-b6ca-70d9c3a46b19\"\n\t\t},\n\t\t\"570278b7-9b72-4299-9fd9-46b253b48e9b\": {\n\t\t\t\"path\": \"570278b7-9b72-4299-9fd9-46b253b48e9b\",\n\t\t\t\"cellName\": \"inviteService.js\",\n\t\t\t\"cellId\": \"570278b7-9b72-4299-9fd9-46b253b48e9b\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"87d3b101-9443-4ed4-9c4f-f759d41677eb\"\n\t\t},\n\t\t\"08853f8a-f596-4df0-9190-dad04f54caef\": {\n\t\t\t\"path\": \"08853f8a-f596-4df0-9190-dad04f54caef\",\n\t\t\t\"cellName\": \"inviteModule.js\",\n\t\t\t\"cellId\": \"08853f8a-f596-4df0-9190-dad04f54caef\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"82cb3dbe-c922-438a-a912-255376f4b380\"\n\t\t},\n\t\t\"1145f351-2257-411d-86f7-30bf8c26ad68\": {\n\t\t\t\"path\": \"1145f351-2257-411d-86f7-30bf8c26ad68\",\n\t\t\t\"cellName\": \"TeamPanel.jsx\",\n\t\t\t\"cellId\": \"1145f351-2257-411d-86f7-30bf8c26ad68\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"425a4c15-043f-4d05-8832-da00e18f97b9\"\n\t\t},\n\t\t\"3de2d413-5e9b-49f4-9409-74be32c52e0f\": {\n\t\t\t\"path\": \"3de2d413-5e9b-49f4-9409-74be32c52e0f\",\n\t\t\t\"cellName\": \"Client: Conditional UI Rendering Based on Role - index.jsx:L37-41\",\n\t\t\t\"cellId\": \"3de2d413-5e9b-49f4-9409-74be32c52e0f\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"33960806-1b9e-4d61-a163-e4bebf82d87a\"\n\t\t},\n\t\t\"client/src/Pages/v1/Account/index.jsx-simstep-2d5a952a-ce62-4948-9309-96b28ad74e59\": {\n\t\t\t\"path\": \"client/src/Pages/v1/Account/index.jsx-simstep-2d5a952a-ce62-4948-9309-96b28ad74e59\",\n\t\t\t\"fileName\": \"index.jsx\",\n\t\t\t\"wiki\": \"A user with 'superadmin' or 'admin' role navigates to the Account page. The application checks the user's role stored in the Redux state to conditionally render the 'Team' management tab. Non-admin users will not see this option.\",\n\t\t\t\"cellName\": \"Client: Conditional UI Rendering Based on Role - index.jsx:L37-41\",\n\t\t\t\"cellId\": \"3de2d413-5e9b-49f4-9409-74be32c52e0f\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 37,\n\t\t\t\"endLine\": 41,\n\t\t\t\"parentCellId\": \"33960806-1b9e-4d61-a163-e4bebf82d87a\",\n\t\t\t\"parentPath\": \"client/src/Pages/v1/Account/index.jsx\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"User and Team Management with Role-Based Access\",\n\t\t\t\t\t\"simStepId\": \"2d5a952a-ce62-4948-9309-96b28ad74e59\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"b27f1bba-c655-40c6-a1dc-71e78c590c92\": {\n\t\t\t\"path\": \"b27f1bba-c655-40c6-a1dc-71e78c590c92\",\n\t\t\t\"cellName\": \"Client: Initiate User Invitation - TeamPanel.jsx:L348-354\",\n\t\t\t\"cellId\": \"b27f1bba-c655-40c6-a1dc-71e78c590c92\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"1145f351-2257-411d-86f7-30bf8c26ad68\"\n\t\t},\n\t\t\"client/src/Pages/v1/Account/components/TeamPanel.jsx-simstep-eebaca25-d588-49c4-a35c-9abc82fde580\": {\n\t\t\t\"path\": \"client/src/Pages/v1/Account/components/TeamPanel.jsx-simstep-eebaca25-d588-49c4-a35c-9abc82fde580\",\n\t\t\t\"fileName\": \"TeamPanel.jsx\",\n\t\t\t\"wiki\": \"In the `TeamPanel`, the admin clicks the 'Add Team Member' button, then selects 'Invite a team member'. A dialog opens, prompting for the new user's email and role. After filling the form and clicking 'E-mail token', the `handleInviteMember` function is triggered to start the invitation process.\",\n\t\t\t\"cellName\": \"Client: Initiate User Invitation - TeamPanel.jsx:L348-354\",\n\t\t\t\"cellId\": \"b27f1bba-c655-40c6-a1dc-71e78c590c92\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 348,\n\t\t\t\"endLine\": 354,\n\t\t\t\"parentCellId\": \"1145f351-2257-411d-86f7-30bf8c26ad68\",\n\t\t\t\"parentPath\": \"client/src/Pages/v1/Account/components/TeamPanel.jsx\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"User and Team Management with Role-Based Access\",\n\t\t\t\t\t\"simStepId\": \"eebaca25-d588-49c4-a35c-9abc82fde580\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"8b3cb6c2-ed57-4510-be15-decb8e3c89e1\": {\n\t\t\t\"path\": \"8b3cb6c2-ed57-4510-be15-decb8e3c89e1\",\n\t\t\t\"cellName\": \"Server: Role-Based Access Control Middleware - isAllowed.js:L39-44\",\n\t\t\t\"cellId\": \"8b3cb6c2-ed57-4510-be15-decb8e3c89e1\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"001fa2e4-eadd-4474-b2ec-79d7ea43465f\"\n\t\t},\n\t\t\"server/src/middleware/v1/isAllowed.js-simstep-50dd7316-7d01-43f7-9036-d97d51a9c178\": {\n\t\t\t\"path\": \"server/src/middleware/v1/isAllowed.js-simstep-50dd7316-7d01-43f7-9036-d97d51a9c178\",\n\t\t\t\"fileName\": \"isAllowed.js\",\n\t\t\t\"wiki\": \"The server receives the request. Before reaching the main controller, the `isAllowed` middleware intercepts the request. It verifies the JWT from the request header and checks if the user's role (e.g., 'superadmin') is present in the list of allowed roles for this route (`['admin', 'superadmin']`).\",\n\t\t\t\"cellName\": \"Server: Role-Based Access Control Middleware - isAllowed.js:L39-44\",\n\t\t\t\"cellId\": \"8b3cb6c2-ed57-4510-be15-decb8e3c89e1\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 39,\n\t\t\t\"endLine\": 44,\n\t\t\t\"parentCellId\": \"001fa2e4-eadd-4474-b2ec-79d7ea43465f\",\n\t\t\t\"parentPath\": \"server/src/middleware/v1/isAllowed.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"User and Team Management with Role-Based Access\",\n\t\t\t\t\t\"simStepId\": \"50dd7316-7d01-43f7-9036-d97d51a9c178\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"ae858158-8db6-4917-8fda-0966a953f6ed\": {\n\t\t\t\"path\": \"ae858158-8db6-4917-8fda-0966a953f6ed\",\n\t\t\t\"cellName\": \"Server: Process Invitation in Service Layer - inviteService.js:L24-28\",\n\t\t\t\"cellId\": \"ae858158-8db6-4917-8fda-0966a953f6ed\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"570278b7-9b72-4299-9fd9-46b253b48e9b\"\n\t\t},\n\t\t\"server/src/service/v1/business/inviteService.js-simstep-55fe9963-30d2-47f8-859f-b485a77064c4\": {\n\t\t\t\"path\": \"server/src/service/v1/business/inviteService.js-simstep-55fe9963-30d2-47f8-859f-b485a77064c4\",\n\t\t\t\"fileName\": \"inviteService.js\",\n\t\t\t\"wiki\": \"The `inviteController` calls the `inviteService`. The service layer handles the business logic: it first requests an invitation token from the database module and then instructs the email service to send the invitation.\",\n\t\t\t\"cellName\": \"Server: Process Invitation in Service Layer - inviteService.js:L24-28\",\n\t\t\t\"cellId\": \"ae858158-8db6-4917-8fda-0966a953f6ed\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 24,\n\t\t\t\"endLine\": 28,\n\t\t\t\"parentCellId\": \"570278b7-9b72-4299-9fd9-46b253b48e9b\",\n\t\t\t\"parentPath\": \"server/src/service/v1/business/inviteService.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"User and Team Management with Role-Based Access\",\n\t\t\t\t\t\"simStepId\": \"55fe9963-30d2-47f8-859f-b485a77064c4\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"a7be2d0b-0227-4228-a0a6-074f7324fd89\": {\n\t\t\t\"path\": \"a7be2d0b-0227-4228-a0a6-074f7324fd89\",\n\t\t\t\"cellName\": \"Server: Dispatch Invitation Email - inviteService.js:L26-28\",\n\t\t\t\"cellId\": \"a7be2d0b-0227-4228-a0a6-074f7324fd89\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"570278b7-9b72-4299-9fd9-46b253b48e9b\"\n\t\t},\n\t\t\"server/src/service/v1/business/inviteService.js-simstep-7d1f86f2-c8d5-48fb-a8c1-b337dc56271f\": {\n\t\t\t\"path\": \"server/src/service/v1/business/inviteService.js-simstep-7d1f86f2-c8d5-48fb-a8c1-b337dc56271f\",\n\t\t\t\"fileName\": \"inviteService.js\",\n\t\t\t\"wiki\": \"After successfully storing the token, the `inviteService` uses the `emailService` to compose and send an email to the new user. The email contains a unique registration link including the generated token.\",\n\t\t\t\"cellName\": \"Server: Dispatch Invitation Email - inviteService.js:L26-28\",\n\t\t\t\"cellId\": \"a7be2d0b-0227-4228-a0a6-074f7324fd89\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 26,\n\t\t\t\"endLine\": 28,\n\t\t\t\"parentCellId\": \"570278b7-9b72-4299-9fd9-46b253b48e9b\",\n\t\t\t\"parentPath\": \"server/src/service/v1/business/inviteService.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"User and Team Management with Role-Based Access\",\n\t\t\t\t\t\"simStepId\": \"7d1f86f2-c8d5-48fb-a8c1-b337dc56271f\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"02d87257-883c-4822-a421-823c983532ec\": {\n\t\t\t\"path\": \"02d87257-883c-4822-a421-823c983532ec\",\n\t\t\t\"cellName\": \"Client: Display Success Feedback - TeamPanel.jsx:L145-149\",\n\t\t\t\"cellId\": \"02d87257-883c-4822-a421-823c983532ec\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"1145f351-2257-411d-86f7-30bf8c26ad68\"\n\t\t},\n\t\t\"client/src/Pages/v1/Account/components/TeamPanel.jsx-simstep-700f35e0-b39d-417c-b0a8-0612feade977\": {\n\t\t\t\"path\": \"client/src/Pages/v1/Account/components/TeamPanel.jsx-simstep-700f35e0-b39d-417c-b0a8-0612feade977\",\n\t\t\t\"fileName\": \"TeamPanel.jsx\",\n\t\t\t\"wiki\": \"The client application receives the successful API response. It then closes the invitation dialog and displays a toast notification to the admin, confirming that the invitation has been sent.\",\n\t\t\t\"cellName\": \"Client: Display Success Feedback - TeamPanel.jsx:L145-149\",\n\t\t\t\"cellId\": \"02d87257-883c-4822-a421-823c983532ec\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 145,\n\t\t\t\"endLine\": 149,\n\t\t\t\"parentCellId\": \"1145f351-2257-411d-86f7-30bf8c26ad68\",\n\t\t\t\"parentPath\": \"client/src/Pages/v1/Account/components/TeamPanel.jsx\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"User and Team Management with Role-Based Access\",\n\t\t\t\t\t\"simStepId\": \"700f35e0-b39d-417c-b0a8-0612feade977\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"c441312f-f3c6-48c6-b1b9-7c12749d91bb\": {\n\t\t\t\"path\": \"c441312f-f3c6-48c6-b1b9-7c12749d91bb\",\n\t\t\t\"cellName\": \"Client: User\\nNavigates to\\nTeam Panel\",\n\t\t\t\"cellId\": \"c441312f-f3c6-48c6-b1b9-7c12749d91bb\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"3cad7666-0d1a-4e31-b6ca-70d9c3a46b19\"\n\t\t},\n\t\t\"generated-edge-simstep-10f80ada-2d0a-4e98-bd5d-057e7d4fe6de-c441312f-f3c6-48c6-b1b9-7c12749d91bb\": {\n\t\t\t\"path\": \"generated-edge-simstep-10f80ada-2d0a-4e98-bd5d-057e7d4fe6de-c441312f-f3c6-48c6-b1b9-7c12749d91bb\",\n\t\t\t\"fileName\": \"index.jsx\",\n\t\t\t\"cellName\": \"Client: User Navigates to Team Panel\",\n\t\t\t\"cellId\": \"c441312f-f3c6-48c6-b1b9-7c12749d91bb\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 98,\n\t\t\t\"endLine\": 98,\n\t\t\t\"parentPath\": \"client/src/Pages/v1/Account/index.jsx\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"User and Team Management with Role-Based Access\",\n\t\t\t\t\t\"simStepId\": \"10f80ada-2d0a-4e98-bd5d-057e7d4fe6de\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"3530244f-2689-444e-bcbf-611db2e3c000\": {\n\t\t\t\"path\": \"3530244f-2689-444e-bcbf-611db2e3c000\",\n\t\t\t\"cellName\": \"API Call:\\nSend Invitation\\nRequest\",\n\t\t\t\"cellId\": \"3530244f-2689-444e-bcbf-611db2e3c000\",\n\t\t\t\"visible\": true\n\t\t},\n\t\t\"generated-edge-simstep-16d87608-4458-430c-b459-cd9b1d413fa6-3530244f-2689-444e-bcbf-611db2e3c000\": {\n\t\t\t\"path\": \"generated-edge-simstep-16d87608-4458-430c-b459-cd9b1d413fa6-3530244f-2689-444e-bcbf-611db2e3c000\",\n\t\t\t\"fileName\": \"TeamPanel.jsx\",\n\t\t\t\"cellName\": \"API Call: Send Invitation Request\",\n\t\t\t\"cellId\": \"3530244f-2689-444e-bcbf-611db2e3c000\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 14,\n\t\t\t\"endLine\": 14,\n\t\t\t\"parentPath\": \"client/src/Pages/v1/Account/components/TeamPanel.jsx\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"User and Team Management with Role-Based Access\",\n\t\t\t\t\t\"simStepId\": \"16d87608-4458-430c-b459-cd9b1d413fa6\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"2ee1c4e8-90fb-4470-ad9f-6ffed5420853\": {\n\t\t\t\"path\": \"2ee1c4e8-90fb-4470-ad9f-6ffed5420853\",\n\t\t\t\"cellName\": \"Server: Forward\\nRequest to\\nController\",\n\t\t\t\"cellId\": \"2ee1c4e8-90fb-4470-ad9f-6ffed5420853\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\"\n\t\t},\n\t\t\"generated-edge-simstep-6c024d4c-178b-45fc-8bca-4fc6c00549a4-2ee1c4e8-90fb-4470-ad9f-6ffed5420853\": {\n\t\t\t\"path\": \"generated-edge-simstep-6c024d4c-178b-45fc-8bca-4fc6c00549a4-2ee1c4e8-90fb-4470-ad9f-6ffed5420853\",\n\t\t\t\"fileName\": \"isAllowed.js\",\n\t\t\t\"cellName\": \"Server: Forward Request to Controller\",\n\t\t\t\"cellId\": \"2ee1c4e8-90fb-4470-ad9f-6ffed5420853\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 61,\n\t\t\t\"endLine\": 68,\n\t\t\t\"parentPath\": \"server/src/middleware/v1/isAllowed.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"User and Team Management with Role-Based Access\",\n\t\t\t\t\t\"simStepId\": \"6c024d4c-178b-45fc-8bca-4fc6c00549a4\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"bdd52e6f-ddf7-4966-b3af-957f9553082f\": {\n\t\t\t\"path\": \"bdd52e6f-ddf7-4966-b3af-957f9553082f\",\n\t\t\t\"cellName\": \"Database Query:\\nCreate and\\nStore Invite\\nToken\",\n\t\t\t\"cellId\": \"bdd52e6f-ddf7-4966-b3af-957f9553082f\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"570278b7-9b72-4299-9fd9-46b253b48e9b\"\n\t\t},\n\t\t\"generated-edge-simstep-c796f8ad-d548-45f3-8d62-67f59c6c1aa4-bdd52e6f-ddf7-4966-b3af-957f9553082f\": {\n\t\t\t\"path\": \"generated-edge-simstep-c796f8ad-d548-45f3-8d62-67f59c6c1aa4-bdd52e6f-ddf7-4966-b3af-957f9553082f\",\n\t\t\t\"fileName\": \"inviteService.js\",\n\t\t\t\"cellName\": \"Database Query: Create and Store Invite Token\",\n\t\t\t\"cellId\": \"bdd52e6f-ddf7-4966-b3af-957f9553082f\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 23,\n\t\t\t\"endLine\": 26,\n\t\t\t\"parentPath\": \"server/src/service/v1/business/inviteService.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"User and Team Management with Role-Based Access\",\n\t\t\t\t\t\"simStepId\": \"c796f8ad-d548-45f3-8d62-67f59c6c1aa4\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"52732a37-82b8-40a7-b12d-dc1b82380b2d\": {\n\t\t\t\"path\": \"52732a37-82b8-40a7-b12d-dc1b82380b2d\",\n\t\t\t\"cellName\": \"API Response:\\nSend Confirmation\\nto Client\",\n\t\t\t\"cellId\": \"52732a37-82b8-40a7-b12d-dc1b82380b2d\",\n\t\t\t\"visible\": true\n\t\t},\n\t\t\"generated-edge-simstep-6ba5094d-d1e6-4ec3-8917-28cdb30f2ef9-52732a37-82b8-40a7-b12d-dc1b82380b2d\": {\n\t\t\t\"path\": \"generated-edge-simstep-6ba5094d-d1e6-4ec3-8917-28cdb30f2ef9-52732a37-82b8-40a7-b12d-dc1b82380b2d\",\n\t\t\t\"fileName\": \"inviteService.js\",\n\t\t\t\"cellName\": \"API Response: Send Confirmation to Client\",\n\t\t\t\"cellId\": \"52732a37-82b8-40a7-b12d-dc1b82380b2d\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 69,\n\t\t\t\"endLine\": 72,\n\t\t\t\"parentPath\": \"server/src/service/v1/business/inviteService.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"User and Team Management with Role-Based Access\",\n\t\t\t\t\t\"simStepId\": \"6ba5094d-d1e6-4ec3-8917-28cdb30f2ef9\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"56dae13e-5735-4089-a9a4-e18be315aff7\": {\n\t\t\t\"path\": \"56dae13e-5735-4089-a9a4-e18be315aff7\",\n\t\t\t\"cellName\": \"BulkImport\",\n\t\t\t\"cellId\": \"56dae13e-5735-4089-a9a4-e18be315aff7\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"7090fcdb-09be-4c85-86fd-e73553bbb2ff\"\n\t\t},\n\t\t\"29b6ad3c-9538-47bc-8796-aab942dc4b71\": {\n\t\t\t\"path\": \"29b6ad3c-9538-47bc-8796-aab942dc4b71\",\n\t\t\t\"cellName\": \"index.jsx\",\n\t\t\t\"cellId\": \"29b6ad3c-9538-47bc-8796-aab942dc4b71\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"56dae13e-5735-4089-a9a4-e18be315aff7\"\n\t\t},\n\t\t\"cd84476a-1c8b-4781-811f-58fb9944365b\": {\n\t\t\t\"path\": \"cd84476a-1c8b-4781-811f-58fb9944365b\",\n\t\t\t\"cellName\": \"Upload.jsx\",\n\t\t\t\"cellId\": \"cd84476a-1c8b-4781-811f-58fb9944365b\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"56dae13e-5735-4089-a9a4-e18be315aff7\"\n\t\t},\n\t\t\"c4caeba8-ed9a-4cbc-9888-38cc8ca55362\": {\n\t\t\t\"path\": \"c4caeba8-ed9a-4cbc-9888-38cc8ca55362\",\n\t\t\t\"cellName\": \"Flow 1: CSV Import - Navigate to Bulk Import Page - index.jsx:L88-91\",\n\t\t\t\"cellId\": \"c4caeba8-ed9a-4cbc-9888-38cc8ca55362\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"c4d7e7dd-75b1-44f1-a34a-6ed290a8e562\"\n\t\t},\n\t\t\"client/src/Routes/index.jsx-simstep-a29da01e-8c5a-4e6d-8d3c-e49af528e4fa\": {\n\t\t\t\"path\": \"client/src/Routes/index.jsx-simstep-a29da01e-8c5a-4e6d-8d3c-e49af528e4fa\",\n\t\t\t\"fileName\": \"index.jsx\",\n\t\t\t\"wiki\": \"The user navigates to the \\\"/uptime/bulk-import\\\" URL, which is routed to the BulkImport component for rendering the UI.\",\n\t\t\t\"cellName\": \"Flow 1: CSV Import - Navigate to Bulk Import Page - index.jsx:L88-91\",\n\t\t\t\"cellId\": \"c4caeba8-ed9a-4cbc-9888-38cc8ca55362\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 88,\n\t\t\t\"endLine\": 91,\n\t\t\t\"parentCellId\": \"c4d7e7dd-75b1-44f1-a34a-6ed290a8e562\",\n\t\t\t\"parentPath\": \"client/src/Routes/index.jsx\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Bulk Monitor Management\",\n\t\t\t\t\t\"simStepId\": \"a29da01e-8c5a-4e6d-8d3c-e49af528e4fa\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"6f1948fa-e84a-4f8e-8f3b-8f24c511b3d8\": {\n\t\t\t\"path\": \"6f1948fa-e84a-4f8e-8f3b-8f24c511b3d8\",\n\t\t\t\"cellName\": \"Flow 1: CSV Import - User Selects File - Upload.jsx:L23-31\",\n\t\t\t\"cellId\": \"6f1948fa-e84a-4f8e-8f3b-8f24c511b3d8\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"cd84476a-1c8b-4781-811f-58fb9944365b\"\n\t\t},\n\t\t\"client/src/Pages/v1/Uptime/BulkImport/Upload.jsx-simstep-bbd04d55-fc6a-4ba8-bcde-5a4dc263d6eb\": {\n\t\t\t\"path\": \"client/src/Pages/v1/Uptime/BulkImport/Upload.jsx-simstep-bbd04d55-fc6a-4ba8-bcde-5a4dc263d6eb\",\n\t\t\t\"fileName\": \"Upload.jsx\",\n\t\t\t\"wiki\": \"The user clicks the 'Select File' button, triggering the file input. When a file is chosen, the `handleFileChange` function validates that it's a CSV file and updates the component's state.\",\n\t\t\t\"cellName\": \"Flow 1: CSV Import - User Selects File - Upload.jsx:L23-31\",\n\t\t\t\"cellId\": \"6f1948fa-e84a-4f8e-8f3b-8f24c511b3d8\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 23,\n\t\t\t\"endLine\": 31,\n\t\t\t\"parentCellId\": \"cd84476a-1c8b-4781-811f-58fb9944365b\",\n\t\t\t\"parentPath\": \"client/src/Pages/v1/Uptime/BulkImport/Upload.jsx\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Bulk Monitor Management\",\n\t\t\t\t\t\"simStepId\": \"bbd04d55-fc6a-4ba8-bcde-5a4dc263d6eb\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"dd2f9356-fad3-47d4-81d5-a5e038298e2b\": {\n\t\t\t\"path\": \"dd2f9356-fad3-47d4-81d5-a5e038298e2b\",\n\t\t\t\"cellName\": \"Flow 1: CSV Import - Submit Upload - index.jsx:L32-45\",\n\t\t\t\"cellId\": \"dd2f9356-fad3-47d4-81d5-a5e038298e2b\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"29b6ad3c-9538-47bc-8796-aab942dc4b71\"\n\t\t},\n\t\t\"client/src/Pages/v1/Uptime/BulkImport/index.jsx-simstep-0139fcaa-eb46-4176-b7bd-1cb15e7f1f4c\": {\n\t\t\t\"path\": \"client/src/Pages/v1/Uptime/BulkImport/index.jsx-simstep-0139fcaa-eb46-4176-b7bd-1cb15e7f1f4c\",\n\t\t\t\"fileName\": \"index.jsx\",\n\t\t\t\"wiki\": \"The user clicks the submit button, which executes the `handleSubmit` function. This function calls the `createBulkMonitors` function provided by the `useCreateBulkMonitors` custom hook.\",\n\t\t\t\"cellName\": \"Flow 1: CSV Import - Submit Upload - index.jsx:L32-45\",\n\t\t\t\"cellId\": \"dd2f9356-fad3-47d4-81d5-a5e038298e2b\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 32,\n\t\t\t\"endLine\": 45,\n\t\t\t\"parentCellId\": \"29b6ad3c-9538-47bc-8796-aab942dc4b71\",\n\t\t\t\"parentPath\": \"client/src/Pages/v1/Uptime/BulkImport/index.jsx\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Bulk Monitor Management\",\n\t\t\t\t\t\"simStepId\": \"0139fcaa-eb46-4176-b7bd-1cb15e7f1f4c\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"5967e576-f542-4c0b-a3f4-9446ae992721\": {\n\t\t\t\"path\": \"5967e576-f542-4c0b-a3f4-9446ae992721\",\n\t\t\t\"cellName\": \"Flow 1: CSV Import - Send API Request - NetworkService.js:L978-983\",\n\t\t\t\"cellId\": \"5967e576-f542-4c0b-a3f4-9446ae992721\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"16731e9d-3f73-4055-9d79-5ca9be679f68\"\n\t\t},\n\t\t\"client/src/Utils/NetworkService.js-simstep-2fc087b3-033d-4cf5-81f2-e35b99a14bce\": {\n\t\t\t\"path\": \"client/src/Utils/NetworkService.js-simstep-2fc087b3-033d-4cf5-81f2-e35b99a14bce\",\n\t\t\t\"fileName\": \"NetworkService.js\",\n\t\t\t\"wiki\": \"The NetworkService sends the `FormData` containing the CSV file to the backend via a POST request to the `/monitors/bulk` endpoint. The `Content-Type` is set to `multipart/form-data`.\",\n\t\t\t\"cellName\": \"Flow 1: CSV Import - Send API Request - NetworkService.js:L978-983\",\n\t\t\t\"cellId\": \"5967e576-f542-4c0b-a3f4-9446ae992721\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 978,\n\t\t\t\"endLine\": 983,\n\t\t\t\"parentCellId\": \"16731e9d-3f73-4055-9d79-5ca9be679f68\",\n\t\t\t\"parentPath\": \"client/src/Utils/NetworkService.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Bulk Monitor Management\",\n\t\t\t\t\t\"simStepId\": \"2fc087b3-033d-4cf5-81f2-e35b99a14bce\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"c1ac3c26-996a-43ef-9c34-4c2776188784\": {\n\t\t\t\"path\": \"c1ac3c26-996a-43ef-9c34-4c2776188784\",\n\t\t\t\"cellName\": \"Flow 1: CSV Import - Server Receives Request - monitorRoute.js:L46\",\n\t\t\t\"cellId\": \"c1ac3c26-996a-43ef-9c34-4c2776188784\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"10611636-ec73-4a26-87a5-654ae64a4843\"\n\t\t},\n\t\t\"server/src/routes/v1/monitorRoute.js-simstep-07bf3d83-047d-4e51-9f96-8c9c64848500\": {\n\t\t\t\"path\": \"server/src/routes/v1/monitorRoute.js-simstep-07bf3d83-047d-4e51-9f96-8c9c64848500\",\n\t\t\t\"fileName\": \"monitorRoute.js\",\n\t\t\t\"wiki\": \"The server's monitor route receives the request. The `multer` middleware processes the file upload, making the file available in `req.file`. The request is then passed to the `createBulkMonitors` controller method.\",\n\t\t\t\"cellName\": \"Flow 1: CSV Import - Server Receives Request - monitorRoute.js:L46\",\n\t\t\t\"cellId\": \"c1ac3c26-996a-43ef-9c34-4c2776188784\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 46,\n\t\t\t\"endLine\": 46,\n\t\t\t\"parentCellId\": \"10611636-ec73-4a26-87a5-654ae64a4843\",\n\t\t\t\"parentPath\": \"server/src/routes/v1/monitorRoute.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Bulk Monitor Management\",\n\t\t\t\t\t\"simStepId\": \"07bf3d83-047d-4e51-9f96-8c9c64848500\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"0e520a6d-34bf-467b-a894-e73979364478\": {\n\t\t\t\"path\": \"0e520a6d-34bf-467b-a894-e73979364478\",\n\t\t\t\"cellName\": \"Flow 1: CSV Import - Controller Processes Data - monitorController.js:L228-232\",\n\t\t\t\"cellId\": \"0e520a6d-34bf-467b-a894-e73979364478\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"341f2784-67ee-4477-9445-a8c240ee6261\"\n\t\t},\n\t\t\"server/src/controllers/v1/monitorController.js-simstep-a3799570-64bf-481e-9ffe-31dbad8a36e4\": {\n\t\t\t\"path\": \"server/src/controllers/v1/monitorController.js-simstep-a3799570-64bf-481e-9ffe-31dbad8a36e4\",\n\t\t\t\"fileName\": \"monitorController.js\",\n\t\t\t\"wiki\": \"The controller validates the presence of the file and extracts the file data (buffer), `userId`, and `teamId`. It then calls the `monitorService.createBulkMonitors` method to handle the core logic.\",\n\t\t\t\"cellName\": \"Flow 1: CSV Import - Controller Processes Data - monitorController.js:L228-232\",\n\t\t\t\"cellId\": \"0e520a6d-34bf-467b-a894-e73979364478\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 228,\n\t\t\t\"endLine\": 232,\n\t\t\t\"parentCellId\": \"341f2784-67ee-4477-9445-a8c240ee6261\",\n\t\t\t\"parentPath\": \"server/src/controllers/v1/monitorController.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Bulk Monitor Management\",\n\t\t\t\t\t\"simStepId\": \"a3799570-64bf-481e-9ffe-31dbad8a36e4\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"6139e487-1dd5-405a-ba7d-ededec4b282e\": {\n\t\t\t\"path\": \"6139e487-1dd5-405a-ba7d-ededec4b282e\",\n\t\t\t\"cellName\": \"Flow 1: CSV Import - Service Parses CSV - monitorService.js:L85-134\",\n\t\t\t\"cellId\": \"6139e487-1dd5-405a-ba7d-ededec4b282e\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"b4e479df-9b21-4430-9383-84831f503c2e\"\n\t\t},\n\t\t\"server/src/service/v1/business/monitorService.js-simstep-2c7c3082-e4b6-4525-860f-2ffcd9e86db1\": {\n\t\t\t\"path\": \"server/src/service/v1/business/monitorService.js-simstep-2c7c3082-e4b6-4525-860f-2ffcd9e86db1\",\n\t\t\t\"fileName\": \"monitorService.js\",\n\t\t\t\"wiki\": \"The monitor service uses the `papaparse` library to parse the CSV file buffer into a JSON object array. In the `complete` callback, it enriches each record with `userId` and `teamId`.\",\n\t\t\t\"cellName\": \"Flow 1: CSV Import - Service Parses CSV - monitorService.js:L85-134\",\n\t\t\t\"cellId\": \"6139e487-1dd5-405a-ba7d-ededec4b282e\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 85,\n\t\t\t\"endLine\": 134,\n\t\t\t\"parentCellId\": \"b4e479df-9b21-4430-9383-84831f503c2e\",\n\t\t\t\"parentPath\": \"server/src/service/v1/business/monitorService.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Bulk Monitor Management\",\n\t\t\t\t\t\"simStepId\": \"2c7c3082-e4b6-4525-860f-2ffcd9e86db1\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"d9d519af-5c4d-4494-929e-a869581c1dc4\": {\n\t\t\t\"path\": \"d9d519af-5c4d-4494-929e-a869581c1dc4\",\n\t\t\t\"cellName\": \"Flow 1: CSV Import - Database Bulk Save - monitorModule.js:L465-468\",\n\t\t\t\"cellId\": \"d9d519af-5c4d-4494-929e-a869581c1dc4\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"630b3ece-2648-48d5-99b5-ef9611de2ad5\"\n\t\t},\n\t\t\"server/src/db/v1/modules/monitorModule.js-simstep-70f18c21-2918-402e-9c35-1bdce8bc82d4\": {\n\t\t\t\"path\": \"server/src/db/v1/modules/monitorModule.js-simstep-70f18c21-2918-402e-9c35-1bdce8bc82d4\",\n\t\t\t\"fileName\": \"monitorModule.js\",\n\t\t\t\"wiki\": \"The `monitorModule` uses `Monitor.bulkSave` to efficiently insert all the new monitor documents into the MongoDB database in a single operation.\",\n\t\t\t\"cellName\": \"Flow 1: CSV Import - Database Bulk Save - monitorModule.js:L465-468\",\n\t\t\t\"cellId\": \"d9d519af-5c4d-4494-929e-a869581c1dc4\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 465,\n\t\t\t\"endLine\": 468,\n\t\t\t\"parentCellId\": \"630b3ece-2648-48d5-99b5-ef9611de2ad5\",\n\t\t\t\"parentPath\": \"server/src/db/v1/modules/monitorModule.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Bulk Monitor Management\",\n\t\t\t\t\t\"simStepId\": \"70f18c21-2918-402e-9c35-1bdce8bc82d4\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"1e1d975f-7f0f-4132-bd71-2563b35e99b3\": {\n\t\t\t\"path\": \"1e1d975f-7f0f-4132-bd71-2563b35e99b3\",\n\t\t\t\"cellName\": \"Flow 1: CSV Import - Enqueue Monitor Jobs - monitorService.js:L128-132\",\n\t\t\t\"cellId\": \"1e1d975f-7f0f-4132-bd71-2563b35e99b3\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"b4e479df-9b21-4430-9383-84831f503c2e\"\n\t\t},\n\t\t\"server/src/service/v1/business/monitorService.js-simstep-66fbf913-e662-4bd9-ada6-077be9e37f07\": {\n\t\t\t\"path\": \"server/src/service/v1/business/monitorService.js-simstep-66fbf913-e662-4bd9-ada6-077be9e37f07\",\n\t\t\t\"fileName\": \"monitorService.js\",\n\t\t\t\"wiki\": \"After the monitors are saved, the service iterates through them and adds a new job to the `jobQueue` for each one, scheduling them for their first check. It then resolves the promise, returning the data up the call stack.\",\n\t\t\t\"cellName\": \"Flow 1: CSV Import - Enqueue Monitor Jobs - monitorService.js:L128-132\",\n\t\t\t\"cellId\": \"1e1d975f-7f0f-4132-bd71-2563b35e99b3\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 128,\n\t\t\t\"endLine\": 132,\n\t\t\t\"parentCellId\": \"b4e479df-9b21-4430-9383-84831f503c2e\",\n\t\t\t\"parentPath\": \"server/src/service/v1/business/monitorService.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Bulk Monitor Management\",\n\t\t\t\t\t\"simStepId\": \"66fbf913-e662-4bd9-ada6-077be9e37f07\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"72b55fa1-d944-4e46-ac98-f6a6cb201afa\": {\n\t\t\t\"path\": \"72b55fa1-d944-4e46-ac98-f6a6cb201afa\",\n\t\t\t\"cellName\": \"Flow 1: CSV Import - Send Success Response - monitorController.js:L232-235\",\n\t\t\t\"cellId\": \"72b55fa1-d944-4e46-ac98-f6a6cb201afa\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"341f2784-67ee-4477-9445-a8c240ee6261\"\n\t\t},\n\t\t\"server/src/controllers/v1/monitorController.js-simstep-f5377571-156f-4c5c-8bab-b6dacdf0fea6\": {\n\t\t\t\"path\": \"server/src/controllers/v1/monitorController.js-simstep-f5377571-156f-4c5c-8bab-b6dacdf0fea6\",\n\t\t\t\"fileName\": \"monitorController.js\",\n\t\t\t\"wiki\": \"The controller constructs a successful JSON response containing a message and the data for the newly created monitors, and sends it back to the client.\",\n\t\t\t\"cellName\": \"Flow 1: CSV Import - Send Success Response - monitorController.js:L232-235\",\n\t\t\t\"cellId\": \"72b55fa1-d944-4e46-ac98-f6a6cb201afa\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 232,\n\t\t\t\"endLine\": 235,\n\t\t\t\"parentCellId\": \"341f2784-67ee-4477-9445-a8c240ee6261\",\n\t\t\t\"parentPath\": \"server/src/controllers/v1/monitorController.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Bulk Monitor Management\",\n\t\t\t\t\t\"simStepId\": \"f5377571-156f-4c5c-8bab-b6dacdf0fea6\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"ae3b7e23-ed64-40aa-9760-389f0a869f8d\": {\n\t\t\t\"path\": \"ae3b7e23-ed64-40aa-9760-389f0a869f8d\",\n\t\t\t\"cellName\": \"Flow 1: CSV Import - Client Handles Success - index.jsx:L37-41\",\n\t\t\t\"cellId\": \"ae3b7e23-ed64-40aa-9760-389f0a869f8d\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"29b6ad3c-9538-47bc-8796-aab942dc4b71\"\n\t\t},\n\t\t\"client/src/Pages/v1/Uptime/BulkImport/index.jsx-simstep-72b3f16d-290d-4a61-8748-2ad90d63ec68\": {\n\t\t\t\"path\": \"client/src/Pages/v1/Uptime/BulkImport/index.jsx-simstep-72b3f16d-290d-4a61-8748-2ad90d63ec68\",\n\t\t\t\"fileName\": \"index.jsx\",\n\t\t\t\"wiki\": \"The client-side promise resolves. The `handleSubmit` function in the `BulkImport` component receives the success status, displays a success toast message, and navigates the user to the main uptime monitoring page.\",\n\t\t\t\"cellName\": \"Flow 1: CSV Import - Client Handles Success - index.jsx:L37-41\",\n\t\t\t\"cellId\": \"ae3b7e23-ed64-40aa-9760-389f0a869f8d\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 37,\n\t\t\t\"endLine\": 41,\n\t\t\t\"parentCellId\": \"29b6ad3c-9538-47bc-8796-aab942dc4b71\",\n\t\t\t\"parentPath\": \"client/src/Pages/v1/Uptime/BulkImport/index.jsx\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Bulk Monitor Management\",\n\t\t\t\t\t\"simStepId\": \"72b3f16d-290d-4a61-8748-2ad90d63ec68\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"26d76516-fd7e-4ae8-956a-d077de4257fa\": {\n\t\t\t\"path\": \"26d76516-fd7e-4ae8-956a-d077de4257fa\",\n\t\t\t\"cellName\": \"Flow 2: CSV Export - Initiate Export - monitorRoute.js:L45\",\n\t\t\t\"cellId\": \"26d76516-fd7e-4ae8-956a-d077de4257fa\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"10611636-ec73-4a26-87a5-654ae64a4843\"\n\t\t},\n\t\t\"server/src/routes/v1/monitorRoute.js-simstep-63d8d81f-f436-4594-a6eb-8c0fd2110bc1\": {\n\t\t\t\"path\": \"server/src/routes/v1/monitorRoute.js-simstep-63d8d81f-f436-4594-a6eb-8c0fd2110bc1\",\n\t\t\t\"fileName\": \"monitorRoute.js\",\n\t\t\t\"wiki\": \"An admin user clicks an 'Export to CSV' button in the UI. This action triggers a call to the `/monitors/export` API endpoint to begin the export process.\",\n\t\t\t\"cellName\": \"Flow 2: CSV Export - Initiate Export - monitorRoute.js:L45\",\n\t\t\t\"cellId\": \"26d76516-fd7e-4ae8-956a-d077de4257fa\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 45,\n\t\t\t\"endLine\": 45,\n\t\t\t\"parentCellId\": \"10611636-ec73-4a26-87a5-654ae64a4843\",\n\t\t\t\"parentPath\": \"server/src/routes/v1/monitorRoute.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Bulk Monitor Management\",\n\t\t\t\t\t\"simStepId\": \"63d8d81f-f436-4594-a6eb-8c0fd2110bc1\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"a3106388-6a3d-4b68-a3fc-3761a0d54f98\": {\n\t\t\t\"path\": \"a3106388-6a3d-4b68-a3fc-3761a0d54f98\",\n\t\t\t\"cellName\": \"Flow 2: CSV Export - Controller Handles Request - monitorController.js:L427-434\",\n\t\t\t\"cellId\": \"a3106388-6a3d-4b68-a3fc-3761a0d54f98\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"341f2784-67ee-4477-9445-a8c240ee6261\"\n\t\t},\n\t\t\"server/src/controllers/v1/monitorController.js-simstep-d9db3f40-8add-4551-9323-274348b9800f\": {\n\t\t\t\"path\": \"server/src/controllers/v1/monitorController.js-simstep-d9db3f40-8add-4551-9323-274348b9800f\",\n\t\t\t\"fileName\": \"monitorController.js\",\n\t\t\t\"wiki\": \"The `exportMonitorsToCSV` method in the monitor controller is invoked. It retrieves the `teamId` from the authenticated user's session and calls the monitor service to perform the export.\",\n\t\t\t\"cellName\": \"Flow 2: CSV Export - Controller Handles Request - monitorController.js:L427-434\",\n\t\t\t\"cellId\": \"a3106388-6a3d-4b68-a3fc-3761a0d54f98\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 427,\n\t\t\t\"endLine\": 434,\n\t\t\t\"parentCellId\": \"341f2784-67ee-4477-9445-a8c240ee6261\",\n\t\t\t\"parentPath\": \"server/src/controllers/v1/monitorController.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Bulk Monitor Management\",\n\t\t\t\t\t\"simStepId\": \"d9db3f40-8add-4551-9323-274348b9800f\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"ab9cb862-0ac7-45a3-9888-f64e87bdda54\": {\n\t\t\t\"path\": \"ab9cb862-0ac7-45a3-9888-f64e87bdda54\",\n\t\t\t\"cellName\": \"Flow 2: CSV Export - Generate CSV - monitorService.js:L245-266\",\n\t\t\t\"cellId\": \"ab9cb862-0ac7-45a3-9888-f64e87bdda54\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"b4e479df-9b21-4430-9383-84831f503c2e\"\n\t\t},\n\t\t\"server/src/service/v1/business/monitorService.js-simstep-85cd1d5d-7ffb-49c5-aacb-907048003fc5\": {\n\t\t\t\"path\": \"server/src/service/v1/business/monitorService.js-simstep-85cd1d5d-7ffb-49c5-aacb-907048003fc5\",\n\t\t\t\"fileName\": \"monitorService.js\",\n\t\t\t\"wiki\": \"The monitor service fetches all monitors for the given `teamId` from the database. It then maps the data into the required format and uses `papaparse` to convert the JSON array into a CSV-formatted string.\",\n\t\t\t\"cellName\": \"Flow 2: CSV Export - Generate CSV - monitorService.js:L245-266\",\n\t\t\t\"cellId\": \"ab9cb862-0ac7-45a3-9888-f64e87bdda54\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 245,\n\t\t\t\"endLine\": 266,\n\t\t\t\"parentCellId\": \"b4e479df-9b21-4430-9383-84831f503c2e\",\n\t\t\t\"parentPath\": \"server/src/service/v1/business/monitorService.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Bulk Monitor Management\",\n\t\t\t\t\t\"simStepId\": \"85cd1d5d-7ffb-49c5-aacb-907048003fc5\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"f151f89d-6399-48f0-aecd-5eb1572b48cc\": {\n\t\t\t\"path\": \"f151f89d-6399-48f0-aecd-5eb1572b48cc\",\n\t\t\t\"cellName\": \"Flow 2: CSV Export - Send File Response - monitorController.js:L434-440\",\n\t\t\t\"cellId\": \"f151f89d-6399-48f0-aecd-5eb1572b48cc\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"341f2784-67ee-4477-9445-a8c240ee6261\"\n\t\t},\n\t\t\"server/src/controllers/v1/monitorController.js-simstep-256095b8-5e3a-4c20-abd9-be9e6a9d0bad\": {\n\t\t\t\"path\": \"server/src/controllers/v1/monitorController.js-simstep-256095b8-5e3a-4c20-abd9-be9e6a9d0bad\",\n\t\t\t\"fileName\": \"monitorController.js\",\n\t\t\t\"wiki\": \"The controller receives the CSV string and uses the `res.file` method to send it back to the client as a file. It sets the `Content-Type` to `text/csv` and `Content-Disposition` to trigger a download with the filename `monitors.csv`.\",\n\t\t\t\"cellName\": \"Flow 2: CSV Export - Send File Response - monitorController.js:L434-440\",\n\t\t\t\"cellId\": \"f151f89d-6399-48f0-aecd-5eb1572b48cc\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 434,\n\t\t\t\"endLine\": 440,\n\t\t\t\"parentCellId\": \"341f2784-67ee-4477-9445-a8c240ee6261\",\n\t\t\t\"parentPath\": \"server/src/controllers/v1/monitorController.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Bulk Monitor Management\",\n\t\t\t\t\t\"simStepId\": \"256095b8-5e3a-4c20-abd9-be9e6a9d0bad\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"d8877474-7203-484f-bd47-fc69e3c7c482\": {\n\t\t\t\"path\": \"d8877474-7203-484f-bd47-fc69e3c7c482\",\n\t\t\t\"cellName\": \"Flow 2: CSV Export - Browser Prompts Download - monitorController.js:L434-440\",\n\t\t\t\"cellId\": \"d8877474-7203-484f-bd47-fc69e3c7c482\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"341f2784-67ee-4477-9445-a8c240ee6261\"\n\t\t},\n\t\t\"server/src/controllers/v1/monitorController.js-simstep-60abdb27-4078-4678-a010-0f6938d4be48\": {\n\t\t\t\"path\": \"server/src/controllers/v1/monitorController.js-simstep-60abdb27-4078-4678-a010-0f6938d4be48\",\n\t\t\t\"fileName\": \"monitorController.js\",\n\t\t\t\"wiki\": \"The browser receives the server's response. The `Content-Disposition` header instructs the browser to prompt the user to save the received data as a file named `monitors.csv`, completing the export process.\",\n\t\t\t\"cellName\": \"Flow 2: CSV Export - Browser Prompts Download - monitorController.js:L434-440\",\n\t\t\t\"cellId\": \"d8877474-7203-484f-bd47-fc69e3c7c482\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 434,\n\t\t\t\"endLine\": 440,\n\t\t\t\"parentCellId\": \"341f2784-67ee-4477-9445-a8c240ee6261\",\n\t\t\t\"parentPath\": \"server/src/controllers/v1/monitorController.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Bulk Monitor Management\",\n\t\t\t\t\t\"simStepId\": \"60abdb27-4078-4678-a010-0f6938d4be48\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"c9a012bc-d53f-494f-82f2-1ee3f40ce646\": {\n\t\t\t\"path\": \"c9a012bc-d53f-494f-82f2-1ee3f40ce646\",\n\t\t\t\"cellName\": \"Flow 1:\\nCSV Import\\n- Render\\nUI\",\n\t\t\t\"cellId\": \"c9a012bc-d53f-494f-82f2-1ee3f40ce646\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"d3264577-10f0-42fe-9411-7e9df0754d1e\"\n\t\t},\n\t\t\"generated-edge-simstep-ef0bbcff-9535-4c0e-a5ca-96c457f89139-c9a012bc-d53f-494f-82f2-1ee3f40ce646\": {\n\t\t\t\"path\": \"generated-edge-simstep-ef0bbcff-9535-4c0e-a5ca-96c457f89139-c9a012bc-d53f-494f-82f2-1ee3f40ce646\",\n\t\t\t\"fileName\": \"index.jsx\",\n\t\t\t\"cellName\": \"Flow 1: CSV Import - Render UI\",\n\t\t\t\"cellId\": \"c9a012bc-d53f-494f-82f2-1ee3f40ce646\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 16,\n\t\t\t\"endLine\": 50,\n\t\t\t\"parentPath\": \"client/src/Routes/index.jsx\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Bulk Monitor Management\",\n\t\t\t\t\t\"simStepId\": \"ef0bbcff-9535-4c0e-a5ca-96c457f89139\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"e03a8ce2-c2cd-4147-8bab-63d6c2cf0a48\": {\n\t\t\t\"path\": \"e03a8ce2-c2cd-4147-8bab-63d6c2cf0a48\",\n\t\t\t\"cellName\": \"Flow 1:\\nCSV Import\\n- File\\nState Update\",\n\t\t\t\"cellId\": \"e03a8ce2-c2cd-4147-8bab-63d6c2cf0a48\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"56dae13e-5735-4089-a9a4-e18be315aff7\"\n\t\t},\n\t\t\"generated-edge-simstep-610120d2-0521-4444-b245-feb97239a389-e03a8ce2-c2cd-4147-8bab-63d6c2cf0a48\": {\n\t\t\t\"path\": \"generated-edge-simstep-610120d2-0521-4444-b245-feb97239a389-e03a8ce2-c2cd-4147-8bab-63d6c2cf0a48\",\n\t\t\t\"fileName\": \"Upload.jsx\",\n\t\t\t\"cellName\": \"Flow 1: CSV Import - File State Update\",\n\t\t\t\"cellId\": \"e03a8ce2-c2cd-4147-8bab-63d6c2cf0a48\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 22,\n\t\t\t\"endLine\": 22,\n\t\t\t\"parentPath\": \"client/src/Pages/v1/Uptime/BulkImport/Upload.jsx\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Bulk Monitor Management\",\n\t\t\t\t\t\"simStepId\": \"610120d2-0521-4444-b245-feb97239a389\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"b8c0292d-afbb-4648-b484-1c27be96d52f\": {\n\t\t\t\"path\": \"b8c0292d-afbb-4648-b484-1c27be96d52f\",\n\t\t\t\"cellName\": \"Flow 1:\\nCSV Import\\n- Prepare\\nForm Data\",\n\t\t\t\"cellId\": \"b8c0292d-afbb-4648-b484-1c27be96d52f\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"d3264577-10f0-42fe-9411-7e9df0754d1e\"\n\t\t},\n\t\t\"generated-edge-simstep-a365d018-e80c-419c-80b3-5ffc8f14dc5c-b8c0292d-afbb-4648-b484-1c27be96d52f\": {\n\t\t\t\"path\": \"generated-edge-simstep-a365d018-e80c-419c-80b3-5ffc8f14dc5c-b8c0292d-afbb-4648-b484-1c27be96d52f\",\n\t\t\t\"fileName\": \"index.jsx\",\n\t\t\t\"cellName\": \"Flow 1: CSV Import - Prepare Form Data\",\n\t\t\t\"cellId\": \"b8c0292d-afbb-4648-b484-1c27be96d52f\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 490,\n\t\t\t\"endLine\": 493,\n\t\t\t\"parentPath\": \"client/src/Pages/v1/Uptime/BulkImport/index.jsx\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Bulk Monitor Management\",\n\t\t\t\t\t\"simStepId\": \"a365d018-e80c-419c-80b3-5ffc8f14dc5c\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"23715cce-c83a-44c0-9853-4c95b85e5ecd\": {\n\t\t\t\"path\": \"23715cce-c83a-44c0-9853-4c95b85e5ecd\",\n\t\t\t\"cellName\": \"Flow 1:\\nCSV Import\\n- Transmit\\nData to\\nServer\",\n\t\t\t\"cellId\": \"23715cce-c83a-44c0-9853-4c95b85e5ecd\",\n\t\t\t\"visible\": true\n\t\t},\n\t\t\"generated-edge-simstep-e6dec1dc-33cb-4669-a3b0-7a3c0b233185-23715cce-c83a-44c0-9853-4c95b85e5ecd\": {\n\t\t\t\"path\": \"generated-edge-simstep-e6dec1dc-33cb-4669-a3b0-7a3c0b233185-23715cce-c83a-44c0-9853-4c95b85e5ecd\",\n\t\t\t\"fileName\": \"NetworkService.js\",\n\t\t\t\"cellName\": \"Flow 1: CSV Import - Transmit Data to Server\",\n\t\t\t\"cellId\": \"23715cce-c83a-44c0-9853-4c95b85e5ecd\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 46,\n\t\t\t\"endLine\": 46,\n\t\t\t\"parentPath\": \"client/src/Utils/NetworkService.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Bulk Monitor Management\",\n\t\t\t\t\t\"simStepId\": \"e6dec1dc-33cb-4669-a3b0-7a3c0b233185\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"20d0e690-a569-4c6f-8238-916cac920553\": {\n\t\t\t\"path\": \"20d0e690-a569-4c6f-8238-916cac920553\",\n\t\t\t\"cellName\": \"Flow 1:\\nCSV Import\\n- Route\\nto Controller\",\n\t\t\t\"cellId\": \"20d0e690-a569-4c6f-8238-916cac920553\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\"\n\t\t},\n\t\t\"generated-edge-simstep-c53d3f62-73fe-4fad-9835-ef2c8cf52894-20d0e690-a569-4c6f-8238-916cac920553\": {\n\t\t\t\"path\": \"generated-edge-simstep-c53d3f62-73fe-4fad-9835-ef2c8cf52894-20d0e690-a569-4c6f-8238-916cac920553\",\n\t\t\t\"fileName\": \"monitorRoute.js\",\n\t\t\t\"cellName\": \"Flow 1: CSV Import - Route to Controller\",\n\t\t\t\"cellId\": \"20d0e690-a569-4c6f-8238-916cac920553\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 206,\n\t\t\t\"endLine\": 212,\n\t\t\t\"parentPath\": \"server/src/routes/v1/monitorRoute.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Bulk Monitor Management\",\n\t\t\t\t\t\"simStepId\": \"c53d3f62-73fe-4fad-9835-ef2c8cf52894\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"7292bf6e-431d-4a9d-94ce-2bcfabcaa79d\": {\n\t\t\t\"path\": \"7292bf6e-431d-4a9d-94ce-2bcfabcaa79d\",\n\t\t\t\"cellName\": \"Flow 1:\\nCSV Import\\n- Controller\\nto Service\",\n\t\t\t\"cellId\": \"7292bf6e-431d-4a9d-94ce-2bcfabcaa79d\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\"\n\t\t},\n\t\t\"generated-edge-simstep-6038422c-ab83-4fc6-a58b-c75734276118-7292bf6e-431d-4a9d-94ce-2bcfabcaa79d\": {\n\t\t\t\"path\": \"generated-edge-simstep-6038422c-ab83-4fc6-a58b-c75734276118-7292bf6e-431d-4a9d-94ce-2bcfabcaa79d\",\n\t\t\t\"fileName\": \"monitorController.js\",\n\t\t\t\"cellName\": \"Flow 1: CSV Import - Controller to Service\",\n\t\t\t\"cellId\": \"7292bf6e-431d-4a9d-94ce-2bcfabcaa79d\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 84,\n\t\t\t\"endLine\": 84,\n\t\t\t\"parentPath\": \"server/src/controllers/v1/monitorController.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Bulk Monitor Management\",\n\t\t\t\t\t\"simStepId\": \"6038422c-ab83-4fc6-a58b-c75734276118\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"b55a0dc6-f596-4e5f-9265-63588b46b519\": {\n\t\t\t\"path\": \"b55a0dc6-f596-4e5f-9265-63588b46b519\",\n\t\t\t\"cellName\": \"Flow 1:\\nCSV Import\\n- Service\\nto Database\\nModule\",\n\t\t\t\"cellId\": \"b55a0dc6-f596-4e5f-9265-63588b46b519\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\"\n\t\t},\n\t\t\"generated-edge-simstep-0115fb69-4959-4b32-bd90-1dcd3c2231f6-b55a0dc6-f596-4e5f-9265-63588b46b519\": {\n\t\t\t\"path\": \"generated-edge-simstep-0115fb69-4959-4b32-bd90-1dcd3c2231f6-b55a0dc6-f596-4e5f-9265-63588b46b519\",\n\t\t\t\"fileName\": \"monitorService.js\",\n\t\t\t\"cellName\": \"Flow 1: CSV Import - Service to Database Module\",\n\t\t\t\"cellId\": \"b55a0dc6-f596-4e5f-9265-63588b46b519\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 126,\n\t\t\t\"endLine\": 126,\n\t\t\t\"parentPath\": \"server/src/service/v1/business/monitorService.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Bulk Monitor Management\",\n\t\t\t\t\t\"simStepId\": \"0115fb69-4959-4b32-bd90-1dcd3c2231f6\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"f27c60ef-fb40-43e2-9750-c2617bdeaf43\": {\n\t\t\t\"path\": \"f27c60ef-fb40-43e2-9750-c2617bdeaf43\",\n\t\t\t\"cellName\": \"Flow 1:\\nCSV Import\\n- Database\\nto Service\",\n\t\t\t\"cellId\": \"f27c60ef-fb40-43e2-9750-c2617bdeaf43\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\"\n\t\t},\n\t\t\"generated-edge-simstep-2ee7bd94-d131-4dd8-bdf8-68433d00472d-f27c60ef-fb40-43e2-9750-c2617bdeaf43\": {\n\t\t\t\"path\": \"generated-edge-simstep-2ee7bd94-d131-4dd8-bdf8-68433d00472d-f27c60ef-fb40-43e2-9750-c2617bdeaf43\",\n\t\t\t\"fileName\": \"monitorModule.js\",\n\t\t\t\"cellName\": \"Flow 1: CSV Import - Database to Service\",\n\t\t\t\"cellId\": \"f27c60ef-fb40-43e2-9750-c2617bdeaf43\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 467,\n\t\t\t\"endLine\": 467,\n\t\t\t\"parentPath\": \"server/src/db/v1/modules/monitorModule.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Bulk Monitor Management\",\n\t\t\t\t\t\"simStepId\": \"2ee7bd94-d131-4dd8-bdf8-68433d00472d\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"c449f81a-d6af-4f7a-b2d8-050a9a9ee0f9\": {\n\t\t\t\"path\": \"c449f81a-d6af-4f7a-b2d8-050a9a9ee0f9\",\n\t\t\t\"cellName\": \"Flow 1:\\nCSV Import\\n- Service\\nto Controller\",\n\t\t\t\"cellId\": \"c449f81a-d6af-4f7a-b2d8-050a9a9ee0f9\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\"\n\t\t},\n\t\t\"generated-edge-simstep-94d5772d-3f46-4d43-b764-3493db5c4971-c449f81a-d6af-4f7a-b2d8-050a9a9ee0f9\": {\n\t\t\t\"path\": \"generated-edge-simstep-94d5772d-3f46-4d43-b764-3493db5c4971-c449f81a-d6af-4f7a-b2d8-050a9a9ee0f9\",\n\t\t\t\"fileName\": \"monitorService.js\",\n\t\t\t\"cellName\": \"Flow 1: CSV Import - Service to Controller\",\n\t\t\t\"cellId\": \"c449f81a-d6af-4f7a-b2d8-050a9a9ee0f9\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 230,\n\t\t\t\"endLine\": 230,\n\t\t\t\"parentPath\": \"server/src/service/v1/business/monitorService.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Bulk Monitor Management\",\n\t\t\t\t\t\"simStepId\": \"94d5772d-3f46-4d43-b764-3493db5c4971\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"926a330c-a9c5-4983-a4b5-70359813e49a\": {\n\t\t\t\"path\": \"926a330c-a9c5-4983-a4b5-70359813e49a\",\n\t\t\t\"cellName\": \"Flow 1:\\nCSV Import\\n- Transmit\\nSuccess to\\nClient\",\n\t\t\t\"cellId\": \"926a330c-a9c5-4983-a4b5-70359813e49a\",\n\t\t\t\"visible\": true\n\t\t},\n\t\t\"generated-edge-simstep-c60a3adb-dd81-41b0-95e4-a0a6d23f9dd0-926a330c-a9c5-4983-a4b5-70359813e49a\": {\n\t\t\t\"path\": \"generated-edge-simstep-c60a3adb-dd81-41b0-95e4-a0a6d23f9dd0-926a330c-a9c5-4983-a4b5-70359813e49a\",\n\t\t\t\"fileName\": \"monitorController.js\",\n\t\t\t\"cellName\": \"Flow 1: CSV Import - Transmit Success to Client\",\n\t\t\t\"cellId\": \"926a330c-a9c5-4983-a4b5-70359813e49a\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 494,\n\t\t\t\"endLine\": 494,\n\t\t\t\"parentPath\": \"server/src/controllers/v1/monitorController.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Bulk Monitor Management\",\n\t\t\t\t\t\"simStepId\": \"c60a3adb-dd81-41b0-95e4-a0a6d23f9dd0\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"febea87e-5033-479c-ba7a-eb35d98db899\": {\n\t\t\t\"path\": \"febea87e-5033-479c-ba7a-eb35d98db899\",\n\t\t\t\"cellName\": \"Flow 2:\\nCSV Export\\n- Transmit\\nRequest to\\nServer\",\n\t\t\t\"cellId\": \"febea87e-5033-479c-ba7a-eb35d98db899\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\"\n\t\t},\n\t\t\"generated-edge-simstep-53cebb8e-cf45-49eb-a7d3-98fd87af21b4-febea87e-5033-479c-ba7a-eb35d98db899\": {\n\t\t\t\"path\": \"generated-edge-simstep-53cebb8e-cf45-49eb-a7d3-98fd87af21b4-febea87e-5033-479c-ba7a-eb35d98db899\",\n\t\t\t\"fileName\": \"monitorRoute.js\",\n\t\t\t\"cellName\": \"Flow 2: CSV Export - Transmit Request to Server\",\n\t\t\t\"cellId\": \"febea87e-5033-479c-ba7a-eb35d98db899\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 45,\n\t\t\t\"endLine\": 45,\n\t\t\t\"parentPath\": \"server/src/routes/v1/monitorRoute.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Bulk Monitor Management\",\n\t\t\t\t\t\"simStepId\": \"53cebb8e-cf45-49eb-a7d3-98fd87af21b4\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"3e0f0966-5c2f-41af-9bcc-e8f615e03a00\": {\n\t\t\t\"path\": \"3e0f0966-5c2f-41af-9bcc-e8f615e03a00\",\n\t\t\t\"cellName\": \"Flow 2:\\nCSV Export\\n- Controller\\nto Service\",\n\t\t\t\"cellId\": \"3e0f0966-5c2f-41af-9bcc-e8f615e03a00\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\"\n\t\t},\n\t\t\"generated-edge-simstep-74e95fb5-863c-4137-a41b-d7a32efa04a5-3e0f0966-5c2f-41af-9bcc-e8f615e03a00\": {\n\t\t\t\"path\": \"generated-edge-simstep-74e95fb5-863c-4137-a41b-d7a32efa04a5-3e0f0966-5c2f-41af-9bcc-e8f615e03a00\",\n\t\t\t\"fileName\": \"monitorController.js\",\n\t\t\t\"cellName\": \"Flow 2: CSV Export - Controller to Service\",\n\t\t\t\"cellId\": \"3e0f0966-5c2f-41af-9bcc-e8f615e03a00\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 245,\n\t\t\t\"endLine\": 245,\n\t\t\t\"parentPath\": \"server/src/controllers/v1/monitorController.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Bulk Monitor Management\",\n\t\t\t\t\t\"simStepId\": \"74e95fb5-863c-4137-a41b-d7a32efa04a5\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"ad300b1c-6748-40f9-a7c9-5895e0915991\": {\n\t\t\t\"path\": \"ad300b1c-6748-40f9-a7c9-5895e0915991\",\n\t\t\t\"cellName\": \"Flow 2:\\nCSV Export\\n- Service\\nto Controller\",\n\t\t\t\"cellId\": \"ad300b1c-6748-40f9-a7c9-5895e0915991\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\"\n\t\t},\n\t\t\"generated-edge-simstep-4deb5e47-2ac4-4638-9ee6-48295d027bcd-ad300b1c-6748-40f9-a7c9-5895e0915991\": {\n\t\t\t\"path\": \"generated-edge-simstep-4deb5e47-2ac4-4638-9ee6-48295d027bcd-ad300b1c-6748-40f9-a7c9-5895e0915991\",\n\t\t\t\"fileName\": \"monitorService.js\",\n\t\t\t\"cellName\": \"Flow 2: CSV Export - Service to Controller\",\n\t\t\t\"cellId\": \"ad300b1c-6748-40f9-a7c9-5895e0915991\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 432,\n\t\t\t\"endLine\": 432,\n\t\t\t\"parentPath\": \"server/src/service/v1/business/monitorService.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Bulk Monitor Management\",\n\t\t\t\t\t\"simStepId\": \"4deb5e47-2ac4-4638-9ee6-48295d027bcd\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"3dfb432a-2ce4-4f92-98ce-5d114b5f7f03\": {\n\t\t\t\"path\": \"3dfb432a-2ce4-4f92-98ce-5d114b5f7f03\",\n\t\t\t\"cellName\": \"Flow 2:\\nCSV Export\\n- Transmit\\nFile to\\nClient\",\n\t\t\t\"cellId\": \"3dfb432a-2ce4-4f92-98ce-5d114b5f7f03\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"341f2784-67ee-4477-9445-a8c240ee6261\"\n\t\t},\n\t\t\"generated-edge-simstep-605f4cbd-1f7f-4e89-b028-f18737ac7fb1-3dfb432a-2ce4-4f92-98ce-5d114b5f7f03\": {\n\t\t\t\"path\": \"generated-edge-simstep-605f4cbd-1f7f-4e89-b028-f18737ac7fb1-3dfb432a-2ce4-4f92-98ce-5d114b5f7f03\",\n\t\t\t\"fileName\": \"monitorController.js\",\n\t\t\t\"cellName\": \"Flow 2: CSV Export - Transmit File to Client\",\n\t\t\t\"cellId\": \"3dfb432a-2ce4-4f92-98ce-5d114b5f7f03\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 434,\n\t\t\t\"endLine\": 440,\n\t\t\t\"parentPath\": \"server/src/controllers/v1/monitorController.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"Bulk Monitor Management\",\n\t\t\t\t\t\"simStepId\": \"605f4cbd-1f7f-4e89-b028-f18737ac7fb1\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"50f77798-f41b-4f5b-b096-7afc921a0419\": {\n\t\t\t\"path\": \"50f77798-f41b-4f5b-b096-7afc921a0419\",\n\t\t\t\"cellName\": \"Settings\",\n\t\t\t\"cellId\": \"50f77798-f41b-4f5b-b096-7afc921a0419\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"1a083b4a-787c-4eb4-8029-6700de987679\"\n\t\t},\n\t\t\"1716ec41-8b42-4386-9850-55b8a607638e\": {\n\t\t\t\"path\": \"1716ec41-8b42-4386-9850-55b8a607638e\",\n\t\t\t\"cellName\": \"Logs\",\n\t\t\t\"cellId\": \"1716ec41-8b42-4386-9850-55b8a607638e\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"1a083b4a-787c-4eb4-8029-6700de987679\"\n\t\t},\n\t\t\"8ee5d524-e61d-4e39-a729-babf54929def\": {\n\t\t\t\"path\": \"8ee5d524-e61d-4e39-a729-babf54929def\",\n\t\t\t\"cellName\": \"settingsHooks.js\",\n\t\t\t\"cellId\": \"8ee5d524-e61d-4e39-a729-babf54929def\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"3bf0c0f9-cbb0-4f0c-8cb3-6e2a4abc0961\"\n\t\t},\n\t\t\"a1fea5b0-fb7c-4189-9484-9d3312660767\": {\n\t\t\t\"path\": \"a1fea5b0-fb7c-4189-9484-9d3312660767\",\n\t\t\t\"cellName\": \"settingsController.js\",\n\t\t\t\"cellId\": \"a1fea5b0-fb7c-4189-9484-9d3312660767\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"fc591f7a-d4ac-4565-949d-a87a58a79bbc\"\n\t\t},\n\t\t\"5882419e-8a92-4edd-a71a-1252983f9af7\": {\n\t\t\t\"path\": \"5882419e-8a92-4edd-a71a-1252983f9af7\",\n\t\t\t\"cellName\": \"diagnosticController.js\",\n\t\t\t\"cellId\": \"5882419e-8a92-4edd-a71a-1252983f9af7\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"fc591f7a-d4ac-4565-949d-a87a58a79bbc\"\n\t\t},\n\t\t\"d4b34195-7e1e-47a0-9303-603987c81f95\": {\n\t\t\t\"path\": \"d4b34195-7e1e-47a0-9303-603987c81f95\",\n\t\t\t\"cellName\": \"index.jsx\",\n\t\t\t\"cellId\": \"d4b34195-7e1e-47a0-9303-603987c81f95\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"50f77798-f41b-4f5b-b096-7afc921a0419\"\n\t\t},\n\t\t\"d8aa5b9e-f2a7-44c8-8813-d79c3f3238ee\": {\n\t\t\t\"path\": \"d8aa5b9e-f2a7-44c8-8813-d79c3f3238ee\",\n\t\t\t\"cellName\": \"SettingsEmail.jsx\",\n\t\t\t\"cellId\": \"d8aa5b9e-f2a7-44c8-8813-d79c3f3238ee\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"50f77798-f41b-4f5b-b096-7afc921a0419\"\n\t\t},\n\t\t\"e0cb598c-e300-4fd3-8554-db7ffd6201f1\": {\n\t\t\t\"path\": \"e0cb598c-e300-4fd3-8554-db7ffd6201f1\",\n\t\t\t\"cellName\": \"Diagnostics\",\n\t\t\t\"cellId\": \"e0cb598c-e300-4fd3-8554-db7ffd6201f1\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"1716ec41-8b42-4386-9850-55b8a607638e\"\n\t\t},\n\t\t\"643b26c1-3bfb-4c41-8179-96dfc237d99e\": {\n\t\t\t\"path\": \"643b26c1-3bfb-4c41-8179-96dfc237d99e\",\n\t\t\t\"cellName\": \"diagnosticService.js\",\n\t\t\t\"cellId\": \"643b26c1-3bfb-4c41-8179-96dfc237d99e\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"87d3b101-9443-4ed4-9c4f-f759d41677eb\"\n\t\t},\n\t\t\"87e0e2ea-4a6d-460d-95bc-31e2efd9c9cf\": {\n\t\t\t\"path\": \"87e0e2ea-4a6d-460d-95bc-31e2efd9c9cf\",\n\t\t\t\"cellName\": \"index.jsx\",\n\t\t\t\"cellId\": \"87e0e2ea-4a6d-460d-95bc-31e2efd9c9cf\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"e0cb598c-e300-4fd3-8554-db7ffd6201f1\"\n\t\t},\n\t\t\"97908daf-d071-4df5-8366-1f5f4d8d534a\": {\n\t\t\t\"path\": \"97908daf-d071-4df5-8366-1f5f4d8d534a\",\n\t\t\t\"cellName\": \"Flow 1: Render Settings Page - index.jsx:L25-52\",\n\t\t\t\"cellId\": \"97908daf-d071-4df5-8366-1f5f4d8d534a\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"d4b34195-7e1e-47a0-9303-603987c81f95\"\n\t\t},\n\t\t\"client/src/Pages/v1/Settings/index.jsx-simstep-64e9f1af-13b7-4361-a2a9-3f45760e316d\": {\n\t\t\t\"path\": \"client/src/Pages/v1/Settings/index.jsx-simstep-64e9f1af-13b7-4361-a2a9-3f45760e316d\",\n\t\t\t\"fileName\": \"index.jsx\",\n\t\t\t\"wiki\": \"The user navigates to the settings page. The main `Settings` component fetches existing settings using the `useFetchSettings` hook and renders various sub-components for different configuration areas like TimeZone, UI, PageSpeed, Email, etc.\",\n\t\t\t\"cellName\": \"Flow 1: Render Settings Page - index.jsx:L25-52\",\n\t\t\t\"cellId\": \"97908daf-d071-4df5-8366-1f5f4d8d534a\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 25,\n\t\t\t\"endLine\": 52,\n\t\t\t\"parentCellId\": \"d4b34195-7e1e-47a0-9303-603987c81f95\",\n\t\t\t\"parentPath\": \"client/src/Pages/v1/Settings/index.jsx\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"System Administration and Configuration\",\n\t\t\t\t\t\"simStepId\": \"64e9f1af-13b7-4361-a2a9-3f45760e316d\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"83596bd1-dfca-4196-b52e-955f6824fafb\": {\n\t\t\t\"path\": \"83596bd1-dfca-4196-b52e-955f6824fafb\",\n\t\t\t\"cellName\": \"Backend: Retrieve Settings from Database - settingsController.js:L40-49\",\n\t\t\t\"cellId\": \"83596bd1-dfca-4196-b52e-955f6824fafb\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"a1fea5b0-fb7c-4189-9484-9d3312660767\"\n\t\t},\n\t\t\"server/src/controllers/v1/settingsController.js-simstep-441b0c45-5f27-478d-8ca8-58fbd5f460ea\": {\n\t\t\t\"path\": \"server/src/controllers/v1/settingsController.js-simstep-441b0c45-5f27-478d-8ca8-58fbd5f460ea\",\n\t\t\t\"fileName\": \"settingsController.js\",\n\t\t\t\"wiki\": \"The `settingsController` handles the GET request. It calls the `settingsService` to fetch settings from the database. Sensitive data like passwords is sanitized, and flags like `emailPasswordSet` are added before sending the data to the client.\",\n\t\t\t\"cellName\": \"Backend: Retrieve Settings from Database - settingsController.js:L40-49\",\n\t\t\t\"cellId\": \"83596bd1-dfca-4196-b52e-955f6824fafb\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 40,\n\t\t\t\"endLine\": 49,\n\t\t\t\"parentCellId\": \"a1fea5b0-fb7c-4189-9484-9d3312660767\",\n\t\t\t\"parentPath\": \"server/src/controllers/v1/settingsController.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"System Administration and Configuration\",\n\t\t\t\t\t\"simStepId\": \"441b0c45-5f27-478d-8ca8-58fbd5f460ea\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"09cb194a-0ea4-46e2-b32b-36b62fa87f40\": {\n\t\t\t\"path\": \"09cb194a-0ea4-46e2-b32b-36b62fa87f40\",\n\t\t\t\"cellName\": \"User Interaction: Modify Email Settings - SettingsEmail.jsx:L119-167\",\n\t\t\t\"cellId\": \"09cb194a-0ea4-46e2-b32b-36b62fa87f40\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"d8aa5b9e-f2a7-44c8-8813-d79c3f3238ee\"\n\t\t},\n\t\t\"client/src/Pages/v1/Settings/SettingsEmail.jsx-simstep-ae5c5146-4dbb-4612-9d23-086e57f72474\": {\n\t\t\t\"path\": \"client/src/Pages/v1/Settings/SettingsEmail.jsx-simstep-ae5c5146-4dbb-4612-9d23-086e57f72474\",\n\t\t\t\"fileName\": \"SettingsEmail.jsx\",\n\t\t\t\"wiki\": \"The user interacts with the `SettingsEmail` component, filling in SMTP server details. The component's state is updated via the `handleChange` function passed down from the parent `Settings` component, which prepares the new configuration data.\",\n\t\t\t\"cellName\": \"User Interaction: Modify Email Settings - SettingsEmail.jsx:L119-167\",\n\t\t\t\"cellId\": \"09cb194a-0ea4-46e2-b32b-36b62fa87f40\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 119,\n\t\t\t\"endLine\": 167,\n\t\t\t\"parentCellId\": \"d8aa5b9e-f2a7-44c8-8813-d79c3f3238ee\",\n\t\t\t\"parentPath\": \"client/src/Pages/v1/Settings/SettingsEmail.jsx\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"System Administration and Configuration\",\n\t\t\t\t\t\"simStepId\": \"ae5c5146-4dbb-4612-9d23-086e57f72474\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"1b2cf182-9ee3-4218-a7ec-b74e427ccddf\": {\n\t\t\t\"path\": \"1b2cf182-9ee3-4218-a7ec-b74e427ccddf\",\n\t\t\t\"cellName\": \"API Call: Update Application Settings - settingsHooks.js:L41-67\",\n\t\t\t\"cellId\": \"1b2cf182-9ee3-4218-a7ec-b74e427ccddf\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"8ee5d524-e61d-4e39-a729-babf54929def\"\n\t\t},\n\t\t\"client/src/Hooks/v1/settingsHooks.js-simstep-d7098072-9a83-4369-8176-9646ba34e186\": {\n\t\t\t\"path\": \"client/src/Hooks/v1/settingsHooks.js-simstep-d7098072-9a83-4369-8176-9646ba34e186\",\n\t\t\t\"fileName\": \"settingsHooks.js\",\n\t\t\t\"wiki\": \"The `handleSave` function calls `saveSettings` from the `useSaveSettings` hook. This triggers a PUT request to `/api/v1/settings` with the new configuration in the request body.\",\n\t\t\t\"cellName\": \"API Call: Update Application Settings - settingsHooks.js:L41-67\",\n\t\t\t\"cellId\": \"1b2cf182-9ee3-4218-a7ec-b74e427ccddf\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 41,\n\t\t\t\"endLine\": 67,\n\t\t\t\"parentCellId\": \"8ee5d524-e61d-4e39-a729-babf54929def\",\n\t\t\t\"parentPath\": \"client/src/Hooks/v1/settingsHooks.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"System Administration and Configuration\",\n\t\t\t\t\t\"simStepId\": \"d7098072-9a83-4369-8176-9646ba34e186\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"cce3b9c8-f3b7-434b-b3c6-d8d164714f86\": {\n\t\t\t\"path\": \"cce3b9c8-f3b7-434b-b3c6-d8d164714f86\",\n\t\t\t\"cellName\": \"Backend: Persist Updated Settings - settingsController.js:L54-64\",\n\t\t\t\"cellId\": \"cce3b9c8-f3b7-434b-b3c6-d8d164714f86\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"a1fea5b0-fb7c-4189-9484-9d3312660767\"\n\t\t},\n\t\t\"server/src/controllers/v1/settingsController.js-simstep-7632e8d2-4086-4169-ae3f-bfbf8d657987\": {\n\t\t\t\"path\": \"server/src/controllers/v1/settingsController.js-simstep-7632e8d2-4086-4169-ae3f-bfbf8d657987\",\n\t\t\t\"fileName\": \"settingsController.js\",\n\t\t\t\"wiki\": \"The `settingsController` receives the PUT request, validates the body, and calls the `db.settingsModule.updateAppSettings` method to update the settings document in the database.\",\n\t\t\t\"cellName\": \"Backend: Persist Updated Settings - settingsController.js:L54-64\",\n\t\t\t\"cellId\": \"cce3b9c8-f3b7-434b-b3c6-d8d164714f86\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 54,\n\t\t\t\"endLine\": 64,\n\t\t\t\"parentCellId\": \"a1fea5b0-fb7c-4189-9484-9d3312660767\",\n\t\t\t\"parentPath\": \"server/src/controllers/v1/settingsController.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"System Administration and Configuration\",\n\t\t\t\t\t\"simStepId\": \"7632e8d2-4086-4169-ae3f-bfbf8d657987\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"fff5dde4-8eb8-4c21-9c6d-0845a9749ff3\": {\n\t\t\t\"path\": \"fff5dde4-8eb8-4c21-9c6d-0845a9749ff3\",\n\t\t\t\"cellName\": \"UI Update: Display Success Confirmation - settingsHooks.js:L58\",\n\t\t\t\"cellId\": \"fff5dde4-8eb8-4c21-9c6d-0845a9749ff3\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"8ee5d524-e61d-4e39-a729-babf54929def\"\n\t\t},\n\t\t\"client/src/Hooks/v1/settingsHooks.js-simstep-a157bd07-b969-44f8-914c-3d8393c1605a\": {\n\t\t\t\"path\": \"client/src/Hooks/v1/settingsHooks.js-simstep-a157bd07-b969-44f8-914c-3d8393c1605a\",\n\t\t\t\"fileName\": \"settingsHooks.js\",\n\t\t\t\"wiki\": \"The frontend network service receives the successful API response. The `saveSettings` hook then calls `createToast` with a success message, which is displayed to the user.\",\n\t\t\t\"cellName\": \"UI Update: Display Success Confirmation - settingsHooks.js:L58\",\n\t\t\t\"cellId\": \"fff5dde4-8eb8-4c21-9c6d-0845a9749ff3\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 58,\n\t\t\t\"endLine\": 58,\n\t\t\t\"parentCellId\": \"8ee5d524-e61d-4e39-a729-babf54929def\",\n\t\t\t\"parentPath\": \"client/src/Hooks/v1/settingsHooks.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"System Administration and Configuration\",\n\t\t\t\t\t\"simStepId\": \"a157bd07-b969-44f8-914c-3d8393c1605a\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"704e2ec8-9f2f-47e5-852f-c6ada67a02e0\": {\n\t\t\t\"path\": \"704e2ec8-9f2f-47e5-852f-c6ada67a02e0\",\n\t\t\t\"cellName\": \"Flow 2: Navigate to Diagnostics Page - index.jsx:L14-15\",\n\t\t\t\"cellId\": \"704e2ec8-9f2f-47e5-852f-c6ada67a02e0\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"87e0e2ea-4a6d-460d-95bc-31e2efd9c9cf\"\n\t\t},\n\t\t\"client/src/Pages/v1/Logs/Diagnostics/index.jsx-simstep-a9b24b5f-534b-4baf-a185-bac7c32a1c42\": {\n\t\t\t\"path\": \"client/src/Pages/v1/Logs/Diagnostics/index.jsx-simstep-a9b24b5f-534b-4baf-a185-bac7c32a1c42\",\n\t\t\t\"fileName\": \"index.jsx\",\n\t\t\t\"wiki\": \"The user navigates to the 'Logs' page and selects the 'Diagnostics' tab. The `Diagnostics` component renders and immediately calls the `useFetchDiagnostics` hook to retrieve system health data.\",\n\t\t\t\"cellName\": \"Flow 2: Navigate to Diagnostics Page - index.jsx:L14-15\",\n\t\t\t\"cellId\": \"704e2ec8-9f2f-47e5-852f-c6ada67a02e0\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 14,\n\t\t\t\"endLine\": 15,\n\t\t\t\"parentCellId\": \"87e0e2ea-4a6d-460d-95bc-31e2efd9c9cf\",\n\t\t\t\"parentPath\": \"client/src/Pages/v1/Logs/Diagnostics/index.jsx\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"System Administration and Configuration\",\n\t\t\t\t\t\"simStepId\": \"a9b24b5f-534b-4baf-a185-bac7c32a1c42\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"09f07e80-185e-4547-aab4-edaf8ae7501e\": {\n\t\t\t\"path\": \"09f07e80-185e-4547-aab4-edaf8ae7501e\",\n\t\t\t\"cellName\": \"Backend: Gather System Statistics - diagnosticService.js:L39-95\",\n\t\t\t\"cellId\": \"09f07e80-185e-4547-aab4-edaf8ae7501e\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"643b26c1-3bfb-4c41-8179-96dfc237d99e\"\n\t\t},\n\t\t\"server/src/service/v1/business/diagnosticService.js-simstep-8fb704ca-67d9-437c-90d8-01302634d568\": {\n\t\t\t\"path\": \"server/src/service/v1/business/diagnosticService.js-simstep-8fb704ca-67d9-437c-90d8-01302634d568\",\n\t\t\t\"fileName\": \"diagnosticService.js\",\n\t\t\t\"wiki\": \"The `diagnosticController` receives the request and calls `diagnosticService.getSystemStats()`. This service uses native Node.js modules like `os` and `v8` to collect metrics on memory, CPU, heap statistics, and process uptime.\",\n\t\t\t\"cellName\": \"Backend: Gather System Statistics - diagnosticService.js:L39-95\",\n\t\t\t\"cellId\": \"09f07e80-185e-4547-aab4-edaf8ae7501e\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 39,\n\t\t\t\"endLine\": 95,\n\t\t\t\"parentCellId\": \"643b26c1-3bfb-4c41-8179-96dfc237d99e\",\n\t\t\t\"parentPath\": \"server/src/service/v1/business/diagnosticService.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"System Administration and Configuration\",\n\t\t\t\t\t\"simStepId\": \"8fb704ca-67d9-437c-90d8-01302634d568\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"4b418736-6b72-47e0-917a-d86d4bed9ecd\": {\n\t\t\t\"path\": \"4b418736-6b72-47e0-917a-d86d4bed9ecd\",\n\t\t\t\"cellName\": \"UI Update: Display System Health - index.jsx:L59-63\",\n\t\t\t\"cellId\": \"4b418736-6b72-47e0-917a-d86d4bed9ecd\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"87e0e2ea-4a6d-460d-95bc-31e2efd9c9cf\"\n\t\t},\n\t\t\"client/src/Pages/v1/Logs/Diagnostics/index.jsx-simstep-e6c94f52-a599-4568-a06f-2db18f963817\": {\n\t\t\t\"path\": \"client/src/Pages/v1/Logs/Diagnostics/index.jsx-simstep-e6c94f52-a599-4568-a06f-2db18f963817\",\n\t\t\t\"fileName\": \"index.jsx\",\n\t\t\t\"wiki\": \"The frontend receives the diagnostic data. The `Diagnostics` component passes this data to its children, `Gauges` and `StatusBoxes`, which then render the information as interactive gauges and statistical boxes.\",\n\t\t\t\"cellName\": \"UI Update: Display System Health - index.jsx:L59-63\",\n\t\t\t\"cellId\": \"4b418736-6b72-47e0-917a-d86d4bed9ecd\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 59,\n\t\t\t\"endLine\": 63,\n\t\t\t\"parentCellId\": \"87e0e2ea-4a6d-460d-95bc-31e2efd9c9cf\",\n\t\t\t\"parentPath\": \"client/src/Pages/v1/Logs/Diagnostics/index.jsx\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"System Administration and Configuration\",\n\t\t\t\t\t\"simStepId\": \"e6c94f52-a599-4568-a06f-2db18f963817\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"f6d80f09-ae83-4c95-aba0-4efffeda38e0\": {\n\t\t\t\"path\": \"f6d80f09-ae83-4c95-aba0-4efffeda38e0\",\n\t\t\t\"cellName\": \"API Call:\\nFetch Application\\nSettings\",\n\t\t\t\"cellId\": \"f6d80f09-ae83-4c95-aba0-4efffeda38e0\",\n\t\t\t\"visible\": true\n\t\t},\n\t\t\"generated-edge-simstep-dca4a33c-b666-47b8-896b-370ed9d6f9c5-f6d80f09-ae83-4c95-aba0-4efffeda38e0\": {\n\t\t\t\"path\": \"generated-edge-simstep-dca4a33c-b666-47b8-896b-370ed9d6f9c5-f6d80f09-ae83-4c95-aba0-4efffeda38e0\",\n\t\t\t\"fileName\": \"index.jsx\",\n\t\t\t\"cellName\": \"API Call: Fetch Application Settings\",\n\t\t\t\"cellId\": \"f6d80f09-ae83-4c95-aba0-4efffeda38e0\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 692,\n\t\t\t\"endLine\": 698,\n\t\t\t\"parentPath\": \"client/src/Pages/v1/Settings/index.jsx\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"System Administration and Configuration\",\n\t\t\t\t\t\"simStepId\": \"dca4a33c-b666-47b8-896b-370ed9d6f9c5\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"195ad532-9858-493e-876a-6ec457811d1d\": {\n\t\t\t\"path\": \"195ad532-9858-493e-876a-6ec457811d1d\",\n\t\t\t\"cellName\": \"API Response:\\nSend Settings\\nto Client\",\n\t\t\t\"cellId\": \"195ad532-9858-493e-876a-6ec457811d1d\",\n\t\t\t\"visible\": true\n\t\t},\n\t\t\"generated-edge-simstep-aacc9302-6ca8-45c6-acb8-956d8d0242c2-195ad532-9858-493e-876a-6ec457811d1d\": {\n\t\t\t\"path\": \"generated-edge-simstep-aacc9302-6ca8-45c6-acb8-956d8d0242c2-195ad532-9858-493e-876a-6ec457811d1d\",\n\t\t\t\"fileName\": \"settingsController.js\",\n\t\t\t\"cellName\": \"API Response: Send Settings to Client\",\n\t\t\t\"cellId\": \"195ad532-9858-493e-876a-6ec457811d1d\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 45,\n\t\t\t\"endLine\": 48,\n\t\t\t\"parentPath\": \"server/src/controllers/v1/settingsController.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"System Administration and Configuration\",\n\t\t\t\t\t\"simStepId\": \"aacc9302-6ca8-45c6-acb8-956d8d0242c2\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"8c107d79-f796-49eb-ab88-f553dd6f9d95\": {\n\t\t\t\"path\": \"8c107d79-f796-49eb-ab88-f553dd6f9d95\",\n\t\t\t\"cellName\": \"User Action:\\nSave Settings\",\n\t\t\t\"cellId\": \"8c107d79-f796-49eb-ab88-f553dd6f9d95\",\n\t\t\t\"visible\": true,\n\t\t\t\"parentCellId\": \"d3264577-10f0-42fe-9411-7e9df0754d1e\"\n\t\t},\n\t\t\"generated-edge-simstep-e7e82a97-1409-4bc5-ae27-b4ff5ba746df-8c107d79-f796-49eb-ab88-f553dd6f9d95\": {\n\t\t\t\"path\": \"generated-edge-simstep-e7e82a97-1409-4bc5-ae27-b4ff5ba746df-8c107d79-f796-49eb-ab88-f553dd6f9d95\",\n\t\t\t\"fileName\": \"SettingsEmail.jsx\",\n\t\t\t\"cellName\": \"User Action: Save Settings\",\n\t\t\t\"cellId\": \"8c107d79-f796-49eb-ab88-f553dd6f9d95\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 258,\n\t\t\t\"endLine\": 261,\n\t\t\t\"parentPath\": \"client/src/Pages/v1/Settings/SettingsEmail.jsx\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"System Administration and Configuration\",\n\t\t\t\t\t\"simStepId\": \"e7e82a97-1409-4bc5-ae27-b4ff5ba746df\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"ce3ed3ba-a35b-4881-8dfd-f8425b9bf812\": {\n\t\t\t\"path\": \"ce3ed3ba-a35b-4881-8dfd-f8425b9bf812\",\n\t\t\t\"cellName\": \"Data Transmission:\\nSend Updated\\nSettings to\\nServer\",\n\t\t\t\"cellId\": \"ce3ed3ba-a35b-4881-8dfd-f8425b9bf812\",\n\t\t\t\"visible\": true\n\t\t},\n\t\t\"generated-edge-simstep-383387e5-4623-44ab-b2c4-d9ea046f4547-ce3ed3ba-a35b-4881-8dfd-f8425b9bf812\": {\n\t\t\t\"path\": \"generated-edge-simstep-383387e5-4623-44ab-b2c4-d9ea046f4547-ce3ed3ba-a35b-4881-8dfd-f8425b9bf812\",\n\t\t\t\"fileName\": \"settingsHooks.js\",\n\t\t\t\"cellName\": \"Data Transmission: Send Updated Settings to Server\",\n\t\t\t\"cellId\": \"ce3ed3ba-a35b-4881-8dfd-f8425b9bf812\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 711,\n\t\t\t\"endLine\": 717,\n\t\t\t\"parentPath\": \"client/src/Hooks/v1/settingsHooks.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"System Administration and Configuration\",\n\t\t\t\t\t\"simStepId\": \"383387e5-4623-44ab-b2c4-d9ea046f4547\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"fbe9b160-307e-4f51-8f72-713fda5373c8\": {\n\t\t\t\"path\": \"fbe9b160-307e-4f51-8f72-713fda5373c8\",\n\t\t\t\"cellName\": \"API Response:\\nConfirm Settings\\nUpdate\",\n\t\t\t\"cellId\": \"fbe9b160-307e-4f51-8f72-713fda5373c8\",\n\t\t\t\"visible\": true\n\t\t},\n\t\t\"generated-edge-simstep-0afcde35-7d51-4939-aae8-bac5ac83c49d-fbe9b160-307e-4f51-8f72-713fda5373c8\": {\n\t\t\t\"path\": \"generated-edge-simstep-0afcde35-7d51-4939-aae8-bac5ac83c49d-fbe9b160-307e-4f51-8f72-713fda5373c8\",\n\t\t\t\"fileName\": \"settingsController.js\",\n\t\t\t\"cellName\": \"API Response: Confirm Settings Update\",\n\t\t\t\"cellId\": \"fbe9b160-307e-4f51-8f72-713fda5373c8\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 60,\n\t\t\t\"endLine\": 63,\n\t\t\t\"parentPath\": \"server/src/controllers/v1/settingsController.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"System Administration and Configuration\",\n\t\t\t\t\t\"simStepId\": \"0afcde35-7d51-4939-aae8-bac5ac83c49d\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"499dfe1f-77d4-4b26-a12c-45240691109e\": {\n\t\t\t\"path\": \"499dfe1f-77d4-4b26-a12c-45240691109e\",\n\t\t\t\"cellName\": \"API Call:\\nFetch System\\nDiagnostics\",\n\t\t\t\"cellId\": \"499dfe1f-77d4-4b26-a12c-45240691109e\",\n\t\t\t\"visible\": true\n\t\t},\n\t\t\"generated-edge-simstep-23b8ad7d-8967-4e48-814c-1a7bf5b4dfac-499dfe1f-77d4-4b26-a12c-45240691109e\": {\n\t\t\t\"path\": \"generated-edge-simstep-23b8ad7d-8967-4e48-814c-1a7bf5b4dfac-499dfe1f-77d4-4b26-a12c-45240691109e\",\n\t\t\t\"fileName\": \"index.jsx\",\n\t\t\t\"cellName\": \"API Call: Fetch System Diagnostics\",\n\t\t\t\"cellId\": \"499dfe1f-77d4-4b26-a12c-45240691109e\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 1113,\n\t\t\t\"endLine\": 1119,\n\t\t\t\"parentPath\": \"client/src/Pages/v1/Logs/Diagnostics/index.jsx\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"System Administration and Configuration\",\n\t\t\t\t\t\"simStepId\": \"23b8ad7d-8967-4e48-814c-1a7bf5b4dfac\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"d0f92604-a6fa-4d85-9716-ea8f32db78e0\": {\n\t\t\t\"path\": \"d0f92604-a6fa-4d85-9716-ea8f32db78e0\",\n\t\t\t\"cellName\": \"API Response:\\nSend Diagnostics\\nData to\\nClient\",\n\t\t\t\"cellId\": \"d0f92604-a6fa-4d85-9716-ea8f32db78e0\",\n\t\t\t\"visible\": true\n\t\t},\n\t\t\"generated-edge-simstep-44a4372f-a903-4c43-a9a5-c7549c875e11-d0f92604-a6fa-4d85-9716-ea8f32db78e0\": {\n\t\t\t\"path\": \"generated-edge-simstep-44a4372f-a903-4c43-a9a5-c7549c875e11-d0f92604-a6fa-4d85-9716-ea8f32db78e0\",\n\t\t\t\"fileName\": \"diagnosticService.js\",\n\t\t\t\"cellName\": \"API Response: Send Diagnostics Data to Client\",\n\t\t\t\"cellId\": \"d0f92604-a6fa-4d85-9716-ea8f32db78e0\",\n\t\t\t\"visible\": true,\n\t\t\t\"startLine\": 52,\n\t\t\t\"endLine\": 55,\n\t\t\t\"parentPath\": \"server/src/service/v1/business/diagnosticService.js\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simulationKey\": \"System Administration and Configuration\",\n\t\t\t\t\t\"simStepId\": \"44a4372f-a903-4c43-a9a5-c7549c875e11\"\n\t\t\t\t}\n\t\t\t]\n\t\t}\n\t},\n\t\"simulations\": {\n\t\t\"Comprehensive Uptime Monitoring for Various Services\": {\n\t\t\t\"name\": \"Comprehensive Uptime Monitoring for Various Services\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"ab5de0b9-c70d-492c-98d9-8ddee66284ad\",\n\t\t\t\t\t\"diagramNodeId\": \"7a2da928-a65c-49d8-b0a3-c159a6df2bc5\",\n\t\t\t\t\t\"simStepLabel\": \"Uptime Monitor Creation: Display Form\",\n\t\t\t\t\t\"simStepDescription\": \"The user navigates to the 'Create Uptime Monitor' page. The `UptimeCreate` React component renders the form, allowing the user to select the monitor type (HTTP, Ping, Docker, etc.) and input details like URL, name, and check interval.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Pages/v1/Uptime/Create/index.jsx\",\n\t\t\t\t\t\t\"startLine\": \"315\",\n\t\t\t\t\t\t\"endLine\": \"802\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"UptimeCreate\",\n\t\t\t\t\t\t\t\"monitor\",\n\t\t\t\t\t\t\t\"setMonitor\",\n\t\t\t\t\t\t\t\"onChange\",\n\t\t\t\t\t\t\t\"onSubmit\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\n  \\\"type\\\": \\\"http\\\",\\n  \\\"statusWindowSize\\\": 5,\\n  \\\"statusWindowThreshold\\\": 60,\\n  \\\"matchMethod\\\": \\\"equal\\\",\\n  \\\"interval\\\": 60000,\\n  \\\"ignoreTlsErrors\\\": false,\\n  \\\"notifications\\\": [],\\n  \\\"url\\\": \\\"\\\",\\n  \\\"name\\\": \\\"\\\"\\n}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"888df086-41bb-469d-9c0a-daf74bdecb9f\",\n\t\t\t\t\t\"diagramNodeId\": \"0e09aa33-d7c7-4c89-9da8-f0937658f4d3\",\n\t\t\t\t\t\"simStepLabel\": \"Uptime Monitor Creation: Form Submission\",\n\t\t\t\t\t\"simStepDescription\": \"After filling the form, the user clicks the 'Create monitor' button, which triggers the `onSubmit` event handler, passing the current state of the form.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Pages/v1/Uptime/Create/index.jsx\",\n\t\t\t\t\t\t\"startLine\": \"435\",\n\t\t\t\t\t\t\"endLine\": \"443\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"onSubmit\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\n  \\\"type\\\": \\\"http\\\",\\n  \\\"url\\\": \\\"https://google.com\\\",\\n  \\\"name\\\": \\\"My Google Monitor\\\",\\n  \\\"interval\\\": 60000,\\n  \\\"notifications\\\": []\\n}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\n  \\\"type\\\": \\\"http\\\",\\n  \\\"url\\\": \\\"https://google.com\\\",\\n  \\\"name\\\": \\\"My Google Monitor\\\",\\n  \\\"interval\\\": 60000,\\n  \\\"notifications\\\": []\\n}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"e02ddf57-270e-4f71-b4c4-d5183bb7879a\",\n\t\t\t\t\t\"diagramNodeId\": \"a81f4ae8-41fe-4d1b-95ce-86abcc67b53c\",\n\t\t\t\t\t\"simStepLabel\": \"Uptime Monitor Creation: Handle Form Submission and Validation\",\n\t\t\t\t\t\"simStepDescription\": \"The `onSubmit` function in `UptimeCreate.jsx` is executed. It prevents the default form submission, constructs a `form` object with monitor data, validates it using `monitorValidation`, and then calls the `createMonitor` function from the `useCreateMonitor` hook.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Pages/v1/Uptime/Create/index.jsx\",\n\t\t\t\t\t\t\"startLine\": \"170\",\n\t\t\t\t\t\t\"endLine\": \"248\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"onSubmit\",\n\t\t\t\t\t\t\t\"monitorValidation\",\n\t\t\t\t\t\t\t\"createMonitor\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\n  \\\"type\\\": \\\"http\\\",\\n  \\\"url\\\": \\\"google.com\\\",\\n  \\\"name\\\": \\\"My Google Monitor\\\",\\n  \\\"interval\\\": 60000,\\n  \\\"notifications\\\": []\\n}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\n  \\\"monitor\\\": {\\n    \\\"url\\\": \\\"http://google.com\\\",\\n    \\\"name\\\": \\\"My Google Monitor\\\",\\n    \\\"statusWindowSize\\\": 5,\\n    \\\"statusWindowThreshold\\\": 60,\\n    \\\"type\\\": \\\"http\\\",\\n    \\\"interval\\\": 60000,\\n    \\\"description\\\": \\\"My Google Monitor\\\",\\n    \\\"notifications\\\": []\\n  },\\n  \\\"redirect\\\": \\\"/uptime\\\"\\n}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"3fe0afaa-c673-4b52-a0c4-02a3ffd3a075\",\n\t\t\t\t\t\"diagramNodeId\": \"1f6f04a9-0123-4729-b06a-8f3da6d1b58c\",\n\t\t\t\t\t\"simStepLabel\": \"Uptime Monitor Creation: Call Network Service\",\n\t\t\t\t\t\"simStepDescription\": \"The `createMonitor` function from the `useCreateMonitor` hook is called, which in turn calls `networkService.createMonitor` to send the monitor data to the backend API.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Hooks/v1/monitorHooks.js\",\n\t\t\t\t\t\t\"startLine\": \"306\",\n\t\t\t\t\t\t\"endLine\": \"306\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"networkService.createMonitor\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\n  \\\"monitor\\\": {\\n    \\\"url\\\": \\\"http://google.com\\\",\\n    \\\"name\\\": \\\"My Google Monitor\\\",\\n    \\\"type\\\": \\\"http\\\",\\n    \\\"interval\\\": 60000,\\n    \\\"notifications\\\": []\\n  }\\n}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\n  \\\"monitor\\\": {\\n    \\\"url\\\": \\\"http://google.com\\\",\\n    \\\"name\\\": \\\"My Google Monitor\\\",\\n    \\\"type\\\": \\\"http\\\",\\n    \\\"interval\\\": 60000,\\n    \\\"notifications\\\": []\\n  }\\n}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"14e9986b-c6ce-475e-97ed-da1fa2b6968d\",\n\t\t\t\t\t\"diagramNodeId\": \"a30ac765-c546-4993-988e-8c8cfdb7532f\",\n\t\t\t\t\t\"simStepLabel\": \"Uptime Monitor Creation: Send API Request\",\n\t\t\t\t\t\"simStepDescription\": \"The `createMonitor` method in `NetworkService.js` makes an HTTP POST request to the `/monitors` endpoint on the server, sending the new monitor's data in the request body.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Utils/NetworkService.js\",\n\t\t\t\t\t\t\"startLine\": \"119\",\n\t\t\t\t\t\t\"endLine\": \"121\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"createMonitor\",\n\t\t\t\t\t\t\t\"this.axiosInstance.post\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\n  \\\"monitor\\\": {\\n    \\\"url\\\": \\\"http://google.com\\\",\\n    \\\"name\\\": \\\"My Google Monitor\\\",\\n    \\\"type\\\": \\\"http\\\",\\n    \\\"interval\\\": 60000,\\n    \\\"notifications\\\": []\\n  }\\n}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\n  \\\"status\\\": 200,\\n  \\\"data\\\": {\\n    \\\"_id\\\": \\\"60d21b4667d0d8992e610c85\\\",\\n    \\\"name\\\": \\\"My Google Monitor\\\",\\n    \\\"url\\\": \\\"http://google.com\\\",\\n    \\\"type\\\": \\\"http\\\",\\n    \\\"interval\\\": 60000,\\n    \\\"isActive\\\": true\\n  }\\n}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"13dd0564-44a5-43ea-a163-ce1148cc48e7\",\n\t\t\t\t\t\"diagramNodeId\": \"b6d963d5-c613-407a-9ce9-60a04048dea7\",\n\t\t\t\t\t\"simStepLabel\": \"Uptime Monitor Creation: API Route to Controller\",\n\t\t\t\t\t\"simStepDescription\": \"The server's router receives the POST request on `/api/v1/monitors` and forwards it to the `createMonitor` method in the `MonitorController`.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/routes/v1/monitorRoute.js\",\n\t\t\t\t\t\t\"startLine\": \"35\",\n\t\t\t\t\t\t\"endLine\": \"35\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"this.router.post\",\n\t\t\t\t\t\t\t\"this.monitorController.createMonitor\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\n  \\\"headers\\\": {\\n    \\\"Authorization\\\": \\\"Bearer <jwt>\\\"\\n  },\\n  \\\"body\\\": {\\n    \\\"name\\\": \\\"My Google Monitor\\\",\\n    \\\"url\\\": \\\"http://google.com\\\",\\n    \\\"type\\\": \\\"http\\\",\\n    \\\"interval\\\": 60000\\n  }\\n}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\n  \\\"headers\\\": {\\n    \\\"Authorization\\\": \\\"Bearer <jwt>\\\"\\n  },\\n  \\\"body\\\": {\\n    \\\"name\\\": \\\"My Google Monitor\\\",\\n    \\\"url\\\": \\\"http://google.com\\\",\\n    \\\"type\\\": \\\"http\\\",\\n    \\\"interval\\\": 60000\\n  }\\n}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"38fd069d-9c44-4078-954b-3a0899e9acf4\",\n\t\t\t\t\t\"diagramNodeId\": \"f0409948-75dc-457f-a02d-6b9774258e48\",\n\t\t\t\t\t\"simStepLabel\": \"Uptime Monitor Creation: Controller to Service\",\n\t\t\t\t\t\"simStepDescription\": \"The `MonitorController` extracts the user and team ID from the request and calls the `createMonitor` method in the `MonitorService`, passing along the monitor data from the request body.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/controllers/v1/monitorController.js\",\n\t\t\t\t\t\t\"startLine\": \"195\",\n\t\t\t\t\t\t\"endLine\": \"195\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"this.monitorService.createMonitor\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\n  \\\"user\\\": {\\n    \\\"_id\\\": \\\"user-123\\\",\\n    \\\"teamId\\\": \\\"team-abc\\\"\\n  },\\n  \\\"body\\\": {\\n    \\\"name\\\": \\\"My Google Monitor\\\",\\n    \\\"url\\\": \\\"http://google.com\\\",\\n    \\\"type\\\": \\\"http\\\"\\n  }\\n}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\n  \\\"teamId\\\": \\\"team-abc\\\",\\n  \\\"userId\\\": \\\"user-123\\\",\\n  \\\"body\\\": {\\n    \\\"name\\\": \\\"My Google Monitor\\\",\\n    \\\"url\\\": \\\"http://google.com\\\",\\n    \\\"type\\\": \\\"http\\\"\\n  }\\n}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"a6f4c967-b1a8-4804-bc2e-67f47a7b68f9\",\n\t\t\t\t\t\"diagramNodeId\": \"a6bccd1d-4272-4df7-a7c8-b3979e37b8d7\",\n\t\t\t\t\t\"simStepLabel\": \"Uptime Monitor Creation: Service to DB Module\",\n\t\t\t\t\t\"simStepDescription\": \"The `MonitorService` calls the `createMonitor` method of the `monitorModule` to handle the database interaction.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/service/v1/business/monitorService.js\",\n\t\t\t\t\t\t\"startLine\": \"74\",\n\t\t\t\t\t\t\"endLine\": \"78\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"this.db.monitorModule.createMonitor\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\n  \\\"teamId\\\": \\\"team-abc\\\",\\n  \\\"userId\\\": \\\"user-123\\\",\\n  \\\"body\\\": {\\n    \\\"name\\\": \\\"My Google Monitor\\\",\\n    \\\"url\\\": \\\"http://google.com\\\",\\n    \\\"type\\\": \\\"http\\\"\\n  }\\n}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\n  \\\"teamId\\\": \\\"team-abc\\\",\\n  \\\"userId\\\": \\\"user-123\\\",\\n  \\\"body\\\": {\\n    \\\"name\\\": \\\"My Google Monitor\\\",\\n    \\\"url\\\": \\\"http://google.com\\\",\\n    \\\"type\\\": \\\"http\\\"\\n  }\\n}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"ca3ad309-323a-418d-a171-c16f56fae23c\",\n\t\t\t\t\t\"diagramNodeId\": \"2d407bfd-e4b0-46b8-99e7-121c507d525f\",\n\t\t\t\t\t\"simStepLabel\": \"Uptime Monitor Creation: Save Monitor to Database\",\n\t\t\t\t\t\"simStepDescription\": \"The `monitorModule` creates a new `Monitor` model instance with the provided data and saves it to the MongoDB database. The newly created document, including its generated `_id`, is returned.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/db/v1/modules/monitorModule.js\",\n\t\t\t\t\t\t\"startLine\": \"454\",\n\t\t\t\t\t\t\"endLine\": \"455\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"this.Monitor\",\n\t\t\t\t\t\t\t\"monitor.save\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\n  \\\"teamId\\\": \\\"team-abc\\\",\\n  \\\"userId\\\": \\\"user-123\\\",\\n  \\\"body\\\": {\\n    \\\"name\\\": \\\"My Google Monitor\\\",\\n    \\\"url\\\": \\\"http://google.com\\\",\\n    \\\"type\\\": \\\"http\\\"\\n  }\\n}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\n  \\\"_id\\\": \\\"60d21b4667d0d8992e610c85\\\",\\n  \\\"name\\\": \\\"My Google Monitor\\\",\\n  \\\"url\\\": \\\"http://google.com\\\",\\n  \\\"type\\\": \\\"http\\\",\\n  \\\"interval\\\": 60000,\\n  \\\"userId\\\": \\\"user-123\\\",\\n  \\\"teamId\\\": \\\"team-abc\\\",\\n  \\\"isActive\\\": true,\\n  \\\"createdAt\\\": \\\"2023-01-01T12:00:00Z\\\",\\n  \\\"updatedAt\\\": \\\"2023-01-01T12:00:00Z\\\"\\n}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"71ec03b6-1166-4c5d-9ada-0875a0866e30\",\n\t\t\t\t\t\"diagramNodeId\": \"de320ac1-0949-4297-be7c-b9d7a14e0fec\",\n\t\t\t\t\t\"simStepLabel\": \"Uptime Monitor Creation: Service to Job Queue\",\n\t\t\t\t\t\"simStepDescription\": \"After successfully saving the monitor to the database, the `MonitorService` returns the new monitor object and then calls `jobQueue.addJob` to schedule the first and subsequent checks for this monitor.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/service/v1/business/monitorService.js\",\n\t\t\t\t\t\t\"startLine\": \"80\",\n\t\t\t\t\t\t\"endLine\": \"80\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"this.jobQueue.addJob\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\n  \\\"_id\\\": \\\"60d21b4667d0d8992e610c85\\\",\\n  \\\"name\\\": \\\"My Google Monitor\\\",\\n  \\\"url\\\": \\\"http://google.com\\\",\\n  \\\"type\\\": \\\"http\\\",\\n  \\\"interval\\\": 60000,\\n  \\\"isActive\\\": true\\n}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\n  \\\"_id\\\": \\\"60d21b4667d0d8992e610c85\\\",\\n  \\\"name\\\": \\\"My Google Monitor\\\",\\n  \\\"url\\\": \\\"http://google.com\\\",\\n  \\\"type\\\": \\\"http\\\",\\n  \\\"interval\\\": 60000,\\n  \\\"isActive\\\": true\\n}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"2702bfca-7611-4562-8d3e-a05af8257871\",\n\t\t\t\t\t\"diagramNodeId\": \"51e8db5f-2fdd-4ddc-9605-43981db9d940\",\n\t\t\t\t\t\"simStepLabel\": \"Uptime Monitor Creation: Schedule Job\",\n\t\t\t\t\t\"simStepDescription\": \"The `SuperSimpleQueue` receives the new monitor and uses its `scheduler.addJob` method to create a recurring job based on the monitor's interval. The monitor object itself is stored as data for the job.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/service/v1/infrastructure/SuperSimpleQueue/SuperSimpleQueue.js\",\n\t\t\t\t\t\t\"startLine\": \"50\",\n\t\t\t\t\t\t\"endLine\": \"57\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"addJob\",\n\t\t\t\t\t\t\t\"this.scheduler.addJob\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\n  \\\"_id\\\": \\\"60d21b4667d0d8992e610c85\\\",\\n  \\\"name\\\": \\\"My Google Monitor\\\",\\n  \\\"url\\\": \\\"http://google.com\\\",\\n  \\\"type\\\": \\\"http\\\",\\n  \\\"interval\\\": 60000,\\n  \\\"isActive\\\": true\\n}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\n  \\\"id\\\": \\\"60d21b4667d0d8992e610c85\\\",\\n  \\\"template\\\": \\\"monitor-job\\\",\\n  \\\"repeat\\\": 60000,\\n  \\\"active\\\": true,\\n  \\\"data\\\": { ...monitor object ... }\\n}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"e22a708a-a348-4775-8ee3-f32a35446e24\",\n\t\t\t\t\t\"diagramNodeId\": \"18c13391-0cf7-4303-8180-0a40cfd64b58\",\n\t\t\t\t\t\"simStepLabel\": \"Service Monitoring: Job Execution\",\n\t\t\t\t\t\"simStepDescription\": \"The scheduler triggers a monitor job at the specified interval. The `getMonitorJob` function in `SuperSimpleQueueHelper` is executed, which first checks if the monitor is in a maintenance window.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/service/v1/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.js\",\n\t\t\t\t\t\t\"startLine\": \"27\",\n\t\t\t\t\t\t\"endLine\": \"73\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"getMonitorJob\",\n\t\t\t\t\t\t\t\"isInMaintenanceWindow\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\n  \\\"id\\\": \\\"60d21b4667d0d8992e610c85\\\",\\n  \\\"data\\\": {\\n    \\\"_id\\\": \\\"60d21b4667d0d8992e610c85\\\",\\n    \\\"name\\\": \\\"My Google Monitor\\\",\\n    \\\"url\\\": \\\"http://google.com\\\",\\n    \\\"type\\\": \\\"http\\\",\\n    \\\"interval\\\": 60000\\n  }\\n}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\n  \\\"_id\\\": \\\"60d21b4667d0d8992e610c85\\\",\\n  \\\"name\\\": \\\"My Google Monitor\\\",\\n  \\\"url\\\": \\\"http://google.com\\\",\\n  \\\"type\\\": \\\"http\\\",\\n  \\\"interval\\\": 60000\\n}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"1d7580f2-f107-4008-a207-b8ec07998721\",\n\t\t\t\t\t\"diagramNodeId\": \"38ba9b22-5b26-432d-a856-0eceb792c737\",\n\t\t\t\t\t\"simStepLabel\": \"Service Monitoring: Request Service Status\",\n\t\t\t\t\t\"simStepDescription\": \"Assuming no active maintenance, the job helper calls `networkService.requestStatus`, passing the monitor object to perform the actual availability check.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/service/v1/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.js\",\n\t\t\t\t\t\t\"startLine\": \"45\",\n\t\t\t\t\t\t\"endLine\": \"45\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"this.networkService.requestStatus\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\n  \\\"_id\\\": \\\"60d21b4667d0d8992e610c85\\\",\\n  \\\"name\\\": \\\"My Google Monitor\\\",\\n  \\\"url\\\": \\\"http://google.com\\\",\\n  \\\"type\\\": \\\"http\\\",\\n  \\\"interval\\\": 60000\\n}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\n  \\\"_id\\\": \\\"60d21b4667d0d8992e610c85\\\",\\n  \\\"name\\\": \\\"My Google Monitor\\\",\\n  \\\"url\\\": \\\"http://google.com\\\",\\n  \\\"type\\\": \\\"http\\\",\\n  \\\"interval\\\": 60000\\n}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"84f82fea-e306-4e0b-8222-e9705803d51a\",\n\t\t\t\t\t\"diagramNodeId\": \"5c900373-e6ba-44d5-b341-676a32d659c8\",\n\t\t\t\t\t\"simStepLabel\": \"Service Monitoring: Perform Network Check\",\n\t\t\t\t\t\"simStepDescription\": \"The `requestStatus` method in the network service acts as a router. Based on the monitor's `type` (e.g., 'http', 'ping', 'docker'), it calls the corresponding specialized request function (e.g., `requestHttp`) to perform the check and constructs a standardized response object.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/service/v1/infrastructure/networkService.js\",\n\t\t\t\t\t\t\"startLine\": \"44\",\n\t\t\t\t\t\t\"endLine\": \"59\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"requestStatus\",\n\t\t\t\t\t\t\t\"requestHttp\",\n\t\t\t\t\t\t\t\"requestPing\",\n\t\t\t\t\t\t\t\"requestDocker\",\n\t\t\t\t\t\t\t\"requestPort\",\n\t\t\t\t\t\t\t\"requestGame\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\n  \\\"_id\\\": \\\"60d21b4667d0d8992e610c85\\\",\\n  \\\"name\\\": \\\"My Google Monitor\\\",\\n  \\\"url\\\": \\\"http://google.com\\\",\\n  \\\"type\\\": \\\"http\\\"\\n}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\n  \\\"monitorId\\\": \\\"60d21b4667d0d8992e610c85\\\",\\n  \\\"type\\\": \\\"http\\\",\\n  \\\"status\\\": true,\\n  \\\"code\\\": 200,\\n  \\\"responseTime\\\": 150,\\n  \\\"message\\\": \\\"OK\\\"\\n}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"9b0ada30-d3e6-4b2c-b3ff-f50615139588\",\n\t\t\t\t\t\"diagramNodeId\": \"5e80734c-7b72-41be-9068-30cda3ffb425\",\n\t\t\t\t\t\"simStepLabel\": \"Service Monitoring: Propagate Network Response\",\n\t\t\t\t\t\"simStepDescription\": \"The network response object, containing the result of the check (status, response time, status code), is returned to the job handler in `SuperSimpleQueueHelper`.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/service/v1/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.js\",\n\t\t\t\t\t\t\"startLine\": \"45\",\n\t\t\t\t\t\t\"endLine\": \"45\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"networkResponse\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\n  \\\"monitorId\\\": \\\"60d21b4667d0d8992e610c85\\\",\\n  \\\"type\\\": \\\"http\\\",\\n  \\\"status\\\": true,\\n  \\\"code\\\": 200,\\n  \\\"responseTime\\\": 150,\\n  \\\"message\\\": \\\"OK\\\"\\n}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\n  \\\"monitorId\\\": \\\"60d21b4667d0d8992e610c85\\\",\\n  \\\"type\\\": \\\"http\\\",\\n  \\\"status\\\": true,\\n  \\\"code\\\": 200,\\n  \\\"responseTime\\\": 150,\\n  \\\"message\\\": \\\"OK\\\"\\n}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"c66a04c6-113e-4391-ab71-93fc612279ef\",\n\t\t\t\t\t\"diagramNodeId\": \"45e38f3a-a7c3-4de7-b3dc-589361d793fd\",\n\t\t\t\t\t\"simStepLabel\": \"Service Monitoring: Update Monitor Status\",\n\t\t\t\t\t\"simStepDescription\": \"The job handler passes the network response to `statusService.updateStatus`. This service creates a new `Check` document in the database, updates the monitor's status based on a sliding window and threshold, and calculates running statistics.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/service/v1/infrastructure/statusService.js\",\n\t\t\t\t\t\t\"startLine\": \"108\",\n\t\t\t\t\t\t\"endLine\": \"183\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"updateStatus\",\n\t\t\t\t\t\t\t\"buildCheck\",\n\t\t\t\t\t\t\t\"insertCheck\",\n\t\t\t\t\t\t\t\"updateRunningStats\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\n  \\\"monitorId\\\": \\\"60d21b4667d0d8992e610c85\\\",\\n  \\\"status\\\": true,\\n  \\\"responseTime\\\": 150,\\n  \\\"code\\\": 200\\n}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\n  \\\"monitor\\\": { ...updated monitor object ... },\\n  \\\"statusChanged\\\": false,\\n  \\\"prevStatus\\\": true\\n}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"9896c387-4fca-47ad-82eb-7301286decb7\",\n\t\t\t\t\t\"diagramNodeId\": \"0a7e4a72-b644-4bd8-afa1-ae8a1d6c111c\",\n\t\t\t\t\t\"simStepLabel\": \"Service Monitoring: Check for Status Change\",\n\t\t\t\t\t\"simStepDescription\": \"The result from `statusService`, indicating whether the monitor's overall status changed (e.g., from 'up' to 'down'), is returned to the job handler.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/service/v1/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.js\",\n\t\t\t\t\t\t\"startLine\": \"51\",\n\t\t\t\t\t\t\"endLine\": \"51\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"updatedMonitor\",\n\t\t\t\t\t\t\t\"statusChanged\",\n\t\t\t\t\t\t\t\"prevStatus\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\n  \\\"monitor\\\": { ...updated monitor object ... },\\n  \\\"statusChanged\\\": false,\\n  \\\"prevStatus\\\": true\\n}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\n  \\\"monitor\\\": { ...updated monitor object ... },\\n  \\\"statusChanged\\\": false,\\n  \\\"prevStatus\\\": true\\n}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"1a260a75-cf50-4f7a-90b0-c280b512a5cb\",\n\t\t\t\t\t\"diagramNodeId\": \"9f3ea7fc-16d3-4d36-97eb-66f8808425cc\",\n\t\t\t\t\t\"simStepLabel\": \"Service Monitoring: Handle Notifications (Conditional)\",\n\t\t\t\t\t\"simStepDescription\": \"If `statusChanged` is true, the job handler calls `notificationService.handleNotifications`. The service identifies the notification channels associated with the monitor and sends out alerts (e.g., email, webhook, Discord) with details about the status change.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/service/v1/infrastructure/notificationService.js\",\n\t\t\t\t\t\t\"startLine\": \"76\",\n\t\t\t\t\t\t\"endLine\": \"92\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"handleNotifications\",\n\t\t\t\t\t\t\t\"notifyAll\",\n\t\t\t\t\t\t\t\"buildStatusEmail\",\n\t\t\t\t\t\t\t\"buildWebhookMessage\",\n\t\t\t\t\t\t\t\"buildHardwareAlerts\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\n  \\\"monitorId\\\": \\\"60d21b4667d0d8992e610c85\\\",\\n  \\\"status\\\": false,\\n  \\\"monitor\\\": { ... },\\n  \\\"statusChanged\\\": true,\\n  \\\"prevStatus\\\": true\\n}\",\n\t\t\t\t\t\"outputDataExample\": \"{}\"\n\t\t\t\t}\n\t\t\t],\n\t\t\t\"description\": \"<ul><li>The core feature of Checkmate is to monitor the availability and response time of services</li><li>Users can configure different types of monitors for various needs</li><li>- Supports multiple protocols including HTTP(s), Ping, Port, and Docker containers</li><li>- Users can set the check frequency, from one to five minutes, to define how often the service is checked</li><li>- Advanced HTTP matching is available, allowing checks against JSON responses using JMESPath, regex, or simple inclusion/equality</li><li>- Game server monitoring is also a specific type of monitor supported by the application</li></ul>\",\n\t\t\t\"simulationNodesAndEdges\": {\n\t\t\t\t\"7a2da928-a65c-49d8-b0a3-c159a6df2bc5\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"ab5de0b9-c70d-492c-98d9-8ddee66284ad\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"a81f4ae8-41fe-4d1b-95ce-86abcc67b53c\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"e02ddf57-270e-4f71-b4c4-d5183bb7879a\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"a30ac765-c546-4993-988e-8c8cfdb7532f\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"14e9986b-c6ce-475e-97ed-da1fa2b6968d\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"f0409948-75dc-457f-a02d-6b9774258e48\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"38fd069d-9c44-4078-954b-3a0899e9acf4\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"2d407bfd-e4b0-46b8-99e7-121c507d525f\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"ca3ad309-323a-418d-a171-c16f56fae23c\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"51e8db5f-2fdd-4ddc-9605-43981db9d940\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"2702bfca-7611-4562-8d3e-a05af8257871\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"18c13391-0cf7-4303-8180-0a40cfd64b58\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"e22a708a-a348-4775-8ee3-f32a35446e24\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"5c900373-e6ba-44d5-b341-676a32d659c8\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"84f82fea-e306-4e0b-8222-e9705803d51a\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"45e38f3a-a7c3-4de7-b3dc-589361d793fd\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"c66a04c6-113e-4391-ab71-93fc612279ef\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"9f3ea7fc-16d3-4d36-97eb-66f8808425cc\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"1a260a75-cf50-4f7a-90b0-c280b512a5cb\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"0e09aa33-d7c7-4c89-9da8-f0937658f4d3\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"888df086-41bb-469d-9c0a-daf74bdecb9f\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"1f6f04a9-0123-4729-b06a-8f3da6d1b58c\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"3fe0afaa-c673-4b52-a0c4-02a3ffd3a075\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"b6d963d5-c613-407a-9ce9-60a04048dea7\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"13dd0564-44a5-43ea-a163-ce1148cc48e7\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"a6bccd1d-4272-4df7-a7c8-b3979e37b8d7\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"a6f4c967-b1a8-4804-bc2e-67f47a7b68f9\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"de320ac1-0949-4297-be7c-b9d7a14e0fec\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"71ec03b6-1166-4c5d-9ada-0875a0866e30\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"38ba9b22-5b26-432d-a856-0eceb792c737\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"1d7580f2-f107-4008-a207-b8ec07998721\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"5e80734c-7b72-41be-9068-30cda3ffb425\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"9b0ada30-d3e6-4b2c-b3ff-f50615139588\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"0a7e4a72-b644-4bd8-afa1-ae8a1d6c111c\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"9896c387-4fca-47ad-82eb-7301286decb7\"\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"isAIGenerated\": true,\n\t\t\t\"keywords\": \"Monitor, checkService, UptimeCreate\",\n\t\t\t\"generationPrompt\": \"Comprehensive Uptime Monitoring for Various Services\",\n\t\t\t\"generationKeywords\": \"Monitor, checkService, UptimeCreate\"\n\t\t},\n\t\t\"Infrastructure and Hardware Health Monitoring\": {\n\t\t\t\"name\": \"Infrastructure and Hardware Health Monitoring\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"80dd889a-1fc9-4d56-b9cf-5b45bf1110b1\",\n\t\t\t\t\t\"diagramNodeId\": \"9651d084-5c16-4417-89c1-f52ae6572a95\",\n\t\t\t\t\t\"simStepLabel\": \"Configuration: User Sets Alert Thresholds\",\n\t\t\t\t\t\"simStepDescription\": \"A user navigates to the 'Create Infrastructure Monitor' page to set up monitoring for a new server. They enable alerts for CPU, memory, and disk usage, and define specific thresholds for each metric. For example, an alert is configured to trigger if CPU usage exceeds 80%.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Pages/v1/Infrastructure/Create/Components/CustomAlertsSection.jsx\",\n\t\t\t\t\t\t\"startLine\": \"45\",\n\t\t\t\t\t\t\"endLine\": \"53\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"CustomThreshold\",\n\t\t\t\t\t\t\t\"METRICS\",\n\t\t\t\t\t\t\t\"METRIC_PREFIX\",\n\t\t\t\t\t\t\t\"handleCheckboxChange\",\n\t\t\t\t\t\t\t\"infrastructureMonitor\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\n  \\\"infrastructureMonitor\\\": {\\n    \\\"url\\\": \\\"my-server.example.com\\\",\\n    \\\"name\\\": \\\"Production Web Server\\\",\\n    \\\"cpu\\\": false,\\n    \\\"usage_cpu\\\": \\\"\\\",\\n    \\\"memory\\\": false,\\n    \\\"usage_memory\\\": \\\"\\\",\\n    \\\"disk\\\": false,\\n    \\\"usage_disk\\\": \\\"\\\"\\n  }\\n}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\n  \\\"infrastructureMonitor\\\": {\\n    \\\"url\\\": \\\"my-server.example.com\\\",\\n    \\\"name\\\": \\\"Production Web Server\\\",\\n    \\\"cpu\\\": true,\\n    \\\"usage_cpu\\\": \\\"80\\\",\\n    \\\"memory\\\": true,\\n    \\\"usage_memory\\\": \\\"75\\\",\\n    \\\"disk\\\": true,\\n    \\\"usage_disk\\\": \\\"90\\\"\\n  }\\n}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"815f96af-c28e-4f80-b4ab-18a6fb23eee0\",\n\t\t\t\t\t\"diagramNodeId\": \"1c5c9857-bf32-40e4-921b-957c252dac2a\",\n\t\t\t\t\t\"simStepLabel\": \"API Call: Submit Monitor Configuration\",\n\t\t\t\t\t\"simStepDescription\": \"After configuring the monitor and its alert thresholds, the user saves the configuration. The frontend application constructs a monitor object with `type: 'hardware'` and sends it to the backend via a POST request to create the new monitor.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Hooks/v1/monitorHooks.js\",\n\t\t\t\t\t\t\"startLine\": \"386\",\n\t\t\t\t\t\t\"endLine\": \"389\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"updatedFields\",\n\t\t\t\t\t\t\t\"monitor.type\",\n\t\t\t\t\t\t\t\"monitor.thresholds\",\n\t\t\t\t\t\t\t\"monitor.secret\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\n  \\\"monitor\\\": {\\n    \\\"name\\\": \\\"Production Web Server\\\",\\n    \\\"url\\\": \\\"http://my-server.example.com\\\",\\n    \\\"type\\\": \\\"hardware\\\",\\n    \\\"interval\\\": 15000,\\n    \\\"secret\\\": \\\"super-secret-key\\\",\\n    \\\"thresholds\\\": {\\n      \\\"usage_cpu\\\": 0.8,\\n      \\\"usage_memory\\\": 0.75,\\n      \\\"usage_disk\\\": 0.9\\n    }\\n  }\\n}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\n  \\\"monitor\\\": {\\n    \\\"name\\\": \\\"Production Web Server\\\",\\n    \\\"url\\\": \\\"http://my-server.example.com\\\",\\n    \\\"type\\\": \\\"hardware\\\",\\n    \\\"interval\\\": 15000,\\n    \\\"secret\\\": \\\"super-secret-key\\\",\\n    \\\"thresholds\\\": {\\n      \\\"usage_cpu\\\": 0.8,\\n      \\\"usage_memory\\\": 0.75,\\n      \\\"usage_disk\\\": 0.9\\n    }\\n  }\\n}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"ed6e7faf-69dd-4d0b-bda8-137739ed288b\",\n\t\t\t\t\t\"diagramNodeId\": \"4c47b5f2-5363-4816-9745-30e61d184c7a\",\n\t\t\t\t\t\"simStepLabel\": \"Automated Check: Backend Fetches Hardware Data\",\n\t\t\t\t\t\"simStepDescription\": \"The Checkmate server's job queue periodically initiates a check for the newly created hardware monitor. It makes an HTTP request to the monitor's URL, which points to the external 'Capture' agent running on the target server.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/service/v1/infrastructure/networkService.js\",\n\t\t\t\t\t\t\"startLine\": \"7\",\n\t\t\t\t\t\t\"endLine\": \"14\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"TYPE_HARDWARE\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\n  \\\"monitor\\\": {\\n    \\\"_id\\\": \\\"65ada27a51442afd52857053\\\",\\n    \\\"name\\\": \\\"Production Web Server\\\",\\n    \\\"url\\\": \\\"http://my-server.example.com\\\",\\n    \\\"type\\\": \\\"hardware\\\",\\n    \\\"interval\\\": 15000\\n  }\\n}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\n  \\\"networkResponse\\\": {\\n    \\\"ok\\\": true,\\n    \\\"status\\\": 200,\\n    \\\"statusText\\\": \\\"OK\\\",\\n    \\\"payload\\\": {\\n      \\\"data\\\": {\\n        \\\"cpu\\\": {\\n          \\\"usage_percent\\\": 0.85\\n        },\\n        \\\"memory\\\": {\\n          \\\"usage_percent\\\": 0.65\\n        },\\n        \\\"disk\\\": [\\n          {\\n            \\\"usage_percent\\\": 0.5\\n          }\\n        ]\\n      }\\n    }\\n  }\\n}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"4434dca1-2048-4458-a70b-b70d569e378d\",\n\t\t\t\t\t\"diagramNodeId\": \"a64547c9-d9e6-4941-8e5e-f49add06516b\",\n\t\t\t\t\t\"simStepLabel\": \"Automated Check: Data Received from Capture Agent\",\n\t\t\t\t\t\"simStepDescription\": \"The 'Capture' agent responds to the server's request with a JSON payload containing detailed hardware metrics, including CPU usage, memory consumption, disk space, and network statistics.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/service/v1/infrastructure/statusService.js\",\n\t\t\t\t\t\t\"startLine\": \"266\",\n\t\t\t\t\t\t\"endLine\": \"273\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"payload\",\n\t\t\t\t\t\t\t\"cpu\",\n\t\t\t\t\t\t\t\"memory\",\n\t\t\t\t\t\t\t\"disk\",\n\t\t\t\t\t\t\t\"host\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\n  \\\"data\\\": {\\n    \\\"cpu\\\": {\\n      \\\"physical_core\\\": 4,\\n      \\\"logical_core\\\": 8,\\n      \\\"frequency\\\": 3400,\\n      \\\"usage_percent\\\": 0.85,\\n      \\\"temperature\\\": [65, 66, 65, 67]\\n    },\\n    \\\"memory\\\": {\\n      \\\"total_bytes\\\": 17179869184,\\n      \\\"used_bytes\\\": 11166914970,\\n      \\\"usage_percent\\\": 0.65\\n    },\\n    \\\"disk\\\": [\\n      {\\n        \\\"name\\\": \\\"/dev/sda1\\\",\\n        \\\"total_bytes\\\": 250685575168,\\n        \\\"used_bytes\\\": 125342787584,\\n        \\\"usage_percent\\\": 0.5\\n      }\\n    ],\\n    \\\"host\\\": {\\n      \\\"os\\\": \\\"Ubuntu 22.04 LTS\\\"\\n    }\\n  },\\n  \\\"errors\\\": []\\n}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\n  \\\"data\\\": {\\n    \\\"cpu\\\": {\\n      \\\"physical_core\\\": 4,\\n      \\\"logical_core\\\": 8,\\n      \\\"frequency\\\": 3400,\\n      \\\"usage_percent\\\": 0.85,\\n      \\\"temperature\\\": [65, 66, 65, 67]\\n    },\\n    \\\"memory\\\": {\\n      \\\"total_bytes\\\": 17179869184,\\n      \\\"used_bytes\\\": 11166914970,\\n      \\\"usage_percent\\\": 0.65\\n    },\\n    \\\"disk\\\": [\\n      {\\n        \\\"name\\\": \\\"/dev/sda1\\\",\\n        \\\"total_bytes\\\": 250685575168,\\n        \\\"used_bytes\\\": 125342787584,\\n        \\\"usage_percent\\\": 0.5\\n      }\\n    ],\\n    \\\"host\\\": {\\n      \\\"os\\\": \\\"Ubuntu 22.04 LTS\\\"\\n    }\\n  },\\n  \\\"errors\\\": []\\n}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"e5b90cf2-9369-4741-9803-c835a81c009b\",\n\t\t\t\t\t\"diagramNodeId\": \"c1bf10c9-8c1a-44f4-8e23-39708f0301e8\",\n\t\t\t\t\t\"simStepLabel\": \"Automated Check: Process and Store Hardware Data\",\n\t\t\t\t\t\"simStepDescription\": \"The backend's StatusService receives the payload from the Capture agent. It parses the data and constructs a 'check' document. This document, containing the detailed hardware metrics, is then saved to the database for historical tracking and visualization.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/service/v1/infrastructure/statusService.js\",\n\t\t\t\t\t\t\"startLine\": \"265\",\n\t\t\t\t\t\t\"endLine\": \"274\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"buildCheck\",\n\t\t\t\t\t\t\t\"type\",\n\t\t\t\t\t\t\t\"payload\",\n\t\t\t\t\t\t\t\"check.cpu\",\n\t\t\t\t\t\t\t\"check.memory\",\n\t\t\t\t\t\t\t\"check.disk\",\n\t\t\t\t\t\t\t\"check.host\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\n  \\\"networkResponse\\\": {\\n    \\\"type\\\": \\\"hardware\\\",\\n    \\\"payload\\\": {\\n      \\\"data\\\": {\\n        \\\"cpu\\\": { \\\"usage_percent\\\": 0.85 },\\n        \\\"memory\\\": { \\\"usage_percent\\\": 0.65 },\\n        \\\"disk\\\": [{ \\\"usage_percent\\\": 0.5 }],\\n        \\\"host\\\": { \\\"os\\\": \\\"Ubuntu 22.04 LTS\\\" }\\n      }\\n    }\\n  }\\n}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\n  \\\"check\\\": {\\n    \\\"monitorId\\\": \\\"65ada27a51442afd52857053\\\",\\n    \\\"type\\\": \\\"hardware\\\",\\n    \\\"status\\\": true,\\n    \\\"cpu\\\": { \\\"usage_percent\\\": 0.85 },\\n    \\\"memory\\\": { \\\"usage_percent\\\": 0.65 },\\n    \\\"disk\\\": [{ \\\"usage_percent\\\": 0.5 }],\\n    \\\"host\\\": { \\\"os\\\": \\\"Ubuntu 22.04 LTS\\\" }\\n  }\\n}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"b019a6d0-a23a-4a1d-bd21-644f01996f14\",\n\t\t\t\t\t\"diagramNodeId\": \"7a250d09-50c6-4935-b10c-626b0ebe1fba\",\n\t\t\t\t\t\"simStepLabel\": \"Automated Check: Pass Data for Alert Evaluation\",\n\t\t\t\t\t\"simStepDescription\": \"After storing the check data, the system passes the complete network response, including monitor details and the latest metrics, to the notification service to evaluate if any alerts need to be triggered.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/service/v1/infrastructure/notificationService.js\",\n\t\t\t\t\t\t\"startLine\": \"60\",\n\t\t\t\t\t\t\"endLine\": \"79\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"handleNotifications\",\n\t\t\t\t\t\t\t\"networkResponse\",\n\t\t\t\t\t\t\t\"monitor.type\",\n\t\t\t\t\t\t\t\"thresholds\",\n\t\t\t\t\t\t\t\"metrics\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\n  \\\"networkResponse\\\": {\\n    \\\"monitor\\\": {\\n      \\\"_id\\\": \\\"65ada27a51442afd52857053\\\",\\n      \\\"name\\\": \\\"Production Web Server\\\",\\n      \\\"thresholds\\\": {\\n        \\\"usage_cpu\\\": 0.8\\n      },\\n      \\\"notifications\\\": [\\\"65a5b0b3e8a2b0e6e8c7b8e3\\\"]\\n    },\\n    \\\"payload\\\": {\\n      \\\"data\\\": {\\n        \\\"cpu\\\": { \\\"usage_percent\\\": 0.85 }\\n      }\\n    }\\n  }\\n}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\n  \\\"networkResponse\\\": {\\n    \\\"monitor\\\": {\\n      \\\"_id\\\": \\\"65ada27a51442afd52857053\\\",\\n      \\\"name\\\": \\\"Production Web Server\\\",\\n      \\\"thresholds\\\": {\\n        \\\"usage_cpu\\\": 0.8\\n      },\\n      \\\"notifications\\\": [\\\"65a5b0b3e8a2b0e6e8c7b8e3\\\"]\\n    },\\n    \\\"payload\\\": {\\n      \\\"data\\\": {\\n        \\\"cpu\\\": { \\\"usage_percent\\\": 0.85 }\\n      }\\n    }\\n  }\\n}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"07fe8489-1d94-4afb-83f8-7cebb0dff49a\",\n\t\t\t\t\t\"diagramNodeId\": \"d4f48f1a-61de-4cde-87d2-4b5215464899\",\n\t\t\t\t\t\"simStepLabel\": \"Automated Check: Evaluate Data Against Thresholds\",\n\t\t\t\t\t\"simStepDescription\": \"The notification utility function compares the received hardware metrics against the user-defined thresholds stored in the monitor's configuration. In this case, the CPU usage of 85% is greater than the 80% threshold, so an alert condition is met.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/service/v1/infrastructure/notificationUtils.js\",\n\t\t\t\t\t\t\"startLine\": \"95\",\n\t\t\t\t\t\t\"endLine\": \"109\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"buildHardwareAlerts\",\n\t\t\t\t\t\t\t\"thresholds\",\n\t\t\t\t\t\t\t\"metrics\",\n\t\t\t\t\t\t\t\"cpuThreshold\",\n\t\t\t\t\t\t\t\"cpuUsage\",\n\t\t\t\t\t\t\t\"alerts\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\n  \\\"networkResponse\\\": {\\n    \\\"monitor\\\": {\\n      \\\"thresholds\\\": {\\n        \\\"usage_cpu\\\": 0.8\\n      }\\n    },\\n    \\\"payload\\\": {\\n      \\\"data\\\": {\\n        \\\"cpu\\\": {\\n          \\\"usage_percent\\\": 0.85\\n        }\\n      }\\n    }\\n  }\\n}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\n  \\\"alerts\\\": {\\n    \\\"cpu\\\": true,\\n    \\\"memory\\\": false,\\n    \\\"disk\\\": false\\n  }\\n}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"c691b3b9-88b3-4c88-a399-ff9fd5866194\",\n\t\t\t\t\t\"diagramNodeId\": \"3d357de8-9fd2-4d0b-9623-f36fce4cf1de\",\n\t\t\t\t\t\"simStepLabel\": \"Automated Check: Generate Alert Notification Content\",\n\t\t\t\t\t\"simStepDescription\": \"Since the CPU threshold was breached, the system constructs a user-friendly alert message. For email notifications, it builds an HTML email detailing the alert, including the monitor name, the metric that triggered the alert, the current value, and the threshold.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/service/v1/infrastructure/notificationUtils.js\",\n\t\t\t\t\t\t\"startLine\": \"177\",\n\t\t\t\t\t\t\"endLine\": \"183\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"buildHardwareEmail\",\n\t\t\t\t\t\t\t\"networkResponse\",\n\t\t\t\t\t\t\t\"alerts\",\n\t\t\t\t\t\t\t\"template\",\n\t\t\t\t\t\t\t\"context\",\n\t\t\t\t\t\t\t\"subject\",\n\t\t\t\t\t\t\t\"html\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\n  \\\"networkResponse\\\": {\\n    \\\"monitor\\\": {\\n      \\\"name\\\": \\\"Production Web Server\\\",\\n      \\\"url\\\": \\\"http://my-server.example.com\\\"\\n    }\\n  },\\n  \\\"alerts\\\": [\\n    \\\"Your current CPU usage (85%) is above your threshold (80%)\\\"\\n  ]\\n}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\n  \\\"subject\\\": \\\"Monitor Production Web Server infrastructure alerts\\\",\\n  \\\"html\\\": \\\"...HTML content for the email...\\\"\\n}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"c27365db-9db6-4cc9-96f0-4f046fd38562\",\n\t\t\t\t\t\"diagramNodeId\": \"801fe70a-1a19-406c-8f0d-770b0cb74409\",\n\t\t\t\t\t\"simStepLabel\": \"Visualization: User Views Monitor Details\",\n\t\t\t\t\t\"simStepDescription\": \"A user navigates to the details page for their 'Production Web Server' monitor in the Checkmate UI to view its performance. The React component for the details page mounts and prepares to fetch data.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Pages/v1/Infrastructure/Details/index.jsx\",\n\t\t\t\t\t\t\"startLine\": \"23\",\n\t\t\t\t\t\t\"endLine\": \"31\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"InfrastructureDetails\",\n\t\t\t\t\t\t\t\"useParams\",\n\t\t\t\t\t\t\t\"useState\",\n\t\t\t\t\t\t\t\"dateRange\",\n\t\t\t\t\t\t\t\"monitorId\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\n  \\\"path\\\": \\\"/infrastructure/65ada27a51442afd52857053\\\"\\n}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\n  \\\"monitorId\\\": \\\"65ada27a51442afd52857053\\\",\\n  \\\"dateRange\\\": \\\"recent\\\"\\n}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"a5d20172-1c95-4c9e-af39-f86a498734bb\",\n\t\t\t\t\t\"diagramNodeId\": \"00921831-b1d9-4a5a-ae6f-5ddee7cfc1e4\",\n\t\t\t\t\t\"simStepLabel\": \"API Call: Request for Historical Hardware Data\",\n\t\t\t\t\t\"simStepDescription\": \"The frontend makes a GET request to the backend API to fetch the historical hardware data for the specified monitor and the selected time range (e.g., 'recent').\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Utils/NetworkService.js\",\n\t\t\t\t\t\t\"startLine\": \"198\",\n\t\t\t\t\t\t\"endLine\": \"206\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"getHardwareDetailsByMonitorId\",\n\t\t\t\t\t\t\t\"config.monitorId\",\n\t\t\t\t\t\t\t\"config.dateRange\",\n\t\t\t\t\t\t\t\"this.axiosInstance.get\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\n  \\\"monitorId\\\": \\\"65ada27a51442afd52857053\\\",\\n  \\\"dateRange\\\": \\\"recent\\\"\\n}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\n  \\\"request\\\": \\\"GET /api/v1/monitors/hardware/details/65ada27a51442afd52857053?dateRange=recent\\\"\\n}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"8502ae1f-f029-446e-9dde-59c2aba87a8a\",\n\t\t\t\t\t\"diagramNodeId\": \"9ef7c423-f4fc-4caf-9bf5-c1aa3002ca03\",\n\t\t\t\t\t\"simStepLabel\": \"Backend: Aggregate Historical Data\",\n\t\t\t\t\t\"simStepDescription\": \"The backend receives the request and executes a database aggregation pipeline. This query fetches all 'hardware' checks for the monitor within the given date range and calculates metrics like average CPU usage, average memory usage, and average temperatures, grouped by time intervals.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/db/v1/modules/monitorModule.js\",\n\t\t\t\t\t\t\"startLine\": \"312\",\n\t\t\t\t\t\t\"endLine\": \"322\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"getHardwareDetailsById\",\n\t\t\t\t\t\t\t\"monitorId\",\n\t\t\t\t\t\t\t\"dateRange\",\n\t\t\t\t\t\t\t\"buildHardwareDetailsPipeline\",\n\t\t\t\t\t\t\t\"hardwareStats\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\n  \\\"monitorId\\\": \\\"65ada27a51442afd52857053\\\",\\n  \\\"dateRange\\\": \\\"recent\\\"\\n}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\n  \\\"stats\\\": {\\n    \\\"checks\\\": [\\n      {\\n        \\\"_id\\\": \\\"2023-10-27T10:00:00Z\\\",\\n        \\\"avgCpuUsage\\\": 0.85,\\n        \\\"avgMemoryUsage\\\": 0.65\\n      },\\n      {\\n        \\\"_id\\\": \\\"2023-10-27T10:01:00Z\\\",\\n        \\\"avgCpuUsage\\\": 0.82,\\n        \\\"avgMemoryUsage\\\": 0.66\\n      }\\n    ],\\n    \\\"latestCheck\\\": {\\n      \\\"cpu\\\": { \\\"usage_percent\\\": 0.85 },\\n      \\\"memory\\\": { \\\"usage_percent\\\": 0.65 }\\n    }\\n  }\\n}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"627fcb0c-0282-4b4d-8c55-aceb636e4da0\",\n\t\t\t\t\t\"diagramNodeId\": \"60308696-6f8a-43c8-b9a1-da199ef500cd\",\n\t\t\t\t\t\"simStepLabel\": \"API Response: Send Aggregated Data to Frontend\",\n\t\t\t\t\t\"simStepDescription\": \"The backend sends the aggregated hardware statistics back to the frontend in a structured JSON format, ready for visualization.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/db/v1/modules/monitorModuleQueries.js\",\n\t\t\t\t\t\t\"startLine\": \"247\",\n\t\t\t\t\t\t\"endLine\": \"262\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"buildHardwareDetailsPipeline\",\n\t\t\t\t\t\t\t\"$group\",\n\t\t\t\t\t\t\t\"avgCpuUsage\",\n\t\t\t\t\t\t\t\"avgMemoryUsage\",\n\t\t\t\t\t\t\t\"avgTemperatures\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\n  \\\"stats\\\": {\\n    \\\"checks\\\": [\\n      {\\n        \\\"_id\\\": \\\"2023-10-27T10:00:00Z\\\",\\n        \\\"avgCpuUsage\\\": 0.85,\\n        \\\"avgMemoryUsage\\\": 0.65,\\n        \\\"avgTemperature\\\": [65.5]\\n      },\\n      {\\n        \\\"_id\\\": \\\"2023-10-27T10:01:00Z\\\",\\n        \\\"avgCpuUsage\\\": 0.82,\\n        \\\"avgMemoryUsage\\\": 0.66,\\n        \\\"avgTemperature\\\": [66.0]\\n      }\\n    ],\\n    \\\"latestCheck\\\": {\\n      \\\"cpu\\\": { \\\"usage_percent\\\": 0.85, \\\"physical_core\\\": 4, \\\"frequency\\\": 3400 },\\n      \\\"memory\\\": { \\\"usage_percent\\\": 0.65, \\\"total_bytes\\\": 17179869184, \\\"used_bytes\\\": 11166914970 }\\n    }\\n  }\\n}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\n  \\\"stats\\\": {\\n    \\\"checks\\\": [\\n      {\\n        \\\"_id\\\": \\\"2023-10-27T10:00:00Z\\\",\\n        \\\"avgCpuUsage\\\": 0.85,\\n        \\\"avgMemoryUsage\\\": 0.65,\\n        \\\"avgTemperature\\\": [65.5]\\n      },\\n      {\\n        \\\"_id\\\": \\\"2023-10-27T10:01:00Z\\\",\\n        \\\"avgCpuUsage\\\": 0.82,\\n        \\\"avgMemoryUsage\\\": 0.66,\\n        \\\"avgTemperature\\\": [66.0]\\n      }\\n    ],\\n    \\\"latestCheck\\\": {\\n      \\\"cpu\\\": { \\\"usage_percent\\\": 0.85, \\\"physical_core\\\": 4, \\\"frequency\\\": 3400 },\\n      \\\"memory\\\": { \\\"usage_percent\\\": 0.65, \\\"total_bytes\\\": 17179869184, \\\"used_bytes\\\": 11166914970 }\\n    }\\n  }\\n}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"6eedce82-b9c8-4022-95e5-3a6e00628105\",\n\t\t\t\t\t\"diagramNodeId\": \"9ea2e32d-1ea8-42f2-9a17-613844723ae6\",\n\t\t\t\t\t\"simStepLabel\": \"Visualization: Frontend Renders Charts and Gauges\",\n\t\t\t\t\t\"simStepDescription\": \"The frontend components on the Infrastructure Details page receive the aggregated data. The 'GaugeBoxes' component uses the 'latestCheck' data to render real-time gauges for current CPU and memory usage, while the 'AreaChartBoxes' component uses the historical 'checks' data to render time-series charts.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Pages/v1/Infrastructure/Details/Components/GaugeBoxes/index.jsx\",\n\t\t\t\t\t\t\"startLine\": \"22\",\n\t\t\t\t\t\t\"endLine\": \"51\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"Gauges\",\n\t\t\t\t\t\t\t\"latestCheck\",\n\t\t\t\t\t\t\t\"memoryUsagePercent\",\n\t\t\t\t\t\t\t\"cpuUsagePercent\",\n\t\t\t\t\t\t\t\"gauges\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\n  \\\"monitor\\\": {\\n    \\\"stats\\\": {\\n      \\\"checks\\\": [\\n        { \\\"_id\\\": \\\"2023-10-27T10:00:00Z\\\", \\\"avgCpuUsage\\\": 0.85 },\\n        { \\\"_id\\\": \\\"2023-10-27T10:01:00Z\\\", \\\"avgCpuUsage\\\": 0.82 }\\n      ],\\n      \\\"latestCheck\\\": {\\n        \\\"cpu\\\": { \\\"usage_percent\\\": 0.85, \\\"physical_core\\\": 4, \\\"frequency\\\": 3400 },\\n        \\\"memory\\\": { \\\"usage_percent\\\": 0.65, \\\"total_bytes\\\": 17179869184, \\\"used_bytes\\\": 11166914970 }\\n      }\\n    }\\n  }\\n}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\n  \\\"rendered_gauges\\\": [\\n    {\\n      \\\"type\\\": \\\"memory\\\",\\n      \\\"value\\\": \\\"65%\\\",\\n      \\\"heading\\\": \\\"Memory usage\\\"\\n    },\\n    {\\n      \\\"type\\\": \\\"cpu\\\",\\n      \\\"value\\\": \\\"85%\\\",\\n      \\\"heading\\\": \\\"CPU usage\\\"\\n    }\\n  ]\\n}\"\n\t\t\t\t}\n\t\t\t],\n\t\t\t\"description\": \"<ul><li>Checkmate provides detailed monitoring of server hardware resources, requiring an external agent called 'Capture'</li><li>- Tracks key metrics such as CPU usage, temperature, memory consumption, and disk space</li><li>- Visualizes historical hardware data through detailed charts and real-time gauges</li><li>- Users can configure alert thresholds for each metric (CPU, memory, disk, temperature) to get notified about potential issues proactively</li><li>- Provides insights into network statistics, including data sent/received and packet information</li></ul>\",\n\t\t\t\"simulationNodesAndEdges\": {\n\t\t\t\t\"9651d084-5c16-4417-89c1-f52ae6572a95\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"80dd889a-1fc9-4d56-b9cf-5b45bf1110b1\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"4c47b5f2-5363-4816-9745-30e61d184c7a\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"ed6e7faf-69dd-4d0b-bda8-137739ed288b\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"c1bf10c9-8c1a-44f4-8e23-39708f0301e8\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"e5b90cf2-9369-4741-9803-c835a81c009b\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"d4f48f1a-61de-4cde-87d2-4b5215464899\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"07fe8489-1d94-4afb-83f8-7cebb0dff49a\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"801fe70a-1a19-406c-8f0d-770b0cb74409\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"c27365db-9db6-4cc9-96f0-4f046fd38562\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"9ef7c423-f4fc-4caf-9bf5-c1aa3002ca03\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"8502ae1f-f029-446e-9dde-59c2aba87a8a\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"9ea2e32d-1ea8-42f2-9a17-613844723ae6\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"6eedce82-b9c8-4022-95e5-3a6e00628105\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"1c5c9857-bf32-40e4-921b-957c252dac2a\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"815f96af-c28e-4f80-b4ab-18a6fb23eee0\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"a64547c9-d9e6-4941-8e5e-f49add06516b\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"4434dca1-2048-4458-a70b-b70d569e378d\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"7a250d09-50c6-4935-b10c-626b0ebe1fba\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"b019a6d0-a23a-4a1d-bd21-644f01996f14\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"3d357de8-9fd2-4d0b-9623-f36fce4cf1de\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"c691b3b9-88b3-4c88-a399-ff9fd5866194\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"00921831-b1d9-4a5a-ae6f-5ddee7cfc1e4\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"a5d20172-1c95-4c9e-af39-f86a498734bb\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"60308696-6f8a-43c8-b9a1-da199ef500cd\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"627fcb0c-0282-4b4d-8c55-aceb636e4da0\"\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"isAIGenerated\": true,\n\t\t\t\"keywords\": \"hardware, InfrastructureDetails, cpu\",\n\t\t\t\"generationPrompt\": \"Infrastructure and Hardware Health Monitoring\",\n\t\t\t\"generationKeywords\": \"hardware, InfrastructureDetails, cpu\"\n\t\t},\n\t\t\"Multi-Channel Alerting and Notifications\": {\n\t\t\t\"name\": \"Multi-Channel Alerting and Notifications\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"e924ec15-1bea-4e3b-befb-a8bf30cbf740\",\n\t\t\t\t\t\"diagramNodeId\": \"15486629-84b3-463a-962b-06083f69e4bf\",\n\t\t\t\t\t\"simStepLabel\": \"Flow 1: Render Notification Creation Form\",\n\t\t\t\t\t\"simStepDescription\": \"User accesses the `/notifications/create` route, which renders the `CreateNotifications` component. This component displays a form for setting up a new notification channel, including fields for name, type, and provider-specific details.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Pages/v1/Notifications/create/index.jsx\",\n\t\t\t\t\t\t\"startLine\": \"157\",\n\t\t\t\t\t\t\"endLine\": \"321\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"CreateNotifications\",\n\t\t\t\t\t\t\t\"notification\",\n\t\t\t\t\t\t\t\"onChange\",\n\t\t\t\t\t\t\t\"onSubmit\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\n  \\\"route\\\": \\\"/notifications/create\\\"\\n}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\n  \\\"renderedComponent\\\": \\\"CreateNotifications\\\",\\n  \\\"formFields\\\": [\\\"notificationName\\\", \\\"type\\\", \\\"address\\\", \\\"slackWebhookUrl\\\", etc...]\\n}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"71dbcd41-c6d4-4514-b5a4-6c966ca7ba6f\",\n\t\t\t\t\t\"diagramNodeId\": \"54497b9a-4910-4df4-b016-480b9ac250a7\",\n\t\t\t\t\t\"simStepLabel\": \"Flow 1: Submit Form Data for Creation\",\n\t\t\t\t\t\"simStepDescription\": \"After filling the form, the user clicks 'Save'. The `onSubmit` function is triggered, which calls the `createNotification` function from the `useCreateNotification` hook with the form data.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Pages/v1/Notifications/create/index.jsx\",\n\t\t\t\t\t\t\"startLine\": \"96\",\n\t\t\t\t\t\t\"endLine\": \"101\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"onSubmit\",\n\t\t\t\t\t\t\t\"createNotification\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\n  \\\"notificationName\\\": \\\"Production Slack Alerts\\\",\\n  \\\"type\\\": \\\"slack\\\",\\n  \\\"slackWebhookUrl\\\": \\\"https://hooks.slack.com/services/T01ABCD/B01EFGH/xXxXxXxXxX\\\",\\n  \\\"isDefault\\\": false\\n}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\n  \\\"notificationName\\\": \\\"Production Slack Alerts\\\",\\n  \\\"type\\\": \\\"slack\\\",\\n  \\\"slackWebhookUrl\\\": \\\"https://hooks.slack.com/services/T01ABCD/B01EFGH/xXxXxXxXxX\\\",\\n  \\\"isDefault\\\": false\\n}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"383c6be8-aa51-4398-9ae3-21035413f73a\",\n\t\t\t\t\t\"diagramNodeId\": \"a07b805e-e55f-46cb-b54b-765b7813b0ca\",\n\t\t\t\t\t\"simStepLabel\": \"Flow 1: Frontend API Call\",\n\t\t\t\t\t\"simStepDescription\": \"The `createNotification` hook executes an asynchronous function that calls `networkService.createNotification` to send the new notification data to the backend API.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Hooks/v1/useNotifications.js\",\n\t\t\t\t\t\t\"startLine\": \"14\",\n\t\t\t\t\t\t\"endLine\": \"17\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"createNotification\",\n\t\t\t\t\t\t\t\"networkService\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\n  \\\"notificationName\\\": \\\"Production Slack Alerts\\\",\\n  \\\"type\\\": \\\"slack\\\",\\n  \\\"slackWebhookUrl\\\": \\\"https://hooks.slack.com/services/T01ABCD/B01EFGH/xXxXxXxXxX\\\",\\n  \\\"isDefault\\\": false\\n}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\n  \\\"status\\\": \\\"pending\\\",\\n  \\\"promise\\\": {}\\n}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"162d8d2f-6cd1-45fa-8711-1ee85c5f86ef\",\n\t\t\t\t\t\"diagramNodeId\": \"dc135d8d-0515-403d-ae58-f3c04647b2ae\",\n\t\t\t\t\t\"simStepLabel\": \"Flow 1: HTTP POST Request\",\n\t\t\t\t\t\"simStepDescription\": \"The `NetworkService` constructs and sends an HTTP POST request to the `/notifications` endpoint with the notification data in the request body.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Utils/NetworkService.js\",\n\t\t\t\t\t\t\"startLine\": \"1064\",\n\t\t\t\t\t\t\"endLine\": \"1066\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"createNotification\",\n\t\t\t\t\t\t\t\"this.axiosInstance\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\n  \\\"url\\\": \\\"/notifications\\\",\\n  \\\"method\\\": \\\"POST\\\",\\n  \\\"data\\\": {\\n    \\\"notificationName\\\": \\\"Production Slack Alerts\\\",\\n    \\\"type\\\": \\\"slack\\\",\\n    \\\"slackWebhookUrl\\\": \\\"https://hooks.slack.com/services/T01ABCD/B01EFGH/xXxXxXxXxX\\\",\\n    \\\"isDefault\\\": false\\n  }\\n}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\n  \\\"url\\\": \\\"/notifications\\\",\\n  \\\"method\\\": \\\"POST\\\",\\n  \\\"data\\\": {\\n    \\\"notificationName\\\": \\\"Production Slack Alerts\\\",\\n    \\\"type\\\": \\\"slack\\\",\\n    \\\"slackWebhookUrl\\\": \\\"https://hooks.slack.com/services/T01ABCD/B01EFGH/xXxXxXxXxX\\\",\\n    \\\"isDefault\\\": false\\n  }\\n}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"2f9266c9-4cbc-4b50-a280-cf8b5800d540\",\n\t\t\t\t\t\"diagramNodeId\": \"d0a4737f-715f-4f50-b6d5-5e4b31f86f93\",\n\t\t\t\t\t\"simStepLabel\": \"Flow 1: Backend Route Handling\",\n\t\t\t\t\t\"simStepDescription\": \"The backend server receives the POST request. The Express router matches the `/notifications` path and forwards the request to the `createNotification` method of the `NotificationController`.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/routes/v1/notificationRoute.js\",\n\t\t\t\t\t\t\"startLine\": \"10\",\n\t\t\t\t\t\t\"endLine\": \"10\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"this.router\",\n\t\t\t\t\t\t\t\"this.notificationController.createNotification\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\n  \\\"request\\\": {\\n    \\\"path\\\": \\\"/notifications\\\",\\n    \\\"method\\\": \\\"POST\\\",\\n    \\\"body\\\": {\\n      \\\"notificationName\\\": \\\"Production Slack Alerts\\\",\\n      \\\"type\\\": \\\"slack\\\",\\n      \\\"slackWebhookUrl\\\": \\\"https://hooks.slack.com/services/T01ABCD/B01EFGH/xXxXxXxXxX\\\"\\n    }\\n  }\\n}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\n  \\\"handler\\\": \\\"notificationController.createNotification\\\"\\n}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"73e63d2f-2b43-488d-9e86-170f511673f5\",\n\t\t\t\t\t\"diagramNodeId\": \"7b9ebb0e-a6b2-438c-bfed-9c851a1bccbc\",\n\t\t\t\t\t\"simStepLabel\": \"Flow 1: Controller to Database Module\",\n\t\t\t\t\t\"simStepDescription\": \"The `createNotification` method in the controller validates the request body, appends user/team context, and then calls the `createNotification` method in the `notificationModule` to persist the data.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/controllers/v1/notificationController.js\",\n\t\t\t\t\t\t\"startLine\": \"55\",\n\t\t\t\t\t\t\"endLine\": \"55\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"body\",\n\t\t\t\t\t\t\t\"this.db.notificationModule.createNotification\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\n  \\\"notificationName\\\": \\\"Production Slack Alerts\\\",\\n  \\\"type\\\": \\\"slack\\\",\\n  \\\"slackWebhookUrl\\\": \\\"https://hooks.slack.com/services/T01ABCD/B01EFGH/xXxXxXxXxX\\\",\\n  \\\"userId\\\": \\\"user-123\\\",\\n  \\\"teamId\\\": \\\"team-456\\\"\\n}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\n  \\\"notificationName\\\": \\\"Production Slack Alerts\\\",\\n  \\\"type\\\": \\\"slack\\\",\\n  \\\"slackWebhookUrl\\\": \\\"https://hooks.slack.com/services/T01ABCD/B01EFGH/xXxXxXxXxX\\\",\\n  \\\"userId\\\": \\\"user-123\\\",\\n  \\\"teamId\\\": \\\"team-456\\\"\\n}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"d29ab4ab-be50-4f17-af6e-2c61cec9d0ab\",\n\t\t\t\t\t\"diagramNodeId\": \"4a796ccf-40a9-4446-a109-6a6eed52e898\",\n\t\t\t\t\t\"simStepLabel\": \"Flow 1: Database Insertion\",\n\t\t\t\t\t\"simStepDescription\": \"The `notificationModule` creates a new instance of the `Notification` model with the provided data and saves it to the MongoDB database.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/db/v1/modules/notificationModule.js\",\n\t\t\t\t\t\t\"startLine\": \"10\",\n\t\t\t\t\t\t\"endLine\": \"13\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"notificationData\",\n\t\t\t\t\t\t\t\"this.Notification\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\n  \\\"notificationName\\\": \\\"Production Slack Alerts\\\",\\n  \\\"type\\\": \\\"slack\\\",\\n  \\\"slackWebhookUrl\\\": \\\"https://hooks.slack.com/services/T01ABCD/B01EFGH/xXxXxXxXxX\\\",\\n  \\\"userId\\\": \\\"user-123\\\",\\n  \\\"teamId\\\": \\\"team-456\\\"\\n}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\n  \\\"_id\\\": \\\"60d5ecf31c9d440000a1b2c3\\\",\\n  \\\"notificationName\\\": \\\"Production Slack Alerts\\\",\\n  \\\"type\\\": \\\"slack\\\",\\n  \\\"slackWebhookUrl\\\": \\\"https://hooks.slack.com/services/T01ABCD/B01EFGH/xXxXxXxXxX\\\",\\n  \\\"userId\\\": \\\"user-123\\\",\\n  \\\"teamId\\\": \\\"team-456\\\",\\n  \\\"createdAt\\\": \\\"2023-10-27T10:00:00Z\\\",\\n  \\\"updatedAt\\\": \\\"2023-10-27T10:00:00Z\\\"\\n}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"d390ef45-f2fe-4806-a45a-cc9c84b48a5a\",\n\t\t\t\t\t\"diagramNodeId\": \"279155cd-ff31-41a2-8f5f-a538f01bfa66\",\n\t\t\t\t\t\"simStepLabel\": \"Flow 1: User Clicks Test Notification Button\",\n\t\t\t\t\t\"simStepDescription\": \"The user clicks the 'Test notification' button, which invokes the `onTestNotification` handler. This handler calls the `testNotification` function from the `useTestNotification` hook.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Pages/v1/Notifications/create/index.jsx\",\n\t\t\t\t\t\t\"startLine\": \"281\",\n\t\t\t\t\t\t\"endLine\": \"285\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"onTestNotification\",\n\t\t\t\t\t\t\t\"testNotification\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\n  \\\"notificationName\\\": \\\"Production Slack Alerts\\\",\\n  \\\"type\\\": \\\"slack\\\",\\n  \\\"slackWebhookUrl\\\": \\\"https://hooks.slack.com/services/T01ABCD/B01EFGH/xXxXxXxXxX\\\",\\n  \\\"isDefault\\\": false\\n}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\n  \\\"notificationName\\\": \\\"Production Slack Alerts\\\",\\n  \\\"type\\\": \\\"slack\\\",\\n  \\\"slackWebhookUrl\\\": \\\"https://hooks.slack.com/services/T01ABCD/B01EFGH/xXxXxXxXxX\\\",\\n  \\\"isDefault\\\": false\\n}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"c1b17b64-90e9-48bc-8927-25d7ebfc3036\",\n\t\t\t\t\t\"diagramNodeId\": \"29c2c56e-9dc0-4304-bfbf-e0c0f8915a39\",\n\t\t\t\t\t\"simStepLabel\": \"Flow 1: Backend Receives Test Request\",\n\t\t\t\t\t\"simStepDescription\": \"The client sends a POST request to `/notifications/test`. The router directs this request to the `testNotification` method in the `NotificationController`.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/routes/v1/notificationRoute.js\",\n\t\t\t\t\t\t\"startLine\": \"13\",\n\t\t\t\t\t\t\"endLine\": \"13\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"this.router\",\n\t\t\t\t\t\t\t\"this.notificationController.testNotification\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\n  \\\"request\\\": {\\n    \\\"path\\\": \\\"/notifications/test\\\",\\n    \\\"method\\\": \\\"POST\\\",\\n    \\\"body\\\": {\\n      \\\"type\\\": \\\"slack\\\",\\n      \\\"slackWebhookUrl\\\": \\\"https://hooks.slack.com/services/T01ABCD/B01EFGH/xXxXxXxXxX\\\"\\n    }\\n  }\\n}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\n  \\\"handler\\\": \\\"notificationController.testNotification\\\"\\n}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"6f2bf027-50d9-472e-9569-808a64fce7cf\",\n\t\t\t\t\t\"diagramNodeId\": \"57018b30-e2f4-4eb2-a1da-fe75afbb8c2f\",\n\t\t\t\t\t\"simStepLabel\": \"Flow 1: Controller to Notification Service\",\n\t\t\t\t\t\"simStepDescription\": \"The `testNotification` controller method passes the notification configuration from the request body to the `sendTestNotification` method of the `NotificationService`.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/controllers/v1/notificationController.js\",\n\t\t\t\t\t\t\"startLine\": \"22\",\n\t\t\t\t\t\t\"endLine\": \"22\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"notification\",\n\t\t\t\t\t\t\t\"this.notificationService.sendTestNotification\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\n  \\\"type\\\": \\\"slack\\\",\\n  \\\"slackWebhookUrl\\\": \\\"https://hooks.slack.com/services/T01ABCD/B01EFGH/xXxXxXxXxX\\\"\\n}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\n  \\\"type\\\": \\\"slack\\\",\\n  \\\"slackWebhookUrl\\\": \\\"https://hooks.slack.com/services/T01ABCD/B01EFGH/xXxXxXxXxX\\\"\\n}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"f29f9be1-a0cd-43a3-b259-e5105a25ce41\",\n\t\t\t\t\t\"diagramNodeId\": \"1cc01e08-4a6c-4526-b8a7-5ee8a06c1709\",\n\t\t\t\t\t\"simStepLabel\": \"Flow 1: Send Test Notification\",\n\t\t\t\t\t\"simStepDescription\": \"The `NotificationService` prepares a standard test message and calls its internal `sendNotification` method. This method identifies the notification type (e.g., email, Slack) and uses the corresponding service (e.g., EmailService, NetworkService for webhooks) to dispatch the test message.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/service/v1/infrastructure/notificationService.js\",\n\t\t\t\t\t\t\"startLine\": \"120\",\n\t\t\t\t\t\t\"endLine\": \"123\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"sendTestNotification\",\n\t\t\t\t\t\t\t\"sendNotification\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\n  \\\"type\\\": \\\"slack\\\",\\n  \\\"slackWebhookUrl\\\": \\\"https://hooks.slack.com/services/T01ABCD/B01EFGH/xXxXxXxXxX\\\"\\n}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\n  \\\"success\\\": true\\n}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"157cec87-9b76-4a1c-9d85-0a6d3decbaa3\",\n\t\t\t\t\t\"diagramNodeId\": \"28f1eabb-4f24-4944-8a0a-04f41ceb8589\",\n\t\t\t\t\t\"simStepLabel\": \"Flow 2: Job Execution and Status Update\",\n\t\t\t\t\t\"simStepDescription\": \"A background job is generated for a monitor. When executed, it performs a network check, saves the result, and updates the monitor's status via `statusService.updateMonitorStatus`.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/service/v2/infrastructure/JobGenerator.ts\",\n\t\t\t\t\t\t\"startLine\": \"43\",\n\t\t\t\t\t\t\"endLine\": \"66\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"generateJob\",\n\t\t\t\t\t\t\t\"networkService.check\",\n\t\t\t\t\t\t\t\"statusService.updateMonitorStatus\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\n  \\\"monitor\\\": {\\n    \\\"_id\\\": \\\"60d5f1b31c9d440000a1b2c4\\\",\\n    \\\"name\\\": \\\"Main API\\\",\\n    \\\"type\\\": \\\"http\\\",\\n    \\\"url\\\": \\\"https://api.example.com/health\\\",\\n    \\\"status\\\": \\\"up\\\"\\n  }\\n}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\n  \\\"updatedMonitor\\\": {\\n    \\\"_id\\\": \\\"60d5f1b31c9d440000a1b2c4\\\",\\n    \\\"name\\\": \\\"Main API\\\",\\n    \\\"url\\\": \\\"https://api.example.com/health\\\",\\n    \\\"status\\\": \\\"down\\\"\\n  },\\n  \\\"statusChanged\\\": true\\n}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"b7ec7415-fcae-4077-8c19-302a015b00b5\",\n\t\t\t\t\t\"diagramNodeId\": \"50797935-1447-47a4-891b-9e886e5601fa\",\n\t\t\t\t\t\"simStepLabel\": \"Flow 2: Status Change Detected\",\n\t\t\t\t\t\"simStepDescription\": \"The `updateMonitorStatus` function returns a boolean indicating if the monitor's status has changed (e.g., from 'up' to 'down'). This boolean is used as a condition to trigger notifications.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/service/v2/infrastructure/JobGenerator.ts\",\n\t\t\t\t\t\t\"startLine\": \"60\",\n\t\t\t\t\t\t\"endLine\": \"60\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"statusChanged\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\n  \\\"statusChanged\\\": true\\n}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\n  \\\"statusChanged\\\": true\\n}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"55ad645b-118a-478e-a00c-09ef82357008\",\n\t\t\t\t\t\"diagramNodeId\": \"31fe5a28-0640-4b52-841b-dd02e2ae646e\",\n\t\t\t\t\t\"simStepLabel\": \"Flow 2: Initiate Notification Handling\",\n\t\t\t\t\t\"simStepDescription\": \"If the monitor's status has changed, the `handleNotifications` method of the `NotificationService` is invoked with the updated monitor's data.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/service/v2/infrastructure/JobGenerator.ts\",\n\t\t\t\t\t\t\"startLine\": \"61\",\n\t\t\t\t\t\t\"endLine\": \"61\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"this.notificationService.handleNotifications\",\n\t\t\t\t\t\t\t\"updatedMonitor\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\n  \\\"updatedMonitor\\\": {\\n    \\\"_id\\\": \\\"60d5f1b31c9d440000a1b2c4\\\",\\n    \\\"name\\\": \\\"Main API\\\",\\n    \\\"url\\\": \\\"https://api.example.com/health\\\",\\n    \\\"status\\\": \\\"down\\\",\\n    \\\"notifications\\\": [\\\"60d5ecf31c9d440000a1b2c3\\\"]\\n  }\\n}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\n  \\\"status\\\": \\\"pending\\\",\\n  \\\"promise\\\": {}\\n}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"b7259d77-c8df-4060-ac03-58728ae3eb54\",\n\t\t\t\t\t\"diagramNodeId\": \"c778c6b9-c12e-45c0-8682-2c9e892867b0\",\n\t\t\t\t\t\"simStepLabel\": \"Flow 2: Monitor Data Passed to Notification Service\",\n\t\t\t\t\t\"simStepDescription\": \"The monitor object, which includes its current status ('down') and a list of associated notification channels, is passed to the `NotificationService`.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/service/v2/infrastructure/NotificationService.ts\",\n\t\t\t\t\t\t\"startLine\": \"7\",\n\t\t\t\t\t\t\"endLine\": \"7\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"handleNotifications\",\n\t\t\t\t\t\t\t\"monitor\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\n  \\\"monitor\\\": {\\n    \\\"_id\\\": \\\"60d5f1b31c9d440000a1b2c4\\\",\\n    \\\"name\\\": \\\"Main API\\\",\\n    \\\"status\\\": \\\"down\\\",\\n    \\\"notifications\\\": [\\\"60d5ecf31c9d440000a1b2c3\\\"]\\n  }\\n}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\n  \\\"monitor\\\": {\\n    \\\"_id\\\": \\\"60d5f1b31c9d440000a1b2c4\\\",\\n    \\\"name\\\": \\\"Main API\\\",\\n    \\\"status\\\": \\\"down\\\",\\n    \\\"notifications\\\": [\\\"60d5ecf31c9d440000a1b2c3\\\"]\\n  }\\n}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"8d1176f3-c755-401d-9ca8-234689b4b837\",\n\t\t\t\t\t\"diagramNodeId\": \"78e5cb9f-6a97-4d31-a487-fe7dbce5d7d1\",\n\t\t\t\t\t\"simStepLabel\": \"Flow 2: Dispatch Alerts\",\n\t\t\t\t\t\"simStepDescription\": \"The `handleNotifications` method retrieves the full details for each associated notification channel. It then iterates through them, using specific provider services (e.g., `SlackService`, `EmailService`) to format and send a tailored alert message for each channel, notifying users that the monitor is down.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/service/v2/infrastructure/NotificationService.ts\",\n\t\t\t\t\t\t\"startLine\": \"28\",\n\t\t\t\t\t\t\"endLine\": \"57\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"handleNotifications\",\n\t\t\t\t\t\t\t\"channels\",\n\t\t\t\t\t\t\t\"emailService.send\",\n\t\t\t\t\t\t\t\"slackService.send\",\n\t\t\t\t\t\t\t\"discordService.send\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\n  \\\"monitor\\\": {\\n    \\\"_id\\\": \\\"60d5f1b31c9d440000a1b2c4\\\",\\n    \\\"name\\\": \\\"Main API\\\",\\n    \\\"status\\\": \\\"down\\\",\\n    \\\"notifications\\\": [\\\"60d5ecf31c9d440000a1b2c3\\\"]\\n  }\\n}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\n  \\\"dispatchResults\\\": [\\n    {\\n      \\\"channelId\\\": \\\"60d5ecf31c9d440000a1b2c3\\\",\\n      \\\"status\\\": \\\"success\\\"\\n    }\\n  ]\\n}\"\n\t\t\t\t}\n\t\t\t],\n\t\t\t\"description\": \"<ul><li>A critical feature that makes the monitoring data actionable by alerting users when an issue is detected</li><li>- Users can create and manage notification channels for different services</li><li>- Supports a wide range of notification providers including Email, Slack, Discord, Webhooks, PagerDuty, and Matrix</li><li>- Notifications are triggered based on monitor status changes (e</li><li>g</li><li>, from 'up' to 'down') or when hardware metrics cross pre-defined thresholds</li><li>- Users can test notification configurations to ensure they are working correctly before attaching them to monitors</li></ul>\",\n\t\t\t\"simulationNodesAndEdges\": {\n\t\t\t\t\"15486629-84b3-463a-962b-06083f69e4bf\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"e924ec15-1bea-4e3b-befb-a8bf30cbf740\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"a07b805e-e55f-46cb-b54b-765b7813b0ca\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"383c6be8-aa51-4398-9ae3-21035413f73a\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"d0a4737f-715f-4f50-b6d5-5e4b31f86f93\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"2f9266c9-4cbc-4b50-a280-cf8b5800d540\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"4a796ccf-40a9-4446-a109-6a6eed52e898\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"d29ab4ab-be50-4f17-af6e-2c61cec9d0ab\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"29c2c56e-9dc0-4304-bfbf-e0c0f8915a39\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"c1b17b64-90e9-48bc-8927-25d7ebfc3036\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"1cc01e08-4a6c-4526-b8a7-5ee8a06c1709\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"f29f9be1-a0cd-43a3-b259-e5105a25ce41\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"28f1eabb-4f24-4944-8a0a-04f41ceb8589\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"157cec87-9b76-4a1c-9d85-0a6d3decbaa3\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"31fe5a28-0640-4b52-841b-dd02e2ae646e\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"55ad645b-118a-478e-a00c-09ef82357008\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"78e5cb9f-6a97-4d31-a487-fe7dbce5d7d1\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"8d1176f3-c755-401d-9ca8-234689b4b837\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"54497b9a-4910-4df4-b016-480b9ac250a7\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"71dbcd41-c6d4-4514-b5a4-6c966ca7ba6f\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"dc135d8d-0515-403d-ae58-f3c04647b2ae\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"162d8d2f-6cd1-45fa-8711-1ee85c5f86ef\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"7b9ebb0e-a6b2-438c-bfed-9c851a1bccbc\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"73e63d2f-2b43-488d-9e86-170f511673f5\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"279155cd-ff31-41a2-8f5f-a538f01bfa66\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"d390ef45-f2fe-4806-a45a-cc9c84b48a5a\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"57018b30-e2f4-4eb2-a1da-fe75afbb8c2f\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"6f2bf027-50d9-472e-9569-808a64fce7cf\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"50797935-1447-47a4-891b-9e886e5601fa\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"b7ec7415-fcae-4077-8c19-302a015b00b5\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"c778c6b9-c12e-45c0-8682-2c9e892867b0\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"b7259d77-c8df-4060-ac03-58728ae3eb54\"\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"isAIGenerated\": true,\n\t\t\t\"keywords\": \"NotificationService, sendNotification, createNotification\",\n\t\t\t\"generationPrompt\": \"Multi-Channel Alerting and Notifications\",\n\t\t\t\"generationKeywords\": \"NotificationService, sendNotification, createNotification\"\n\t\t},\n\t\t\"Customizable Public and Private Status Pages\": {\n\t\t\t\"name\": \"Customizable Public and Private Status Pages\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"de7b5d1f-b370-42a4-a410-4178f1e2d3a6\",\n\t\t\t\t\t\"diagramNodeId\": \"00289d11-0015-4b2a-9c5b-dc9fd0f32b80\",\n\t\t\t\t\t\"simStepLabel\": \"Create Status Page: User Initiates Creation\",\n\t\t\t\t\t\"simStepDescription\": \"The user navigates to the 'Create Status Page' screen. The `CreateStatusPage` component renders the UI, including tabs for configuration, and initializes the form state.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Pages/v1/StatusPage/Create/index.jsx\",\n\t\t\t\t\t\t\"startLine\": \"26\",\n\t\t\t\t\t\t\"endLine\": \"313\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"CreateStatusPage\",\n\t\t\t\t\t\t\t\"form\",\n\t\t\t\t\t\t\t\"setForm\",\n\t\t\t\t\t\t\t\"errors\",\n\t\t\t\t\t\t\t\"setErrors\",\n\t\t\t\t\t\t\t\"handleFormChange\",\n\t\t\t\t\t\t\t\"handleSubmit\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"form\\\":{\\\"companyName\\\":\\\"\\\",\\\"url\\\":\\\"\\\",\\\"timezone\\\":\\\"UTC\\\",\\\"color\\\":\\\"#FF5733\\\",\\\"isPublished\\\":false,\\\"logo\\\":null,\\\"monitors\\\":[],\\\"showUptimePercentage\\\":true,\\\"showCharts\\\":true,\\\"showAdminLoginLink\\\":false},\\\"errors\\\":{}}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"d419f7b6-7b9b-4494-9fad-83e3ce208ca4\",\n\t\t\t\t\t\"diagramNodeId\": \"de23eee2-b60a-4236-a890-3c5b78388bb3\",\n\t\t\t\t\t\"simStepLabel\": \"Create Status Page: Form Submission\",\n\t\t\t\t\t\"simStepDescription\": \"The user fills out the form and clicks the 'Save' button, which triggers the `handleSubmit` function. This function validates the form data and calls the `createStatusPage` function from the `useCreateStatusPage` hook.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Pages/v1/StatusPage/Create/index.jsx\",\n\t\t\t\t\t\t\"startLine\": \"143\",\n\t\t\t\t\t\t\"endLine\": \"159\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"handleSubmit\",\n\t\t\t\t\t\t\t\"createStatusPage\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"form\\\":{\\\"companyName\\\":\\\"My Awesome Service\\\",\\\"url\\\":\\\"my-awesome-service\\\",\\\"timezone\\\":\\\"America/New_York\\\",\\\"color\\\":\\\"#3B82F6\\\",\\\"isPublished\\\":true,\\\"logo\\\":{\\\"src\\\":\\\"data:image/png;base64,...\\\",\\\"name\\\":\\\"logo.png\\\",\\\"type\\\":\\\"image/png\\\",\\\"size\\\":12345},\\\"monitors\\\":[\\\"65aee7cc1c363d5032a03972\\\"],\\\"showUptimePercentage\\\":true,\\\"showCharts\\\":true,\\\"showAdminLoginLink\\\":true}}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"form\\\":{\\\"companyName\\\":\\\"My Awesome Service\\\",\\\"url\\\":\\\"my-awesome-service\\\",\\\"timezone\\\":\\\"America/New_York\\\",\\\"color\\\":\\\"#3B82F6\\\",\\\"isPublished\\\":true,\\\"logo\\\":{\\\"src\\\":\\\"data:image/png;base64,...\\\",\\\"name\\\":\\\"logo.png\\\",\\\"type\\\":\\\"image/png\\\",\\\"size\\\":12345},\\\"monitors\\\":[\\\"65aee7cc1c363d5032a03972\\\"],\\\"showUptimePercentage\\\":true,\\\"showCharts\\\":true,\\\"showAdminLoginLink\\\":true}}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"3c99ae6a-b671-4f47-bed0-ddccd8ff5d35\",\n\t\t\t\t\t\"diagramNodeId\": \"aa5d6d07-05f0-45f3-b19a-199af50e35f1\",\n\t\t\t\t\t\"simStepLabel\": \"Create Status Page: Client Hook Sends API Request\",\n\t\t\t\t\t\"simStepDescription\": \"The `useCreateStatusPage` hook receives the form data and uses the `networkService` to send a request to the backend API to create or update the status page.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Pages/v1/StatusPage/Create/Hooks/useCreateStatusPage.jsx\",\n\t\t\t\t\t\t\"startLine\": \"8\",\n\t\t\t\t\t\t\"endLine\": \"11\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"createStatusPage\",\n\t\t\t\t\t\t\t\"networkService.createStatusPage\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"form\\\":{\\\"companyName\\\":\\\"My Awesome Service\\\",\\\"url\\\":\\\"my-awesome-service\\\",\\\"timezone\\\":\\\"America/New_York\\\",\\\"color\\\":\\\"#3B82F6\\\",\\\"isPublished\\\":true,\\\"logo\\\":{\\\"src\\\":\\\"data:image/png;base64,...\\\"},\\\"monitors\\\":[\\\"65aee7cc1c363d5032a03972\\\"]}}\",\n\t\t\t\t\t\"outputDataExample\": \"{}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"8a2ab372-73db-4b9f-bc0e-6a20f15a4d79\",\n\t\t\t\t\t\"diagramNodeId\": \"d7faa713-4204-4a97-a172-d621da36c287\",\n\t\t\t\t\t\"simStepLabel\": \"Create Status Page: API Call to Backend\",\n\t\t\t\t\t\"simStepDescription\": \"The `NetworkService` class constructs a `FormData` object from the form data and sends a POST request to the `/api/v1/status-page` endpoint. The logo is sent as a file upload.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Utils/NetworkService.js\",\n\t\t\t\t\t\t\"startLine\": \"912\",\n\t\t\t\t\t\t\"endLine\": \"944\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"createStatusPage\",\n\t\t\t\t\t\t\t\"axiosInstance.post\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"form\\\":{\\\"companyName\\\":\\\"My Awesome Service\\\",\\\"url\\\":\\\"my-awesome-service\\\"...}, \\\"isCreate\\\": true}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"form\\\":{\\\"companyName\\\":\\\"My Awesome Service\\\",\\\"url\\\":\\\"my-awesome-service\\\"...}, \\\"isCreate\\\": true}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"84f11567-b3c4-42a2-aa7f-d78c1412099a\",\n\t\t\t\t\t\"diagramNodeId\": \"3efddcad-588f-4492-9808-b0c81c823c96\",\n\t\t\t\t\t\"simStepLabel\": \"Create Status Page: Backend Route Handling\",\n\t\t\t\t\t\"simStepDescription\": \"The backend router receives the POST request on `/api/v1/status-page`. It uses `multer` to handle the file upload and forwards the request to the `createStatusPage` method in the `StatusPageController`.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/routes/v1/statusPageRoute.js\",\n\t\t\t\t\t\t\"startLine\": \"14\",\n\t\t\t\t\t\t\"endLine\": \"14\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"router.post\",\n\t\t\t\t\t\t\t\"upload.single\",\n\t\t\t\t\t\t\t\"verifyJWT\",\n\t\t\t\t\t\t\t\"this.statusPageController.createStatusPage\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"method\\\":\\\"POST\\\",\\\"url\\\":\\\"/api/v1/status-page\\\",\\\"body\\\":{\\\"companyName\\\":\\\"My Awesome Service\\\",...},\\\"file\\\":{...}}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"req\\\":{...},\\\"res\\\":{...}}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"0923a533-c572-4da3-ad87-cdfff111f3bb\",\n\t\t\t\t\t\"diagramNodeId\": \"a3f28fa6-8268-4c13-95a0-83e3b1abdcb0\",\n\t\t\t\t\t\"simStepLabel\": \"Create Status Page: Data Passed to Controller\",\n\t\t\t\t\t\"simStepDescription\": \"The router passes the request object, containing form data in `req.body`, the uploaded logo in `req.file`, and user details in `req.user`, to the controller method.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/routes/v1/statusPageRoute.js\",\n\t\t\t\t\t\t\"startLine\": \"14\",\n\t\t\t\t\t\t\"endLine\": \"14\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"statusPageController.createStatusPage\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"req\\\":{\\\"body\\\":{\\\"companyName\\\":\\\"My Awesome Service\\\",...},\\\"file\\\":{\\\"fieldname\\\":\\\"logo\\\",...},\\\"user\\\":{\\\"_id\\\":\\\"65aee7cc1c363d5032a03970\\\",\\\"teamId\\\":\\\"65aee7cc1c363d5032a03971\\\"}}}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"req\\\":{\\\"body\\\":{\\\"companyName\\\":\\\"My Awesome Service\\\",...},\\\"file\\\":{\\\"fieldname\\\":\\\"logo\\\",...},\\\"user\\\":{\\\"_id\\\":\\\"65aee7cc1c363d5032a03970\\\",\\\"teamId\\\":\\\"65aee7cc1c363d5032a03971\\\"}}}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"01694730-8a75-4949-8815-bb4d6e3e2b42\",\n\t\t\t\t\t\"diagramNodeId\": \"f15ef77e-380f-4768-98cb-7f0dd4113841\",\n\t\t\t\t\t\"simStepLabel\": \"Create Status Page: Controller Logic\",\n\t\t\t\t\t\"simStepDescription\": \"The `StatusPageController` validates the incoming request body and file. It then calls the `statusPageModule` to persist the new status page in the database.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/controllers/v1/statusPageController.js\",\n\t\t\t\t\t\t\"startLine\": \"18\",\n\t\t\t\t\t\t\"endLine\": \"24\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"createStatusPageBodyValidation\",\n\t\t\t\t\t\t\t\"imageValidation\",\n\t\t\t\t\t\t\t\"this.db.statusPageModule.createStatusPage\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"req\\\":{\\\"body\\\":{...},\\\"file\\\":{...},\\\"user\\\":{...}}}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"statusPageData\\\":{...},\\\"image\\\":{...},\\\"userId\\\":\\\"65aee7cc1c363d5032a03970\\\",\\\"teamId\\\":\\\"65aee7cc1c363d5032a03971\\\"}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"67603f03-c088-4ed0-9f18-072435134cdd\",\n\t\t\t\t\t\"diagramNodeId\": \"9735611c-924b-49aa-92e8-10d8a86ac288\",\n\t\t\t\t\t\"simStepLabel\": \"Create Status Page: Data Sent to DB Module\",\n\t\t\t\t\t\"simStepDescription\": \"The controller passes the processed status page data, image buffer, user ID, and team ID to the `createStatusPage` function in the database module.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/controllers/v1/statusPageController.js\",\n\t\t\t\t\t\t\"startLine\": \"21\",\n\t\t\t\t\t\t\"endLine\": \"21\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"this.db.statusPageModule.createStatusPage\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"statusPageData\\\":{\\\"companyName\\\":\\\"My Awesome Service\\\",...},\\\"image\\\":{\\\"buffer\\\":<Buffer>,\\\"mimetype\\\":\\\"image/png\\\"},\\\"userId\\\":\\\"65aee7cc1c363d5032a03970\\\",\\\"teamId\\\":\\\"65aee7cc1c363d5032a03971\\\"}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"statusPageData\\\":{\\\"companyName\\\":\\\"My Awesome Service\\\",...},\\\"image\\\":{\\\"buffer\\\":<Buffer>,\\\"mimetype\\\":\\\"image/png\\\"},\\\"userId\\\":\\\"65aee7cc1c363d5032a03970\\\",\\\"teamId\\\":\\\"65aee7cc1c363d5032a03971\\\"}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"b6fa93cd-6fca-4d9e-969a-5400e2437ee8\",\n\t\t\t\t\t\"diagramNodeId\": \"e234917e-a950-48f5-b864-cd957b2216e1\",\n\t\t\t\t\t\"simStepLabel\": \"Create Status Page: Database Record Creation\",\n\t\t\t\t\t\"simStepDescription\": \"The `StatusPageModule` creates a new instance of the `StatusPage` Mongoose model, populates it with the provided data including the image buffer, and saves it to the MongoDB database. It also handles duplicate URL errors.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/db/v1/modules/statusPageModule.js\",\n\t\t\t\t\t\t\"startLine\": \"14\",\n\t\t\t\t\t\t\"endLine\": \"34\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"createStatusPage\",\n\t\t\t\t\t\t\t\"new this.StatusPage\",\n\t\t\t\t\t\t\t\"statusPage.save\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"statusPageData\\\":{...},\\\"image\\\":{...},\\\"userId\\\":\\\"...\\\",\\\"teamId\\\":\\\"...\\\"}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"_id\\\":\\\"65aee7dd1c363d5032a03975\\\",\\\"companyName\\\":\\\"My Awesome Service\\\",\\\"url\\\":\\\"my-awesome-service\\\",\\\"userId\\\":\\\"65aee7cc1c363d5032a03970\\\",...}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"ea4b3532-baae-4890-a73e-2ca385d0319e\",\n\t\t\t\t\t\"diagramNodeId\": \"40cb7d7b-2888-44de-bb7d-7735af70ba34\",\n\t\t\t\t\t\"simStepLabel\": \"Create Status Page: Database Result Returned\",\n\t\t\t\t\t\"simStepDescription\": \"The newly created status page document is returned from the database module to the controller.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/db/v1/modules/statusPageModule.js\",\n\t\t\t\t\t\t\"startLine\": \"27\",\n\t\t\t\t\t\t\"endLine\": \"27\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"statusPage\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"_id\\\":\\\"65aee7dd1c363d5032a03975\\\",\\\"companyName\\\":\\\"My Awesome Service\\\",\\\"url\\\":\\\"my-awesome-service\\\",...}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"_id\\\":\\\"65aee7dd1c363d5032a03975\\\",\\\"companyName\\\":\\\"My Awesome Service\\\",\\\"url\\\":\\\"my-awesome-service\\\",...}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"2a115421-5175-4c8f-8cdd-62f3fe148af5\",\n\t\t\t\t\t\"diagramNodeId\": \"058ded1f-83ce-40a7-a99d-d178c81fe557\",\n\t\t\t\t\t\"simStepLabel\": \"Create Status Page: Controller Sends Success Response\",\n\t\t\t\t\t\"simStepDescription\": \"The controller receives the newly created status page object from the database module and sends a successful JSON response back to the client, including a success message and the new data.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/controllers/v1/statusPageController.js\",\n\t\t\t\t\t\t\"startLine\": \"25\",\n\t\t\t\t\t\t\"endLine\": \"28\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"res.success\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"_id\\\":\\\"65aee7dd1c363d5032a03975\\\",\\\"companyName\\\":\\\"My Awesome Service\\\",...}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"msg\\\":\\\"Status page created successfully\\\",\\\"data\\\":{\\\"_id\\\":\\\"65aee7dd1c363d5032a03975\\\",...}}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"210acc07-81c3-4394-b566-41f6031e8eeb\",\n\t\t\t\t\t\"diagramNodeId\": \"c3f83811-8674-4dbb-9f84-79499f97fb1f\",\n\t\t\t\t\t\"simStepLabel\": \"Create Status Page: UI Receives Response and Redirects\",\n\t\t\t\t\t\"simStepDescription\": \"The client-side `handleSubmit` function receives the successful response. It displays a success toast message and navigates the user to the newly created status page.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Pages/v1/StatusPage/Create/index.jsx\",\n\t\t\t\t\t\t\"startLine\": \"151\",\n\t\t\t\t\t\t\"endLine\": \"156\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"createToast\",\n\t\t\t\t\t\t\t\"navigate\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"success\\\":true}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"success\\\":true}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"132354d7-df7a-4e03-9d00-16d54f836a1b\",\n\t\t\t\t\t\"diagramNodeId\": \"30aaee38-f509-4e19-a917-e6d2f4bba61c\",\n\t\t\t\t\t\"simStepLabel\": \"View Status Page: User Navigates to URL\",\n\t\t\t\t\t\"simStepDescription\": \"A user accesses a status page URL (e.g., /status/uptime/my-awesome-service). The React router matches the path and renders the `Status` component, which is responsible for fetching and displaying the page details.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Routes/index.jsx\",\n\t\t\t\t\t\t\"startLine\": \"148\",\n\t\t\t\t\t\t\"endLine\": \"152\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"Route\",\n\t\t\t\t\t\t\t\"Status\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"url\\\":\\\"/status/uptime/my-awesome-service\\\"}\",\n\t\t\t\t\t\"outputDataExample\": \"{}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"2ba49e28-1cac-47f5-9118-ab930788736a\",\n\t\t\t\t\t\"diagramNodeId\": \"0575bf87-5362-4988-b895-7e514148d420\",\n\t\t\t\t\t\"simStepLabel\": \"View Status Page: Component Triggers Data Fetch\",\n\t\t\t\t\t\"simStepDescription\": \"The `Status` component mounts and calls the `useStatusPageFetch` hook, which is responsible for initiating the API call to fetch the status page data from the backend.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Pages/v1/StatusPage/Status/index.jsx\",\n\t\t\t\t\t\t\"startLine\": \"29\",\n\t\t\t\t\t\t\"endLine\": \"29\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"useStatusPageFetch\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"isCreate\\\":false, \\\"url\\\":\\\"my-awesome-service\\\"}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"isCreate\\\":false, \\\"url\\\":\\\"my-awesome-service\\\"}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"b57bb249-9066-454e-aa8c-89108fdfcc2e\",\n\t\t\t\t\t\"diagramNodeId\": \"ecfb2d04-2681-4f16-af75-632f69e1a868\",\n\t\t\t\t\t\"simStepLabel\": \"View Status Page: Client Hook Sends API Request\",\n\t\t\t\t\t\"simStepDescription\": \"The `useStatusPageFetch` hook uses the `networkService` to send a GET request to the backend API to retrieve the status page data based on its URL.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Pages/v1/StatusPage/Status/Hooks/useStatusPageFetch.jsx\",\n\t\t\t\t\t\t\"startLine\": \"15\",\n\t\t\t\t\t\t\"endLine\": \"18\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"fetchStatusPage\",\n\t\t\t\t\t\t\t\"networkService.getStatusPageByUrl\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"url\\\":\\\"my-awesome-service\\\", \\\"type\\\":\\\"uptime\\\"}\",\n\t\t\t\t\t\"outputDataExample\": \"{}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"de0714d2-bf1e-4a1a-a389-60793de8b772\",\n\t\t\t\t\t\"diagramNodeId\": \"ae1c9341-0e39-4d91-a9ac-5cc8a627c247\",\n\t\t\t\t\t\"simStepLabel\": \"View Status Page: API Call to Backend\",\n\t\t\t\t\t\"simStepDescription\": \"The `NetworkService` class makes a GET request to the `/api/v1/status-page/:url` endpoint to fetch the status page details.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Utils/NetworkService.js\",\n\t\t\t\t\t\t\"startLine\": \"896\",\n\t\t\t\t\t\t\"endLine\": \"902\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"getStatusPageByUrl\",\n\t\t\t\t\t\t\t\"axiosInstance.get\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"url\\\":\\\"my-awesome-service\\\",\\\"type\\\":\\\"uptime\\\"}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"url\\\":\\\"my-awesome-service\\\",\\\"type\\\":\\\"uptime\\\"}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"477c6821-b29b-4b38-8930-ced21b8a75e5\",\n\t\t\t\t\t\"diagramNodeId\": \"2e26cd2f-1413-4c16-8e63-ea7808ab6c52\",\n\t\t\t\t\t\"simStepLabel\": \"View Status Page: Backend Route Handling\",\n\t\t\t\t\t\"simStepDescription\": \"The backend router receives the GET request on `/api/v1/status-page/:url` and forwards it to the `getStatusPageByUrl` method in the `StatusPageController`.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/routes/v1/statusPageRoute.js\",\n\t\t\t\t\t\t\"startLine\": \"16\",\n\t\t\t\t\t\t\"endLine\": \"16\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"router.get\",\n\t\t\t\t\t\t\t\"this.statusPageController.getStatusPageByUrl\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"method\\\":\\\"GET\\\",\\\"url\\\":\\\"/api/v1/status-page/my-awesome-service\\\"}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"req\\\":{...},\\\"res\\\":{...}}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"b79b8922-4de6-477d-8648-37b4bd9a6767\",\n\t\t\t\t\t\"diagramNodeId\": \"5735f30c-b55f-444a-9236-f3d75f68ed27\",\n\t\t\t\t\t\"simStepLabel\": \"View Status Page: Data Passed to Controller\",\n\t\t\t\t\t\"simStepDescription\": \"The router passes the request object, containing the URL in `req.params`, to the controller method.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/routes/v1/statusPageRoute.js\",\n\t\t\t\t\t\t\"startLine\": \"16\",\n\t\t\t\t\t\t\"endLine\": \"16\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"statusPageController.getStatusPageByUrl\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"req\\\":{\\\"params\\\":{\\\"url\\\":\\\"my-awesome-service\\\"}}}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"req\\\":{\\\"params\\\":{\\\"url\\\":\\\"my-awesome-service\\\"}}}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"5bdbd179-ce8f-4171-a073-af72a99b4468\",\n\t\t\t\t\t\"diagramNodeId\": \"9f217674-4cd7-4ef8-b088-d5620042a7ba\",\n\t\t\t\t\t\"simStepLabel\": \"View Status Page: Controller Logic\",\n\t\t\t\t\t\"simStepDescription\": \"The `StatusPageController` validates the request parameters and calls the `statusPageModule` to retrieve the status page data from the database.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/controllers/v1/statusPageController.js\",\n\t\t\t\t\t\t\"startLine\": \"75\",\n\t\t\t\t\t\t\"endLine\": \"78\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"getStatusPageByUrl\",\n\t\t\t\t\t\t\t\"this.db.statusPageModule.getStatusPageByUrl\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"req\\\":{\\\"params\\\":{\\\"url\\\":\\\"my-awesome-service\\\"}}}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"url\\\":\\\"my-awesome-service\\\"}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"788307ef-4cfa-4f5a-b2e9-a0bfc7a378d8\",\n\t\t\t\t\t\"diagramNodeId\": \"dace45d6-fb25-4dae-b940-49ef7d77bbed\",\n\t\t\t\t\t\"simStepLabel\": \"View Status Page: URL Sent to DB Module\",\n\t\t\t\t\t\"simStepDescription\": \"The controller passes the URL string to the `getStatusPageByUrl` function in the database module.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/controllers/v1/statusPageController.js\",\n\t\t\t\t\t\t\"startLine\": \"78\",\n\t\t\t\t\t\t\"endLine\": \"78\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"this.db.statusPageModule.getStatusPageByUrl\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"url\\\":\\\"my-awesome-service\\\"}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"url\\\":\\\"my-awesome-service\\\"}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"ceb044e9-6545-4d04-bf79-ec8146eb8ec9\",\n\t\t\t\t\t\"diagramNodeId\": \"26da60f9-dde4-44ec-be89-91858cc14f90\",\n\t\t\t\t\t\"simStepLabel\": \"View Status Page: Database Record Retrieval\",\n\t\t\t\t\t\"simStepDescription\": \"The `StatusPageModule` executes a complex MongoDB aggregation pipeline to find the status page by its URL, and then look up and join data for all associated monitors and their recent checks.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/db/v1/modules/statusPageModule.js\",\n\t\t\t\t\t\t\"startLine\": \"89\",\n\t\t\t\t\t\t\"endLine\": \"299\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"getStatusPage\",\n\t\t\t\t\t\t\t\"this.StatusPage.aggregate\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"url\\\":\\\"my-awesome-service\\\"}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"statusPage\\\":{\\\"_id\\\":\\\"...\\\",\\\"companyName\\\":\\\"My Awesome Service\\\",...},\\\"monitors\\\":[{\\\"_id\\\":\\\"...\\\",\\\"name\\\":\\\"Main Website\\\",...}]}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"4d3fad92-8fa9-4a8f-be3b-f09eda2f8dd4\",\n\t\t\t\t\t\"diagramNodeId\": \"137a5ab7-1e49-42ec-869d-58f7f2380cb3\",\n\t\t\t\t\t\"simStepLabel\": \"View Status Page: Database Result Returned\",\n\t\t\t\t\t\"simStepDescription\": \"The aggregated status page and monitor data is returned from the database module to the controller.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/db/v1/modules/statusPageModule.js\",\n\t\t\t\t\t\t\"startLine\": \"291\",\n\t\t\t\t\t\t\"endLine\": \"291\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"statusPage\",\n\t\t\t\t\t\t\t\"normalizedMonitors\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"statusPage\\\":{...},\\\"monitors\\\":[...]}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"statusPage\\\":{...},\\\"monitors\\\":[...]}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"83224406-2f1d-4030-9beb-d65c2baf544d\",\n\t\t\t\t\t\"diagramNodeId\": \"d76e70e0-41f9-46cc-b775-b2027c5a0d5b\",\n\t\t\t\t\t\"simStepLabel\": \"View Status Page: Controller Sends Success Response\",\n\t\t\t\t\t\"simStepDescription\": \"The controller receives the status page data and sends a successful JSON response back to the client.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/controllers/v1/statusPageController.js\",\n\t\t\t\t\t\t\"startLine\": \"79\",\n\t\t\t\t\t\t\"endLine\": \"82\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"res.success\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"statusPage\\\":{...},\\\"monitors\\\":[...]}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"msg\\\":\\\"Got status page by url successfully\\\",\\\"data\\\":{\\\"statusPage\\\":{...},\\\"monitors\\\":[...]}}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"d5f3c300-9777-4e09-bb05-f1281c2ff29a\",\n\t\t\t\t\t\"diagramNodeId\": \"04a33e4f-1dfe-4c5a-8b30-01ed0591c380\",\n\t\t\t\t\t\"simStepLabel\": \"View Status Page: UI Receives Data\",\n\t\t\t\t\t\"simStepDescription\": \"The `useStatusPageFetch` hook receives the API response, processes the data, and updates the component's state, triggering a re-render.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Pages/v1/StatusPage/Status/Hooks/useStatusPageFetch.jsx\",\n\t\t\t\t\t\t\"startLine\": \"20\",\n\t\t\t\t\t\t\"endLine\": \"26\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"setStatusPage\",\n\t\t\t\t\t\t\t\"setMonitors\",\n\t\t\t\t\t\t\t\"getMonitorWithPercentage\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"data\\\":{\\\"data\\\":{\\\"statusPage\\\":{...},\\\"monitors\\\":[...]}}}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"statusPage\\\":{...},\\\"monitors\\\":[...]}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"3d51e811-a659-442e-97e0-00798cd15647\",\n\t\t\t\t\t\"diagramNodeId\": \"f59b91de-5196-4a43-9d57-3f28402c0672\",\n\t\t\t\t\t\"simStepLabel\": \"View Status Page: Component Renders UI\",\n\t\t\t\t\t\"simStepDescription\": \"The `Status` component re-renders with the fetched data. It displays the company name, logo, overall status bar, and a list of monitors with their individual status and historical uptime charts.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Pages/v1/StatusPage/Status/index.jsx\",\n\t\t\t\t\t\t\"startLine\": \"145\",\n\t\t\t\t\t\t\"endLine\": \"163\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"ControlsHeader\",\n\t\t\t\t\t\t\t\"StatusBar\",\n\t\t\t\t\t\t\t\"MonitorsList\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"statusPage\\\":{...},\\\"monitors\\\":[...]}\",\n\t\t\t\t\t\"outputDataExample\": \"{}\"\n\t\t\t\t}\n\t\t\t],\n\t\t\t\"description\": \"<ul><li>Allows users to create dedicated pages to communicate the status of their services to internal teams or external customers</li><li>- Users can create a status page with a custom URL, company name, and logo</li><li>- Select which monitors to display on the status page, providing granular control over what information is shared</li><li>- Options to show or hide historical charts and uptime percentages for transparency</li><li>- Includes settings for custom CSS and an optional link back to the admin login page</li></ul>\",\n\t\t\t\"simulationNodesAndEdges\": {\n\t\t\t\t\"00289d11-0015-4b2a-9c5b-dc9fd0f32b80\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"de7b5d1f-b370-42a4-a410-4178f1e2d3a6\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"aa5d6d07-05f0-45f3-b19a-199af50e35f1\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"3c99ae6a-b671-4f47-bed0-ddccd8ff5d35\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"3efddcad-588f-4492-9808-b0c81c823c96\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"84f11567-b3c4-42a2-aa7f-d78c1412099a\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"f15ef77e-380f-4768-98cb-7f0dd4113841\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"01694730-8a75-4949-8815-bb4d6e3e2b42\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"e234917e-a950-48f5-b864-cd957b2216e1\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"b6fa93cd-6fca-4d9e-969a-5400e2437ee8\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"058ded1f-83ce-40a7-a99d-d178c81fe557\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"2a115421-5175-4c8f-8cdd-62f3fe148af5\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"30aaee38-f509-4e19-a917-e6d2f4bba61c\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"132354d7-df7a-4e03-9d00-16d54f836a1b\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"ecfb2d04-2681-4f16-af75-632f69e1a868\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"b57bb249-9066-454e-aa8c-89108fdfcc2e\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"2e26cd2f-1413-4c16-8e63-ea7808ab6c52\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"477c6821-b29b-4b38-8930-ced21b8a75e5\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"9f217674-4cd7-4ef8-b088-d5620042a7ba\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"5bdbd179-ce8f-4171-a073-af72a99b4468\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"26da60f9-dde4-44ec-be89-91858cc14f90\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"ceb044e9-6545-4d04-bf79-ec8146eb8ec9\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"d76e70e0-41f9-46cc-b775-b2027c5a0d5b\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"83224406-2f1d-4030-9beb-d65c2baf544d\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"f59b91de-5196-4a43-9d57-3f28402c0672\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"3d51e811-a659-442e-97e0-00798cd15647\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"de23eee2-b60a-4236-a890-3c5b78388bb3\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"d419f7b6-7b9b-4494-9fad-83e3ce208ca4\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"d7faa713-4204-4a97-a172-d621da36c287\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"8a2ab372-73db-4b9f-bc0e-6a20f15a4d79\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"a3f28fa6-8268-4c13-95a0-83e3b1abdcb0\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"0923a533-c572-4da3-ad87-cdfff111f3bb\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"9735611c-924b-49aa-92e8-10d8a86ac288\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"67603f03-c088-4ed0-9f18-072435134cdd\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"40cb7d7b-2888-44de-bb7d-7735af70ba34\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"ea4b3532-baae-4890-a73e-2ca385d0319e\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"c3f83811-8674-4dbb-9f84-79499f97fb1f\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"210acc07-81c3-4394-b566-41f6031e8eeb\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"0575bf87-5362-4988-b895-7e514148d420\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"2ba49e28-1cac-47f5-9118-ab930788736a\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"ae1c9341-0e39-4d91-a9ac-5cc8a627c247\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"de0714d2-bf1e-4a1a-a389-60793de8b772\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"5735f30c-b55f-444a-9236-f3d75f68ed27\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"b79b8922-4de6-477d-8648-37b4bd9a6767\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"dace45d6-fb25-4dae-b940-49ef7d77bbed\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"788307ef-4cfa-4f5a-b2e9-a0bfc7a378d8\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"137a5ab7-1e49-42ec-869d-58f7f2380cb3\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"4d3fad92-8fa9-4a8f-be3b-f09eda2f8dd4\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"04a33e4f-1dfe-4c5a-8b30-01ed0591c380\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"d5f3c300-9777-4e09-bb05-f1281c2ff29a\"\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"isAIGenerated\": true,\n\t\t\t\"keywords\": \"StatusPage, createStatusPage, getStatusPageByUrl\",\n\t\t\t\"generationPrompt\": \"Customizable Public and Private Status Pages\",\n\t\t\t\"generationKeywords\": \"StatusPage, createStatusPage, getStatusPageByUrl\"\n\t\t},\n\t\t\"Incident History, Analysis, and Management\": {\n\t\t\t\"name\": \"Incident History, Analysis, and Management\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"35195328-9847-4678-b014-9331553f0d19\",\n\t\t\t\t\t\"diagramNodeId\": \"78a8a7c5-41d3-4453-a7f7-ac632bbef288\",\n\t\t\t\t\t\"simStepLabel\": \"Navigate to Monitor Details\",\n\t\t\t\t\t\"simStepDescription\": \"The user navigates to the details page for a specific uptime monitor. The `UptimeDetails` component mounts and initializes its state and hooks.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Pages/v1/Uptime/Details/index.jsx\",\n\t\t\t\t\t\t\"startLine\": \"27\",\n\t\t\t\t\t\t\"endLine\": \"188\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"UptimeDetails\",\n\t\t\t\t\t\t\t\"useParams\",\n\t\t\t\t\t\t\t\"useFetchChecksByMonitor\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"url\\\": \\\"/uptime/65a12f60e9a5d109f7596a77\\\"}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"monitorId\\\": \\\"65a12f60e9a5d109f7596a77\\\"}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"49979250-1a32-4da5-95e0-58652fe218f9\",\n\t\t\t\t\t\"diagramNodeId\": \"e90e4943-6108-46e3-8a2c-a9a1c7361279\",\n\t\t\t\t\t\"simStepLabel\": \"Trigger Check History Fetch\",\n\t\t\t\t\t\"simStepDescription\": \"The `UptimeDetails` component calls the `useFetchChecksByMonitor` hook to retrieve the historical check data for the specified monitor.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Pages/v1/Uptime/Details/index.jsx\",\n\t\t\t\t\t\t\"startLine\": \"69\",\n\t\t\t\t\t\t\"endLine\": \"77\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"useFetchChecksByMonitor\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"monitorId\\\": \\\"65a12f60e9a5d109f7596a77\\\", \\\"type\\\": \\\"http\\\", \\\"sortOrder\\\": \\\"desc\\\", \\\"page\\\": 0, \\\"rowsPerPage\\\": 10}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"monitorId\\\": \\\"65a12f60e9a5d109f7596a77\\\", \\\"type\\\": \\\"http\\\", \\\"sortOrder\\\": \\\"desc\\\", \\\"page\\\": 0, \\\"rowsPerPage\\\": 10}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"8dc4347c-3e9e-40d7-ae6f-54684f2e6956\",\n\t\t\t\t\t\"diagramNodeId\": \"4a5847d0-91a0-4b4c-8517-2f4ff9a7e8d4\",\n\t\t\t\t\t\"simStepLabel\": \"Fetch Monitor Checks Hook\",\n\t\t\t\t\t\"simStepDescription\": \"The `useFetchChecksByMonitor` custom hook executes. It sets the loading state and prepares to call the network service to fetch the data from the backend API.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Hooks/v1/checkHooks.js\",\n\t\t\t\t\t\t\"startLine\": \"89\",\n\t\t\t\t\t\t\"endLine\": \"121\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"useFetchChecksByMonitor\",\n\t\t\t\t\t\t\t\"useEffect\",\n\t\t\t\t\t\t\t\"networkService.getChecksByMonitor\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"monitorId\\\": \\\"65a12f60e9a5d109f7596a77\\\", \\\"page\\\": 0, \\\"rowsPerPage\\\": 10, \\\"sortOrder\\\": \\\"desc\\\"}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"config\\\": {\\\"monitorId\\\": \\\"65a12f60e9a5d109f7596a77\\\", \\\"sortOrder\\\": \\\"desc\\\", \\\"page\\\": \\\"0\\\", \\\"rowsPerPage\\\": \\\"10\\\", \\\"status\\\": undefined}}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"336b534d-8d6a-4639-af8e-889b38f51ab1\",\n\t\t\t\t\t\"diagramNodeId\": \"2b8ae59e-ed8d-4837-9a9b-64eb480f982c\",\n\t\t\t\t\t\"simStepLabel\": \"API Request for Check History\",\n\t\t\t\t\t\"simStepDescription\": \"The `NetworkService` constructs and sends an HTTP GET request to the backend API endpoint to retrieve the paginated list of checks for the specified monitor.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Utils/NetworkService.js\",\n\t\t\t\t\t\t\"startLine\": \"551\",\n\t\t\t\t\t\t\"endLine\": \"562\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"getChecksByMonitor\",\n\t\t\t\t\t\t\t\"this.axiosInstance.get\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"config\\\": {\\\"monitorId\\\": \\\"65a12f60e9a5d109f7596a77\\\", \\\"sortOrder\\\": \\\"desc\\\", \\\"page\\\": \\\"0\\\", \\\"rowsPerPage\\\": \\\"10\\\"}}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"config\\\": {\\\"monitorId\\\": \\\"65a12f60e9a5d109f7596a77\\\", \\\"sortOrder\\\": \\\"desc\\\", \\\"page\\\": \\\"0\\\", \\\"rowsPerPage\\\": \\\"10\\\"}}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"c5fd192f-ea28-48a0-b3e7-5bc04f521192\",\n\t\t\t\t\t\"diagramNodeId\": \"cdd090be-0b62-45b4-baa0-fec01fc3ffd1\",\n\t\t\t\t\t\"simStepLabel\": \"Route Request to Controller\",\n\t\t\t\t\t\"simStepDescription\": \"The backend Express router receives the incoming GET request and matches it to the appropriate route, forwarding the request to the `getChecksByMonitor` method in the `CheckController`.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/routes/v1/checkRoute.js\",\n\t\t\t\t\t\t\"startLine\": \"19\",\n\t\t\t\t\t\t\"endLine\": \"19\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"this.router.get\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"request\\\": \\\"GET /api/v1/checks/65a12f60e9a5d109f7596a77?sortOrder=desc&page=0&rowsPerPage=10\\\"}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"controllerMethod\\\": \\\"getChecksByMonitor\\\"}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"4f73f0fe-b390-4fe1-a354-eb0857835126\",\n\t\t\t\t\t\"diagramNodeId\": \"839ba9f6-8a34-4919-a04a-13fba1795c61\",\n\t\t\t\t\t\"simStepLabel\": \"Forward Request to Service Layer\",\n\t\t\t\t\t\"simStepDescription\": \"The `CheckController` validates the request parameters and calls the `CheckService` to handle the business logic of fetching the monitor checks.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/controllers/v1/checkController.js\",\n\t\t\t\t\t\t\"startLine\": \"81\",\n\t\t\t\t\t\t\"endLine\": \"85\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"getChecksByMonitor\",\n\t\t\t\t\t\t\t\"this.checkService.getChecksByMonitor\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"monitorId\\\": \\\"65a12f60e9a5d109f7596a77\\\", \\\"query\\\": {\\\"sortOrder\\\": \\\"desc\\\", \\\"page\\\": \\\"0\\\", \\\"rowsPerPage\\\": \\\"10\\\"}, \\\"teamId\\\": \\\"65a12f50e9a5d109f7596a66\\\"}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"monitorId\\\": \\\"65a12f60e9a5d109f7596a77\\\", \\\"query\\\": {\\\"sortOrder\\\": \\\"desc\\\", \\\"page\\\": \\\"0\\\", \\\"rowsPerPage\\\": \\\"10\\\"}, \\\"teamId\\\": \\\"65a12f50e9a5d109f7596a66\\\"}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"83fea05d-8306-4a73-a43f-882cdd14f50f\",\n\t\t\t\t\t\"diagramNodeId\": \"499b46a2-f2a2-4ccd-aecd-012eade2bd23\",\n\t\t\t\t\t\"simStepLabel\": \"Fetch Checks from Database\",\n\t\t\t\t\t\"simStepDescription\": \"The `CheckService` calls the `checkModule` to interact with the database. It passes the necessary parameters to query for the check history.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/service/v1/business/checkService.js\",\n\t\t\t\t\t\t\"startLine\": \"36\",\n\t\t\t\t\t\t\"endLine\": \"45\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"getChecksByMonitor\",\n\t\t\t\t\t\t\t\"this.db.checkModule.getChecksByMonitor\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"monitorId\\\": \\\"65a12f60e9a5d109f7596a77\\\", \\\"query\\\": {\\\"sortOrder\\\": \\\"desc\\\", \\\"page\\\": \\\"0\\\", \\\"rowsPerPage\\\": \\\"10\\\"}, \\\"teamId\\\": \\\"65a12f50e9a5d109f7596a66\\\"}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"monitorId\\\": \\\"65a12f60e9a5d109f7596a77\\\", \\\"sortOrder\\\": \\\"desc\\\", \\\"dateRange\\\": undefined, \\\"filter\\\": undefined, \\\"ack\\\": undefined, \\\"page\\\": \\\"0\\\", \\\"rowsPerPage\\\": \\\"10\\\", \\\"status\\\": undefined}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"65da1a9e-041c-4656-9c5b-0a92b761a9be\",\n\t\t\t\t\t\"diagramNodeId\": \"42d3bc70-701a-4be0-96b4-d6c2f0519b49\",\n\t\t\t\t\t\"simStepLabel\": \"Execute Database Query\",\n\t\t\t\t\t\"simStepDescription\": \"The `checkModule` constructs and executes a MongoDB aggregation pipeline on the `Check` collection to find, sort, and paginate the historical checks for the given monitor.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/db/v1/modules/checkModule.js\",\n\t\t\t\t\t\t\"startLine\": \"28\",\n\t\t\t\t\t\t\"endLine\": \"108\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"getChecksByMonitor\",\n\t\t\t\t\t\t\t\"this.Check.aggregate\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"monitorId\\\": \\\"65a12f60e9a5d109f7596a77\\\", \\\"sortOrder\\\": -1, \\\"page\\\": 0, \\\"rowsPerPage\\\": 10}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"monitorId\\\": \\\"65a12f60e9a5d109f7596a77\\\", \\\"sortOrder\\\": -1, \\\"page\\\": 0, \\\"rowsPerPage\\\": 10}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"5768fdc5-045c-48ef-b0c9-79769403648f\",\n\t\t\t\t\t\"diagramNodeId\": \"14df9f01-1358-442d-96f5-eab9a4c4abbf\",\n\t\t\t\t\t\"simStepLabel\": \"Return Check Data\",\n\t\t\t\t\t\"simStepDescription\": \"The database returns the query results, which flow back up through the `checkModule` and `checkService`. The `checkController` then formats a successful JSON response.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/controllers/v1/checkController.js\",\n\t\t\t\t\t\t\"startLine\": \"87\",\n\t\t\t\t\t\t\"endLine\": \"90\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"res.success\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"checksCount\\\": 152, \\\"checks\\\": [{\\\"_id\\\": \\\"...\\\", \\\"status\\\": false}, {\\\"...\\\"}]}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"msg\\\": \\\"Got checks successfully\\\", \\\"data\\\": {\\\"checksCount\\\": 152, \\\"checks\\\": [{\\\"_id\\\": \\\"...\\\"}]}}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"2c1bdec8-d0e6-4163-a99c-f27899b987c5\",\n\t\t\t\t\t\"diagramNodeId\": \"6c5b028c-356c-43c8-a35a-b47448cd8695\",\n\t\t\t\t\t\"simStepLabel\": \"API Response with Check History\",\n\t\t\t\t\t\"simStepDescription\": \"The backend sends the HTTP response containing the historical check data back to the client.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Utils/NetworkService.js\",\n\t\t\t\t\t\t\"startLine\": \"560\",\n\t\t\t\t\t\t\"endLine\": \"560\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"this.axiosInstance.get\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"success\\\": true, \\\"msg\\\": \\\"Got checks successfully\\\", \\\"data\\\": {\\\"checksCount\\\": 152, \\\"checks\\\": [{\\\"_id\\\": \\\"65a13f60e9a5d109f7596b88\\\", \\\"status\\\": false, \\\"httpStatusCode\\\": 503, \\\"responseTime\\\": 1200}, {\\\"_id\\\": \\\"65a13f50e9a5d109f7596b77\\\", \\\"status\\\": true, \\\"httpStatusCode\\\": 200, \\\"responseTime\\\": 250}]}}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"success\\\": true, \\\"msg\\\": \\\"Got checks successfully\\\", \\\"data\\\": {\\\"checksCount\\\": 152, \\\"checks\\\": [{\\\"_id\\\": \\\"65a13f60e9a5d109f7596b88\\\", \\\"status\\\": false, \\\"httpStatusCode\\\": 503, \\\"responseTime\\\": 1200}, {\\\"_id\\\": \\\"65a13f50e9a5d109f7596b77\\\", \\\"status\\\": true, \\\"httpStatusCode\\\": 200, \\\"responseTime\\\": 250}]}}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"faba07f3-7460-47ae-924d-f92f5b2e821d\",\n\t\t\t\t\t\"diagramNodeId\": \"ceb9cda3-968d-44aa-b223-49902adb93b4\",\n\t\t\t\t\t\"simStepLabel\": \"Update Frontend State\",\n\t\t\t\t\t\"simStepDescription\": \"The `useFetchChecksByMonitor` hook receives the data from the API call and updates the component's state with the new list of checks and the total count.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Hooks/v1/checkHooks.js\",\n\t\t\t\t\t\t\"startLine\": \"109\",\n\t\t\t\t\t\t\"endLine\": \"110\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"setChecks\",\n\t\t\t\t\t\t\t\"setChecksCount\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"data\\\": {\\\"checksCount\\\": 152, \\\"checks\\\": [{\\\"_id\\\": \\\"...\\\"}]}}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"checks\\\": [{\\\"_id\\\": \\\"...\\\"}], \\\"checksCount\\\": 152}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"9405dce1-0565-4dfa-9539-a048472acda9\",\n\t\t\t\t\t\"diagramNodeId\": \"74b0dd89-9fea-4219-af1f-9571316a9d5a\",\n\t\t\t\t\t\"simStepLabel\": \"Pass Data to UI Components\",\n\t\t\t\t\t\"simStepDescription\": \"The state update triggers a re-render of the `UptimeDetails` page, passing the `checks` and `checksCount` as props to child components like `ResponseTable`.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Pages/v1/Uptime/Details/index.jsx\",\n\t\t\t\t\t\t\"startLine\": \"175\",\n\t\t\t\t\t\t\"endLine\": \"186\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"ResponseTable\",\n\t\t\t\t\t\t\t\"checks\",\n\t\t\t\t\t\t\t\"checksCount\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"checks\\\": [{\\\"_id\\\": \\\"65a13f60e9a5d109f7596b88\\\", \\\"status\\\": false, \\\"httpStatusCode\\\": 503}, {\\\"_id\\\": \\\"65a13f50e9a5d109f7596b77\\\", \\\"status\\\": true, \\\"httpStatusCode\\\": 200}], \\\"checksCount\\\": 152}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"checks\\\": [{\\\"_id\\\": \\\"65a13f60e9a5d109f7596b88\\\", \\\"status\\\": false, \\\"httpStatusCode\\\": 503}, {\\\"_id\\\": \\\"65a13f50e9a5d109f7596b77\\\", \\\"status\\\": true, \\\"httpStatusCode\\\": 200}], \\\"checksCount\\\": 152}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"2b1651cd-2e70-4cc6-b2bb-23f94fa73d66\",\n\t\t\t\t\t\"diagramNodeId\": \"c996f7ca-9384-4252-b343-7bfc049d14bb\",\n\t\t\t\t\t\"simStepLabel\": \"Render Historical Data Table\",\n\t\t\t\t\t\"simStepDescription\": \"The `ResponseTable` component receives the list of checks and renders them in a data table, allowing the user to view the incident history, including status, response time, and when the check occurred.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Pages/v1/Uptime/Details/Components/ResponseTable/index.jsx\",\n\t\t\t\t\t\t\"startLine\": \"11\",\n\t\t\t\t\t\t\"endLine\": \"92\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"ResponseTable\",\n\t\t\t\t\t\t\t\"Table\",\n\t\t\t\t\t\t\t\"TablePagination\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"checks\\\": [{\\\"_id\\\": \\\"65a13f60e9a5d109f7596b88\\\", \\\"status\\\": false, \\\"httpStatusCode\\\": 503}, {\\\"_id\\\": \\\"65a13f50e9a5d109f7596b77\\\", \\\"status\\\": true, \\\"httpStatusCode\\\": 200}]}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"tableRows\\\": [{\\\"id\\\": \\\"status\\\", \\\"content\\\": \\\"Status\\\", \\\"render\\\": \\\"...\\\"}, {\\\"id\\\": \\\"httpStatus\\\", \\\"content\\\": \\\"HTTP Status\\\", \\\"render\\\": \\\"...\\\"}]}\"\n\t\t\t\t}\n\t\t\t],\n\t\t\t\"description\": \"<ul><li>Provides detailed historical data and tools to manage monitoring events, which are treated as incidents</li><li>- Every check result is stored, creating a comprehensive log of uptime, downtime, and response time history for each monitor</li><li>- The UI includes detailed views with charts and tables to analyze performance trends and past incidents</li><li>- Users can acknowledge incidents (failed checks), which helps in tracking the response to an outage</li><li>- All historical check data can be purged on a per-monitor or per-team basis</li></ul>\",\n\t\t\t\"simulationNodesAndEdges\": {\n\t\t\t\t\"78a8a7c5-41d3-4453-a7f7-ac632bbef288\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"35195328-9847-4678-b014-9331553f0d19\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"4a5847d0-91a0-4b4c-8517-2f4ff9a7e8d4\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"8dc4347c-3e9e-40d7-ae6f-54684f2e6956\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"cdd090be-0b62-45b4-baa0-fec01fc3ffd1\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"c5fd192f-ea28-48a0-b3e7-5bc04f521192\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"499b46a2-f2a2-4ccd-aecd-012eade2bd23\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"83fea05d-8306-4a73-a43f-882cdd14f50f\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"14df9f01-1358-442d-96f5-eab9a4c4abbf\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"5768fdc5-045c-48ef-b0c9-79769403648f\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"ceb9cda3-968d-44aa-b223-49902adb93b4\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"faba07f3-7460-47ae-924d-f92f5b2e821d\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"c996f7ca-9384-4252-b343-7bfc049d14bb\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"2b1651cd-2e70-4cc6-b2bb-23f94fa73d66\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"e90e4943-6108-46e3-8a2c-a9a1c7361279\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"49979250-1a32-4da5-95e0-58652fe218f9\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"2b8ae59e-ed8d-4837-9a9b-64eb480f982c\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"336b534d-8d6a-4639-af8e-889b38f51ab1\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"839ba9f6-8a34-4919-a04a-13fba1795c61\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"4f73f0fe-b390-4fe1-a354-eb0857835126\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"42d3bc70-701a-4be0-96b4-d6c2f0519b49\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"65da1a9e-041c-4656-9c5b-0a92b761a9be\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"6c5b028c-356c-43c8-a35a-b47448cd8695\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"2c1bdec8-d0e6-4163-a99c-f27899b987c5\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"74b0dd89-9fea-4219-af1f-9571316a9d5a\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"9405dce1-0565-4dfa-9539-a048472acda9\"\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"isAIGenerated\": true,\n\t\t\t\"keywords\": \"Check, getChecksByMonitor, ResponseTable\",\n\t\t\t\"generationPrompt\": \"Incident History, Analysis, and Management\",\n\t\t\t\"generationKeywords\": \"Check, getChecksByMonitor, ResponseTable\"\n\t\t},\n\t\t\"Website Performance and Page Speed Monitoring\": {\n\t\t\t\"name\": \"Website Performance and Page Speed Monitoring\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"b0cc6e6a-961e-4ea9-aa8a-6bfa44d6ba12\",\n\t\t\t\t\t\"diagramNodeId\": \"0622b212-3a4a-484d-9b7a-125864d785cd\",\n\t\t\t\t\t\"simStepLabel\": \"Create PageSpeed Monitor\",\n\t\t\t\t\t\"simStepDescription\": \"The user navigates to the PageSpeed creation page, fills in the details for a new monitor (URL, name, interval), and submits the form. This triggers the `handleSubmit` function, which calls the `createMonitor` hook to send the data to the backend API.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Pages/v1/PageSpeed/Create/index.jsx\",\n\t\t\t\t\t\t\"startLine\": \"111\",\n\t\t\t\t\t\t\"endLine\": \"143\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"handleSubmit\",\n\t\t\t\t\t\t\t\"createMonitor\",\n\t\t\t\t\t\t\t\"updateMonitor\",\n\t\t\t\t\t\t\t\"monitor\",\n\t\t\t\t\t\t\t\"form\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"formState\\\": {\\\"url\\\": \\\"https://example.com\\\",\\\"name\\\": \\\"Example Homepage\\\",\\\"type\\\": \\\"pagespeed\\\",\\\"interval\\\": 180000}}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"monitor\\\": {\\\"url\\\": \\\"https://example.com\\\",\\\"name\\\": \\\"Example Homepage\\\",\\\"type\\\": \\\"pagespeed\\\",\\\"interval\\\": 180000}, \\\"redirect\\\": \\\"/pagespeed\\\"}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"f8df1cad-6051-466e-a13e-47d710ba1c14\",\n\t\t\t\t\t\"diagramNodeId\": \"b8e83b0a-69ff-4c34-a7fe-cb8c9ba85438\",\n\t\t\t\t\t\"simStepLabel\": \"API Call: Create Monitor\",\n\t\t\t\t\t\"simStepDescription\": \"The frontend sends a POST request to the backend API to create a new monitor record in the database. This request includes the monitor's configuration details.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Pages/v1/PageSpeed/Create/index.jsx\",\n\t\t\t\t\t\t\"startLine\": \"119\",\n\t\t\t\t\t\t\"endLine\": \"119\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"createMonitor\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"monitor\\\": {\\\"url\\\": \\\"https://example.com\\\",\\\"name\\\": \\\"Example Homepage\\\",\\\"type\\\": \\\"pagespeed\\\",\\\"notifications\\\": [],\\\"interval\\\": 180000}, \\\"redirect\\\": \\\"/pagespeed\\\"}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"monitor\\\": {\\\"url\\\": \\\"https://example.com\\\",\\\"name\\\": \\\"Example Homepage\\\",\\\"type\\\": \\\"pagespeed\\\",\\\"notifications\\\": [],\\\"interval\\\": 180000}, \\\"redirect\\\": \\\"/pagespeed\\\"}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"53968267-0c6e-42f4-88b3-cd90f44532ae\",\n\t\t\t\t\t\"diagramNodeId\": \"6527fb47-157e-4bba-9aed-adde061c5689\",\n\t\t\t\t\t\"simStepLabel\": \"Backend Requests PageSpeed Analysis\",\n\t\t\t\t\t\"simStepDescription\": \"A background job for the newly created monitor triggers the `NetworkService` to request a performance analysis from the Google PageSpeed Insights API. It constructs the API URL using the monitor's target URL and the configured PageSpeed API key.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/service/v2/infrastructure/NetworkService.ts\",\n\t\t\t\t\t\t\"startLine\": \"129\",\n\t\t\t\t\t\t\"endLine\": \"162\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"requestPagespeed\",\n\t\t\t\t\t\t\t\"apiKey\",\n\t\t\t\t\t\t\t\"pagespeedUrl\",\n\t\t\t\t\t\t\t\"pagespeedResponse\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"monitor\\\": {\\\"_id\\\": \\\"64b9a6b3e1b6f0b3e8a7d1c0\\\",\\\"url\\\": \\\"https://example.com\\\",\\\"type\\\": \\\"pagespeed\\\"}}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"statusResponse\\\": {\\\"monitorId\\\": \\\"64b9a6b3e1b6f0b3e8a7d1c0\\\",\\\"status\\\": \\\"up\\\",\\\"responseTime\\\": 450, \\\"payload\\\": {\\\"lighthouseResult\\\": {...}}}}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"0b380571-3896-4365-b5dc-187494f02e0d\",\n\t\t\t\t\t\"diagramNodeId\": \"0d3c8091-3d91-4e42-9b46-7e35ed726a7a\",\n\t\t\t\t\t\"simStepLabel\": \"Google PageSpeed API Response\",\n\t\t\t\t\t\"simStepDescription\": \"The Google PageSpeed Insights API responds with a detailed JSON payload containing the Lighthouse analysis results, including scores for performance, accessibility, SEO, and best practices.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/service/v2/infrastructure/NetworkService.ts\",\n\t\t\t\t\t\t\"startLine\": \"156\",\n\t\t\t\t\t\t\"endLine\": \"156\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"payload\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"lighthouseResult\\\": {\\\"categories\\\": {\\\"performance\\\": {\\\"score\\\": 0.92},\\\"accessibility\\\": {\\\"score\\\": 0.98},\\\"best-practices\\\": {\\\"score\\\": 1},\\\"seo\\\": {\\\"score\\\": 0.95}},\\\"audits\\\": {\\\"first-contentful-paint\\\": {\\\"score\\\": 0.99,\\\"numericValue\\\": 850},\\\"largest-contentful-paint\\\": {\\\"score\\\": 0.91,\\\"numericValue\\\": 1450}}}}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"lighthouseResult\\\": {\\\"categories\\\": {\\\"performance\\\": {\\\"score\\\": 0.92},\\\"accessibility\\\": {\\\"score\\\": 0.98},\\\"best-practices\\\": {\\\"score\\\": 1},\\\"seo\\\": {\\\"score\\\": 0.95}},\\\"audits\\\": {\\\"first-contentful-paint\\\": {\\\"score\\\": 0.99,\\\"numericValue\\\": 850},\\\"largest-contentful-paint\\\": {\\\"score\\\": 0.91,\\\"numericValue\\\": 1450}}}}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"01206383-2db8-4b18-84d0-be2a0289c196\",\n\t\t\t\t\t\"diagramNodeId\": \"f89cbd87-c961-4f8b-92b6-714da57718d5\",\n\t\t\t\t\t\"simStepLabel\": \"Backend Processes Lighthouse Data\",\n\t\t\t\t\t\"simStepDescription\": \"The `CheckService` receives the raw data from the Google API. The `buildPagespeedCheck` function extracts and transforms the relevant scores and audit details into a structured `Check` object, preparing it for database storage.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/service/v2/business/CheckService.ts\",\n\t\t\t\t\t\t\"startLine\": \"82\",\n\t\t\t\t\t\t\"endLine\": \"102\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"buildPagespeedCheck\",\n\t\t\t\t\t\t\t\"isPagespeedPayload\",\n\t\t\t\t\t\t\t\"lighthouseResult\",\n\t\t\t\t\t\t\t\"check.lighthouse\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"statusResponse\\\": {\\\"payload\\\": {\\\"lighthouseResult\\\": {\\\"categories\\\": {\\\"performance\\\": {\\\"score\\\": 0.92},\\\"accessibility\\\": {\\\"score\\\": 0.98},\\\"best-practices\\\": {\\\"score\\\": 1},\\\"seo\\\": {\\\"score\\\": 0.95}},\\\"audits\\\": {\\\"cumulative-layout-shift\\\": {},\\\"speed-index\\\": {},\\\"first-contentful-paint\\\": {},\\\"largest-contentful-paint\\\": {},\\\"total-blocking-time\\\": {}}}}}}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"check\\\": {\\\"lighthouse\\\": {\\\"accessibility\\\": 0.98,\\\"bestPractices\\\": 1,\\\"seo\\\": 0.95,\\\"performance\\\": 0.92,\\\"audits\\\": {\\\"cls\\\": {},\\\"si\\\": {},\\\"fcp\\\": {},\\\"lcp\\\": {},\\\"tbt\\\": {}}}}}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"a629a102-0df1-4798-a7a2-45c8f6cdad29\",\n\t\t\t\t\t\"diagramNodeId\": \"27c7191b-80a2-475b-9371-e106108aff1c\",\n\t\t\t\t\t\"simStepLabel\": \"Store Processed Check Data\",\n\t\t\t\t\t\"simStepDescription\": \"The processed and structured check data, containing the key performance metrics, is saved to the 'checks' collection in the database, associated with the corresponding monitor ID.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/db/v2/models/checks/Check.ts\",\n\t\t\t\t\t\t\"startLine\": \"237\",\n\t\t\t\t\t\t\"endLine\": \"268\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"lighthouse\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"check\\\": {\\\"monitorId\\\": \\\"64b9a6b3e1b6f0b3e8a7d1c0\\\", \\\"status\\\": \\\"up\\\", \\\"responseTime\\\": 450, \\\"lighthouse\\\": {\\\"performance\\\": 0.92, \\\"accessibility\\\": 0.98, \\\"bestPractices\\\": 1, \\\"seo\\\": 0.95, \\\"audits\\\": {...}}}}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"check\\\": {\\\"monitorId\\\": \\\"64b9a6b3e1b6f0b3e8a7d1c0\\\", \\\"status\\\": \\\"up\\\", \\\"responseTime\\\": 450, \\\"lighthouse\\\": {\\\"performance\\\": 0.92, \\\"accessibility\\\": 0.98, \\\"bestPractices\\\": 1, \\\"seo\\\": 0.95, \\\"audits\\\": {...}}}}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"5616ac6d-c281-4879-82f1-6590c721c8f7\",\n\t\t\t\t\t\"diagramNodeId\": \"ca6ee27b-1fbf-49de-978a-d6de259cc3d5\",\n\t\t\t\t\t\"simStepLabel\": \"Backend Aggregates Performance Data\",\n\t\t\t\t\t\"simStepDescription\": \"When a user views the details of a PageSpeed monitor, the frontend requests historical data. The `MonitorService` on the backend uses a MongoDB aggregation pipeline to group checks by time intervals and calculate average scores for metrics like performance, SEO, etc. This is defined by helper functions like `getPageSpeedGroup`.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/service/v2/business/MonitorService.ts\",\n\t\t\t\t\t\t\"startLine\": \"106\",\n\t\t\t\t\t\t\"endLine\": \"120\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"getPageSpeedGroup\",\n\t\t\t\t\t\t\t\"accessibility\",\n\t\t\t\t\t\t\t\"bestPractices\",\n\t\t\t\t\t\t\t\"seo\",\n\t\t\t\t\t\t\t\"performance\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"monitorId\\\": \\\"64b9a6b3e1b6f0b3e8a7d1c0\\\", \\\"range\\\": \\\"7d\\\"}\",\n\t\t\t\t\t\"outputDataExample\": \"[{\\\"_id\\\": \\\"2023-07-20T10:00:00Z\\\", \\\"avgResponseTime\\\": 450, \\\"performance\\\": 0.92, \\\"seo\\\": 0.95, \\\"accessibility\\\": 0.98, \\\"bestPractices\\\": 1.0}, {\\\"_id\\\": \\\"2023-07-20T11:00:00Z\\\", \\\"avgResponseTime\\\": 465, \\\"performance\\\": 0.91, \\\"seo\\\": 0.95, \\\"accessibility\\\": 0.98, \\\"bestPractices\\\": 1.0}]\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"4ed43eaf-fa8f-4fce-af87-8a5f74dd5c08\",\n\t\t\t\t\t\"diagramNodeId\": \"7be432cd-2587-4eab-abdc-f7b9c1923597\",\n\t\t\t\t\t\"simStepLabel\": \"Aggregated Data Transmitted to Frontend\",\n\t\t\t\t\t\"simStepDescription\": \"The backend sends the aggregated and time-series formatted performance data to the frontend in a JSON response.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/service/v2/business/MonitorService.ts\",\n\t\t\t\t\t\t\"startLine\": \"368\",\n\t\t\t\t\t\t\"endLine\": \"372\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"Check.aggregate\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"[{\\\"_id\\\": \\\"2023-07-20T10:00:00Z\\\", \\\"performance\\\": 0.92, \\\"seo\\\": 0.95, \\\"accessibility\\\": 0.98}, {\\\"_id\\\": \\\"2023-07-20T11:00:00Z\\\", \\\"performance\\\": 0.91, \\\"seo\\\": 0.95, \\\"accessibility\\\": 0.98}]\",\n\t\t\t\t\t\"outputDataExample\": \"[{\\\"_id\\\": \\\"2023-07-20T10:00:00Z\\\", \\\"performance\\\": 0.92, \\\"seo\\\": 0.95, \\\"accessibility\\\": 0.98}, {\\\"_id\\\": \\\"2023-07-20T11:00:00Z\\\", \\\"performance\\\": 0.91, \\\"seo\\\": 0.95, \\\"accessibility\\\": 0.98}]\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"0ec0eb06-05eb-4204-b077-9e47eb2cc316\",\n\t\t\t\t\t\"diagramNodeId\": \"9ef9e218-4742-487a-9a88-5c70e788ccdc\",\n\t\t\t\t\t\"simStepLabel\": \"Frontend Renders Performance Charts\",\n\t\t\t\t\t\"simStepDescription\": \"The `PageSpeedDetails` component receives the historical data from the backend. It then passes this data to specialized child components like `PageSpeedAreaChart` and `PerformanceReport` to render visualizations of the website's performance over time.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Pages/v1/PageSpeed/Details/index.jsx\",\n\t\t\t\t\t\t\"startLine\": \"91\",\n\t\t\t\t\t\t\"endLine\": \"126\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"PageSpeedStatusBoxes\",\n\t\t\t\t\t\t\t\"MonitorTimeFrameHeader\",\n\t\t\t\t\t\t\t\"PageSpeedAreaChart\",\n\t\t\t\t\t\t\t\"PerformanceReport\",\n\t\t\t\t\t\t\t\"monitor\",\n\t\t\t\t\t\t\t\"audits\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"monitor\\\": {\\\"checks\\\": [{\\\"createdAt\\\": \\\"2023-07-20T10:00:00Z\\\", \\\"performance\\\": 0.92, \\\"seo\\\": 0.95}, {\\\"createdAt\\\": \\\"2023-07-20T11:00:00Z\\\", \\\"performance\\\": 0.91, \\\"seo\\\": 0.95}]}}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"renderedUI\\\": \\\"A page with charts and graphs showing performance trends.\\\"}\"\n\t\t\t\t}\n\t\t\t],\n\t\t\t\"description\": \"<ul><li>Integrates with Google's PageSpeed Insights to monitor and analyze web page performance</li><li>- Tracks key web vitals and performance metrics such as SEO, Accessibility, Best Practices, and Performance scores</li><li>- Provides a grid view of all page speed monitors for a quick overview of website health</li><li>- Detailed reports show historical performance data, allowing users to track improvements or regressions over time</li><li>- This feature requires a Google PageSpeed API key to be configured in the settings</li></ul>\",\n\t\t\t\"simulationNodesAndEdges\": {\n\t\t\t\t\"0622b212-3a4a-484d-9b7a-125864d785cd\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"b0cc6e6a-961e-4ea9-aa8a-6bfa44d6ba12\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"6527fb47-157e-4bba-9aed-adde061c5689\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"53968267-0c6e-42f4-88b3-cd90f44532ae\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"f89cbd87-c961-4f8b-92b6-714da57718d5\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"01206383-2db8-4b18-84d0-be2a0289c196\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"ca6ee27b-1fbf-49de-978a-d6de259cc3d5\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"5616ac6d-c281-4879-82f1-6590c721c8f7\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"9ef9e218-4742-487a-9a88-5c70e788ccdc\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"0ec0eb06-05eb-4204-b077-9e47eb2cc316\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"b8e83b0a-69ff-4c34-a7fe-cb8c9ba85438\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"f8df1cad-6051-466e-a13e-47d710ba1c14\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"0d3c8091-3d91-4e42-9b46-7e35ed726a7a\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"0b380571-3896-4365-b5dc-187494f02e0d\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"27c7191b-80a2-475b-9371-e106108aff1c\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"a629a102-0df1-4798-a7a2-45c8f6cdad29\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"7be432cd-2587-4eab-abdc-f7b9c1923597\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"4ed43eaf-fa8f-4fce-af87-8a5f74dd5c08\"\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"isAIGenerated\": true,\n\t\t\t\"keywords\": \"pagespeed, lighthouse, performance\",\n\t\t\t\"generationPrompt\": \"Website Performance and Page Speed Monitoring\",\n\t\t\t\"generationKeywords\": \"pagespeed, lighthouse, performance\"\n\t\t},\n\t\t\"Scheduled Maintenance Windows\": {\n\t\t\t\"name\": \"Scheduled Maintenance Windows\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"2401ef7a-8d8e-4056-868a-547ab213daf1\",\n\t\t\t\t\t\"diagramNodeId\": \"20335f29-a2ac-4e0c-aba6-28707748ecd4\",\n\t\t\t\t\t\"simStepLabel\": \"Flow: Create Maintenance Window - User Interaction\",\n\t\t\t\t\t\"simStepDescription\": \"A user navigates to the 'Create Maintenance Window' page. They fill out a form with details such as a name, start date/time, duration, recurrence, and select the monitors to which this window will apply.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Pages/v1/Maintenance/CreateMaintenance/index.jsx\",\n\t\t\t\t\t\t\"startLine\": \"46\",\n\t\t\t\t\t\t\"endLine\": \"131\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"CreateMaintenance\",\n\t\t\t\t\t\t\t\"form\",\n\t\t\t\t\t\t\t\"setForm\",\n\t\t\t\t\t\t\t\"handleFormChange\",\n\t\t\t\t\t\t\t\"handleSubmit\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"name\\\":\\\"Server Patching Window\\\",\\\"startDate\\\":\\\"2023-10-27T00:00:00.000Z\\\",\\\"startTime\\\":\\\"2023-10-27T02:00:00.000Z\\\",\\\"duration\\\":\\\"60\\\",\\\"durationUnit\\\":\\\"minutes\\\",\\\"repeat\\\":\\\"none\\\",\\\"monitors\\\":[{\\\"_id\\\":\\\"652ff379963e792a5a3a0e4e\\\",\\\"name\\\":\\\"Main Production Server\\\"}]}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"f881435b-3bc2-453d-b6bf-56ad3a12f120\",\n\t\t\t\t\t\"diagramNodeId\": \"d3bdc6ff-875e-472e-88c8-eb10b20c526e\",\n\t\t\t\t\t\"simStepLabel\": \"Flow: Create Maintenance Window - Form Submission\",\n\t\t\t\t\t\"simStepDescription\": \"Upon clicking the 'Create Maintenance' button, the form state is passed to the `handleSubmit` function which then calls the `handleSubmitForm` action from a custom hook.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Pages/v1/Maintenance/CreateMaintenance/index.jsx\",\n\t\t\t\t\t\t\"startLine\": \"108\",\n\t\t\t\t\t\t\"endLine\": \"109\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"handleSubmit\",\n\t\t\t\t\t\t\t\"handleSubmitForm\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"name\\\":\\\"Server Patching Window\\\",\\\"startDate\\\":\\\"2023-10-27T00:00:00.000Z\\\",\\\"startTime\\\":\\\"2023-10-27T02:00:00.000Z\\\",\\\"duration\\\":\\\"60\\\",\\\"durationUnit\\\":\\\"minutes\\\",\\\"repeat\\\":\\\"none\\\",\\\"monitors\\\":[{\\\"_id\\\":\\\"652ff379963e792a5a3a0e4e\\\",\\\"name\\\":\\\"Main Production Server\\\"}]}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"name\\\":\\\"Server Patching Window\\\",\\\"startDate\\\":\\\"2023-10-27T00:00:00.000Z\\\",\\\"startTime\\\":\\\"2023-10-27T02:00:00.000Z\\\",\\\"duration\\\":\\\"60\\\",\\\"durationUnit\\\":\\\"minutes\\\",\\\"repeat\\\":\\\"none\\\",\\\"monitors\\\":[{\\\"_id\\\":\\\"652ff379963e792a5a3a0e4e\\\",\\\"name\\\":\\\"Main Production Server\\\"}]}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"5e0d7085-099b-478a-afaa-47ad4dd07043\",\n\t\t\t\t\t\"diagramNodeId\": \"5bdfdfa4-5d93-49fa-b05c-905813e6cf9d\",\n\t\t\t\t\t\"simStepLabel\": \"Flow: Create Maintenance Window - Prepare API Request\",\n\t\t\t\t\t\"simStepDescription\": \"The `handleSubmitForm` hook processes the form data, calculates start and end timestamps, and constructs a request object. It then determines whether to call `createMaintenanceWindow` or `editMaintenanceWindow` on the network service.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Pages/v1/Maintenance/CreateMaintenance/hooks/useMaintenanceActions.jsx\",\n\t\t\t\t\t\t\"startLine\": \"25\",\n\t\t\t\t\t\t\"endLine\": \"58\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"handleSubmitForm\",\n\t\t\t\t\t\t\t\"networkService.createMaintenanceWindow\",\n\t\t\t\t\t\t\t\"networkService.editMaintenanceWindow\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"form\\\":{\\\"name\\\":\\\"Server Patching Window\\\",\\\"startDate\\\":\\\"2023-10-27T00:00:00.000Z\\\",\\\"startTime\\\":\\\"2023-10-27T02:00:00.000Z\\\",\\\"duration\\\":\\\"60\\\",\\\"durationUnit\\\":\\\"minutes\\\",\\\"repeat\\\":\\\"none\\\",\\\"monitors\\\":[{\\\"_id\\\":\\\"652ff379963e792a5a3a0e4e\\\"}]}}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"maintenanceWindow\\\":{\\\"name\\\":\\\"Server Patching Window\\\",\\\"start\\\":\\\"2023-10-27T02:00:00.000Z\\\",\\\"end\\\":\\\"2023-10-27T03:00:00.000Z\\\",\\\"repeat\\\":0,\\\"oneTime\\\":true,\\\"monitors\\\":[\\\"652ff379963e792a5a3a0e4e\\\"],\\\"expiry\\\":\\\"2023-10-27T03:00:00.000Z\\\"}}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"0660b48b-139f-4ecf-b7d9-f12f544e0ab5\",\n\t\t\t\t\t\"diagramNodeId\": \"fd5e4447-123b-4b2d-8bce-1d1ae7cb00af\",\n\t\t\t\t\t\"simStepLabel\": \"Flow: Create Maintenance Window - API Call\",\n\t\t\t\t\t\"simStepDescription\": \"The `NetworkService` sends the prepared maintenance window data as a POST request to the `/api/v1/maintenance-window` endpoint.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Utils/NetworkService.js\",\n\t\t\t\t\t\t\"startLine\": \"762\",\n\t\t\t\t\t\t\"endLine\": \"766\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"createMaintenanceWindow\",\n\t\t\t\t\t\t\t\"this.axiosInstance.post\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"maintenanceWindow\\\":{\\\"name\\\":\\\"Server Patching Window\\\",\\\"start\\\":\\\"2023-10-27T02:00:00.000Z\\\",\\\"end\\\":\\\"2023-10-27T03:00:00.000Z\\\",\\\"repeat\\\":0,\\\"oneTime\\\":true,\\\"monitors\\\":[\\\"652ff379963e792a5a3a0e4e\\\"],\\\"expiry\\\":\\\"2023-10-27T03:00:00.000Z\\\"}}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"maintenanceWindow\\\":{\\\"name\\\":\\\"Server Patching Window\\\",\\\"start\\\":\\\"2023-10-27T02:00:00.000Z\\\",\\\"end\\\":\\\"2023-10-27T03:00:00.000Z\\\",\\\"repeat\\\":0,\\\"oneTime\\\":true,\\\"monitors\\\":[\\\"652ff379963e792a5a3a0e4e\\\"],\\\"expiry\\\":\\\"2023-10-27T03:00:00.000Z\\\"}}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"3e93ef65-8e2c-405b-8dc1-56d8e93937b3\",\n\t\t\t\t\t\"diagramNodeId\": \"a391e8ea-9dbe-4fe4-90df-bf475d8b7ef8\",\n\t\t\t\t\t\"simStepLabel\": \"Flow: Create Maintenance Window - API Routing\",\n\t\t\t\t\t\"simStepDescription\": \"The backend Express server receives the request. The routing configuration maps the `/api/v1/maintenance-window` path to the `maintenanceWindowRoutes`, which in turn directs the POST request to the `createMaintenanceWindows` method in the controller.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/config/routes.js\",\n\t\t\t\t\t\t\"startLine\": \"43\",\n\t\t\t\t\t\t\"endLine\": \"43\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"app\",\n\t\t\t\t\t\t\t\"verifyJWT\",\n\t\t\t\t\t\t\t\"maintenanceWindowRoutes\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"method\\\":\\\"POST\\\",\\\"url\\\":\\\"/api/v1/maintenance-window\\\",\\\"body\\\":{\\\"name\\\":\\\"Server Patching Window\\\",\\\"start\\\":\\\"2023-10-27T02:00:00.000Z\\\",\\\"end\\\":\\\"2023-10-27T03:00:00.000Z\\\",\\\"repeat\\\":0,\\\"oneTime\\\":true,\\\"monitors\\\":[\\\"652ff379963e792a5a3a0e4e\\\"]}}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"controllerMethod\\\":\\\"createMaintenanceWindows\\\",\\\"params\\\":{}}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"e4cc5ce8-6da9-4281-9204-29c061ab13ce\",\n\t\t\t\t\t\"diagramNodeId\": \"e2588541-3ffc-47c6-8f8a-41d30ea7fc72\",\n\t\t\t\t\t\"simStepLabel\": \"Flow: Create Maintenance Window - Controller Invocation\",\n\t\t\t\t\t\"simStepDescription\": \"The request and response objects are passed from the router to the `createMaintenanceWindows` controller method.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/routes/v1/maintenanceWindowRoute.js\",\n\t\t\t\t\t\t\"startLine\": \"10\",\n\t\t\t\t\t\t\"endLine\": \"10\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"this.router.post\",\n\t\t\t\t\t\t\t\"this.mwController.createMaintenanceWindows\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"req\\\": {\\\"body\\\": {\\\"name\\\":\\\"Server Patching Window\\\", \\\"monitors\\\":[\\\"652ff379963e792a5a3a0e4e\\\"]}, \\\"user\\\": {\\\"teamId\\\":\\\"652ff379963e792a5a3a0e4d\\\"}}}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"req\\\": {\\\"body\\\": {\\\"name\\\":\\\"Server Patching Window\\\", \\\"monitors\\\":[\\\"652ff379963e792a5a3a0e4e\\\"]}, \\\"user\\\": {\\\"teamId\\\":\\\"652ff379963e792a5a3a0e4d\\\"}}}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"95fc1919-339d-4659-98cb-3dc50f662075\",\n\t\t\t\t\t\"diagramNodeId\": \"0fae6e75-38ea-444d-a1bf-0f820ba443b9\",\n\t\t\t\t\t\"simStepLabel\": \"Flow: Create Maintenance Window - Controller Logic\",\n\t\t\t\t\t\"simStepDescription\": \"The `maintenanceWindowController` validates the request body using Joi, ensures a `teamId` exists on the user object, and then calls the `maintenanceWindowService` to handle the business logic of creating the window.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/controllers/v1/maintenanceWindowController.js\",\n\t\t\t\t\t\t\"startLine\": \"27\",\n\t\t\t\t\t\t\"endLine\": \"41\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"createMaintenanceWindows\",\n\t\t\t\t\t\t\t\"createMaintenanceWindowBodyValidation\",\n\t\t\t\t\t\t\t\"this.maintenanceWindowService.createMaintenanceWindow\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"req\\\": {\\\"body\\\": {\\\"name\\\":\\\"Server Patching Window\\\", \\\"monitors\\\":[\\\"652ff379963e792a5a3a0e4e\\\"]}, \\\"user\\\": {\\\"teamId\\\":\\\"652ff379963e792a5a3a0e4d\\\"}}}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"teamId\\\":\\\"652ff379963e792a5a3a0e4d\\\",\\\"body\\\":{\\\"name\\\":\\\"Server Patching Window\\\",\\\"monitors\\\":[\\\"652ff379963e792a5a3a0e4e\\\"]}}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"c3d1a95c-e93d-499a-8830-a6d870902414\",\n\t\t\t\t\t\"diagramNodeId\": \"e1d59cf6-0d96-4e0a-ad17-2a7984a9157f\",\n\t\t\t\t\t\"simStepLabel\": \"Flow: Create Maintenance Window - Service Layer Call\",\n\t\t\t\t\t\"simStepDescription\": \"The controller passes the teamId and request body to the `createMaintenanceWindow` method in the `maintenanceWindowService`.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/controllers/v1/maintenanceWindowController.js\",\n\t\t\t\t\t\t\"startLine\": \"35\",\n\t\t\t\t\t\t\"endLine\": \"35\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"this.maintenanceWindowService.createMaintenanceWindow\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"teamId\\\":\\\"652ff379963e792a5a3a0e4d\\\",\\\"body\\\":{\\\"name\\\":\\\"Server Patching Window\\\",\\\"monitors\\\":[\\\"652ff379963e792a5a3a0e4e\\\"]}}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"teamId\\\":\\\"652ff379963e792a5a3a0e4d\\\",\\\"body\\\":{\\\"name\\\":\\\"Server Patching Window\\\",\\\"monitors\\\":[\\\"652ff379963e792a5a3a0e4e\\\"]}}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"6e2cf739-1514-4c37-9874-10b68a47010e\",\n\t\t\t\t\t\"diagramNodeId\": \"560d268b-ef0f-4cd2-bcfe-9dc0a0e2ce6f\",\n\t\t\t\t\t\"simStepLabel\": \"Flow: Create Maintenance Window - Business Logic Execution\",\n\t\t\t\t\t\"simStepDescription\": \"The `maintenanceWindowService` verifies that all monitors specified in the request belong to the user's team. It then iterates through each monitor ID and prepares a separate database transaction to create a maintenance window record for each one.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/service/v1/business/maintenanceWindowService.js\",\n\t\t\t\t\t\t\"startLine\": \"18\",\n\t\t\t\t\t\t\"endLine\": \"39\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"createMaintenanceWindow\",\n\t\t\t\t\t\t\t\"this.db.monitorModule.getMonitorsByIds\",\n\t\t\t\t\t\t\t\"this.db.maintenanceWindowModule.createMaintenanceWindow\",\n\t\t\t\t\t\t\t\"Promise.all\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"teamId\\\":\\\"652ff379963e792a5a3a0e4d\\\",\\\"body\\\":{\\\"name\\\":\\\"Server Patching Window\\\",\\\"start\\\":\\\"2023-10-27T02:00:00.000Z\\\",\\\"end\\\":\\\"2023-10-27T03:00:00.000Z\\\",\\\"monitors\\\":[\\\"652ff379963e792a5a3a0e4e\\\"]}}\",\n\t\t\t\t\t\"outputDataExample\": \"[{\\\"teamId\\\":\\\"652ff379963e792a5a3a0e4d\\\",\\\"monitorId\\\":\\\"652ff379963e792a5a3a0e4e\\\",\\\"name\\\":\\\"Server Patching Window\\\",\\\"start\\\":\\\"2023-10-27T02:00:00.000Z\\\",\\\"end\\\":\\\"2023-10-27T03:00:00.000Z\\\"}]\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"80aed28e-68b6-47bf-8bc9-ededb4824066\",\n\t\t\t\t\t\"diagramNodeId\": \"12d0ab8a-392f-48fa-9efa-06ffe1f3a252\",\n\t\t\t\t\t\"simStepLabel\": \"Flow: Create Maintenance Window - Database Module Call\",\n\t\t\t\t\t\"simStepDescription\": \"For each monitor, the service layer calls the `createMaintenanceWindow` method in the `maintenanceWindowModule`, passing the structured data for the new record.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/service/v1/business/maintenanceWindowService.js\",\n\t\t\t\t\t\t\"startLine\": \"28\",\n\t\t\t\t\t\t\"endLine\": \"37\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"dbTransactions\",\n\t\t\t\t\t\t\t\"this.db.maintenanceWindowModule.createMaintenanceWindow\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"teamId\\\":\\\"652ff379963e792a5a3a0e4d\\\",\\\"monitorId\\\":\\\"652ff379963e792a5a3a0e4e\\\",\\\"name\\\":\\\"Server Patching Window\\\",\\\"start\\\":\\\"2023-10-27T02:00:00.000Z\\\",\\\"end\\\":\\\"2023-10-27T03:00:00.000Z\\\",\\\"oneTime\\\":true}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"teamId\\\":\\\"652ff379963e792a5a3a0e4d\\\",\\\"monitorId\\\":\\\"652ff379963e792a5a3a0e4e\\\",\\\"name\\\":\\\"Server Patching Window\\\",\\\"start\\\":\\\"2023-10-27T02:00:00.000Z\\\",\\\"end\\\":\\\"2023-10-27T03:00:00.000Z\\\",\\\"oneTime\\\":true}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"a3c47fd4-c701-46c2-9aff-94a667b3e368\",\n\t\t\t\t\t\"diagramNodeId\": \"3890b98d-a133-4279-a961-5d2facc6a17a\",\n\t\t\t\t\t\"simStepLabel\": \"Flow: Create Maintenance Window - Database Record Creation\",\n\t\t\t\t\t\"simStepDescription\": \"The `maintenanceWindowModule` instantiates a new `MaintenanceWindow` Mongoose model. If the window is a one-time event, it sets an `expiry` field to the end time for automatic cleanup by MongoDB's TTL index. Finally, it saves the new document to the database.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/db/v1/modules/maintenanceWindowModule.js\",\n\t\t\t\t\t\t\"startLine\": \"7\",\n\t\t\t\t\t\t\"endLine\": \"22\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"createMaintenanceWindow\",\n\t\t\t\t\t\t\t\"this.MaintenanceWindow\",\n\t\t\t\t\t\t\t\"maintenanceWindow.save\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"teamId\\\":\\\"652ff379963e792a5a3a0e4d\\\",\\\"monitorId\\\":\\\"652ff379963e792a5a3a0e4e\\\",\\\"name\\\":\\\"Server Patching Window\\\",\\\"start\\\":\\\"2023-10-27T02:00:00.000Z\\\",\\\"end\\\":\\\"2023-10-27T03:00:00.000Z\\\",\\\"oneTime\\\":true}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"_id\\\":\\\"653ba9a6331a31004887396a\\\",\\\"monitorId\\\":\\\"652ff379963e792a5a3a0e4e\\\",\\\"teamId\\\":\\\"652ff379963e792a5a3a0e4d\\\",\\\"name\\\":\\\"Server Patching Window\\\",\\\"active\\\":true,\\\"start\\\":\\\"2023-10-27T02:00:00.000Z\\\",\\\"end\\\":\\\"2023-10-27T03:00:00.000Z\\\",\\\"expiry\\\":\\\"2023-10-27T03:00:00.000Z\\\"}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"69fdc2a9-837f-466c-9562-a12319019580\",\n\t\t\t\t\t\"diagramNodeId\": \"fcf4eef4-394c-4872-9124-f7a0b32cdc3b\",\n\t\t\t\t\t\"simStepLabel\": \"Flow: Create Maintenance Window - API Response\",\n\t\t\t\t\t\"simStepDescription\": \"After the database operations are complete, a success response is sent back through the layers to the frontend.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/controllers/v1/maintenanceWindowController.js\",\n\t\t\t\t\t\t\"startLine\": \"37\",\n\t\t\t\t\t\t\"endLine\": \"39\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"res.success\",\n\t\t\t\t\t\t\t\"this.stringService.maintenanceWindowCreate\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"msg\\\":\\\"Maintenance Window created successfully.\\\"}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"msg\\\":\\\"Maintenance Window created successfully.\\\"}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"ebe8fd52-f2a1-4a98-a71b-b04d6f4cdadc\",\n\t\t\t\t\t\"diagramNodeId\": \"a5a84b08-8c70-4023-8d08-b74e23aab4d7\",\n\t\t\t\t\t\"simStepLabel\": \"Flow: Create Maintenance Window - UI Update\",\n\t\t\t\t\t\"simStepDescription\": \"The frontend receives the success response. A success toast message is displayed, and the user is navigated back to the main maintenance windows table.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Pages/v1/Maintenance/CreateMaintenance/index.jsx\",\n\t\t\t\t\t\t\"startLine\": \"111\",\n\t\t\t\t\t\t\"endLine\": \"119\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"request\",\n\t\t\t\t\t\t\t\"createToast\",\n\t\t\t\t\t\t\t\"navigate\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"data\\\":{\\\"msg\\\":\\\"Maintenance Window created successfully.\\\"}}\",\n\t\t\t\t\t\"outputDataExample\": \"{}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"82b5ea14-bb00-4511-aba4-76196029fd81\",\n\t\t\t\t\t\"diagramNodeId\": \"d145bb4c-e1e0-473a-b6bc-decc932b738b\",\n\t\t\t\t\t\"simStepLabel\": \"Flow: View Maintenance Windows - Page Load\",\n\t\t\t\t\t\"simStepDescription\": \"User navigates to the '/maintenance' page. The `Maintenance` component mounts and triggers a `useEffect` hook to fetch the list of maintenance windows.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Pages/v1/Maintenance/index.jsx\",\n\t\t\t\t\t\t\"startLine\": \"25\",\n\t\t\t\t\t\t\"endLine\": \"47\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"useEffect\",\n\t\t\t\t\t\t\t\"networkService.getMaintenanceWindowsByTeamId\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"page\\\":0,\\\"rowsPerPage\\\":5}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"7e20cd6c-d24e-4540-86d6-d6a9fa087314\",\n\t\t\t\t\t\"diagramNodeId\": \"7f921125-500f-4902-abc3-936ecac033d8\",\n\t\t\t\t\t\"simStepLabel\": \"Flow: View Maintenance Windows - API Call\",\n\t\t\t\t\t\"simStepDescription\": \"The `networkService` makes a GET request to the backend API to fetch the maintenance windows for the user's team, including pagination parameters.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Utils/NetworkService.js\",\n\t\t\t\t\t\t\"startLine\": \"824\",\n\t\t\t\t\t\t\"endLine\": \"824\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"getMaintenanceWindowsByTeamId\",\n\t\t\t\t\t\t\t\"this.axiosInstance.get\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"page\\\":0,\\\"rowsPerPage\\\":5}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"page\\\":0,\\\"rowsPerPage\\\":5}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"1251da83-5949-4e24-a1d2-fc74ff785aa9\",\n\t\t\t\t\t\"diagramNodeId\": \"c35a065c-2808-402c-877e-9055d956ce0d\",\n\t\t\t\t\t\"simStepLabel\": \"Flow: View Maintenance Windows - Controller and Service\",\n\t\t\t\t\t\"simStepDescription\": \"The backend routes the request to `maintenanceWindowController.getMaintenanceWindowsByTeamId`. This controller calls the corresponding service, which in turn calls the database module to query for the data.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/controllers/v1/maintenanceWindowController.js\",\n\t\t\t\t\t\t\"startLine\": \"75\",\n\t\t\t\t\t\t\"endLine\": \"75\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"this.maintenanceWindowService.getMaintenanceWindowsByTeamId\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"teamId\\\":\\\"652ff379963e792a5a3a0e4d\\\",\\\"query\\\":{\\\"page\\\":\\\"0\\\",\\\"rowsPerPage\\\":\\\"5\\\"}}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"teamId\\\":\\\"652ff379963e792a5a3a0e4d\\\",\\\"query\\\":{\\\"page\\\":\\\"0\\\",\\\"rowsPerPage\\\":\\\"5\\\"}}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"feb8bd4f-339f-4132-a709-89c63c4efa9c\",\n\t\t\t\t\t\"diagramNodeId\": \"c3127c74-43f1-42d7-8da6-b0a494c3658f\",\n\t\t\t\t\t\"simStepLabel\": \"Flow: View Maintenance Windows - Database Query\",\n\t\t\t\t\t\"simStepDescription\": \"The service layer invokes the database module to fetch the maintenance windows from the database.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/service/v1/business/maintenanceWindowService.js\",\n\t\t\t\t\t\t\"startLine\": \"48\",\n\t\t\t\t\t\t\"endLine\": \"48\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"this.db.maintenanceWindowModule.getMaintenanceWindowsByTeamId\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"teamId\\\":\\\"652ff379963e792a5a3a0e4d\\\",\\\"query\\\":{\\\"page\\\":\\\"0\\\",\\\"rowsPerPage\\\":\\\"5\\\"}}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"teamId\\\":\\\"652ff379963e792a5a3a0e4d\\\",\\\"query\\\":{\\\"page\\\":\\\"0\\\",\\\"rowsPerPage\\\":\\\"5\\\"}}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"9bfbae5a-f487-40ef-86f5-04a1cc3c7662\",\n\t\t\t\t\t\"diagramNodeId\": \"27d9160a-4f8d-4dff-a09b-1678bc28cf2c\",\n\t\t\t\t\t\"simStepLabel\": \"Flow: View Maintenance Windows - Data Retrieval\",\n\t\t\t\t\t\"simStepDescription\": \"The `maintenanceWindowModule` constructs a MongoDB query to find all maintenance windows for the given `teamId`, applying pagination (skip, limit) and sorting. It executes the query and returns the results along with the total count.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/db/v1/modules/maintenanceWindowModule.js\",\n\t\t\t\t\t\t\"startLine\": \"37\",\n\t\t\t\t\t\t\"endLine\": \"66\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"getMaintenanceWindowsByTeamId\",\n\t\t\t\t\t\t\t\"this.MaintenanceWindow.countDocuments\",\n\t\t\t\t\t\t\t\"this.MaintenanceWindow.find\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"teamId\\\":\\\"652ff379963e792a5a3a0e4d\\\",\\\"query\\\":{\\\"page\\\":\\\"0\\\",\\\"rowsPerPage\\\":\\\"5\\\"}}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"maintenanceWindows\\\":[{\\\"_id\\\":\\\"653ba9a6331a31004887396a\\\",\\\"name\\\":\\\"Server Patching Window\\\"}],\\\"maintenanceWindowCount\\\":1}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"eda86dca-dea6-4671-a079-7d212f4f18c4\",\n\t\t\t\t\t\"diagramNodeId\": \"6c9979cd-1cc1-4227-b535-2ec3a10ca27e\",\n\t\t\t\t\t\"simStepLabel\": \"Flow: View Maintenance Windows - Data Return to Frontend\",\n\t\t\t\t\t\"simStepDescription\": \"The fetched data is sent back in the API response to the client.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/controllers/v1/maintenanceWindowController.js\",\n\t\t\t\t\t\t\"startLine\": \"77\",\n\t\t\t\t\t\t\"endLine\": \"80\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"res.success\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"data\\\":{\\\"maintenanceWindows\\\":[{\\\"_id\\\":\\\"653ba9a6331a31004887396a\\\",\\\"name\\\":\\\"Server Patching Window\\\"}],\\\"maintenanceWindowCount\\\":1}}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"data\\\":{\\\"maintenanceWindows\\\":[{\\\"_id\\\":\\\"653ba9a6331a31004887396a\\\",\\\"name\\\":\\\"Server Patching Window\\\"}],\\\"maintenanceWindowCount\\\":1}}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"acf97639-e291-4ca6-81a6-d0487397f42a\",\n\t\t\t\t\t\"diagramNodeId\": \"970e2002-7c0e-40ef-80d8-e5e6d0a60735\",\n\t\t\t\t\t\"simStepLabel\": \"Flow: View Maintenance Windows - UI Rendering\",\n\t\t\t\t\t\"simStepDescription\": \"The client receives the data and updates its state. The `MaintenanceTable` component then renders the list of maintenance windows in a table, displaying their names, schedules, and providing actions like edit or delete.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Pages/v1/Maintenance/MaintenanceTable/index.jsx\",\n\t\t\t\t\t\t\"startLine\": \"195\",\n\t\t\t\t\t\t\"endLine\": \"201\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"Table\",\n\t\t\t\t\t\t\t\"headers\",\n\t\t\t\t\t\t\t\"maintenanceWindows\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"maintenanceWindows\\\":[{\\\"_id\\\":\\\"653ba9a6331a31004887396a\\\",\\\"name\\\":\\\"Server Patching Window\\\"}],\\\"maintenanceWindowCount\\\":1}\",\n\t\t\t\t\t\"outputDataExample\": \"{}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"a47affaf-b952-46d6-9709-6120a77690e1\",\n\t\t\t\t\t\"diagramNodeId\": \"23630a1f-7452-4373-a864-7ec7821137f2\",\n\t\t\t\t\t\"simStepLabel\": \"Flow: Monitor Suppression - Job Execution Start\",\n\t\t\t\t\t\"simStepDescription\": \"The `SuperSimpleQueue` processing system picks up a job to check a specific monitor. The job handler is retrieved from `SuperSimpleQueueHelper`.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/service/v1/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.js\",\n\t\t\t\t\t\t\"startLine\": \"30\",\n\t\t\t\t\t\t\"endLine\": \"45\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"getMonitorJob\",\n\t\t\t\t\t\t\t\"this.isInMaintenanceWindow\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"monitor\\\":{\\\"_id\\\":\\\"652ff379963e792a5a3a0e4e\\\",\\\"teamId\\\":\\\"652ff379963e792a5a3a0e4d\\\",\\\"name\\\":\\\"Main Production Server\\\"}}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"monitorId\\\":\\\"652ff379963e792a5a3a0e4e\\\",\\\"teamId\\\":\\\"652ff379963e792a5a3a0e4d\\\"}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"87583096-f1ec-4160-ae52-5238f32ed0ab\",\n\t\t\t\t\t\"diagramNodeId\": \"c99291bb-7316-440e-9a7f-323ee39e26b8\",\n\t\t\t\t\t\"simStepLabel\": \"Flow: Monitor Suppression - Maintenance Check Call\",\n\t\t\t\t\t\"simStepDescription\": \"Before performing the monitor check, the `getMonitorJob` function calls `isInMaintenanceWindow`, passing the monitor's ID and team ID to see if it should be suppressed.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/service/v1/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.js\",\n\t\t\t\t\t\t\"startLine\": \"36\",\n\t\t\t\t\t\t\"endLine\": \"36\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"this.isInMaintenanceWindow\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"monitorId\\\":\\\"652ff379963e792a5a3a0e4e\\\",\\\"teamId\\\":\\\"652ff379963e792a5a3a0e4d\\\"}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"monitorId\\\":\\\"652ff379963e792a5a3a0e4e\\\",\\\"teamId\\\":\\\"652ff379963e792a5a3a0e4d\\\"}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"2127e749-80b4-499a-ae14-8dc2dcc9db9b\",\n\t\t\t\t\t\"diagramNodeId\": \"fc78b5b6-7fad-4f8f-a5a3-c7c38931daba\",\n\t\t\t\t\t\"simStepLabel\": \"Flow: Monitor Suppression - Fetching Maintenance Windows\",\n\t\t\t\t\t\"simStepDescription\": \"The `isInMaintenanceWindow` function calls the database module to fetch all maintenance windows associated with the given monitor ID and team ID.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/service/v1/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.js\",\n\t\t\t\t\t\t\"startLine\": \"80\",\n\t\t\t\t\t\t\"endLine\": \"83\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"this.db.maintenanceWindowModule.getMaintenanceWindowsByMonitorId\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"monitorId\\\":\\\"652ff379963e792a5a3a0e4e\\\",\\\"teamId\\\":\\\"652ff379963e792a5a3a0e4d\\\"}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"monitorId\\\":\\\"652ff379963e792a5a3a0e4e\\\",\\\"teamId\\\":\\\"652ff379963e792a5a3a0e4d\\\"}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"e6542e14-556d-482a-8c35-f7b03997be49\",\n\t\t\t\t\t\"diagramNodeId\": \"8a13e585-2310-420b-9e92-211b6d65f201\",\n\t\t\t\t\t\"simStepLabel\": \"Flow: Monitor Suppression - Database Result Return\",\n\t\t\t\t\t\"simStepDescription\": \"The database module returns a list of maintenance window documents that match the monitor ID.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/db/v1/modules/maintenanceWindowModule.js\",\n\t\t\t\t\t\t\"startLine\": \"69\",\n\t\t\t\t\t\t\"endLine\": \"76\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"getMaintenanceWindowsByMonitorId\",\n\t\t\t\t\t\t\t\"this.MaintenanceWindow.find\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"[{\\\"_id\\\":\\\"653ba9a6331a31004887396a\\\",\\\"monitorId\\\":\\\"652ff379963e792a5a3a0e4e\\\",\\\"active\\\":true,\\\"start\\\":\\\"2023-10-27T02:00:00.000Z\\\",\\\"end\\\":\\\"2023-10-27T03:00:00.000Z\\\"}]\",\n\t\t\t\t\t\"outputDataExample\": \"[{\\\"_id\\\":\\\"653ba9a6331a31004887396a\\\",\\\"monitorId\\\":\\\"652ff379963e792a5a3a0e4e\\\",\\\"active\\\":true,\\\"start\\\":\\\"2023-10-27T02:00:00.000Z\\\",\\\"end\\\":\\\"2023-10-27T03:00:00.000Z\\\"}]\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"6ba6b9d1-5fc3-454e-8744-2022b5192ed9\",\n\t\t\t\t\t\"diagramNodeId\": \"0fe32416-db43-49b9-9438-3796ba1a0add\",\n\t\t\t\t\t\"simStepLabel\": \"Flow: Monitor Suppression - Time Evaluation\",\n\t\t\t\t\t\"simStepDescription\": \"The `isInMaintenanceWindow` function iterates through the returned windows. For each active window, it checks if the current time (`new Date()`) is between the `start` and `end` times.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/service/v1/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.js\",\n\t\t\t\t\t\t\"startLine\": \"85\",\n\t\t\t\t\t\t\"endLine\": \"113\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"maintenanceWindows.reduce\",\n\t\t\t\t\t\t\t\"start\",\n\t\t\t\t\t\t\t\"end\",\n\t\t\t\t\t\t\t\"now\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"[{\\\"_id\\\":\\\"653ba9a6331a31004887396a\\\",\\\"monitorId\\\":\\\"652ff379963e792a5a3a0e4e\\\",\\\"active\\\":true,\\\"start\\\":\\\"2023-10-27T02:00:00.000Z\\\",\\\"end\\\":\\\"2023-10-27T03:00:00.000Z\\\"}]\",\n\t\t\t\t\t\"outputDataExample\": \"true\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"a715d98f-60bf-4f32-aae6-21ee4e09f4da\",\n\t\t\t\t\t\"diagramNodeId\": \"40f4d9df-4c0f-4384-901c-8d7117e3b538\",\n\t\t\t\t\t\"simStepLabel\": \"Flow: Monitor Suppression - Return Suppression Flag\",\n\t\t\t\t\t\"simStepDescription\": \"The boolean result (true if in maintenance, false otherwise) is returned to the `getMonitorJob` function.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/service/v1/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.js\",\n\t\t\t\t\t\t\"startLine\": \"114\",\n\t\t\t\t\t\t\"endLine\": \"114\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"maintenanceWindowIsActive\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"true\",\n\t\t\t\t\t\"outputDataExample\": \"true\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"e59fe64e-f06b-4855-b631-923bb5a68540\",\n\t\t\t\t\t\"diagramNodeId\": \"01e042c3-40b4-416a-8d9e-6d6fd323d60b\",\n\t\t\t\t\t\"simStepLabel\": \"Flow: Monitor Suppression - Conditional Job Termination\",\n\t\t\t\t\t\"simStepDescription\": \"If the `isInMaintenanceWindow` function returns true, the `getMonitorJob` logs that the monitor is in a maintenance window and terminates its execution for this cycle, effectively suppressing the check.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/service/v1/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.js\",\n\t\t\t\t\t\t\"startLine\": \"37\",\n\t\t\t\t\t\t\"endLine\": \"44\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"maintenanceWindowActive\",\n\t\t\t\t\t\t\t\"this.logger.info\",\n\t\t\t\t\t\t\t\"return\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"maintenanceWindowActive\\\": true}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"message\\\":\\\"Monitor 652ff379963e792a5a3a0e4e is in maintenance window\\\"}\"\n\t\t\t\t}\n\t\t\t],\n\t\t\t\"description\": \"<ul><li>Allows users to schedule maintenance periods to prevent false alarms and avoid skewing uptime statistics during planned downtime</li><li>- Users can define a start and end time for a maintenance window</li><li>- Specific monitors or all monitors can be associated with a maintenance window</li><li>- During a scheduled maintenance, notifications for associated monitors are suppressed</li><li>- Provides a central table to view all active, upcoming, and past maintenance windows</li></ul>\",\n\t\t\t\"simulationNodesAndEdges\": {\n\t\t\t\t\"20335f29-a2ac-4e0c-aba6-28707748ecd4\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"2401ef7a-8d8e-4056-868a-547ab213daf1\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"5bdfdfa4-5d93-49fa-b05c-905813e6cf9d\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"5e0d7085-099b-478a-afaa-47ad4dd07043\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"a391e8ea-9dbe-4fe4-90df-bf475d8b7ef8\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"3e93ef65-8e2c-405b-8dc1-56d8e93937b3\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"0fae6e75-38ea-444d-a1bf-0f820ba443b9\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"95fc1919-339d-4659-98cb-3dc50f662075\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"560d268b-ef0f-4cd2-bcfe-9dc0a0e2ce6f\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"6e2cf739-1514-4c37-9874-10b68a47010e\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"3890b98d-a133-4279-a961-5d2facc6a17a\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"a3c47fd4-c701-46c2-9aff-94a667b3e368\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"a5a84b08-8c70-4023-8d08-b74e23aab4d7\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"ebe8fd52-f2a1-4a98-a71b-b04d6f4cdadc\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"d145bb4c-e1e0-473a-b6bc-decc932b738b\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"82b5ea14-bb00-4511-aba4-76196029fd81\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"c35a065c-2808-402c-877e-9055d956ce0d\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"1251da83-5949-4e24-a1d2-fc74ff785aa9\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"27d9160a-4f8d-4dff-a09b-1678bc28cf2c\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"9bfbae5a-f487-40ef-86f5-04a1cc3c7662\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"970e2002-7c0e-40ef-80d8-e5e6d0a60735\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"acf97639-e291-4ca6-81a6-d0487397f42a\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"23630a1f-7452-4373-a864-7ec7821137f2\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"a47affaf-b952-46d6-9709-6120a77690e1\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"fc78b5b6-7fad-4f8f-a5a3-c7c38931daba\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"2127e749-80b4-499a-ae14-8dc2dcc9db9b\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"0fe32416-db43-49b9-9438-3796ba1a0add\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"6ba6b9d1-5fc3-454e-8744-2022b5192ed9\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"01e042c3-40b4-416a-8d9e-6d6fd323d60b\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"e59fe64e-f06b-4855-b631-923bb5a68540\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"d3bdc6ff-875e-472e-88c8-eb10b20c526e\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"f881435b-3bc2-453d-b6bf-56ad3a12f120\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"fd5e4447-123b-4b2d-8bce-1d1ae7cb00af\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"0660b48b-139f-4ecf-b7d9-f12f544e0ab5\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"e2588541-3ffc-47c6-8f8a-41d30ea7fc72\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"e4cc5ce8-6da9-4281-9204-29c061ab13ce\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"e1d59cf6-0d96-4e0a-ad17-2a7984a9157f\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"c3d1a95c-e93d-499a-8830-a6d870902414\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"12d0ab8a-392f-48fa-9efa-06ffe1f3a252\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"80aed28e-68b6-47bf-8bc9-ededb4824066\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"fcf4eef4-394c-4872-9124-f7a0b32cdc3b\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"69fdc2a9-837f-466c-9562-a12319019580\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"7f921125-500f-4902-abc3-936ecac033d8\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"7e20cd6c-d24e-4540-86d6-d6a9fa087314\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"c3127c74-43f1-42d7-8da6-b0a494c3658f\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"feb8bd4f-339f-4132-a709-89c63c4efa9c\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"6c9979cd-1cc1-4227-b535-2ec3a10ca27e\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"eda86dca-dea6-4671-a079-7d212f4f18c4\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"c99291bb-7316-440e-9a7f-323ee39e26b8\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"87583096-f1ec-4160-ae52-5238f32ed0ab\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"8a13e585-2310-420b-9e92-211b6d65f201\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"e6542e14-556d-482a-8c35-f7b03997be49\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"40f4d9df-4c0f-4384-901c-8d7117e3b538\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"a715d98f-60bf-4f32-aae6-21ee4e09f4da\"\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"isAIGenerated\": true,\n\t\t\t\"keywords\": \"MaintenanceWindow, createMaintenanceWindow, maintenanceWindowController\",\n\t\t\t\"generationPrompt\": \"Scheduled Maintenance Windows\",\n\t\t\t\"generationKeywords\": \"MaintenanceWindow, createMaintenanceWindow, maintenanceWindowController\"\n\t\t},\n\t\t\"User and Team Management with Role-Based Access\": {\n\t\t\t\"name\": \"User and Team Management with Role-Based Access\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"2d5a952a-ce62-4948-9309-96b28ad74e59\",\n\t\t\t\t\t\"diagramNodeId\": \"3de2d413-5e9b-49f4-9409-74be32c52e0f\",\n\t\t\t\t\t\"simStepLabel\": \"Client: Conditional UI Rendering Based on Role\",\n\t\t\t\t\t\"simStepDescription\": \"A user with 'superadmin' or 'admin' role navigates to the Account page. The application checks the user's role stored in the Redux state to conditionally render the 'Team' management tab. Non-admin users will not see this option.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Pages/v1/Account/index.jsx\",\n\t\t\t\t\t\t\"startLine\": \"37\",\n\t\t\t\t\t\t\"endLine\": \"41\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"user.role\",\n\t\t\t\t\t\t\t\"requiredRoles\",\n\t\t\t\t\t\t\t\"hideTeams\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\n  \\\"user\\\": {\\n    \\\"_id\\\": \\\"60f8f7b3a7b3c2a3e4f5a6b7\\\",\\n    \\\"firstName\\\": \\\"Jane\\\",\\n    \\\"lastName\\\": \\\"Doe\\\",\\n    \\\"email\\\": \\\"jane.doe@example.com\\\",\\n    \\\"role\\\": [\\\"superadmin\\\"],\\n    \\\"teamId\\\": \\\"60f8f7b3a7b3c2a3e4f5a6b8\\\"\\n  }\\n}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\n  \\\"hideTeams\\\": false,\\n  \\\"tabList\\\": [\\n    {\\n      \\\"name\\\": \\\"Profile\\\",\\n      \\\"value\\\": \\\"profile\\\"\\n    },\\n    {\\n      \\\"name\\\": \\\"Password\\\",\\n      \\\"value\\\": \\\"password\\\"\\n    },\\n    {\\n      \\\"name\\\": \\\"Team\\\",\\n      \\\"value\\\": \\\"team\\\"\\n    }\\n  ]\\n}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"10f80ada-2d0a-4e98-bd5d-057e7d4fe6de\",\n\t\t\t\t\t\"diagramNodeId\": \"c441312f-f3c6-48c6-b1b9-7c12749d91bb\",\n\t\t\t\t\t\"simStepLabel\": \"Client: User Navigates to Team Panel\",\n\t\t\t\t\t\"simStepDescription\": \"The user clicks on the 'Team' tab, which navigates them to the team management view. The user's role data is implicitly passed through the application state to render the appropriate components.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Pages/v1/Account/index.jsx\",\n\t\t\t\t\t\t\"startLine\": \"98\",\n\t\t\t\t\t\t\"endLine\": \"98\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"TeamPanel\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\n  \\\"navigationPath\\\": \\\"/account/team\\\",\\n  \\\"userState\\\": {\\n    \\\"role\\\": [\\\"superadmin\\\"]\\n  }\\n}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\n  \\\"navigationPath\\\": \\\"/account/team\\\",\\n  \\\"userState\\\": {\\n    \\\"role\\\": [\\\"superadmin\\\"]\\n  }\\n}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"eebaca25-d588-49c4-a35c-9abc82fde580\",\n\t\t\t\t\t\"diagramNodeId\": \"b27f1bba-c655-40c6-a1dc-71e78c590c92\",\n\t\t\t\t\t\"simStepLabel\": \"Client: Initiate User Invitation\",\n\t\t\t\t\t\"simStepDescription\": \"In the `TeamPanel`, the admin clicks the 'Add Team Member' button, then selects 'Invite a team member'. A dialog opens, prompting for the new user's email and role. After filling the form and clicking 'E-mail token', the `handleInviteMember` function is triggered to start the invitation process.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Pages/v1/Account/components/TeamPanel.jsx\",\n\t\t\t\t\t\t\"startLine\": \"348\",\n\t\t\t\t\t\t\"endLine\": \"354\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"handleInviteMember\",\n\t\t\t\t\t\t\t\"Button\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\n  \\\"email\\\": \\\"new.developer@example.com\\\",\\n  \\\"role\\\": [\\\"user\\\"]\\n}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\n  \\\"apiCall\\\": \\\"networkService.sendInviteEmail\\\",\\n  \\\"payload\\\": {\\n    \\\"email\\\": \\\"new.developer@example.com\\\",\\n    \\\"role\\\": [\\\"user\\\"]\\n  }\\n}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"16d87608-4458-430c-b459-cd9b1d413fa6\",\n\t\t\t\t\t\"diagramNodeId\": \"3530244f-2689-444e-bcbf-611db2e3c000\",\n\t\t\t\t\t\"simStepLabel\": \"API Call: Send Invitation Request\",\n\t\t\t\t\t\"simStepDescription\": \"The client sends a POST request to the `/api/v1/invite/send` endpoint. The request includes the new user's email and selected role in the body, and the admin's authentication token in the headers.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/routes/v1/inviteRoute.js\",\n\t\t\t\t\t\t\"startLine\": \"14\",\n\t\t\t\t\t\t\"endLine\": \"14\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"this.router.post\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\n  \\\"endpoint\\\": \\\"/api/v1/invite/send\\\",\\n  \\\"method\\\": \\\"POST\\\",\\n  \\\"headers\\\": {\\n    \\\"Authorization\\\": \\\"Bearer <jwt_token>\\\"\\n  },\\n  \\\"body\\\": {\\n    \\\"email\\\": \\\"new.developer@example.com\\\",\\n    \\\"role\\\": [\\\"user\\\"]\\n  }\\n}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\n  \\\"endpoint\\\": \\\"/api/v1/invite/send\\\",\\n  \\\"method\\\": \\\"POST\\\",\\n  \\\"headers\\\": {\\n    \\\"Authorization\\\": \\\"Bearer <jwt_token>\\\"\\n  },\\n  \\\"body\\\": {\\n    \\\"email\\\": \\\"new.developer@example.com\\\",\\n    \\\"role\\\": [\\\"user\\\"]\\n  }\\n}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"50dd7316-7d01-43f7-9036-d97d51a9c178\",\n\t\t\t\t\t\"diagramNodeId\": \"8b3cb6c2-ed57-4510-be15-decb8e3c89e1\",\n\t\t\t\t\t\"simStepLabel\": \"Server: Role-Based Access Control Middleware\",\n\t\t\t\t\t\"simStepDescription\": \"The server receives the request. Before reaching the main controller, the `isAllowed` middleware intercepts the request. It verifies the JWT from the request header and checks if the user's role (e.g., 'superadmin') is present in the list of allowed roles for this route (`['admin', 'superadmin']`).\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/middleware/v1/isAllowed.js\",\n\t\t\t\t\t\t\"startLine\": \"39\",\n\t\t\t\t\t\t\"endLine\": \"44\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"decoded.role\",\n\t\t\t\t\t\t\t\"allowedRoles\",\n\t\t\t\t\t\t\t\"hasRole\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\n  \\\"req\\\": {\\n    \\\"user\\\": {\\n      \\\"_id\\\": \\\"60f8f7b3a7b3c2a3e4f5a6b7\\\",\\n      \\\"role\\\": [\\\"superadmin\\\"],\\n      \\\"teamId\\\": \\\"60f8f7b3a7b3c2a3e4f5a6b8\\\"\\n    },\\n    \\\"headers\\\": {\\n      \\\"authorization\\\": \\\"Bearer <jwt_token>\\\"\\n    }\\n  },\\n  \\\"allowedRoles\\\": [\\\"admin\\\", \\\"superadmin\\\"]\\n}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\n  \\\"result\\\": \\\"next() called\\\",\\n  \\\"req\\\": {\\n    \\\"user\\\": {\\n      \\\"_id\\\": \\\"60f8f7b3a7b3c2a3e4f5a6b7\\\",\\n      \\\"role\\\": [\\\"superadmin\\\"],\\n      \\\"teamId\\\": \\\"60f8f7b3a7b3c2a3e4f5a6b8\\\"\\n    },\\n    \\\"headers\\\": {\\n      \\\"authorization\\\": \\\"Bearer <jwt_token>\\\"\\n    }\\n  }\\n}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"6c024d4c-178b-45fc-8bca-4fc6c00549a4\",\n\t\t\t\t\t\"diagramNodeId\": \"2ee1c4e8-90fb-4470-ad9f-6ffed5420853\",\n\t\t\t\t\t\"simStepLabel\": \"Server: Forward Request to Controller\",\n\t\t\t\t\t\"simStepDescription\": \"Since the user's role is authorized, the middleware calls `next()` to pass the request object, now populated with user data, to the next handler in the chain: `inviteController.sendInviteEmail`.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/controllers/v1/inviteController.js\",\n\t\t\t\t\t\t\"startLine\": \"61\",\n\t\t\t\t\t\t\"endLine\": \"68\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"sendInviteEmail\",\n\t\t\t\t\t\t\t\"this.inviteService.sendInviteEmail\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\n  \\\"req\\\": {\\n    \\\"user\\\": {\\n      \\\"_id\\\": \\\"60f8f7b3a7b3c2a3e4f5a6b7\\\",\\n      \\\"firstName\\\": \\\"Jane\\\",\\n      \\\"role\\\": [\\\"superadmin\\\"],\\n      \\\"teamId\\\": \\\"60f8f7b3a7b3c2a3e4f5a6b8\\\"\\n    },\\n    \\\"body\\\": {\\n      \\\"email\\\": \\\"new.developer@example.com\\\",\\n      \\\"role\\\": [\\\"user\\\"]\\n    }\\n  }\\n}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\n  \\\"req\\\": {\\n    \\\"user\\\": {\\n      \\\"_id\\\": \\\"60f8f7b3a7b3c2a3e4f5a6b7\\\",\\n      \\\"firstName\\\": \\\"Jane\\\",\\n      \\\"role\\\": [\\\"superadmin\\\"],\\n      \\\"teamId\\\": \\\"60f8f7b3a7b3c2a3e4f5a6b8\\\"\\n    },\\n    \\\"body\\\": {\\n      \\\"email\\\": \\\"new.developer@example.com\\\",\\n      \\\"role\\\": [\\\"user\\\"]\\n    }\\n  }\\n}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"55fe9963-30d2-47f8-859f-b485a77064c4\",\n\t\t\t\t\t\"diagramNodeId\": \"ae858158-8db6-4917-8fda-0966a953f6ed\",\n\t\t\t\t\t\"simStepLabel\": \"Server: Process Invitation in Service Layer\",\n\t\t\t\t\t\"simStepDescription\": \"The `inviteController` calls the `inviteService`. The service layer handles the business logic: it first requests an invitation token from the database module and then instructs the email service to send the invitation.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/service/v1/business/inviteService.js\",\n\t\t\t\t\t\t\"startLine\": \"24\",\n\t\t\t\t\t\t\"endLine\": \"28\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"sendInviteEmail\",\n\t\t\t\t\t\t\t\"this.db.inviteModule.requestInviteToken\",\n\t\t\t\t\t\t\t\"this.emailService.sendInviteEmail\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\n  \\\"inviteRequest\\\": {\\n    \\\"email\\\": \\\"new.developer@example.com\\\",\\n    \\\"role\\\": [\\\"user\\\"],\\n    \\\"teamId\\\": \\\"60f8f7b3a7b3c2a3e4f5a6b8\\\"\\n  },\\n  \\\"firstName\\\": \\\"Jane\\\"\\n}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\n  \\\"inviteToken\\\": {\\n    \\\"token\\\": \\\"a1b2c3d4e5f6...\\\",\\n    \\\"email\\\": \\\"new.developer@example.com\\\"\\n  }\\n}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"c796f8ad-d548-45f3-8d62-67f59c6c1aa4\",\n\t\t\t\t\t\"diagramNodeId\": \"bdd52e6f-ddf7-4966-b3af-957f9553082f\",\n\t\t\t\t\t\"simStepLabel\": \"Database Query: Create and Store Invite Token\",\n\t\t\t\t\t\"simStepDescription\": \"The `inviteService` calls the `inviteModule` to generate and persist a unique invitation token. This involves creating a new document in the `InviteToken` collection with the invitee's details and a securely generated random token.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/db/v1/modules/inviteModule.js\",\n\t\t\t\t\t\t\"startLine\": \"23\",\n\t\t\t\t\t\t\"endLine\": \"26\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"requestInviteToken\",\n\t\t\t\t\t\t\t\"InviteToken\",\n\t\t\t\t\t\t\t\"invite.save\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\n  \\\"email\\\": \\\"new.developer@example.com\\\",\\n  \\\"role\\\": [\\\"user\\\"],\\n  \\\"teamId\\\": \\\"60f8f7b3a7b3c2a3e4f5a6b8\\\"\\n}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\n  \\\"_id\\\": \\\"61f8f7b3a7b3c2a3e4f5a6b9\\\",\\n  \\\"email\\\": \\\"new.developer@example.com\\\",\\n  \\\"role\\\": [\\\"user\\\"],\\n  \\\"teamId\\\": \\\"60f8f7b3a7b3c2a3e4f5a6b8\\\",\\n  \\\"token\\\": \\\"a1b2c3d4e5f6...\\\",\\n  \\\"createdAt\\\": \\\"2023-10-27T10:00:00.000Z\\\"\\n}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"7d1f86f2-c8d5-48fb-a8c1-b337dc56271f\",\n\t\t\t\t\t\"diagramNodeId\": \"a7be2d0b-0227-4228-a0a6-074f7324fd89\",\n\t\t\t\t\t\"simStepLabel\": \"Server: Dispatch Invitation Email\",\n\t\t\t\t\t\"simStepDescription\": \"After successfully storing the token, the `inviteService` uses the `emailService` to compose and send an email to the new user. The email contains a unique registration link including the generated token.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/service/v1/business/inviteService.js\",\n\t\t\t\t\t\t\"startLine\": \"26\",\n\t\t\t\t\t\t\"endLine\": \"28\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"this.emailService.sendInviteEmail\",\n\t\t\t\t\t\t\t\"inviteToken\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\n  \\\"to\\\": \\\"new.developer@example.com\\\",\\n  \\\"token\\\": \\\"a1b2c3d4e5f6...\\\",\\n  \\\"inviterName\\\": \\\"Jane\\\"\\n}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\n  \\\"status\\\": \\\"success\\\",\\n  \\\"messageId\\\": \\\"<message-id@example.com>\\\"\\n}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"6ba5094d-d1e6-4ec3-8917-28cdb30f2ef9\",\n\t\t\t\t\t\"diagramNodeId\": \"52732a37-82b8-40a7-b12d-dc1b82380b2d\",\n\t\t\t\t\t\"simStepLabel\": \"API Response: Send Confirmation to Client\",\n\t\t\t\t\t\"simStepDescription\": \"The server's controller, having successfully processed the invitation, sends a JSON response back to the client indicating that the invite was sent successfully.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/controllers/v1/inviteController.js\",\n\t\t\t\t\t\t\"startLine\": \"69\",\n\t\t\t\t\t\t\"endLine\": \"72\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"res.success\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\n  \\\"success\\\": true,\\n  \\\"msg\\\": \\\"Invite sent successfully\\\",\\n  \\\"data\\\": {\\n    \\\"token\\\": \\\"a1b2c3d4e5f6...\\\",\\n    \\\"email\\\": \\\"new.developer@example.com\\\"\\n  }\\n}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\n  \\\"success\\\": true,\\n  \\\"msg\\\": \\\"Invite sent successfully\\\",\\n  \\\"data\\\": {\\n    \\\"token\\\": \\\"a1b2c3d4e5f6...\\\",\\n    \\\"email\\\": \\\"new.developer@example.com\\\"\\n  }\\n}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"700f35e0-b39d-417c-b0a8-0612feade977\",\n\t\t\t\t\t\"diagramNodeId\": \"02d87257-883c-4822-a421-823c983532ec\",\n\t\t\t\t\t\"simStepLabel\": \"Client: Display Success Feedback\",\n\t\t\t\t\t\"simStepDescription\": \"The client application receives the successful API response. It then closes the invitation dialog and displays a toast notification to the admin, confirming that the invitation has been sent.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Pages/v1/Account/components/TeamPanel.jsx\",\n\t\t\t\t\t\t\"startLine\": \"145\",\n\t\t\t\t\t\t\"endLine\": \"149\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"createToast\",\n\t\t\t\t\t\t\t\"closeInviteModal\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\n  \\\"response\\\": {\\n    \\\"status\\\": 200,\\n    \\\"data\\\": {\\n      \\\"success\\\": true,\\n      \\\"msg\\\": \\\"Invite sent successfully\\\"\\n    }\\n  }\\n}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\n  \\\"uiState\\\": {\\n    \\\"toast\\\": {\\n      \\\"type\\\": \\\"success\\\",\\n      \\\"message\\\": \\\"Invite sent successfully\\\"\\n    }\\n  }\\n}\"\n\t\t\t\t}\n\t\t\t],\n\t\t\t\"description\": \"<ul><li>Enables collaborative use of the application within an organization with proper access controls</li><li>- The system supports multiple users organized into teams</li><li>- Implements role-based access control (RBAC) with roles like 'superadmin' and 'admin', restricting access to sensitive areas like settings and user management</li><li>- Superadmins can invite new users to the team via email, assigning them a specific role</li><li>- Users can manage their own profiles and change their passwords</li></ul>\",\n\t\t\t\"simulationNodesAndEdges\": {\n\t\t\t\t\"3de2d413-5e9b-49f4-9409-74be32c52e0f\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"2d5a952a-ce62-4948-9309-96b28ad74e59\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"b27f1bba-c655-40c6-a1dc-71e78c590c92\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"eebaca25-d588-49c4-a35c-9abc82fde580\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"8b3cb6c2-ed57-4510-be15-decb8e3c89e1\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"50dd7316-7d01-43f7-9036-d97d51a9c178\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"ae858158-8db6-4917-8fda-0966a953f6ed\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"55fe9963-30d2-47f8-859f-b485a77064c4\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"a7be2d0b-0227-4228-a0a6-074f7324fd89\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"7d1f86f2-c8d5-48fb-a8c1-b337dc56271f\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"02d87257-883c-4822-a421-823c983532ec\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"700f35e0-b39d-417c-b0a8-0612feade977\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"c441312f-f3c6-48c6-b1b9-7c12749d91bb\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"10f80ada-2d0a-4e98-bd5d-057e7d4fe6de\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"3530244f-2689-444e-bcbf-611db2e3c000\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"16d87608-4458-430c-b459-cd9b1d413fa6\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"2ee1c4e8-90fb-4470-ad9f-6ffed5420853\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"6c024d4c-178b-45fc-8bca-4fc6c00549a4\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"bdd52e6f-ddf7-4966-b3af-957f9553082f\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"c796f8ad-d548-45f3-8d62-67f59c6c1aa4\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"52732a37-82b8-40a7-b12d-dc1b82380b2d\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"6ba5094d-d1e6-4ec3-8917-28cdb30f2ef9\"\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"isAIGenerated\": true,\n\t\t\t\"keywords\": \"isAllowed, RoleProtectedRoute, Team\",\n\t\t\t\"generationPrompt\": \"User and Team Management with Role-Based Access\",\n\t\t\t\"generationKeywords\": \"isAllowed, RoleProtectedRoute, Team\"\n\t\t},\n\t\t\"Bulk Monitor Management\": {\n\t\t\t\"name\": \"Bulk Monitor Management\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"a29da01e-8c5a-4e6d-8d3c-e49af528e4fa\",\n\t\t\t\t\t\"diagramNodeId\": \"c4caeba8-ed9a-4cbc-9888-38cc8ca55362\",\n\t\t\t\t\t\"simStepLabel\": \"Flow 1: CSV Import - Navigate to Bulk Import Page\",\n\t\t\t\t\t\"simStepDescription\": \"The user navigates to the \\\"/uptime/bulk-import\\\" URL, which is routed to the BulkImport component for rendering the UI.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Routes/index.jsx\",\n\t\t\t\t\t\t\"startLine\": \"88\",\n\t\t\t\t\t\t\"endLine\": \"91\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"Route\",\n\t\t\t\t\t\t\t\"BulkImport\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"url\\\": \\\"/uptime/bulk-import\\\"}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"component\\\": \\\"BulkImport\\\"}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"ef0bbcff-9535-4c0e-a5ca-96c457f89139\",\n\t\t\t\t\t\"diagramNodeId\": \"c9a012bc-d53f-494f-82f2-1ee3f40ce646\",\n\t\t\t\t\t\"simStepLabel\": \"Flow 1: CSV Import - Render UI\",\n\t\t\t\t\t\"simStepDescription\": \"The BulkImport component is rendered, displaying the file upload interface to the user.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Pages/v1/Uptime/BulkImport/index.jsx\",\n\t\t\t\t\t\t\"startLine\": \"16\",\n\t\t\t\t\t\t\"endLine\": \"50\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"BulkImport\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"props\\\": {}}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"props\\\": {}}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"bbd04d55-fc6a-4ba8-bcde-5a4dc263d6eb\",\n\t\t\t\t\t\"diagramNodeId\": \"6f1948fa-e84a-4f8e-8f3b-8f24c511b3d8\",\n\t\t\t\t\t\"simStepLabel\": \"Flow 1: CSV Import - User Selects File\",\n\t\t\t\t\t\"simStepDescription\": \"The user clicks the 'Select File' button, triggering the file input. When a file is chosen, the `handleFileChange` function validates that it's a CSV file and updates the component's state.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Pages/v1/Uptime/BulkImport/Upload.jsx\",\n\t\t\t\t\t\t\"startLine\": \"23\",\n\t\t\t\t\t\t\"endLine\": \"31\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"handleFileChange\",\n\t\t\t\t\t\t\t\"selectedFile\",\n\t\t\t\t\t\t\t\"setError\",\n\t\t\t\t\t\t\t\"setFile\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"event\\\": {\\\"target\\\": {\\\"files\\\": [{\\\"name\\\": \\\"monitors_to_import.csv\\\", \\\"type\\\": \\\"text/csv\\\", \\\"size\\\": 512}]}}}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"stateUpdate\\\": {\\\"selectedFile\\\": {\\\"name\\\": \\\"monitors_to_import.csv\\\", \\\"type\\\": \\\"text/csv\\\", \\\"size\\\": 512}}}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"610120d2-0521-4444-b245-feb97239a389\",\n\t\t\t\t\t\"diagramNodeId\": \"e03a8ce2-c2cd-4147-8bab-63d6c2cf0a48\",\n\t\t\t\t\t\"simStepLabel\": \"Flow 1: CSV Import - File State Update\",\n\t\t\t\t\t\"simStepDescription\": \"The selected file object is passed from the UploadFile component to the parent BulkImport component via the `onFileSelect` prop, updating its `selectedFile` state.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Pages/v1/Uptime/BulkImport/index.jsx\",\n\t\t\t\t\t\t\"startLine\": \"22\",\n\t\t\t\t\t\t\"endLine\": \"22\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"setSelectedFile\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"selectedFile\\\": {\\\"name\\\": \\\"monitors_to_import.csv\\\", \\\"type\\\": \\\"text/csv\\\", \\\"size\\\": 512}}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"selectedFile\\\": {\\\"name\\\": \\\"monitors_to_import.csv\\\", \\\"type\\\": \\\"text/csv\\\", \\\"size\\\": 512}}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"0139fcaa-eb46-4176-b7bd-1cb15e7f1f4c\",\n\t\t\t\t\t\"diagramNodeId\": \"dd2f9356-fad3-47d4-81d5-a5e038298e2b\",\n\t\t\t\t\t\"simStepLabel\": \"Flow 1: CSV Import - Submit Upload\",\n\t\t\t\t\t\"simStepDescription\": \"The user clicks the submit button, which executes the `handleSubmit` function. This function calls the `createBulkMonitors` function provided by the `useCreateBulkMonitors` custom hook.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Pages/v1/Uptime/BulkImport/index.jsx\",\n\t\t\t\t\t\t\"startLine\": \"32\",\n\t\t\t\t\t\t\"endLine\": \"45\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"handleSubmit\",\n\t\t\t\t\t\t\t\"createBulkMonitors\",\n\t\t\t\t\t\t\t\"selectedFile\",\n\t\t\t\t\t\t\t\"user\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"selectedFile\\\": {\\\"name\\\": \\\"monitors_to_import.csv\\\", \\\"type\\\": \\\"text/csv\\\", \\\"size\\\": 512}}\",\n\t\t\t\t\t\"outputDataExample\": \"null\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"a365d018-e80c-419c-80b3-5ffc8f14dc5c\",\n\t\t\t\t\t\"diagramNodeId\": \"b8c0292d-afbb-4648-b484-1c27be96d52f\",\n\t\t\t\t\t\"simStepLabel\": \"Flow 1: CSV Import - Prepare Form Data\",\n\t\t\t\t\t\"simStepDescription\": \"The `useCreateBulkMonitors` hook creates a `FormData` object and appends the selected CSV file to it, preparing it for the network request.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Hooks/v1/monitorHooks.js\",\n\t\t\t\t\t\t\"startLine\": \"490\",\n\t\t\t\t\t\t\"endLine\": \"493\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"createBulkMonitors\",\n\t\t\t\t\t\t\t\"formData\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"file\\\": {\\\"name\\\": \\\"monitors_to_import.csv\\\", \\\"type\\\": \\\"text/csv\\\", \\\"size\\\": 512}}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"formData\\\": {\\\"csvFile\\\": \\\"<File Object>\\\"}}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"2fc087b3-033d-4cf5-81f2-e35b99a14bce\",\n\t\t\t\t\t\"diagramNodeId\": \"5967e576-f542-4c0b-a3f4-9446ae992721\",\n\t\t\t\t\t\"simStepLabel\": \"Flow 1: CSV Import - Send API Request\",\n\t\t\t\t\t\"simStepDescription\": \"The NetworkService sends the `FormData` containing the CSV file to the backend via a POST request to the `/monitors/bulk` endpoint. The `Content-Type` is set to `multipart/form-data`.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Utils/NetworkService.js\",\n\t\t\t\t\t\t\"startLine\": \"978\",\n\t\t\t\t\t\t\"endLine\": \"983\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"createBulkMonitors\",\n\t\t\t\t\t\t\t\"this.axiosInstance.post\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"url\\\": \\\"/monitors/bulk\\\", \\\"formData\\\": {\\\"csvFile\\\": \\\"<File Object>\\\"}}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"promise\\\": \\\"<Pending Axios Promise>\\\"}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"e6dec1dc-33cb-4669-a3b0-7a3c0b233185\",\n\t\t\t\t\t\"diagramNodeId\": \"23715cce-c83a-44c0-9853-4c95b85e5ecd\",\n\t\t\t\t\t\"simStepLabel\": \"Flow 1: CSV Import - Transmit Data to Server\",\n\t\t\t\t\t\"simStepDescription\": \"The HTTP POST request containing the multipart form data is transmitted from the client to the server's API endpoint.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/routes/v1/monitorRoute.js\",\n\t\t\t\t\t\t\"startLine\": \"46\",\n\t\t\t\t\t\t\"endLine\": \"46\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"this.router.post\",\n\t\t\t\t\t\t\t\"upload.single\",\n\t\t\t\t\t\t\t\"this.monitorController.createBulkMonitors\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"request\\\": {\\\"method\\\": \\\"POST\\\", \\\"endpoint\\\": \\\"/api/v1/monitors/bulk\\\", \\\"headers\\\": {\\\"Content-Type\\\": \\\"multipart/form-data\\\"}, \\\"body\\\": \\\"---boundary\\\\nContent-Disposition: form-data; name=\\\\\\\"csvFile\\\\\\\"; filename=\\\\\\\"monitors.csv\\\\\\\"\\\\n...\\\"}}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"request\\\": {\\\"method\\\": \\\"POST\\\", \\\"endpoint\\\": \\\"/api/v1/monitors/bulk\\\", \\\"headers\\\": {\\\"Content-Type\\\": \\\"multipart/form-data\\\"}, \\\"body\\\": \\\"---boundary\\\\nContent-Disposition: form-data; name=\\\\\\\"csvFile\\\\\\\"; filename=\\\\\\\"monitors.csv\\\\\\\"\\\\n...\\\"}}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"07bf3d83-047d-4e51-9f96-8c9c64848500\",\n\t\t\t\t\t\"diagramNodeId\": \"c1ac3c26-996a-43ef-9c34-4c2776188784\",\n\t\t\t\t\t\"simStepLabel\": \"Flow 1: CSV Import - Server Receives Request\",\n\t\t\t\t\t\"simStepDescription\": \"The server's monitor route receives the request. The `multer` middleware processes the file upload, making the file available in `req.file`. The request is then passed to the `createBulkMonitors` controller method.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/routes/v1/monitorRoute.js\",\n\t\t\t\t\t\t\"startLine\": \"46\",\n\t\t\t\t\t\t\"endLine\": \"46\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"this.router.post\",\n\t\t\t\t\t\t\t\"upload.single\",\n\t\t\t\t\t\t\t\"this.monitorController.createBulkMonitors\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"request\\\": {\\\"endpoint\\\": \\\"/monitors/bulk\\\"}}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"req.file\\\": {\\\"fieldname\\\": \\\"csvFile\\\", \\\"originalname\\\": \\\"monitors.csv\\\", \\\"buffer\\\": \\\"<Buffer ...>\\\"}}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"c53d3f62-73fe-4fad-9835-ef2c8cf52894\",\n\t\t\t\t\t\"diagramNodeId\": \"20d0e690-a569-4c6f-8238-916cac920553\",\n\t\t\t\t\t\"simStepLabel\": \"Flow 1: CSV Import - Route to Controller\",\n\t\t\t\t\t\"simStepDescription\": \"The request object, now populated with the uploaded file buffer by the middleware, is passed from the routing layer to the monitor controller for business logic processing.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/controllers/v1/monitorController.js\",\n\t\t\t\t\t\t\"startLine\": \"206\",\n\t\t\t\t\t\t\"endLine\": \"212\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"createBulkMonitors\",\n\t\t\t\t\t\t\t\"req.file\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"req\\\": {\\\"file\\\": {\\\"buffer\\\": \\\"<Buffer 6e 61 ...>\\\"}, \\\"user\\\": {\\\"_id\\\": \\\"user_123\\\", \\\"teamId\\\": \\\"team_abc\\\"}}}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"req\\\": {\\\"file\\\": {\\\"buffer\\\": \\\"<Buffer 6e 61 ...>\\\"}, \\\"user\\\": {\\\"_id\\\": \\\"user_123\\\", \\\"teamId\\\": \\\"team_abc\\\"}}}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"a3799570-64bf-481e-9ffe-31dbad8a36e4\",\n\t\t\t\t\t\"diagramNodeId\": \"0e520a6d-34bf-467b-a894-e73979364478\",\n\t\t\t\t\t\"simStepLabel\": \"Flow 1: CSV Import - Controller Processes Data\",\n\t\t\t\t\t\"simStepDescription\": \"The controller validates the presence of the file and extracts the file data (buffer), `userId`, and `teamId`. It then calls the `monitorService.createBulkMonitors` method to handle the core logic.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/controllers/v1/monitorController.js\",\n\t\t\t\t\t\t\"startLine\": \"228\",\n\t\t\t\t\t\t\"endLine\": \"232\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"fileData\",\n\t\t\t\t\t\t\t\"monitors\",\n\t\t\t\t\t\t\t\"this.monitorService.createBulkMonitors\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"file\\\": {\\\"buffer\\\": \\\"<Buffer 6e 61 ...>\\\"}, \\\"user\\\": {\\\"_id\\\": \\\"user_123\\\", \\\"teamId\\\": \\\"team_abc\\\"}}\",\n\t\t\t\t\t\"outputDataExample\": \"null\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"6038422c-ab83-4fc6-a58b-c75734276118\",\n\t\t\t\t\t\"diagramNodeId\": \"7292bf6e-431d-4a9d-94ce-2bcfabcaa79d\",\n\t\t\t\t\t\"simStepLabel\": \"Flow 1: CSV Import - Controller to Service\",\n\t\t\t\t\t\"simStepDescription\": \"The file buffer and user/team identifiers are passed from the controller to the monitor service layer.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/service/v1/business/monitorService.js\",\n\t\t\t\t\t\t\"startLine\": \"84\",\n\t\t\t\t\t\t\"endLine\": \"84\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"createBulkMonitors\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"fileData\\\": \\\"<Buffer 6e 61 ...>\\\", \\\"userId\\\": \\\"user_123\\\", \\\"teamId\\\": \\\"team_abc\\\"}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"fileData\\\": \\\"<Buffer 6e 61 ...>\\\", \\\"userId\\\": \\\"user_123\\\", \\\"teamId\\\": \\\"team_abc\\\"}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"2c7c3082-e4b6-4525-860f-2ffcd9e86db1\",\n\t\t\t\t\t\"diagramNodeId\": \"6139e487-1dd5-405a-ba7d-ededec4b282e\",\n\t\t\t\t\t\"simStepLabel\": \"Flow 1: CSV Import - Service Parses CSV\",\n\t\t\t\t\t\"simStepDescription\": \"The monitor service uses the `papaparse` library to parse the CSV file buffer into a JSON object array. In the `complete` callback, it enriches each record with `userId` and `teamId`.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/service/v1/business/monitorService.js\",\n\t\t\t\t\t\t\"startLine\": \"85\",\n\t\t\t\t\t\t\"endLine\": \"134\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"papaparse.parse\",\n\t\t\t\t\t\t\t\"enrichedData\",\n\t\t\t\t\t\t\t\"this.db.monitorModule.createBulkMonitors\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"fileData\\\": \\\"name,type,url\\\\nGoogle,http,https://google.com\\\\n\\\"}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"enrichedData\\\": [{\\\"name\\\": \\\"Google\\\", \\\"type\\\": \\\"http\\\", \\\"url\\\": \\\"https://google.com\\\", \\\"userId\\\": \\\"user_123\\\", \\\"teamId\\\": \\\"team_abc\\\"}]}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"0115fb69-4959-4b32-bd90-1dcd3c2231f6\",\n\t\t\t\t\t\"diagramNodeId\": \"b55a0dc6-f596-4e5f-9265-63588b46b519\",\n\t\t\t\t\t\"simStepLabel\": \"Flow 1: CSV Import - Service to Database Module\",\n\t\t\t\t\t\"simStepDescription\": \"The array of parsed and enriched monitor objects is passed to the database module for persistence.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/service/v1/business/monitorService.js\",\n\t\t\t\t\t\t\"startLine\": \"126\",\n\t\t\t\t\t\t\"endLine\": \"126\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"this.db.monitorModule.createBulkMonitors\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"enrichedData\\\": [{\\\"name\\\": \\\"Google\\\", \\\"type\\\": \\\"http\\\", \\\"url\\\": \\\"https://google.com\\\", \\\"userId\\\": \\\"user_123\\\", \\\"teamId\\\": \\\"team_abc\\\"}]}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"enrichedData\\\": [{\\\"name\\\": \\\"Google\\\", \\\"type\\\": \\\"http\\\", \\\"url\\\": \\\"https://google.com\\\", \\\"userId\\\": \\\"user_123\\\", \\\"teamId\\\": \\\"team_abc\\\"}]}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"70f18c21-2918-402e-9c35-1bdce8bc82d4\",\n\t\t\t\t\t\"diagramNodeId\": \"d9d519af-5c4d-4494-929e-a869581c1dc4\",\n\t\t\t\t\t\"simStepLabel\": \"Flow 1: CSV Import - Database Bulk Save\",\n\t\t\t\t\t\"simStepDescription\": \"The `monitorModule` uses `Monitor.bulkSave` to efficiently insert all the new monitor documents into the MongoDB database in a single operation.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/db/v1/modules/monitorModule.js\",\n\t\t\t\t\t\t\"startLine\": \"465\",\n\t\t\t\t\t\t\"endLine\": \"468\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"createBulkMonitors\",\n\t\t\t\t\t\t\t\"this.Monitor.bulkSave\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"[{\\\"name\\\": \\\"Google\\\", \\\"type\\\": \\\"http\\\", \\\"url\\\": \\\"https://google.com\\\"}]\",\n\t\t\t\t\t\"outputDataExample\": \"[{\\\"_id\\\": \\\"monitor_xyz\\\", \\\"name\\\": \\\"Google\\\"}]\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"2ee7bd94-d131-4dd8-bdf8-68433d00472d\",\n\t\t\t\t\t\"diagramNodeId\": \"f27c60ef-fb40-43e2-9750-c2617bdeaf43\",\n\t\t\t\t\t\"simStepLabel\": \"Flow 1: CSV Import - Database to Service\",\n\t\t\t\t\t\"simStepDescription\": \"The newly created monitor documents, now with database-generated `_id`s, are returned from the database module back to the service layer.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/db/v1/modules/monitorModule.js\",\n\t\t\t\t\t\t\"startLine\": \"467\",\n\t\t\t\t\t\t\"endLine\": \"467\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"monitors\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"[{\\\"_id\\\": \\\"monitor_xyz\\\", \\\"name\\\": \\\"Google\\\"}]\",\n\t\t\t\t\t\"outputDataExample\": \"[{\\\"_id\\\": \\\"monitor_xyz\\\", \\\"name\\\": \\\"Google\\\"}]\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"66fbf913-e662-4bd9-ada6-077be9e37f07\",\n\t\t\t\t\t\"diagramNodeId\": \"1e1d975f-7f0f-4132-bd71-2563b35e99b3\",\n\t\t\t\t\t\"simStepLabel\": \"Flow 1: CSV Import - Enqueue Monitor Jobs\",\n\t\t\t\t\t\"simStepDescription\": \"After the monitors are saved, the service iterates through them and adds a new job to the `jobQueue` for each one, scheduling them for their first check. It then resolves the promise, returning the data up the call stack.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/service/v1/business/monitorService.js\",\n\t\t\t\t\t\t\"startLine\": \"128\",\n\t\t\t\t\t\t\"endLine\": \"132\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"Promise.all\",\n\t\t\t\t\t\t\t\"this.jobQueue.addJob\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"[{\\\"_id\\\": \\\"monitor_xyz\\\", \\\"name\\\": \\\"Google\\\"}]\",\n\t\t\t\t\t\"outputDataExample\": \"[{\\\"_id\\\": \\\"monitor_xyz\\\", \\\"name\\\": \\\"Google\\\"}]\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"94d5772d-3f46-4d43-b764-3493db5c4971\",\n\t\t\t\t\t\"diagramNodeId\": \"c449f81a-d6af-4f7a-b2d8-050a9a9ee0f9\",\n\t\t\t\t\t\"simStepLabel\": \"Flow 1: CSV Import - Service to Controller\",\n\t\t\t\t\t\"simStepDescription\": \"The final list of created monitors is passed back to the controller.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/controllers/v1/monitorController.js\",\n\t\t\t\t\t\t\"startLine\": \"230\",\n\t\t\t\t\t\t\"endLine\": \"230\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"monitors\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"[{\\\"_id\\\": \\\"monitor_xyz\\\", \\\"name\\\": \\\"Google\\\"}]\",\n\t\t\t\t\t\"outputDataExample\": \"[{\\\"_id\\\": \\\"monitor_xyz\\\", \\\"name\\\": \\\"Google\\\"}]\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"f5377571-156f-4c5c-8bab-b6dacdf0fea6\",\n\t\t\t\t\t\"diagramNodeId\": \"72b55fa1-d944-4e46-ac98-f6a6cb201afa\",\n\t\t\t\t\t\"simStepLabel\": \"Flow 1: CSV Import - Send Success Response\",\n\t\t\t\t\t\"simStepDescription\": \"The controller constructs a successful JSON response containing a message and the data for the newly created monitors, and sends it back to the client.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/controllers/v1/monitorController.js\",\n\t\t\t\t\t\t\"startLine\": \"232\",\n\t\t\t\t\t\t\"endLine\": \"235\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"res.success\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"[{\\\"_id\\\": \\\"monitor_xyz\\\", \\\"name\\\": \\\"Google\\\"}]\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"msg\\\": \\\"Monitors created successfully.\\\", \\\"data\\\": [{\\\"_id\\\": \\\"monitor_xyz\\\"}]}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"c60a3adb-dd81-41b0-95e4-a0a6d23f9dd0\",\n\t\t\t\t\t\"diagramNodeId\": \"926a330c-a9c5-4983-a4b5-70359813e49a\",\n\t\t\t\t\t\"simStepLabel\": \"Flow 1: CSV Import - Transmit Success to Client\",\n\t\t\t\t\t\"simStepDescription\": \"The server sends the successful HTTP response back to the client's browser.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Hooks/v1/monitorHooks.js\",\n\t\t\t\t\t\t\"startLine\": \"494\",\n\t\t\t\t\t\t\"endLine\": \"494\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"response\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"status\\\": 200, \\\"body\\\": {\\\"msg\\\": \\\"Monitors created successfully!\\\", \\\"data\\\": [{\\\"_id\\\": \\\"monitor_xyz\\\"}]}}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"status\\\": 200, \\\"body\\\": {\\\"msg\\\": \\\"Monitors created successfully!\\\", \\\"data\\\": [{\\\"_id\\\": \\\"monitor_xyz\\\"}]}}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"72b3f16d-290d-4a61-8748-2ad90d63ec68\",\n\t\t\t\t\t\"diagramNodeId\": \"ae3b7e23-ed64-40aa-9760-389f0a869f8d\",\n\t\t\t\t\t\"simStepLabel\": \"Flow 1: CSV Import - Client Handles Success\",\n\t\t\t\t\t\"simStepDescription\": \"The client-side promise resolves. The `handleSubmit` function in the `BulkImport` component receives the success status, displays a success toast message, and navigates the user to the main uptime monitoring page.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Pages/v1/Uptime/BulkImport/index.jsx\",\n\t\t\t\t\t\t\"startLine\": \"37\",\n\t\t\t\t\t\t\"endLine\": \"41\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"createToast\",\n\t\t\t\t\t\t\t\"navigate\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"success\\\": true, \\\"data\\\": [{\\\"_id\\\": \\\"monitor_xyz\\\"}]}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"navigation\\\": \\\"/uptime\\\"}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"63d8d81f-f436-4594-a6eb-8c0fd2110bc1\",\n\t\t\t\t\t\"diagramNodeId\": \"26d76516-fd7e-4ae8-956a-d077de4257fa\",\n\t\t\t\t\t\"simStepLabel\": \"Flow 2: CSV Export - Initiate Export\",\n\t\t\t\t\t\"simStepDescription\": \"An admin user clicks an 'Export to CSV' button in the UI. This action triggers a call to the `/monitors/export` API endpoint to begin the export process.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/routes/v1/monitorRoute.js\",\n\t\t\t\t\t\t\"startLine\": \"45\",\n\t\t\t\t\t\t\"endLine\": \"45\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"this.router.get\",\n\t\t\t\t\t\t\t\"this.monitorController.exportMonitorsToCSV\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"request\\\": {\\\"method\\\": \\\"GET\\\", \\\"endpoint\\\": \\\"/api/v1/monitors/export\\\"}}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"53cebb8e-cf45-49eb-a7d3-98fd87af21b4\",\n\t\t\t\t\t\"diagramNodeId\": \"febea87e-5033-479c-ba7a-eb35d98db899\",\n\t\t\t\t\t\"simStepLabel\": \"Flow 2: CSV Export - Transmit Request to Server\",\n\t\t\t\t\t\"simStepDescription\": \"An HTTP GET request is sent from the client to the server to fetch the monitor data as a CSV file.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/routes/v1/monitorRoute.js\",\n\t\t\t\t\t\t\"startLine\": \"45\",\n\t\t\t\t\t\t\"endLine\": \"45\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"this.router.get\",\n\t\t\t\t\t\t\t\"this.monitorController.exportMonitorsToCSV\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"request\\\": {\\\"method\\\": \\\"GET\\\", \\\"endpoint\\\": \\\"/api/v1/monitors/export\\\"}}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"request\\\": {\\\"method\\\": \\\"GET\\\", \\\"endpoint\\\": \\\"/api/v1/monitors/export\\\"}}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"d9db3f40-8add-4551-9323-274348b9800f\",\n\t\t\t\t\t\"diagramNodeId\": \"a3106388-6a3d-4b68-a3fc-3761a0d54f98\",\n\t\t\t\t\t\"simStepLabel\": \"Flow 2: CSV Export - Controller Handles Request\",\n\t\t\t\t\t\"simStepDescription\": \"The `exportMonitorsToCSV` method in the monitor controller is invoked. It retrieves the `teamId` from the authenticated user's session and calls the monitor service to perform the export.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/controllers/v1/monitorController.js\",\n\t\t\t\t\t\t\"startLine\": \"427\",\n\t\t\t\t\t\t\"endLine\": \"434\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"exportMonitorsToCSV\",\n\t\t\t\t\t\t\t\"teamId\",\n\t\t\t\t\t\t\t\"this.monitorService.exportMonitorsToCSV\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"req\\\": {\\\"user\\\": {\\\"teamId\\\": \\\"team_abc\\\"}}}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"teamId\\\": \\\"team_abc\\\"}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"74e95fb5-863c-4137-a41b-d7a32efa04a5\",\n\t\t\t\t\t\"diagramNodeId\": \"3e0f0966-5c2f-41af-9bcc-e8f615e03a00\",\n\t\t\t\t\t\"simStepLabel\": \"Flow 2: CSV Export - Controller to Service\",\n\t\t\t\t\t\"simStepDescription\": \"The `teamId` is passed from the controller to the monitor service to ensure only monitors belonging to the correct team are exported.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/service/v1/business/monitorService.js\",\n\t\t\t\t\t\t\"startLine\": \"245\",\n\t\t\t\t\t\t\"endLine\": \"245\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"exportMonitorsToCSV\",\n\t\t\t\t\t\t\t\"teamId\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"teamId\\\": \\\"team_abc\\\"}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"teamId\\\": \\\"team_abc\\\"}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"85cd1d5d-7ffb-49c5-aacb-907048003fc5\",\n\t\t\t\t\t\"diagramNodeId\": \"ab9cb862-0ac7-45a3-9888-f64e87bdda54\",\n\t\t\t\t\t\"simStepLabel\": \"Flow 2: CSV Export - Generate CSV\",\n\t\t\t\t\t\"simStepDescription\": \"The monitor service fetches all monitors for the given `teamId` from the database. It then maps the data into the required format and uses `papaparse` to convert the JSON array into a CSV-formatted string.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/service/v1/business/monitorService.js\",\n\t\t\t\t\t\t\"startLine\": \"245\",\n\t\t\t\t\t\t\"endLine\": \"266\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"getMonitorsByTeamId\",\n\t\t\t\t\t\t\t\"csvData\",\n\t\t\t\t\t\t\t\"this.papaparse.unparse\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"teamId\\\": \\\"team_abc\\\"}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"csv\\\": \\\"name,description,type,url,interval,port,ignoreTlsErrors,isActive\\\\nMy Website,,http,https://example.com,60,,false,true\\\"}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"4deb5e47-2ac4-4638-9ee6-48295d027bcd\",\n\t\t\t\t\t\"diagramNodeId\": \"ad300b1c-6748-40f9-a7c9-5895e0915991\",\n\t\t\t\t\t\"simStepLabel\": \"Flow 2: CSV Export - Service to Controller\",\n\t\t\t\t\t\"simStepDescription\": \"The generated CSV string is returned from the service layer to the controller.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/controllers/v1/monitorController.js\",\n\t\t\t\t\t\t\"startLine\": \"432\",\n\t\t\t\t\t\t\"endLine\": \"432\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"csv\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"csv\\\": \\\"name,description,type,url,...\\\\nMy Website,,http,https://example.com,...\\\"}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"csv\\\": \\\"name,description,type,url,...\\\\nMy Website,,http,https://example.com,...\\\"}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"256095b8-5e3a-4c20-abd9-be9e6a9d0bad\",\n\t\t\t\t\t\"diagramNodeId\": \"f151f89d-6399-48f0-aecd-5eb1572b48cc\",\n\t\t\t\t\t\"simStepLabel\": \"Flow 2: CSV Export - Send File Response\",\n\t\t\t\t\t\"simStepDescription\": \"The controller receives the CSV string and uses the `res.file` method to send it back to the client as a file. It sets the `Content-Type` to `text/csv` and `Content-Disposition` to trigger a download with the filename `monitors.csv`.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/controllers/v1/monitorController.js\",\n\t\t\t\t\t\t\"startLine\": \"434\",\n\t\t\t\t\t\t\"endLine\": \"440\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"res.file\",\n\t\t\t\t\t\t\t\"csv\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"csv\\\": \\\"name,description,type,url,...\\\\nMy Website,,http,https://example.com,...\\\"}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"responseHeaders\\\": {\\\"Content-Type\\\": \\\"text/csv\\\", \\\"Content-Disposition\\\": \\\"attachment; filename=\\\\\\\"monitors.csv\\\\\\\"\\\"}}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"605f4cbd-1f7f-4e89-b028-f18737ac7fb1\",\n\t\t\t\t\t\"diagramNodeId\": \"3dfb432a-2ce4-4f92-98ce-5d114b5f7f03\",\n\t\t\t\t\t\"simStepLabel\": \"Flow 2: CSV Export - Transmit File to Client\",\n\t\t\t\t\t\"simStepDescription\": \"The server sends the HTTP response, which contains the CSV data and headers, to the client's browser.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/controllers/v1/monitorController.js\",\n\t\t\t\t\t\t\"startLine\": \"434\",\n\t\t\t\t\t\t\"endLine\": \"440\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"res.file\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"httpResponse\\\": {\\\"headers\\\": {\\\"Content-Disposition\\\": \\\"attachment; filename=\\\\\\\"monitors.csv\\\\\\\"\\\"}, \\\"body\\\": \\\"name,description,...\\\\n...\\\"}}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"httpResponse\\\": {\\\"headers\\\": {\\\"Content-Disposition\\\": \\\"attachment; filename=\\\\\\\"monitors.csv\\\\\\\"\\\"}, \\\"body\\\": \\\"name,description,...\\\\n...\\\"}}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"60abdb27-4078-4678-a010-0f6938d4be48\",\n\t\t\t\t\t\"diagramNodeId\": \"d8877474-7203-484f-bd47-fc69e3c7c482\",\n\t\t\t\t\t\"simStepLabel\": \"Flow 2: CSV Export - Browser Prompts Download\",\n\t\t\t\t\t\"simStepDescription\": \"The browser receives the server's response. The `Content-Disposition` header instructs the browser to prompt the user to save the received data as a file named `monitors.csv`, completing the export process.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/controllers/v1/monitorController.js\",\n\t\t\t\t\t\t\"startLine\": \"434\",\n\t\t\t\t\t\t\"endLine\": \"440\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"res.file\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"httpResponse\\\": {\\\"headers\\\": {\\\"Content-Disposition\\\": \\\"attachment; filename=\\\\\\\"monitors.csv\\\\\\\"\\\"}}}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"userAction\\\": \\\"File Save Dialog\\\"}\"\n\t\t\t\t}\n\t\t\t],\n\t\t\t\"description\": \"<ul><li>Provides efficiency tools for managing a large number of monitors</li><li>- Users can import multiple monitors at once by uploading a CSV file, saving significant time during initial setup</li><li>- A template CSV is provided to guide the user on the required format and available fields</li><li>- All existing monitors can be exported to a CSV file, useful for backups or migrations</li><li>- Superadmins have the ability to delete all monitors for a team in a single action</li></ul>\",\n\t\t\t\"simulationNodesAndEdges\": {\n\t\t\t\t\"c4caeba8-ed9a-4cbc-9888-38cc8ca55362\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"a29da01e-8c5a-4e6d-8d3c-e49af528e4fa\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"6f1948fa-e84a-4f8e-8f3b-8f24c511b3d8\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"bbd04d55-fc6a-4ba8-bcde-5a4dc263d6eb\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"dd2f9356-fad3-47d4-81d5-a5e038298e2b\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"0139fcaa-eb46-4176-b7bd-1cb15e7f1f4c\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"5967e576-f542-4c0b-a3f4-9446ae992721\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"2fc087b3-033d-4cf5-81f2-e35b99a14bce\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"c1ac3c26-996a-43ef-9c34-4c2776188784\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"07bf3d83-047d-4e51-9f96-8c9c64848500\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"0e520a6d-34bf-467b-a894-e73979364478\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"a3799570-64bf-481e-9ffe-31dbad8a36e4\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"6139e487-1dd5-405a-ba7d-ededec4b282e\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"2c7c3082-e4b6-4525-860f-2ffcd9e86db1\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"d9d519af-5c4d-4494-929e-a869581c1dc4\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"70f18c21-2918-402e-9c35-1bdce8bc82d4\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"1e1d975f-7f0f-4132-bd71-2563b35e99b3\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"66fbf913-e662-4bd9-ada6-077be9e37f07\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"72b55fa1-d944-4e46-ac98-f6a6cb201afa\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"f5377571-156f-4c5c-8bab-b6dacdf0fea6\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"ae3b7e23-ed64-40aa-9760-389f0a869f8d\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"72b3f16d-290d-4a61-8748-2ad90d63ec68\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"26d76516-fd7e-4ae8-956a-d077de4257fa\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"63d8d81f-f436-4594-a6eb-8c0fd2110bc1\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"a3106388-6a3d-4b68-a3fc-3761a0d54f98\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"d9db3f40-8add-4551-9323-274348b9800f\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"ab9cb862-0ac7-45a3-9888-f64e87bdda54\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"85cd1d5d-7ffb-49c5-aacb-907048003fc5\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"f151f89d-6399-48f0-aecd-5eb1572b48cc\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"256095b8-5e3a-4c20-abd9-be9e6a9d0bad\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"d8877474-7203-484f-bd47-fc69e3c7c482\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"60abdb27-4078-4678-a010-0f6938d4be48\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"c9a012bc-d53f-494f-82f2-1ee3f40ce646\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"ef0bbcff-9535-4c0e-a5ca-96c457f89139\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"e03a8ce2-c2cd-4147-8bab-63d6c2cf0a48\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"610120d2-0521-4444-b245-feb97239a389\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"b8c0292d-afbb-4648-b484-1c27be96d52f\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"a365d018-e80c-419c-80b3-5ffc8f14dc5c\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"23715cce-c83a-44c0-9853-4c95b85e5ecd\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"e6dec1dc-33cb-4669-a3b0-7a3c0b233185\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"20d0e690-a569-4c6f-8238-916cac920553\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"c53d3f62-73fe-4fad-9835-ef2c8cf52894\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"7292bf6e-431d-4a9d-94ce-2bcfabcaa79d\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"6038422c-ab83-4fc6-a58b-c75734276118\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"b55a0dc6-f596-4e5f-9265-63588b46b519\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"0115fb69-4959-4b32-bd90-1dcd3c2231f6\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"f27c60ef-fb40-43e2-9750-c2617bdeaf43\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"2ee7bd94-d131-4dd8-bdf8-68433d00472d\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"c449f81a-d6af-4f7a-b2d8-050a9a9ee0f9\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"94d5772d-3f46-4d43-b764-3493db5c4971\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"926a330c-a9c5-4983-a4b5-70359813e49a\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"c60a3adb-dd81-41b0-95e4-a0a6d23f9dd0\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"febea87e-5033-479c-ba7a-eb35d98db899\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"53cebb8e-cf45-49eb-a7d3-98fd87af21b4\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"3e0f0966-5c2f-41af-9bcc-e8f615e03a00\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"74e95fb5-863c-4137-a41b-d7a32efa04a5\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"ad300b1c-6748-40f9-a7c9-5895e0915991\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"4deb5e47-2ac4-4638-9ee6-48295d027bcd\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"3dfb432a-2ce4-4f92-98ce-5d114b5f7f03\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"605f4cbd-1f7f-4e89-b028-f18737ac7fb1\"\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"isAIGenerated\": true,\n\t\t\t\"keywords\": \"bulkImport, createBulkMonitors, exportMonitorsToCSV\",\n\t\t\t\"generationPrompt\": \"Bulk Monitor Management\",\n\t\t\t\"generationKeywords\": \"bulkImport, createBulkMonitors, exportMonitorsToCSV\"\n\t\t},\n\t\t\"System Administration and Configuration\": {\n\t\t\t\"name\": \"System Administration and Configuration\",\n\t\t\t\"simSteps\": [\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"64e9f1af-13b7-4361-a2a9-3f45760e316d\",\n\t\t\t\t\t\"diagramNodeId\": \"97908daf-d071-4df5-8366-1f5f4d8d534a\",\n\t\t\t\t\t\"simStepLabel\": \"Flow 1: Render Settings Page\",\n\t\t\t\t\t\"simStepDescription\": \"The user navigates to the settings page. The main `Settings` component fetches existing settings using the `useFetchSettings` hook and renders various sub-components for different configuration areas like TimeZone, UI, PageSpeed, Email, etc.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Pages/v1/Settings/index.jsx\",\n\t\t\t\t\t\t\"startLine\": \"25\",\n\t\t\t\t\t\t\"endLine\": \"52\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"useFetchSettings\",\n\t\t\t\t\t\t\t\"settingsData\",\n\t\t\t\t\t\t\t\"setSettingsData\",\n\t\t\t\t\t\t\t\"isApiKeySet\",\n\t\t\t\t\t\t\t\"isEmailPasswordSet\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"settingsData\\\": {}, \\\"errors\\\": {}, \\\"isApiKeySet\\\": false, \\\"isEmailPasswordSet\\\": false}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"dca4a33c-b666-47b8-896b-370ed9d6f9c5\",\n\t\t\t\t\t\"diagramNodeId\": \"f6d80f09-ae83-4c95-aba0-4efffeda38e0\",\n\t\t\t\t\t\"simStepLabel\": \"API Call: Fetch Application Settings\",\n\t\t\t\t\t\"simStepDescription\": \"The `useFetchSettings` hook triggers a GET request to the `/api/v1/settings` endpoint to retrieve the current application configuration.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Utils/NetworkService.js\",\n\t\t\t\t\t\t\"startLine\": \"692\",\n\t\t\t\t\t\t\"endLine\": \"698\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"getAppSettings\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"method\\\": \\\"GET\\\", \\\"url\\\": \\\"/api/v1/settings\\\"}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"method\\\": \\\"GET\\\", \\\"url\\\": \\\"/api/v1/settings\\\"}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"441b0c45-5f27-478d-8ca8-58fbd5f460ea\",\n\t\t\t\t\t\"diagramNodeId\": \"83596bd1-dfca-4196-b52e-955f6824fafb\",\n\t\t\t\t\t\"simStepLabel\": \"Backend: Retrieve Settings from Database\",\n\t\t\t\t\t\"simStepDescription\": \"The `settingsController` handles the GET request. It calls the `settingsService` to fetch settings from the database. Sensitive data like passwords is sanitized, and flags like `emailPasswordSet` are added before sending the data to the client.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/controllers/v1/settingsController.js\",\n\t\t\t\t\t\t\"startLine\": \"40\",\n\t\t\t\t\t\t\"endLine\": \"49\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"getAppSettings\",\n\t\t\t\t\t\t\t\"settingsService.getDBSettings\",\n\t\t\t\t\t\t\t\"buildAppSettings\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"request\\\": \\\"GET /api/v1/settings\\\"}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"msg\\\": \\\"Got app settings successfully\\\", \\\"data\\\": {\\\"emailPasswordSet\\\": false, \\\"pagespeedKeySet\\\": false, \\\"settings\\\": {\\\"checkTTL\\\": 7, \\\"timezone\\\": \\\"America/Toronto\\\"}}}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"aacc9302-6ca8-45c6-acb8-956d8d0242c2\",\n\t\t\t\t\t\"diagramNodeId\": \"195ad532-9858-493e-876a-6ec457811d1d\",\n\t\t\t\t\t\"simStepLabel\": \"API Response: Send Settings to Client\",\n\t\t\t\t\t\"simStepDescription\": \"The backend responds to the GET request with a JSON object containing the application settings, which will be used to populate the UI.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/controllers/v1/settingsController.js\",\n\t\t\t\t\t\t\"startLine\": \"45\",\n\t\t\t\t\t\t\"endLine\": \"48\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"res.success\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"msg\\\": \\\"Got app settings successfully\\\", \\\"data\\\": {\\\"emailPasswordSet\\\": false, \\\"pagespeedKeySet\\\": false, \\\"settings\\\": {\\\"checkTTL\\\": 7, \\\"timezone\\\": \\\"America/Toronto\\\", \\\"systemEmailHost\\\": \\\"\\\", \\\"systemEmailPort\\\": \\\"\\\", \\\"systemEmailSecure\\\": false, \\\"systemEmailUser\\\": \\\"\\\", \\\"systemEmailAddress\\\": \\\"\\\"}}}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"msg\\\": \\\"Got app settings successfully\\\", \\\"data\\\": {\\\"emailPasswordSet\\\": false, \\\"pagespeedKeySet\\\": false, \\\"settings\\\": {\\\"checkTTL\\\": 7, \\\"timezone\\\": \\\"America/Toronto\\\", \\\"systemEmailHost\\\": \\\"\\\", \\\"systemEmailPort\\\": \\\"\\\", \\\"systemEmailSecure\\\": false, \\\"systemEmailUser\\\": \\\"\\\", \\\"systemEmailAddress\\\": \\\"\\\"}}}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"ae5c5146-4dbb-4612-9d23-086e57f72474\",\n\t\t\t\t\t\"diagramNodeId\": \"09cb194a-0ea4-46e2-b32b-36b62fa87f40\",\n\t\t\t\t\t\"simStepLabel\": \"User Interaction: Modify Email Settings\",\n\t\t\t\t\t\"simStepDescription\": \"The user interacts with the `SettingsEmail` component, filling in SMTP server details. The component's state is updated via the `handleChange` function passed down from the parent `Settings` component, which prepares the new configuration data.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Pages/v1/Settings/SettingsEmail.jsx\",\n\t\t\t\t\t\t\"startLine\": \"119\",\n\t\t\t\t\t\t\"endLine\": \"167\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"handleChange\",\n\t\t\t\t\t\t\t\"handlePasswordChange\",\n\t\t\t\t\t\t\t\"TextInput\",\n\t\t\t\t\t\t\t\"systemEmailHost\",\n\t\t\t\t\t\t\t\"systemEmailPort\",\n\t\t\t\t\t\t\t\"systemEmailUser\",\n\t\t\t\t\t\t\t\"systemEmailPassword\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"settingsData\\\": {\\\"settings\\\": {\\\"systemEmailHost\\\": \\\"\\\"}}}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"settingsData\\\": {\\\"settings\\\": {\\\"systemEmailHost\\\": \\\"smtp.gmail.com\\\", \\\"systemEmailPort\\\": \\\"465\\\", \\\"systemEmailUser\\\": \\\"user@gmail.com\\\", \\\"systemEmailAddress\\\": \\\"user@gmail.com\\\", \\\"systemEmailPassword\\\": \\\"app-password-123\\\"}}}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"e7e82a97-1409-4bc5-ae27-b4ff5ba746df\",\n\t\t\t\t\t\"diagramNodeId\": \"8c107d79-f796-49eb-ab88-f553dd6f9d95\",\n\t\t\t\t\t\"simStepLabel\": \"User Action: Save Settings\",\n\t\t\t\t\t\"simStepDescription\": \"The user clicks the 'Save' button. This action triggers the `handleSave` function, which validates the new settings and prepares to send them to the backend.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Pages/v1/Settings/index.jsx\",\n\t\t\t\t\t\t\"startLine\": \"258\",\n\t\t\t\t\t\t\"endLine\": \"261\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"handleSave\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"settingsData\\\": {\\\"settings\\\": {\\\"systemEmailHost\\\": \\\"smtp.gmail.com\\\", \\\"systemEmailPort\\\": \\\"465\\\", \\\"systemEmailUser\\\": \\\"user@gmail.com\\\", \\\"systemEmailAddress\\\": \\\"user@gmail.com\\\", \\\"systemEmailPassword\\\": \\\"app-password-123\\\"}}}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"settingsData\\\": {\\\"settings\\\": {\\\"systemEmailHost\\\": \\\"smtp.gmail.com\\\", \\\"systemEmailPort\\\": \\\"465\\\", \\\"systemEmailUser\\\": \\\"user@gmail.com\\\", \\\"systemEmailAddress\\\": \\\"user@gmail.com\\\", \\\"systemEmailPassword\\\": \\\"app-password-123\\\"}}}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"d7098072-9a83-4369-8176-9646ba34e186\",\n\t\t\t\t\t\"diagramNodeId\": \"1b2cf182-9ee3-4218-a7ec-b74e427ccddf\",\n\t\t\t\t\t\"simStepLabel\": \"API Call: Update Application Settings\",\n\t\t\t\t\t\"simStepDescription\": \"The `handleSave` function calls `saveSettings` from the `useSaveSettings` hook. This triggers a PUT request to `/api/v1/settings` with the new configuration in the request body.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Hooks/v1/settingsHooks.js\",\n\t\t\t\t\t\t\"startLine\": \"41\",\n\t\t\t\t\t\t\"endLine\": \"67\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"saveSettings\",\n\t\t\t\t\t\t\t\"networkService.updateAppSettings\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"settings\\\": {\\\"systemEmailHost\\\": \\\"smtp.gmail.com\\\", \\\"systemEmailPort\\\": \\\"465\\\", \\\"systemEmailUser\\\": \\\"user@gmail.com\\\", \\\"systemEmailAddress\\\": \\\"user@gmail.com\\\", \\\"systemEmailPassword\\\": \\\"app-password-123\\\"}}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"settings\\\": {\\\"systemEmailHost\\\": \\\"smtp.gmail.com\\\", \\\"systemEmailPort\\\": \\\"465\\\", \\\"systemEmailUser\\\": \\\"user@gmail.com\\\", \\\"systemEmailAddress\\\": \\\"user@gmail.com\\\", \\\"systemEmailPassword\\\": \\\"app-password-123\\\"}}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"383387e5-4623-44ab-b2c4-d9ea046f4547\",\n\t\t\t\t\t\"diagramNodeId\": \"ce3ed3ba-a35b-4881-8dfd-f8425b9bf812\",\n\t\t\t\t\t\"simStepLabel\": \"Data Transmission: Send Updated Settings to Server\",\n\t\t\t\t\t\"simStepDescription\": \"The PUT request containing the new settings is sent to the backend API endpoint for processing and persistence.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Utils/NetworkService.js\",\n\t\t\t\t\t\t\"startLine\": \"711\",\n\t\t\t\t\t\t\"endLine\": \"717\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"updateAppSettings\",\n\t\t\t\t\t\t\t\"this.axiosInstance.put\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"settings\\\": {\\\"systemEmailHost\\\": \\\"smtp.gmail.com\\\", \\\"systemEmailPort\\\": \\\"465\\\", \\\"systemEmailUser\\\": \\\"user@gmail.com\\\", \\\"systemEmailAddress\\\": \\\"user@gmail.com\\\", \\\"systemEmailPassword\\\": \\\"app-password-123\\\"}}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"settings\\\": {\\\"systemEmailHost\\\": \\\"smtp.gmail.com\\\", \\\"systemEmailPort\\\": \\\"465\\\", \\\"systemEmailUser\\\": \\\"user@gmail.com\\\", \\\"systemEmailAddress\\\": \\\"user@gmail.com\\\", \\\"systemEmailPassword\\\": \\\"app-password-123\\\"}}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"7632e8d2-4086-4169-ae3f-bfbf8d657987\",\n\t\t\t\t\t\"diagramNodeId\": \"cce3b9c8-f3b7-434b-b3c6-d8d164714f86\",\n\t\t\t\t\t\"simStepLabel\": \"Backend: Persist Updated Settings\",\n\t\t\t\t\t\"simStepDescription\": \"The `settingsController` receives the PUT request, validates the body, and calls the `db.settingsModule.updateAppSettings` method to update the settings document in the database.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/controllers/v1/settingsController.js\",\n\t\t\t\t\t\t\"startLine\": \"54\",\n\t\t\t\t\t\t\"endLine\": \"64\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"updateAppSettings\",\n\t\t\t\t\t\t\t\"updateAppSettingsBodyValidation\",\n\t\t\t\t\t\t\t\"db.settingsModule.updateAppSettings\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"settings\\\": {\\\"systemEmailHost\\\": \\\"smtp.gmail.com\\\", \\\"systemEmailPort\\\": \\\"465\\\", \\\"systemEmailUser\\\": \\\"user@gmail.com\\\", \\\"systemEmailAddress\\\": \\\"user@gmail.com\\\", \\\"systemEmailPassword\\\": \\\"app-password-123\\\"}}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"msg\\\": \\\"Updated app settings successfully\\\", \\\"data\\\": {\\\"emailPasswordSet\\\": true, \\\"settings\\\": {\\\"systemEmailHost\\\": \\\"smtp.gmail.com\\\", ...}}}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"0afcde35-7d51-4939-aae8-bac5ac83c49d\",\n\t\t\t\t\t\"diagramNodeId\": \"fbe9b160-307e-4f51-8f72-713fda5373c8\",\n\t\t\t\t\t\"simStepLabel\": \"API Response: Confirm Settings Update\",\n\t\t\t\t\t\"simStepDescription\": \"The backend sends a success response to the client, including the newly saved (and sanitized) settings, confirming the update.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/controllers/v1/settingsController.js\",\n\t\t\t\t\t\t\"startLine\": \"60\",\n\t\t\t\t\t\t\"endLine\": \"63\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"res.success\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"msg\\\": \\\"Updated app settings successfully\\\", \\\"data\\\": {\\\"emailPasswordSet\\\": true, \\\"pagespeedKeySet\\\": false, \\\"settings\\\": {\\\"checkTTL\\\": 7, \\\"timezone\\\": \\\"America/Toronto\\\", \\\"systemEmailHost\\\": \\\"smtp.gmail.com\\\", \\\"systemEmailPort\\\": 465, \\\"systemEmailUser\\\": \\\"user@gmail.com\\\", \\\"systemEmailAddress\\\": \\\"user@gmail.com\\\"}}}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"msg\\\": \\\"Updated app settings successfully\\\", \\\"data\\\": {\\\"emailPasswordSet\\\": true, \\\"pagespeedKeySet\\\": false, \\\"settings\\\": {\\\"checkTTL\\\": 7, \\\"timezone\\\": \\\"America/Toronto\\\", \\\"systemEmailHost\\\": \\\"smtp.gmail.com\\\", \\\"systemEmailPort\\\": 465, \\\"systemEmailUser\\\": \\\"user@gmail.com\\\", \\\"systemEmailAddress\\\": \\\"user@gmail.com\\\"}}}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"a157bd07-b969-44f8-914c-3d8393c1605a\",\n\t\t\t\t\t\"diagramNodeId\": \"fff5dde4-8eb8-4c21-9c6d-0845a9749ff3\",\n\t\t\t\t\t\"simStepLabel\": \"UI Update: Display Success Confirmation\",\n\t\t\t\t\t\"simStepDescription\": \"The frontend network service receives the successful API response. The `saveSettings` hook then calls `createToast` with a success message, which is displayed to the user.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Hooks/v1/settingsHooks.js\",\n\t\t\t\t\t\t\"startLine\": \"58\",\n\t\t\t\t\t\t\"endLine\": \"58\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"createToast\",\n\t\t\t\t\t\t\t\"t(\\\"settingsSuccessSaved\\\")\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"body\\\": \\\"Settings saved successfully\\\"}\",\n\t\t\t\t\t\"outputDataExample\": \"{}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"a9b24b5f-534b-4baf-a185-bac7c32a1c42\",\n\t\t\t\t\t\"diagramNodeId\": \"704e2ec8-9f2f-47e5-852f-c6ada67a02e0\",\n\t\t\t\t\t\"simStepLabel\": \"Flow 2: Navigate to Diagnostics Page\",\n\t\t\t\t\t\"simStepDescription\": \"The user navigates to the 'Logs' page and selects the 'Diagnostics' tab. The `Diagnostics` component renders and immediately calls the `useFetchDiagnostics` hook to retrieve system health data.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Pages/v1/Logs/Diagnostics/index.jsx\",\n\t\t\t\t\t\t\"startLine\": \"14\",\n\t\t\t\t\t\t\"endLine\": \"15\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"useFetchDiagnostics\",\n\t\t\t\t\t\t\t\"diagnostics\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{}\",\n\t\t\t\t\t\"outputDataExample\": \"{}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"23b8ad7d-8967-4e48-814c-1a7bf5b4dfac\",\n\t\t\t\t\t\"diagramNodeId\": \"499dfe1f-77d4-4b26-a12c-45240691109e\",\n\t\t\t\t\t\"simStepLabel\": \"API Call: Fetch System Diagnostics\",\n\t\t\t\t\t\"simStepDescription\": \"The `useFetchDiagnostics` hook triggers a GET request to the `/api/v1/diagnostic/system` endpoint to fetch real-time system metrics.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Utils/NetworkService.js\",\n\t\t\t\t\t\t\"startLine\": \"1113\",\n\t\t\t\t\t\t\"endLine\": \"1119\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"getDiagnostics\",\n\t\t\t\t\t\t\t\"this.axiosInstance.get\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"method\\\": \\\"GET\\\", \\\"url\\\": \\\"/api/v1/diagnostic/system\\\"}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"method\\\": \\\"GET\\\", \\\"url\\\": \\\"/api/v1/diagnostic/system\\\"}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"8fb704ca-67d9-437c-90d8-01302634d568\",\n\t\t\t\t\t\"diagramNodeId\": \"09f07e80-185e-4547-aab4-edaf8ae7501e\",\n\t\t\t\t\t\"simStepLabel\": \"Backend: Gather System Statistics\",\n\t\t\t\t\t\"simStepDescription\": \"The `diagnosticController` receives the request and calls `diagnosticService.getSystemStats()`. This service uses native Node.js modules like `os` and `v8` to collect metrics on memory, CPU, heap statistics, and process uptime.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/service/v1/business/diagnosticService.js\",\n\t\t\t\t\t\t\"startLine\": \"39\",\n\t\t\t\t\t\t\"endLine\": \"95\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"getSystemStats\",\n\t\t\t\t\t\t\t\"os\",\n\t\t\t\t\t\t\t\"process.memoryUsage\",\n\t\t\t\t\t\t\t\"process.cpuUsage\",\n\t\t\t\t\t\t\t\"v8.getHeapStatistics\",\n\t\t\t\t\t\t\t\"process.uptime\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"request\\\": \\\"GET /api/v1/diagnostic/system\\\"}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"osStats\\\": {\\\"totalMemoryBytes\\\": 16777216000, \\\"freeMemoryBytes\\\": 1572864000}, \\\"memoryUsage\\\": {\\\"rss\\\": 123456789}, \\\"cpuUsage\\\": {\\\"usagePercentage\\\": 12.5}, \\\"v8HeapStats\\\": {\\\"usedHeapSizeBytes\\\": 54321098}, \\\"uptimeMs\\\": 86400000}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"44a4372f-a903-4c43-a9a5-c7549c875e11\",\n\t\t\t\t\t\"diagramNodeId\": \"d0f92604-a6fa-4d85-9716-ea8f32db78e0\",\n\t\t\t\t\t\"simStepLabel\": \"API Response: Send Diagnostics Data to Client\",\n\t\t\t\t\t\"simStepDescription\": \"The backend responds with a JSON object containing the comprehensive system diagnostics data.\",\n\t\t\t\t\t\"isEdge\": 1,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"server/src/controllers/v1/diagnosticController.js\",\n\t\t\t\t\t\t\"startLine\": \"52\",\n\t\t\t\t\t\t\"endLine\": \"55\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"res.success\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"msg\\\": \\\"OK\\\", \\\"data\\\": {\\\"osStats\\\": {\\\"totalMemoryBytes\\\": 16777216000, \\\"freeMemoryBytes\\\": 1572864000}, \\\"memoryUsage\\\": {\\\"rss\\\": 123456789}, \\\"cpuUsage\\\": {\\\"usagePercentage\\\": 12.5}, \\\"v8HeapStats\\\": {\\\"usedHeapSizeBytes\\\": 54321098}, \\\"uptimeMs\\\": 86400000}}\",\n\t\t\t\t\t\"outputDataExample\": \"{\\\"msg\\\": \\\"OK\\\", \\\"data\\\": {\\\"osStats\\\": {\\\"totalMemoryBytes\\\": 16777216000, \\\"freeMemoryBytes\\\": 1572864000}, \\\"memoryUsage\\\": {\\\"rss\\\": 123456789}, \\\"cpuUsage\\\": {\\\"usagePercentage\\\": 12.5}, \\\"v8HeapStats\\\": {\\\"usedHeapSizeBytes\\\": 54321098}, \\\"uptimeMs\\\": 86400000}}\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"simStepId\": \"e6c94f52-a599-4568-a06f-2db18f963817\",\n\t\t\t\t\t\"diagramNodeId\": \"4b418736-6b72-47e0-917a-d86d4bed9ecd\",\n\t\t\t\t\t\"simStepLabel\": \"UI Update: Display System Health\",\n\t\t\t\t\t\"simStepDescription\": \"The frontend receives the diagnostic data. The `Diagnostics` component passes this data to its children, `Gauges` and `StatusBoxes`, which then render the information as interactive gauges and statistical boxes.\",\n\t\t\t\t\t\"isEdge\": 0,\n\t\t\t\t\t\"sourceCodeMapping\": {\n\t\t\t\t\t\t\"filePath\": \"client/src/Pages/v1/Logs/Diagnostics/index.jsx\",\n\t\t\t\t\t\t\"startLine\": \"59\",\n\t\t\t\t\t\t\"endLine\": \"63\",\n\t\t\t\t\t\t\"relevantVariables\": [\n\t\t\t\t\t\t\t\"Gauges\",\n\t\t\t\t\t\t\t\"StatusBoxes\",\n\t\t\t\t\t\t\t\"diagnostics\"\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"inputDataExample\": \"{\\\"diagnostics\\\": {\\\"osStats\\\": {\\\"totalMemoryBytes\\\": 16777216000, \\\"freeMemoryBytes\\\": 1572864000}, \\\"cpuUsage\\\": {\\\"usagePercentage\\\": 12.5}, \\\"v8HeapStats\\\": {\\\"usedHeapSizeBytes\\\": 54321098}, \\\"uptimeMs\\\": 86400000}}\",\n\t\t\t\t\t\"outputDataExample\": \"{}\"\n\t\t\t\t}\n\t\t\t],\n\t\t\t\"description\": \"<ul><li>Provides centralized settings for administrators to configure and maintain the Checkmate instance</li><li>- Admins can configure global application settings, including email server (SMTP) details for sending alerts</li><li>- UI settings like theme (light/dark) and default timezone can be customized</li><li>- Data retention policies, such as the Time-To-Live (TTL) for check history, can be adjusted</li><li>- A diagnostics page provides system information and logs for troubleshooting and monitoring the health of the Checkmate application itself</li></ul>\",\n\t\t\t\"simulationNodesAndEdges\": {\n\t\t\t\t\"97908daf-d071-4df5-8366-1f5f4d8d534a\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"64e9f1af-13b7-4361-a2a9-3f45760e316d\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"83596bd1-dfca-4196-b52e-955f6824fafb\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"441b0c45-5f27-478d-8ca8-58fbd5f460ea\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"09cb194a-0ea4-46e2-b32b-36b62fa87f40\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"ae5c5146-4dbb-4612-9d23-086e57f72474\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"1b2cf182-9ee3-4218-a7ec-b74e427ccddf\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"d7098072-9a83-4369-8176-9646ba34e186\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"cce3b9c8-f3b7-434b-b3c6-d8d164714f86\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"7632e8d2-4086-4169-ae3f-bfbf8d657987\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"fff5dde4-8eb8-4c21-9c6d-0845a9749ff3\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"a157bd07-b969-44f8-914c-3d8393c1605a\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"704e2ec8-9f2f-47e5-852f-c6ada67a02e0\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"a9b24b5f-534b-4baf-a185-bac7c32a1c42\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"09f07e80-185e-4547-aab4-edaf8ae7501e\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"8fb704ca-67d9-437c-90d8-01302634d568\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"4b418736-6b72-47e0-917a-d86d4bed9ecd\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"e6c94f52-a599-4568-a06f-2db18f963817\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"f6d80f09-ae83-4c95-aba0-4efffeda38e0\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"dca4a33c-b666-47b8-896b-370ed9d6f9c5\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"195ad532-9858-493e-876a-6ec457811d1d\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"aacc9302-6ca8-45c6-acb8-956d8d0242c2\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"8c107d79-f796-49eb-ab88-f553dd6f9d95\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"e7e82a97-1409-4bc5-ae27-b4ff5ba746df\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"ce3ed3ba-a35b-4881-8dfd-f8425b9bf812\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"383387e5-4623-44ab-b2c4-d9ea046f4547\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"fbe9b160-307e-4f51-8f72-713fda5373c8\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"0afcde35-7d51-4939-aae8-bac5ac83c49d\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"499dfe1f-77d4-4b26-a12c-45240691109e\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"23b8ad7d-8967-4e48-814c-1a7bf5b4dfac\"\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t\"d0f92604-a6fa-4d85-9716-ea8f32db78e0\": {\n\t\t\t\t\t\"simStepIds\": [\n\t\t\t\t\t\t\"44a4372f-a903-4c43-a9a5-c7549c875e11\"\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"isAIGenerated\": true,\n\t\t\t\"keywords\": \"Settings, updateAppSettings, diagnostic\",\n\t\t\t\"generationPrompt\": \"System Administration and Configuration\",\n\t\t\t\"generationKeywords\": \"Settings, updateAppSettings, diagnostic\"\n\t\t}\n\t},\n\t\"cellToPath\": {\n\t\t\"0b23ea66-3e37-4643-b3b9-acb87ea02bae\": \"client\",\n\t\t\"98af25c7-efc2-43d2-a273-c8da4e1038ad\": \"server\",\n\t\t\"d3264577-10f0-42fe-9411-7e9df0754d1e\": \"client/src\",\n\t\t\"35864a2c-7bd0-4428-84fc-c0aa90c7f1be\": \"server/src\",\n\t\t\"f0feab85-316a-41b5-a2f1-629220018846\": \"client/src/Pages\",\n\t\t\"4295a047-076f-4c07-95dd-b3123b6614f7\": \"client/src/Hooks\",\n\t\t\"02b07589-ec21-4366-b7d2-9071e8f3bad8\": \"client/src/Utils\",\n\t\t\"ffaaf471-ac3c-4ea3-a5a9-d5255169e54b\": \"server/src/routes\",\n\t\t\"478e649c-1d1b-41d2-9b7b-6927e1dec7e1\": \"server/src/controllers\",\n\t\t\"99e9b746-7809-41f4-a433-1de7cc90574b\": \"server/src/service\",\n\t\t\"15ee5d81-a0cf-4614-80b8-7a1123ab20b8\": \"server/src/db\",\n\t\t\"1a083b4a-787c-4eb4-8029-6700de987679\": \"client/src/Pages/v1\",\n\t\t\"3bf0c0f9-cbb0-4f0c-8cb3-6e2a4abc0961\": \"client/src/Hooks/v1\",\n\t\t\"16731e9d-3f73-4055-9d79-5ca9be679f68\": \"client/src/Utils/NetworkService.js\",\n\t\t\"d3375a20-2776-4771-b806-649bbeb541bd\": \"server/src/routes/v1\",\n\t\t\"fc591f7a-d4ac-4565-949d-a87a58a79bbc\": \"server/src/controllers/v1\",\n\t\t\"bbbe53d6-f595-498a-ae45-e08611f39c3d\": \"server/src/service/v1\",\n\t\t\"58c5a3fd-1e69-4ca4-a64e-314f5644bdaf\": \"server/src/db/v1\",\n\t\t\"7090fcdb-09be-4c85-86fd-e73553bbb2ff\": \"client/src/Pages/v1/Uptime\",\n\t\t\"595cf0e8-2f86-4543-b51c-b2aeac307f4b\": \"client/src/Hooks/v1/monitorHooks.js\",\n\t\t\"10611636-ec73-4a26-87a5-654ae64a4843\": \"server/src/routes/v1/monitorRoute.js\",\n\t\t\"341f2784-67ee-4477-9445-a8c240ee6261\": \"server/src/controllers/v1/monitorController.js\",\n\t\t\"87d3b101-9443-4ed4-9c4f-f759d41677eb\": \"server/src/service/v1/business\",\n\t\t\"1670815f-860d-4ea4-92e1-b238a799d3dc\": \"server/src/service/v1/infrastructure\",\n\t\t\"82cb3dbe-c922-438a-a912-255376f4b380\": \"server/src/db/v1/modules\",\n\t\t\"3dba5acc-cf25-40b7-ad21-9cd715454cd5\": \"client/src/Pages/v1/Uptime/Create\",\n\t\t\"b4e479df-9b21-4430-9383-84831f503c2e\": \"server/src/service/v1/business/monitorService.js\",\n\t\t\"dda70a36-2d1d-4e46-8bcc-52d0d474bf7b\": \"server/src/service/v1/infrastructure/SuperSimpleQueue\",\n\t\t\"00406786-9663-440a-96b6-919d544732c0\": \"server/src/service/v1/infrastructure/networkService.js\",\n\t\t\"fbd7d244-2f37-453c-8c83-a23a260b26cc\": \"server/src/service/v1/infrastructure/statusService.js\",\n\t\t\"2ff1f030-2080-48da-bbbe-90302fdfc2f7\": \"server/src/service/v1/infrastructure/notificationService.js\",\n\t\t\"630b3ece-2648-48d5-99b5-ef9611de2ad5\": \"server/src/db/v1/modules/monitorModule.js\",\n\t\t\"391ad99e-3114-4f54-a6ca-fd89b33c7e06\": \"client/src/Pages/v1/Uptime/Create/index.jsx\",\n\t\t\"d9c0127e-31aa-4509-b5c9-f7017d10d69a\": \"server/src/service/v1/infrastructure/SuperSimpleQueue/SuperSimpleQueue.js\",\n\t\t\"04c12e9a-e025-457c-a634-5f7472a42985\": \"server/src/service/v1/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.js\",\n\t\t\"7a2da928-a65c-49d8-b0a3-c159a6df2bc5\": \"client/src/Pages/v1/Uptime/Create/index.jsx-simstep-ab5de0b9-c70d-492c-98d9-8ddee66284ad\",\n\t\t\"a81f4ae8-41fe-4d1b-95ce-86abcc67b53c\": \"client/src/Pages/v1/Uptime/Create/index.jsx-simstep-e02ddf57-270e-4f71-b4c4-d5183bb7879a\",\n\t\t\"a30ac765-c546-4993-988e-8c8cfdb7532f\": \"client/src/Utils/NetworkService.js-simstep-14e9986b-c6ce-475e-97ed-da1fa2b6968d\",\n\t\t\"f0409948-75dc-457f-a02d-6b9774258e48\": \"server/src/controllers/v1/monitorController.js-simstep-38fd069d-9c44-4078-954b-3a0899e9acf4\",\n\t\t\"2d407bfd-e4b0-46b8-99e7-121c507d525f\": \"server/src/db/v1/modules/monitorModule.js-simstep-ca3ad309-323a-418d-a171-c16f56fae23c\",\n\t\t\"51e8db5f-2fdd-4ddc-9605-43981db9d940\": \"server/src/service/v1/infrastructure/SuperSimpleQueue/SuperSimpleQueue.js-simstep-2702bfca-7611-4562-8d3e-a05af8257871\",\n\t\t\"18c13391-0cf7-4303-8180-0a40cfd64b58\": \"server/src/service/v1/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.js-simstep-e22a708a-a348-4775-8ee3-f32a35446e24\",\n\t\t\"5c900373-e6ba-44d5-b341-676a32d659c8\": \"server/src/service/v1/infrastructure/networkService.js-simstep-84f82fea-e306-4e0b-8222-e9705803d51a\",\n\t\t\"45e38f3a-a7c3-4de7-b3dc-589361d793fd\": \"server/src/service/v1/infrastructure/statusService.js-simstep-c66a04c6-113e-4391-ab71-93fc612279ef\",\n\t\t\"9f3ea7fc-16d3-4d36-97eb-66f8808425cc\": \"server/src/service/v1/infrastructure/notificationService.js-simstep-1a260a75-cf50-4f7a-90b0-c280b512a5cb\",\n\t\t\"0e09aa33-d7c7-4c89-9da8-f0937658f4d3\": \"generated-edge-simstep-888df086-41bb-469d-9c0a-daf74bdecb9f-0e09aa33-d7c7-4c89-9da8-f0937658f4d3\",\n\t\t\"1f6f04a9-0123-4729-b06a-8f3da6d1b58c\": \"generated-edge-simstep-3fe0afaa-c673-4b52-a0c4-02a3ffd3a075-1f6f04a9-0123-4729-b06a-8f3da6d1b58c\",\n\t\t\"b6d963d5-c613-407a-9ce9-60a04048dea7\": \"generated-edge-simstep-13dd0564-44a5-43ea-a163-ce1148cc48e7-b6d963d5-c613-407a-9ce9-60a04048dea7\",\n\t\t\"a6bccd1d-4272-4df7-a7c8-b3979e37b8d7\": \"generated-edge-simstep-a6f4c967-b1a8-4804-bc2e-67f47a7b68f9-a6bccd1d-4272-4df7-a7c8-b3979e37b8d7\",\n\t\t\"de320ac1-0949-4297-be7c-b9d7a14e0fec\": \"generated-edge-simstep-71ec03b6-1166-4c5d-9ada-0875a0866e30-de320ac1-0949-4297-be7c-b9d7a14e0fec\",\n\t\t\"38ba9b22-5b26-432d-a856-0eceb792c737\": \"generated-edge-simstep-1d7580f2-f107-4008-a207-b8ec07998721-38ba9b22-5b26-432d-a856-0eceb792c737\",\n\t\t\"5e80734c-7b72-41be-9068-30cda3ffb425\": \"generated-edge-simstep-9b0ada30-d3e6-4b2c-b3ff-f50615139588-5e80734c-7b72-41be-9068-30cda3ffb425\",\n\t\t\"0a7e4a72-b644-4bd8-afa1-ae8a1d6c111c\": \"generated-edge-simstep-9896c387-4fca-47ad-82eb-7301286decb7-0a7e4a72-b644-4bd8-afa1-ae8a1d6c111c\",\n\t\t\"3f26b33e-477f-41df-a78a-3e3e4f4209ae\": \"client/src/Pages/v1/Infrastructure\",\n\t\t\"74019e8a-3148-4a32-aae2-5afd16f3eb9b\": \"client/src/Pages/v1/Infrastructure/Create\",\n\t\t\"591128f9-0994-4e01-a1ab-f23357f97aff\": \"client/src/Pages/v1/Infrastructure/Details\",\n\t\t\"4940977f-933d-4bbc-b19e-749647b44d25\": \"server/src/service/v1/infrastructure/notificationUtils.js\",\n\t\t\"a0b22a5a-59e1-47e3-8218-a4ad083b1b71\": \"server/src/db/v1/modules/monitorModuleQueries.js\",\n\t\t\"ceded1fc-87a9-43c8-a756-746be3d4ad8d\": \"client/src/Pages/v1/Infrastructure/Create/Components\",\n\t\t\"e292c552-b3df-4bac-bd9a-8f44c260a5aa\": \"client/src/Pages/v1/Infrastructure/Details/index.jsx\",\n\t\t\"e97d4e61-483e-4ac5-85a1-0ff72fcdd449\": \"client/src/Pages/v1/Infrastructure/Details/Components\",\n\t\t\"83800be3-2a0e-4419-b379-3f995f4050e7\": \"client/src/Pages/v1/Infrastructure/Create/Components/CustomAlertsSection.jsx\",\n\t\t\"6a7c7720-a399-4d4d-8225-36e0b2f59731\": \"client/src/Pages/v1/Infrastructure/Details/Components/GaugeBoxes\",\n\t\t\"8fe3d890-3605-407d-b06c-1d890a354e46\": \"client/src/Pages/v1/Infrastructure/Details/Components/GaugeBoxes/index.jsx\",\n\t\t\"9651d084-5c16-4417-89c1-f52ae6572a95\": \"client/src/Pages/v1/Infrastructure/Create/Components/CustomAlertsSection.jsx-simstep-80dd889a-1fc9-4d56-b9cf-5b45bf1110b1\",\n\t\t\"4c47b5f2-5363-4816-9745-30e61d184c7a\": \"server/src/service/v1/infrastructure/networkService.js-simstep-ed6e7faf-69dd-4d0b-bda8-137739ed288b\",\n\t\t\"c1bf10c9-8c1a-44f4-8e23-39708f0301e8\": \"server/src/service/v1/infrastructure/statusService.js-simstep-e5b90cf2-9369-4741-9803-c835a81c009b\",\n\t\t\"d4f48f1a-61de-4cde-87d2-4b5215464899\": \"server/src/service/v1/infrastructure/notificationUtils.js-simstep-07fe8489-1d94-4afb-83f8-7cebb0dff49a\",\n\t\t\"801fe70a-1a19-406c-8f0d-770b0cb74409\": \"client/src/Pages/v1/Infrastructure/Details/index.jsx-simstep-c27365db-9db6-4cc9-96f0-4f046fd38562\",\n\t\t\"9ef7c423-f4fc-4caf-9bf5-c1aa3002ca03\": \"server/src/db/v1/modules/monitorModule.js-simstep-8502ae1f-f029-446e-9dde-59c2aba87a8a\",\n\t\t\"9ea2e32d-1ea8-42f2-9a17-613844723ae6\": \"client/src/Pages/v1/Infrastructure/Details/Components/GaugeBoxes/index.jsx-simstep-6eedce82-b9c8-4022-95e5-3a6e00628105\",\n\t\t\"1c5c9857-bf32-40e4-921b-957c252dac2a\": \"generated-edge-simstep-815f96af-c28e-4f80-b4ab-18a6fb23eee0-1c5c9857-bf32-40e4-921b-957c252dac2a\",\n\t\t\"a64547c9-d9e6-4941-8e5e-f49add06516b\": \"generated-edge-simstep-4434dca1-2048-4458-a70b-b70d569e378d-a64547c9-d9e6-4941-8e5e-f49add06516b\",\n\t\t\"7a250d09-50c6-4935-b10c-626b0ebe1fba\": \"generated-edge-simstep-b019a6d0-a23a-4a1d-bd21-644f01996f14-7a250d09-50c6-4935-b10c-626b0ebe1fba\",\n\t\t\"3d357de8-9fd2-4d0b-9623-f36fce4cf1de\": \"generated-edge-simstep-c691b3b9-88b3-4c88-a399-ff9fd5866194-3d357de8-9fd2-4d0b-9623-f36fce4cf1de\",\n\t\t\"00921831-b1d9-4a5a-ae6f-5ddee7cfc1e4\": \"generated-edge-simstep-a5d20172-1c95-4c9e-af39-f86a498734bb-00921831-b1d9-4a5a-ae6f-5ddee7cfc1e4\",\n\t\t\"60308696-6f8a-43c8-b9a1-da199ef500cd\": \"generated-edge-simstep-627fcb0c-0282-4b4d-8c55-aceb636e4da0-60308696-6f8a-43c8-b9a1-da199ef500cd\",\n\t\t\"feefae96-61b8-4ac5-a37c-592ed4b2330e\": \"server/src/service/v2\",\n\t\t\"b3575a92-df07-4cf7-810f-8e5e0672d666\": \"client/src/Pages/v1/Notifications\",\n\t\t\"cd2428fd-6545-48dd-b685-5261311b7532\": \"client/src/Hooks/v1/useNotifications.js\",\n\t\t\"96250197-23af-4059-9904-fd6751f70ad5\": \"server/src/routes/v1/notificationRoute.js\",\n\t\t\"8e5941e1-e577-455f-bbf2-83a418ad5908\": \"server/src/controllers/v1/notificationController.js\",\n\t\t\"3f8ff792-40c8-4ae6-9af5-ff8b90da2f9f\": \"server/src/service/v2/infrastructure\",\n\t\t\"a6fb23f0-73bc-40ee-bb3c-ed93605a2bcb\": \"client/src/Pages/v1/Notifications/create\",\n\t\t\"62daeac4-9402-448a-972c-cb8cb760671c\": \"server/src/db/v1/modules/notificationModule.js\",\n\t\t\"159e569d-31d8-4883-b443-4ec08b21a044\": \"server/src/service/v2/infrastructure/JobGenerator.ts\",\n\t\t\"c6d9907f-0a05-4153-a27f-47c3a1c4c0aa\": \"server/src/service/v2/infrastructure/NotificationService.ts\",\n\t\t\"b71b02fb-d08e-4fcf-b959-de1b9547d9c2\": \"client/src/Pages/v1/Notifications/create/index.jsx\",\n\t\t\"15486629-84b3-463a-962b-06083f69e4bf\": \"client/src/Pages/v1/Notifications/create/index.jsx-simstep-e924ec15-1bea-4e3b-befb-a8bf30cbf740\",\n\t\t\"a07b805e-e55f-46cb-b54b-765b7813b0ca\": \"client/src/Hooks/v1/useNotifications.js-simstep-383c6be8-aa51-4398-9ae3-21035413f73a\",\n\t\t\"d0a4737f-715f-4f50-b6d5-5e4b31f86f93\": \"server/src/routes/v1/notificationRoute.js-simstep-2f9266c9-4cbc-4b50-a280-cf8b5800d540\",\n\t\t\"4a796ccf-40a9-4446-a109-6a6eed52e898\": \"server/src/db/v1/modules/notificationModule.js-simstep-d29ab4ab-be50-4f17-af6e-2c61cec9d0ab\",\n\t\t\"29c2c56e-9dc0-4304-bfbf-e0c0f8915a39\": \"server/src/routes/v1/notificationRoute.js-simstep-c1b17b64-90e9-48bc-8927-25d7ebfc3036\",\n\t\t\"1cc01e08-4a6c-4526-b8a7-5ee8a06c1709\": \"server/src/service/v1/infrastructure/notificationService.js-simstep-f29f9be1-a0cd-43a3-b259-e5105a25ce41\",\n\t\t\"28f1eabb-4f24-4944-8a0a-04f41ceb8589\": \"server/src/service/v2/infrastructure/JobGenerator.ts-simstep-157cec87-9b76-4a1c-9d85-0a6d3decbaa3\",\n\t\t\"31fe5a28-0640-4b52-841b-dd02e2ae646e\": \"server/src/service/v2/infrastructure/JobGenerator.ts-simstep-55ad645b-118a-478e-a00c-09ef82357008\",\n\t\t\"78e5cb9f-6a97-4d31-a487-fe7dbce5d7d1\": \"server/src/service/v2/infrastructure/NotificationService.ts-simstep-8d1176f3-c755-401d-9ca8-234689b4b837\",\n\t\t\"54497b9a-4910-4df4-b016-480b9ac250a7\": \"generated-edge-simstep-71dbcd41-c6d4-4514-b5a4-6c966ca7ba6f-54497b9a-4910-4df4-b016-480b9ac250a7\",\n\t\t\"dc135d8d-0515-403d-ae58-f3c04647b2ae\": \"generated-edge-simstep-162d8d2f-6cd1-45fa-8711-1ee85c5f86ef-dc135d8d-0515-403d-ae58-f3c04647b2ae\",\n\t\t\"7b9ebb0e-a6b2-438c-bfed-9c851a1bccbc\": \"generated-edge-simstep-73e63d2f-2b43-488d-9e86-170f511673f5-7b9ebb0e-a6b2-438c-bfed-9c851a1bccbc\",\n\t\t\"279155cd-ff31-41a2-8f5f-a538f01bfa66\": \"generated-edge-simstep-d390ef45-f2fe-4806-a45a-cc9c84b48a5a-279155cd-ff31-41a2-8f5f-a538f01bfa66\",\n\t\t\"57018b30-e2f4-4eb2-a1da-fe75afbb8c2f\": \"generated-edge-simstep-6f2bf027-50d9-472e-9569-808a64fce7cf-57018b30-e2f4-4eb2-a1da-fe75afbb8c2f\",\n\t\t\"50797935-1447-47a4-891b-9e886e5601fa\": \"generated-edge-simstep-b7ec7415-fcae-4077-8c19-302a015b00b5-50797935-1447-47a4-891b-9e886e5601fa\",\n\t\t\"c778c6b9-c12e-45c0-8682-2c9e892867b0\": \"generated-edge-simstep-b7259d77-c8df-4060-ac03-58728ae3eb54-c778c6b9-c12e-45c0-8682-2c9e892867b0\",\n\t\t\"987f145b-5df6-4c30-bf1c-2a2d2b0e5cdc\": \"client/src/Routes\",\n\t\t\"c4d7e7dd-75b1-44f1-a34a-6ed290a8e562\": \"client/src/Routes/index.jsx\",\n\t\t\"9d662180-8b65-4426-ad37-cfed4bc01fb4\": \"client/src/Pages/v1/StatusPage\",\n\t\t\"773e1065-b0a5-46a9-b0cc-6b963f69f5cc\": \"server/src/routes/v1/statusPageRoute.js\",\n\t\t\"17a4f435-5a8e-4433-84a6-9ac17362709a\": \"server/src/controllers/v1/statusPageController.js\",\n\t\t\"08602a28-f073-484e-9403-7eb798126dd4\": \"client/src/Pages/v1/StatusPage/Create\",\n\t\t\"8ef70566-37d9-48fb-b5e8-37e5b68768a2\": \"client/src/Pages/v1/StatusPage/Status\",\n\t\t\"f8541fe3-4bcf-4833-a226-66b5301adf58\": \"server/src/db/v1/modules/statusPageModule.js\",\n\t\t\"e2d2bbf6-dffd-4edf-8c5d-34088d9d4745\": \"client/src/Pages/v1/StatusPage/Create/index.jsx\",\n\t\t\"56f6775e-9843-4ca2-bc8c-1c263b6c35e9\": \"client/src/Pages/v1/StatusPage/Create/Hooks\",\n\t\t\"e1e6f5e0-fd8c-4260-aa4f-cdb096c6b1c3\": \"client/src/Pages/v1/StatusPage/Status/index.jsx\",\n\t\t\"79da0721-d810-4f7f-9cf9-3ea462bf0bff\": \"client/src/Pages/v1/StatusPage/Status/Hooks\",\n\t\t\"3945e05f-2d99-4d6d-9a3e-b6c75ea3c45a\": \"client/src/Pages/v1/StatusPage/Create/Hooks/useCreateStatusPage.jsx\",\n\t\t\"5b2cdab8-66f1-40a1-9621-0efaf54e04ae\": \"client/src/Pages/v1/StatusPage/Status/Hooks/useStatusPageFetch.jsx\",\n\t\t\"00289d11-0015-4b2a-9c5b-dc9fd0f32b80\": \"client/src/Pages/v1/StatusPage/Create/index.jsx-simstep-de7b5d1f-b370-42a4-a410-4178f1e2d3a6\",\n\t\t\"aa5d6d07-05f0-45f3-b19a-199af50e35f1\": \"client/src/Pages/v1/StatusPage/Create/Hooks/useCreateStatusPage.jsx-simstep-3c99ae6a-b671-4f47-bed0-ddccd8ff5d35\",\n\t\t\"3efddcad-588f-4492-9808-b0c81c823c96\": \"server/src/routes/v1/statusPageRoute.js-simstep-84f11567-b3c4-42a2-aa7f-d78c1412099a\",\n\t\t\"f15ef77e-380f-4768-98cb-7f0dd4113841\": \"server/src/controllers/v1/statusPageController.js-simstep-01694730-8a75-4949-8815-bb4d6e3e2b42\",\n\t\t\"e234917e-a950-48f5-b864-cd957b2216e1\": \"server/src/db/v1/modules/statusPageModule.js-simstep-b6fa93cd-6fca-4d9e-969a-5400e2437ee8\",\n\t\t\"058ded1f-83ce-40a7-a99d-d178c81fe557\": \"server/src/controllers/v1/statusPageController.js-simstep-2a115421-5175-4c8f-8cdd-62f3fe148af5\",\n\t\t\"30aaee38-f509-4e19-a917-e6d2f4bba61c\": \"client/src/Routes/index.jsx-simstep-132354d7-df7a-4e03-9d00-16d54f836a1b\",\n\t\t\"ecfb2d04-2681-4f16-af75-632f69e1a868\": \"client/src/Pages/v1/StatusPage/Status/Hooks/useStatusPageFetch.jsx-simstep-b57bb249-9066-454e-aa8c-89108fdfcc2e\",\n\t\t\"2e26cd2f-1413-4c16-8e63-ea7808ab6c52\": \"server/src/routes/v1/statusPageRoute.js-simstep-477c6821-b29b-4b38-8930-ced21b8a75e5\",\n\t\t\"9f217674-4cd7-4ef8-b088-d5620042a7ba\": \"server/src/controllers/v1/statusPageController.js-simstep-5bdbd179-ce8f-4171-a073-af72a99b4468\",\n\t\t\"26da60f9-dde4-44ec-be89-91858cc14f90\": \"server/src/db/v1/modules/statusPageModule.js-simstep-ceb044e9-6545-4d04-bf79-ec8146eb8ec9\",\n\t\t\"d76e70e0-41f9-46cc-b775-b2027c5a0d5b\": \"server/src/controllers/v1/statusPageController.js-simstep-83224406-2f1d-4030-9beb-d65c2baf544d\",\n\t\t\"f59b91de-5196-4a43-9d57-3f28402c0672\": \"client/src/Pages/v1/StatusPage/Status/index.jsx-simstep-3d51e811-a659-442e-97e0-00798cd15647\",\n\t\t\"de23eee2-b60a-4236-a890-3c5b78388bb3\": \"generated-edge-simstep-d419f7b6-7b9b-4494-9fad-83e3ce208ca4-de23eee2-b60a-4236-a890-3c5b78388bb3\",\n\t\t\"d7faa713-4204-4a97-a172-d621da36c287\": \"generated-edge-simstep-8a2ab372-73db-4b9f-bc0e-6a20f15a4d79-d7faa713-4204-4a97-a172-d621da36c287\",\n\t\t\"a3f28fa6-8268-4c13-95a0-83e3b1abdcb0\": \"generated-edge-simstep-0923a533-c572-4da3-ad87-cdfff111f3bb-a3f28fa6-8268-4c13-95a0-83e3b1abdcb0\",\n\t\t\"9735611c-924b-49aa-92e8-10d8a86ac288\": \"generated-edge-simstep-67603f03-c088-4ed0-9f18-072435134cdd-9735611c-924b-49aa-92e8-10d8a86ac288\",\n\t\t\"40cb7d7b-2888-44de-bb7d-7735af70ba34\": \"generated-edge-simstep-ea4b3532-baae-4890-a73e-2ca385d0319e-40cb7d7b-2888-44de-bb7d-7735af70ba34\",\n\t\t\"c3f83811-8674-4dbb-9f84-79499f97fb1f\": \"generated-edge-simstep-210acc07-81c3-4394-b566-41f6031e8eeb-c3f83811-8674-4dbb-9f84-79499f97fb1f\",\n\t\t\"0575bf87-5362-4988-b895-7e514148d420\": \"generated-edge-simstep-2ba49e28-1cac-47f5-9118-ab930788736a-0575bf87-5362-4988-b895-7e514148d420\",\n\t\t\"ae1c9341-0e39-4d91-a9ac-5cc8a627c247\": \"generated-edge-simstep-de0714d2-bf1e-4a1a-a389-60793de8b772-ae1c9341-0e39-4d91-a9ac-5cc8a627c247\",\n\t\t\"5735f30c-b55f-444a-9236-f3d75f68ed27\": \"generated-edge-simstep-b79b8922-4de6-477d-8648-37b4bd9a6767-5735f30c-b55f-444a-9236-f3d75f68ed27\",\n\t\t\"dace45d6-fb25-4dae-b940-49ef7d77bbed\": \"generated-edge-simstep-788307ef-4cfa-4f5a-b2e9-a0bfc7a378d8-dace45d6-fb25-4dae-b940-49ef7d77bbed\",\n\t\t\"137a5ab7-1e49-42ec-869d-58f7f2380cb3\": \"generated-edge-simstep-4d3fad92-8fa9-4a8f-be3b-f09eda2f8dd4-137a5ab7-1e49-42ec-869d-58f7f2380cb3\",\n\t\t\"04a33e4f-1dfe-4c5a-8b30-01ed0591c380\": \"generated-edge-simstep-d5f3c300-9777-4e09-bb05-f1281c2ff29a-04a33e4f-1dfe-4c5a-8b30-01ed0591c380\",\n\t\t\"933a6cdc-349c-4725-b7ae-14cf780bfde8\": \"client/src/Hooks/v1/checkHooks.js\",\n\t\t\"d18dbe1d-2f2c-4336-bd21-47c1670f7bab\": \"server/src/routes/v1/checkRoute.js\",\n\t\t\"d983e54f-2fbe-496a-932d-a827e1124804\": \"server/src/controllers/v1/checkController.js\",\n\t\t\"273f3009-69d0-46fe-af57-3cd94a24b55b\": \"client/src/Pages/v1/Uptime/Details\",\n\t\t\"f90db867-e1e7-4554-b446-fa78fc6a8578\": \"server/src/service/v1/business/checkService.js\",\n\t\t\"860b5eec-a1ce-4e1f-a316-e1586f03af96\": \"server/src/db/v1/modules/checkModule.js\",\n\t\t\"1807d5b9-54be-430b-8997-cada4dd9b521\": \"client/src/Pages/v1/Uptime/Details/index.jsx\",\n\t\t\"6aed78bb-62f1-4ac1-9b9a-9d5977e87404\": \"client/src/Pages/v1/Uptime/Details/Components\",\n\t\t\"5ac0878f-d238-4763-8464-a85b4885a40f\": \"client/src/Pages/v1/Uptime/Details/Components/ResponseTable\",\n\t\t\"d3f74ac7-3b9a-4cae-8d77-a0d5d605bb27\": \"client/src/Pages/v1/Uptime/Details/Components/ResponseTable/index.jsx\",\n\t\t\"78a8a7c5-41d3-4453-a7f7-ac632bbef288\": \"client/src/Pages/v1/Uptime/Details/index.jsx-simstep-35195328-9847-4678-b014-9331553f0d19\",\n\t\t\"4a5847d0-91a0-4b4c-8517-2f4ff9a7e8d4\": \"client/src/Hooks/v1/checkHooks.js-simstep-8dc4347c-3e9e-40d7-ae6f-54684f2e6956\",\n\t\t\"cdd090be-0b62-45b4-baa0-fec01fc3ffd1\": \"server/src/routes/v1/checkRoute.js-simstep-c5fd192f-ea28-48a0-b3e7-5bc04f521192\",\n\t\t\"499b46a2-f2a2-4ccd-aecd-012eade2bd23\": \"server/src/service/v1/business/checkService.js-simstep-83fea05d-8306-4a73-a43f-882cdd14f50f\",\n\t\t\"14df9f01-1358-442d-96f5-eab9a4c4abbf\": \"server/src/controllers/v1/checkController.js-simstep-5768fdc5-045c-48ef-b0c9-79769403648f\",\n\t\t\"ceb9cda3-968d-44aa-b223-49902adb93b4\": \"client/src/Hooks/v1/checkHooks.js-simstep-faba07f3-7460-47ae-924d-f92f5b2e821d\",\n\t\t\"c996f7ca-9384-4252-b343-7bfc049d14bb\": \"client/src/Pages/v1/Uptime/Details/Components/ResponseTable/index.jsx-simstep-2b1651cd-2e70-4cc6-b2bb-23f94fa73d66\",\n\t\t\"e90e4943-6108-46e3-8a2c-a9a1c7361279\": \"generated-edge-simstep-49979250-1a32-4da5-95e0-58652fe218f9-e90e4943-6108-46e3-8a2c-a9a1c7361279\",\n\t\t\"2b8ae59e-ed8d-4837-9a9b-64eb480f982c\": \"generated-edge-simstep-336b534d-8d6a-4639-af8e-889b38f51ab1-2b8ae59e-ed8d-4837-9a9b-64eb480f982c\",\n\t\t\"839ba9f6-8a34-4919-a04a-13fba1795c61\": \"generated-edge-simstep-4f73f0fe-b390-4fe1-a354-eb0857835126-839ba9f6-8a34-4919-a04a-13fba1795c61\",\n\t\t\"42d3bc70-701a-4be0-96b4-d6c2f0519b49\": \"generated-edge-simstep-65da1a9e-041c-4656-9c5b-0a92b761a9be-42d3bc70-701a-4be0-96b4-d6c2f0519b49\",\n\t\t\"6c5b028c-356c-43c8-a35a-b47448cd8695\": \"generated-edge-simstep-2c1bdec8-d0e6-4163-a99c-f27899b987c5-6c5b028c-356c-43c8-a35a-b47448cd8695\",\n\t\t\"74b0dd89-9fea-4219-af1f-9571316a9d5a\": \"generated-edge-simstep-9405dce1-0565-4dfa-9539-a048472acda9-74b0dd89-9fea-4219-af1f-9571316a9d5a\",\n\t\t\"e2f99143-54b7-44dc-b566-1c2fb901bd16\": \"server/src/db/v2\",\n\t\t\"043d3dac-d4bb-449b-a3a7-270d53b66dac\": \"client/src/Pages/v1/PageSpeed\",\n\t\t\"7ef79284-534a-466f-a1f1-4e3a2f56be9d\": \"server/src/service/v2/business\",\n\t\t\"b53384d7-b989-4ac7-bd68-1c3621174ef4\": \"server/src/db/v2/models\",\n\t\t\"414c500b-7b68-42ba-8110-e855efbee750\": \"client/src/Pages/v1/PageSpeed/Create\",\n\t\t\"581b4919-8b0c-4f0d-ae67-ad6de11d8c8b\": \"client/src/Pages/v1/PageSpeed/Details\",\n\t\t\"50aeed0b-bc13-43f7-bb15-cb1b12b2caa7\": \"server/src/service/v2/infrastructure/NetworkService.ts\",\n\t\t\"f0ebd5da-21bb-4d96-8ff9-ca10409acc80\": \"server/src/service/v2/business/CheckService.ts\",\n\t\t\"7a3824cd-24c8-4b32-8b1d-e0bf357262c4\": \"server/src/service/v2/business/MonitorService.ts\",\n\t\t\"64e3bb0a-67f5-4269-9e7d-94fe91ac78fc\": \"server/src/db/v2/models/checks\",\n\t\t\"5ffe0baa-054a-4e5b-8b29-1254f07ea975\": \"client/src/Pages/v1/PageSpeed/Create/index.jsx\",\n\t\t\"c4a7bb58-1d9c-4690-b6b8-460c1cc33702\": \"client/src/Pages/v1/PageSpeed/Details/index.jsx\",\n\t\t\"1425ec43-f0f4-4c8b-a140-176c079219d6\": \"server/src/db/v2/models/checks/Check.ts\",\n\t\t\"0622b212-3a4a-484d-9b7a-125864d785cd\": \"client/src/Pages/v1/PageSpeed/Create/index.jsx-simstep-b0cc6e6a-961e-4ea9-aa8a-6bfa44d6ba12\",\n\t\t\"6527fb47-157e-4bba-9aed-adde061c5689\": \"server/src/service/v2/infrastructure/NetworkService.ts-simstep-53968267-0c6e-42f4-88b3-cd90f44532ae\",\n\t\t\"f89cbd87-c961-4f8b-92b6-714da57718d5\": \"server/src/service/v2/business/CheckService.ts-simstep-01206383-2db8-4b18-84d0-be2a0289c196\",\n\t\t\"ca6ee27b-1fbf-49de-978a-d6de259cc3d5\": \"server/src/service/v2/business/MonitorService.ts-simstep-5616ac6d-c281-4879-82f1-6590c721c8f7\",\n\t\t\"9ef9e218-4742-487a-9a88-5c70e788ccdc\": \"client/src/Pages/v1/PageSpeed/Details/index.jsx-simstep-0ec0eb06-05eb-4204-b077-9e47eb2cc316\",\n\t\t\"b8e83b0a-69ff-4c34-a7fe-cb8c9ba85438\": \"generated-edge-simstep-f8df1cad-6051-466e-a13e-47d710ba1c14-b8e83b0a-69ff-4c34-a7fe-cb8c9ba85438\",\n\t\t\"0d3c8091-3d91-4e42-9b46-7e35ed726a7a\": \"generated-edge-simstep-0b380571-3896-4365-b5dc-187494f02e0d-0d3c8091-3d91-4e42-9b46-7e35ed726a7a\",\n\t\t\"27c7191b-80a2-475b-9371-e106108aff1c\": \"generated-edge-simstep-a629a102-0df1-4798-a7a2-45c8f6cdad29-27c7191b-80a2-475b-9371-e106108aff1c\",\n\t\t\"7be432cd-2587-4eab-abdc-f7b9c1923597\": \"generated-edge-simstep-4ed43eaf-fa8f-4fce-af87-8a5f74dd5c08-7be432cd-2587-4eab-abdc-f7b9c1923597\",\n\t\t\"fe47576c-c186-4950-82a5-b2fd24eb2561\": \"server/src/config\",\n\t\t\"cb53d612-9b89-47da-911c-165d0382a7d8\": \"server/src/config/routes.js\",\n\t\t\"8021b55d-2d3a-4416-b598-e134e76c9434\": \"client/src/Pages/v1/Maintenance\",\n\t\t\"5f21f109-1967-416f-a649-9b48e78b90f6\": \"server/src/routes/v1/maintenanceWindowRoute.js\",\n\t\t\"a0cae18c-3c0e-40d3-ab03-eef7eace65d6\": \"server/src/controllers/v1/maintenanceWindowController.js\",\n\t\t\"6f7119ac-d65a-4fdf-a6f2-31052e0f5549\": \"client/src/Pages/v1/Maintenance/CreateMaintenance\",\n\t\t\"1eae6263-aaa2-4206-b92e-1e67f529c1c9\": \"client/src/Pages/v1/Maintenance/index.jsx\",\n\t\t\"5ad4d33f-0932-479c-bb57-22ce6405758f\": \"client/src/Pages/v1/Maintenance/MaintenanceTable\",\n\t\t\"26b8daff-aa48-4baa-9d6c-05f771bf0990\": \"server/src/service/v1/business/maintenanceWindowService.js\",\n\t\t\"95ed6c41-ebeb-4c08-98c3-bab8b426789e\": \"server/src/db/v1/modules/maintenanceWindowModule.js\",\n\t\t\"92c244d2-e6a7-4804-a643-1e8d36baf9c6\": \"client/src/Pages/v1/Maintenance/CreateMaintenance/index.jsx\",\n\t\t\"015a17fc-3fcf-45e0-8936-19f5e2ca86a3\": \"client/src/Pages/v1/Maintenance/CreateMaintenance/hooks\",\n\t\t\"e7ec5ca9-6d25-4bf2-9695-639556f7d141\": \"client/src/Pages/v1/Maintenance/MaintenanceTable/index.jsx\",\n\t\t\"6ad0396e-9b38-4f5d-9ad9-6c9fcb4434f4\": \"client/src/Pages/v1/Maintenance/CreateMaintenance/hooks/useMaintenanceActions.jsx\",\n\t\t\"20335f29-a2ac-4e0c-aba6-28707748ecd4\": \"client/src/Pages/v1/Maintenance/CreateMaintenance/index.jsx-simstep-2401ef7a-8d8e-4056-868a-547ab213daf1\",\n\t\t\"5bdfdfa4-5d93-49fa-b05c-905813e6cf9d\": \"client/src/Pages/v1/Maintenance/CreateMaintenance/hooks/useMaintenanceActions.jsx-simstep-5e0d7085-099b-478a-afaa-47ad4dd07043\",\n\t\t\"a391e8ea-9dbe-4fe4-90df-bf475d8b7ef8\": \"server/src/config/routes.js-simstep-3e93ef65-8e2c-405b-8dc1-56d8e93937b3\",\n\t\t\"0fae6e75-38ea-444d-a1bf-0f820ba443b9\": \"server/src/controllers/v1/maintenanceWindowController.js-simstep-95fc1919-339d-4659-98cb-3dc50f662075\",\n\t\t\"560d268b-ef0f-4cd2-bcfe-9dc0a0e2ce6f\": \"server/src/service/v1/business/maintenanceWindowService.js-simstep-6e2cf739-1514-4c37-9874-10b68a47010e\",\n\t\t\"3890b98d-a133-4279-a961-5d2facc6a17a\": \"server/src/db/v1/modules/maintenanceWindowModule.js-simstep-a3c47fd4-c701-46c2-9aff-94a667b3e368\",\n\t\t\"a5a84b08-8c70-4023-8d08-b74e23aab4d7\": \"client/src/Pages/v1/Maintenance/CreateMaintenance/index.jsx-simstep-ebe8fd52-f2a1-4a98-a71b-b04d6f4cdadc\",\n\t\t\"d145bb4c-e1e0-473a-b6bc-decc932b738b\": \"client/src/Pages/v1/Maintenance/index.jsx-simstep-82b5ea14-bb00-4511-aba4-76196029fd81\",\n\t\t\"c35a065c-2808-402c-877e-9055d956ce0d\": \"server/src/controllers/v1/maintenanceWindowController.js-simstep-1251da83-5949-4e24-a1d2-fc74ff785aa9\",\n\t\t\"27d9160a-4f8d-4dff-a09b-1678bc28cf2c\": \"server/src/db/v1/modules/maintenanceWindowModule.js-simstep-9bfbae5a-f487-40ef-86f5-04a1cc3c7662\",\n\t\t\"970e2002-7c0e-40ef-80d8-e5e6d0a60735\": \"client/src/Pages/v1/Maintenance/MaintenanceTable/index.jsx-simstep-acf97639-e291-4ca6-81a6-d0487397f42a\",\n\t\t\"23630a1f-7452-4373-a864-7ec7821137f2\": \"server/src/service/v1/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.js-simstep-a47affaf-b952-46d6-9709-6120a77690e1\",\n\t\t\"fc78b5b6-7fad-4f8f-a5a3-c7c38931daba\": \"server/src/service/v1/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.js-simstep-2127e749-80b4-499a-ae14-8dc2dcc9db9b\",\n\t\t\"0fe32416-db43-49b9-9438-3796ba1a0add\": \"server/src/service/v1/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.js-simstep-6ba6b9d1-5fc3-454e-8744-2022b5192ed9\",\n\t\t\"01e042c3-40b4-416a-8d9e-6d6fd323d60b\": \"server/src/service/v1/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.js-simstep-e59fe64e-f06b-4855-b631-923bb5a68540\",\n\t\t\"d3bdc6ff-875e-472e-88c8-eb10b20c526e\": \"generated-edge-simstep-f881435b-3bc2-453d-b6bf-56ad3a12f120-d3bdc6ff-875e-472e-88c8-eb10b20c526e\",\n\t\t\"fd5e4447-123b-4b2d-8bce-1d1ae7cb00af\": \"generated-edge-simstep-0660b48b-139f-4ecf-b7d9-f12f544e0ab5-fd5e4447-123b-4b2d-8bce-1d1ae7cb00af\",\n\t\t\"e2588541-3ffc-47c6-8f8a-41d30ea7fc72\": \"generated-edge-simstep-e4cc5ce8-6da9-4281-9204-29c061ab13ce-e2588541-3ffc-47c6-8f8a-41d30ea7fc72\",\n\t\t\"e1d59cf6-0d96-4e0a-ad17-2a7984a9157f\": \"generated-edge-simstep-c3d1a95c-e93d-499a-8830-a6d870902414-e1d59cf6-0d96-4e0a-ad17-2a7984a9157f\",\n\t\t\"12d0ab8a-392f-48fa-9efa-06ffe1f3a252\": \"generated-edge-simstep-80aed28e-68b6-47bf-8bc9-ededb4824066-12d0ab8a-392f-48fa-9efa-06ffe1f3a252\",\n\t\t\"fcf4eef4-394c-4872-9124-f7a0b32cdc3b\": \"generated-edge-simstep-69fdc2a9-837f-466c-9562-a12319019580-fcf4eef4-394c-4872-9124-f7a0b32cdc3b\",\n\t\t\"7f921125-500f-4902-abc3-936ecac033d8\": \"generated-edge-simstep-7e20cd6c-d24e-4540-86d6-d6a9fa087314-7f921125-500f-4902-abc3-936ecac033d8\",\n\t\t\"c3127c74-43f1-42d7-8da6-b0a494c3658f\": \"generated-edge-simstep-feb8bd4f-339f-4132-a709-89c63c4efa9c-c3127c74-43f1-42d7-8da6-b0a494c3658f\",\n\t\t\"6c9979cd-1cc1-4227-b535-2ec3a10ca27e\": \"generated-edge-simstep-eda86dca-dea6-4671-a079-7d212f4f18c4-6c9979cd-1cc1-4227-b535-2ec3a10ca27e\",\n\t\t\"c99291bb-7316-440e-9a7f-323ee39e26b8\": \"generated-edge-simstep-87583096-f1ec-4160-ae52-5238f32ed0ab-c99291bb-7316-440e-9a7f-323ee39e26b8\",\n\t\t\"8a13e585-2310-420b-9e92-211b6d65f201\": \"generated-edge-simstep-e6542e14-556d-482a-8c35-f7b03997be49-8a13e585-2310-420b-9e92-211b6d65f201\",\n\t\t\"40f4d9df-4c0f-4384-901c-8d7117e3b538\": \"generated-edge-simstep-a715d98f-60bf-4f32-aae6-21ee4e09f4da-40f4d9df-4c0f-4384-901c-8d7117e3b538\",\n\t\t\"a968db5d-8f6d-4fd7-9df0-8b332b521703\": \"server/src/middleware\",\n\t\t\"09082f73-e215-465f-9206-0a963fb4c7cb\": \"server/src/middleware/v1\",\n\t\t\"3cad7666-0d1a-4e31-b6ca-70d9c3a46b19\": \"client/src/Pages/v1/Account\",\n\t\t\"9edafb8a-3661-4a7e-8510-a47f3cbc7564\": \"server/src/routes/v1/inviteRoute.js\",\n\t\t\"001fa2e4-eadd-4474-b2ec-79d7ea43465f\": \"server/src/middleware/v1/isAllowed.js\",\n\t\t\"6a186805-9d50-4bc3-9d56-e627a7ec2eb8\": \"server/src/controllers/v1/inviteController.js\",\n\t\t\"33960806-1b9e-4d61-a163-e4bebf82d87a\": \"client/src/Pages/v1/Account/index.jsx\",\n\t\t\"425a4c15-043f-4d05-8832-da00e18f97b9\": \"client/src/Pages/v1/Account/components\",\n\t\t\"570278b7-9b72-4299-9fd9-46b253b48e9b\": \"server/src/service/v1/business/inviteService.js\",\n\t\t\"08853f8a-f596-4df0-9190-dad04f54caef\": \"server/src/db/v1/modules/inviteModule.js\",\n\t\t\"1145f351-2257-411d-86f7-30bf8c26ad68\": \"client/src/Pages/v1/Account/components/TeamPanel.jsx\",\n\t\t\"3de2d413-5e9b-49f4-9409-74be32c52e0f\": \"client/src/Pages/v1/Account/index.jsx-simstep-2d5a952a-ce62-4948-9309-96b28ad74e59\",\n\t\t\"b27f1bba-c655-40c6-a1dc-71e78c590c92\": \"client/src/Pages/v1/Account/components/TeamPanel.jsx-simstep-eebaca25-d588-49c4-a35c-9abc82fde580\",\n\t\t\"8b3cb6c2-ed57-4510-be15-decb8e3c89e1\": \"server/src/middleware/v1/isAllowed.js-simstep-50dd7316-7d01-43f7-9036-d97d51a9c178\",\n\t\t\"ae858158-8db6-4917-8fda-0966a953f6ed\": \"server/src/service/v1/business/inviteService.js-simstep-55fe9963-30d2-47f8-859f-b485a77064c4\",\n\t\t\"a7be2d0b-0227-4228-a0a6-074f7324fd89\": \"server/src/service/v1/business/inviteService.js-simstep-7d1f86f2-c8d5-48fb-a8c1-b337dc56271f\",\n\t\t\"02d87257-883c-4822-a421-823c983532ec\": \"client/src/Pages/v1/Account/components/TeamPanel.jsx-simstep-700f35e0-b39d-417c-b0a8-0612feade977\",\n\t\t\"c441312f-f3c6-48c6-b1b9-7c12749d91bb\": \"generated-edge-simstep-10f80ada-2d0a-4e98-bd5d-057e7d4fe6de-c441312f-f3c6-48c6-b1b9-7c12749d91bb\",\n\t\t\"3530244f-2689-444e-bcbf-611db2e3c000\": \"generated-edge-simstep-16d87608-4458-430c-b459-cd9b1d413fa6-3530244f-2689-444e-bcbf-611db2e3c000\",\n\t\t\"2ee1c4e8-90fb-4470-ad9f-6ffed5420853\": \"generated-edge-simstep-6c024d4c-178b-45fc-8bca-4fc6c00549a4-2ee1c4e8-90fb-4470-ad9f-6ffed5420853\",\n\t\t\"bdd52e6f-ddf7-4966-b3af-957f9553082f\": \"generated-edge-simstep-c796f8ad-d548-45f3-8d62-67f59c6c1aa4-bdd52e6f-ddf7-4966-b3af-957f9553082f\",\n\t\t\"52732a37-82b8-40a7-b12d-dc1b82380b2d\": \"generated-edge-simstep-6ba5094d-d1e6-4ec3-8917-28cdb30f2ef9-52732a37-82b8-40a7-b12d-dc1b82380b2d\",\n\t\t\"56dae13e-5735-4089-a9a4-e18be315aff7\": \"client/src/Pages/v1/Uptime/BulkImport\",\n\t\t\"29b6ad3c-9538-47bc-8796-aab942dc4b71\": \"client/src/Pages/v1/Uptime/BulkImport/index.jsx\",\n\t\t\"cd84476a-1c8b-4781-811f-58fb9944365b\": \"client/src/Pages/v1/Uptime/BulkImport/Upload.jsx\",\n\t\t\"c4caeba8-ed9a-4cbc-9888-38cc8ca55362\": \"client/src/Routes/index.jsx-simstep-a29da01e-8c5a-4e6d-8d3c-e49af528e4fa\",\n\t\t\"6f1948fa-e84a-4f8e-8f3b-8f24c511b3d8\": \"client/src/Pages/v1/Uptime/BulkImport/Upload.jsx-simstep-bbd04d55-fc6a-4ba8-bcde-5a4dc263d6eb\",\n\t\t\"dd2f9356-fad3-47d4-81d5-a5e038298e2b\": \"client/src/Pages/v1/Uptime/BulkImport/index.jsx-simstep-0139fcaa-eb46-4176-b7bd-1cb15e7f1f4c\",\n\t\t\"5967e576-f542-4c0b-a3f4-9446ae992721\": \"client/src/Utils/NetworkService.js-simstep-2fc087b3-033d-4cf5-81f2-e35b99a14bce\",\n\t\t\"c1ac3c26-996a-43ef-9c34-4c2776188784\": \"server/src/routes/v1/monitorRoute.js-simstep-07bf3d83-047d-4e51-9f96-8c9c64848500\",\n\t\t\"0e520a6d-34bf-467b-a894-e73979364478\": \"server/src/controllers/v1/monitorController.js-simstep-a3799570-64bf-481e-9ffe-31dbad8a36e4\",\n\t\t\"6139e487-1dd5-405a-ba7d-ededec4b282e\": \"server/src/service/v1/business/monitorService.js-simstep-2c7c3082-e4b6-4525-860f-2ffcd9e86db1\",\n\t\t\"d9d519af-5c4d-4494-929e-a869581c1dc4\": \"server/src/db/v1/modules/monitorModule.js-simstep-70f18c21-2918-402e-9c35-1bdce8bc82d4\",\n\t\t\"1e1d975f-7f0f-4132-bd71-2563b35e99b3\": \"server/src/service/v1/business/monitorService.js-simstep-66fbf913-e662-4bd9-ada6-077be9e37f07\",\n\t\t\"72b55fa1-d944-4e46-ac98-f6a6cb201afa\": \"server/src/controllers/v1/monitorController.js-simstep-f5377571-156f-4c5c-8bab-b6dacdf0fea6\",\n\t\t\"ae3b7e23-ed64-40aa-9760-389f0a869f8d\": \"client/src/Pages/v1/Uptime/BulkImport/index.jsx-simstep-72b3f16d-290d-4a61-8748-2ad90d63ec68\",\n\t\t\"26d76516-fd7e-4ae8-956a-d077de4257fa\": \"server/src/routes/v1/monitorRoute.js-simstep-63d8d81f-f436-4594-a6eb-8c0fd2110bc1\",\n\t\t\"a3106388-6a3d-4b68-a3fc-3761a0d54f98\": \"server/src/controllers/v1/monitorController.js-simstep-d9db3f40-8add-4551-9323-274348b9800f\",\n\t\t\"ab9cb862-0ac7-45a3-9888-f64e87bdda54\": \"server/src/service/v1/business/monitorService.js-simstep-85cd1d5d-7ffb-49c5-aacb-907048003fc5\",\n\t\t\"f151f89d-6399-48f0-aecd-5eb1572b48cc\": \"server/src/controllers/v1/monitorController.js-simstep-256095b8-5e3a-4c20-abd9-be9e6a9d0bad\",\n\t\t\"d8877474-7203-484f-bd47-fc69e3c7c482\": \"server/src/controllers/v1/monitorController.js-simstep-60abdb27-4078-4678-a010-0f6938d4be48\",\n\t\t\"c9a012bc-d53f-494f-82f2-1ee3f40ce646\": \"generated-edge-simstep-ef0bbcff-9535-4c0e-a5ca-96c457f89139-c9a012bc-d53f-494f-82f2-1ee3f40ce646\",\n\t\t\"e03a8ce2-c2cd-4147-8bab-63d6c2cf0a48\": \"generated-edge-simstep-610120d2-0521-4444-b245-feb97239a389-e03a8ce2-c2cd-4147-8bab-63d6c2cf0a48\",\n\t\t\"b8c0292d-afbb-4648-b484-1c27be96d52f\": \"generated-edge-simstep-a365d018-e80c-419c-80b3-5ffc8f14dc5c-b8c0292d-afbb-4648-b484-1c27be96d52f\",\n\t\t\"23715cce-c83a-44c0-9853-4c95b85e5ecd\": \"generated-edge-simstep-e6dec1dc-33cb-4669-a3b0-7a3c0b233185-23715cce-c83a-44c0-9853-4c95b85e5ecd\",\n\t\t\"20d0e690-a569-4c6f-8238-916cac920553\": \"generated-edge-simstep-c53d3f62-73fe-4fad-9835-ef2c8cf52894-20d0e690-a569-4c6f-8238-916cac920553\",\n\t\t\"7292bf6e-431d-4a9d-94ce-2bcfabcaa79d\": \"generated-edge-simstep-6038422c-ab83-4fc6-a58b-c75734276118-7292bf6e-431d-4a9d-94ce-2bcfabcaa79d\",\n\t\t\"b55a0dc6-f596-4e5f-9265-63588b46b519\": \"generated-edge-simstep-0115fb69-4959-4b32-bd90-1dcd3c2231f6-b55a0dc6-f596-4e5f-9265-63588b46b519\",\n\t\t\"f27c60ef-fb40-43e2-9750-c2617bdeaf43\": \"generated-edge-simstep-2ee7bd94-d131-4dd8-bdf8-68433d00472d-f27c60ef-fb40-43e2-9750-c2617bdeaf43\",\n\t\t\"c449f81a-d6af-4f7a-b2d8-050a9a9ee0f9\": \"generated-edge-simstep-94d5772d-3f46-4d43-b764-3493db5c4971-c449f81a-d6af-4f7a-b2d8-050a9a9ee0f9\",\n\t\t\"926a330c-a9c5-4983-a4b5-70359813e49a\": \"generated-edge-simstep-c60a3adb-dd81-41b0-95e4-a0a6d23f9dd0-926a330c-a9c5-4983-a4b5-70359813e49a\",\n\t\t\"febea87e-5033-479c-ba7a-eb35d98db899\": \"generated-edge-simstep-53cebb8e-cf45-49eb-a7d3-98fd87af21b4-febea87e-5033-479c-ba7a-eb35d98db899\",\n\t\t\"3e0f0966-5c2f-41af-9bcc-e8f615e03a00\": \"generated-edge-simstep-74e95fb5-863c-4137-a41b-d7a32efa04a5-3e0f0966-5c2f-41af-9bcc-e8f615e03a00\",\n\t\t\"ad300b1c-6748-40f9-a7c9-5895e0915991\": \"generated-edge-simstep-4deb5e47-2ac4-4638-9ee6-48295d027bcd-ad300b1c-6748-40f9-a7c9-5895e0915991\",\n\t\t\"3dfb432a-2ce4-4f92-98ce-5d114b5f7f03\": \"generated-edge-simstep-605f4cbd-1f7f-4e89-b028-f18737ac7fb1-3dfb432a-2ce4-4f92-98ce-5d114b5f7f03\",\n\t\t\"50f77798-f41b-4f5b-b096-7afc921a0419\": \"client/src/Pages/v1/Settings\",\n\t\t\"1716ec41-8b42-4386-9850-55b8a607638e\": \"client/src/Pages/v1/Logs\",\n\t\t\"8ee5d524-e61d-4e39-a729-babf54929def\": \"client/src/Hooks/v1/settingsHooks.js\",\n\t\t\"a1fea5b0-fb7c-4189-9484-9d3312660767\": \"server/src/controllers/v1/settingsController.js\",\n\t\t\"5882419e-8a92-4edd-a71a-1252983f9af7\": \"server/src/controllers/v1/diagnosticController.js\",\n\t\t\"d4b34195-7e1e-47a0-9303-603987c81f95\": \"client/src/Pages/v1/Settings/index.jsx\",\n\t\t\"d8aa5b9e-f2a7-44c8-8813-d79c3f3238ee\": \"client/src/Pages/v1/Settings/SettingsEmail.jsx\",\n\t\t\"e0cb598c-e300-4fd3-8554-db7ffd6201f1\": \"client/src/Pages/v1/Logs/Diagnostics\",\n\t\t\"643b26c1-3bfb-4c41-8179-96dfc237d99e\": \"server/src/service/v1/business/diagnosticService.js\",\n\t\t\"87e0e2ea-4a6d-460d-95bc-31e2efd9c9cf\": \"client/src/Pages/v1/Logs/Diagnostics/index.jsx\",\n\t\t\"97908daf-d071-4df5-8366-1f5f4d8d534a\": \"client/src/Pages/v1/Settings/index.jsx-simstep-64e9f1af-13b7-4361-a2a9-3f45760e316d\",\n\t\t\"83596bd1-dfca-4196-b52e-955f6824fafb\": \"server/src/controllers/v1/settingsController.js-simstep-441b0c45-5f27-478d-8ca8-58fbd5f460ea\",\n\t\t\"09cb194a-0ea4-46e2-b32b-36b62fa87f40\": \"client/src/Pages/v1/Settings/SettingsEmail.jsx-simstep-ae5c5146-4dbb-4612-9d23-086e57f72474\",\n\t\t\"1b2cf182-9ee3-4218-a7ec-b74e427ccddf\": \"client/src/Hooks/v1/settingsHooks.js-simstep-d7098072-9a83-4369-8176-9646ba34e186\",\n\t\t\"cce3b9c8-f3b7-434b-b3c6-d8d164714f86\": \"server/src/controllers/v1/settingsController.js-simstep-7632e8d2-4086-4169-ae3f-bfbf8d657987\",\n\t\t\"fff5dde4-8eb8-4c21-9c6d-0845a9749ff3\": \"client/src/Hooks/v1/settingsHooks.js-simstep-a157bd07-b969-44f8-914c-3d8393c1605a\",\n\t\t\"704e2ec8-9f2f-47e5-852f-c6ada67a02e0\": \"client/src/Pages/v1/Logs/Diagnostics/index.jsx-simstep-a9b24b5f-534b-4baf-a185-bac7c32a1c42\",\n\t\t\"09f07e80-185e-4547-aab4-edaf8ae7501e\": \"server/src/service/v1/business/diagnosticService.js-simstep-8fb704ca-67d9-437c-90d8-01302634d568\",\n\t\t\"4b418736-6b72-47e0-917a-d86d4bed9ecd\": \"client/src/Pages/v1/Logs/Diagnostics/index.jsx-simstep-e6c94f52-a599-4568-a06f-2db18f963817\",\n\t\t\"f6d80f09-ae83-4c95-aba0-4efffeda38e0\": \"generated-edge-simstep-dca4a33c-b666-47b8-896b-370ed9d6f9c5-f6d80f09-ae83-4c95-aba0-4efffeda38e0\",\n\t\t\"195ad532-9858-493e-876a-6ec457811d1d\": \"generated-edge-simstep-aacc9302-6ca8-45c6-acb8-956d8d0242c2-195ad532-9858-493e-876a-6ec457811d1d\",\n\t\t\"8c107d79-f796-49eb-ab88-f553dd6f9d95\": \"generated-edge-simstep-e7e82a97-1409-4bc5-ae27-b4ff5ba746df-8c107d79-f796-49eb-ab88-f553dd6f9d95\",\n\t\t\"ce3ed3ba-a35b-4881-8dfd-f8425b9bf812\": \"generated-edge-simstep-383387e5-4623-44ab-b2c4-d9ea046f4547-ce3ed3ba-a35b-4881-8dfd-f8425b9bf812\",\n\t\t\"fbe9b160-307e-4f51-8f72-713fda5373c8\": \"generated-edge-simstep-0afcde35-7d51-4939-aae8-bac5ac83c49d-fbe9b160-307e-4f51-8f72-713fda5373c8\",\n\t\t\"499dfe1f-77d4-4b26-a12c-45240691109e\": \"generated-edge-simstep-23b8ad7d-8967-4e48-814c-1a7bf5b4dfac-499dfe1f-77d4-4b26-a12c-45240691109e\",\n\t\t\"d0f92604-a6fa-4d85-9716-ea8f32db78e0\": \"generated-edge-simstep-44a4372f-a903-4c43-a9a5-c7549c875e11-d0f92604-a6fa-4d85-9716-ea8f32db78e0\"\n\t}\n}"
  },
  {
    "path": "LICENSE",
    "content": "                    GNU AFFERO GENERAL PUBLIC LICENSE\n                       Version 3, 19 November 2007\n\n Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n                            Preamble\n\n  The GNU Affero General Public License is a free, copyleft license for\nsoftware and other kinds of works, specifically designed to ensure\ncooperation with the community in the case of network server software.\n\n  The licenses for most software and other practical works are designed\nto take away your freedom to share and change the works.  By contrast,\nour General Public Licenses are intended to guarantee your freedom to\nshare and change all versions of a program--to make sure it remains free\nsoftware for all its users.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthem if you wish), that you receive source code or can get it if you\nwant it, that you can change the software or use pieces of it in new\nfree programs, and that you know you can do these things.\n\n  Developers that use our General Public Licenses protect your rights\nwith two steps: (1) assert copyright on the software, and (2) offer\nyou this License which gives you legal permission to copy, distribute\nand/or modify the software.\n\n  A secondary benefit of defending all users' freedom is that\nimprovements made in alternate versions of the program, if they\nreceive widespread use, become available for other developers to\nincorporate.  Many developers of free software are heartened and\nencouraged by the resulting cooperation.  However, in the case of\nsoftware used on network servers, this result may fail to come about.\nThe GNU General Public License permits making a modified version and\nletting the public access it on a server without ever releasing its\nsource code to the public.\n\n  The GNU Affero General Public License is designed specifically to\nensure that, in such cases, the modified source code becomes available\nto the community.  It requires the operator of a network server to\nprovide the source code of the modified version running there to the\nusers of that server.  Therefore, public use of a modified version, on\na publicly accessible server, gives the public access to the source\ncode of the modified version.\n\n  An older license, called the Affero General Public License and\npublished by Affero, was designed to accomplish similar goals.  This is\na different license, not a version of the Affero GPL, but Affero has\nreleased a new version of the Affero GPL which permits relicensing under\nthis license.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\n                       TERMS AND CONDITIONS\n\n  0. Definitions.\n\n  \"This License\" refers to version 3 of the GNU Affero General Public License.\n\n  \"Copyright\" also means copyright-like laws that apply to other kinds of\nworks, such as semiconductor masks.\n\n  \"The Program\" refers to any copyrightable work licensed under this\nLicense.  Each licensee is addressed as \"you\".  \"Licensees\" and\n\"recipients\" may be individuals or organizations.\n\n  To \"modify\" a work means to copy from or adapt all or part of the work\nin a fashion requiring copyright permission, other than the making of an\nexact copy.  The resulting work is called a \"modified version\" of the\nearlier work or a work \"based on\" the earlier work.\n\n  A \"covered work\" means either the unmodified Program or a work based\non the Program.\n\n  To \"propagate\" a work means to do anything with it that, without\npermission, would make you directly or secondarily liable for\ninfringement under applicable copyright law, except executing it on a\ncomputer or modifying a private copy.  Propagation includes copying,\ndistribution (with or without modification), making available to the\npublic, and in some countries other activities as well.\n\n  To \"convey\" a work means any kind of propagation that enables other\nparties to make or receive copies.  Mere interaction with a user through\na computer network, with no transfer of a copy, is not conveying.\n\n  An interactive user interface displays \"Appropriate Legal Notices\"\nto the extent that it includes a convenient and prominently visible\nfeature that (1) displays an appropriate copyright notice, and (2)\ntells the user that there is no warranty for the work (except to the\nextent that warranties are provided), that licensees may convey the\nwork under this License, and how to view a copy of this License.  If\nthe interface presents a list of user commands or options, such as a\nmenu, a prominent item in the list meets this criterion.\n\n  1. Source Code.\n\n  The \"source code\" for a work means the preferred form of the work\nfor making modifications to it.  \"Object code\" means any non-source\nform of a work.\n\n  A \"Standard Interface\" means an interface that either is an official\nstandard defined by a recognized standards body, or, in the case of\ninterfaces specified for a particular programming language, one that\nis widely used among developers working in that language.\n\n  The \"System Libraries\" of an executable work include anything, other\nthan the work as a whole, that (a) is included in the normal form of\npackaging a Major Component, but which is not part of that Major\nComponent, and (b) serves only to enable use of the work with that\nMajor Component, or to implement a Standard Interface for which an\nimplementation is available to the public in source code form.  A\n\"Major Component\", in this context, means a major essential component\n(kernel, window system, and so on) of the specific operating system\n(if any) on which the executable work runs, or a compiler used to\nproduce the work, or an object code interpreter used to run it.\n\n  The \"Corresponding Source\" for a work in object code form means all\nthe source code needed to generate, install, and (for an executable\nwork) run the object code and to modify the work, including scripts to\ncontrol those activities.  However, it does not include the work's\nSystem Libraries, or general-purpose tools or generally available free\nprograms which are used unmodified in performing those activities but\nwhich are not part of the work.  For example, Corresponding Source\nincludes interface definition files associated with source files for\nthe work, and the source code for shared libraries and dynamically\nlinked subprograms that the work is specifically designed to require,\nsuch as by intimate data communication or control flow between those\nsubprograms and other parts of the work.\n\n  The Corresponding Source need not include anything that users\ncan regenerate automatically from other parts of the Corresponding\nSource.\n\n  The Corresponding Source for a work in source code form is that\nsame work.\n\n  2. Basic Permissions.\n\n  All rights granted under this License are granted for the term of\ncopyright on the Program, and are irrevocable provided the stated\nconditions are met.  This License explicitly affirms your unlimited\npermission to run the unmodified Program.  The output from running a\ncovered work is covered by this License only if the output, given its\ncontent, constitutes a covered work.  This License acknowledges your\nrights of fair use or other equivalent, as provided by copyright law.\n\n  You may make, run and propagate covered works that you do not\nconvey, without conditions so long as your license otherwise remains\nin force.  You may convey covered works to others for the sole purpose\nof having them make modifications exclusively for you, or provide you\nwith facilities for running those works, provided that you comply with\nthe terms of this License in conveying all material for which you do\nnot control copyright.  Those thus making or running the covered works\nfor you must do so exclusively on your behalf, under your direction\nand control, on terms that prohibit them from making any copies of\nyour copyrighted material outside their relationship with you.\n\n  Conveying under any other circumstances is permitted solely under\nthe conditions stated below.  Sublicensing is not allowed; section 10\nmakes it unnecessary.\n\n  3. Protecting Users' Legal Rights From Anti-Circumvention Law.\n\n  No covered work shall be deemed part of an effective technological\nmeasure under any applicable law fulfilling obligations under article\n11 of the WIPO copyright treaty adopted on 20 December 1996, or\nsimilar laws prohibiting or restricting circumvention of such\nmeasures.\n\n  When you convey a covered work, you waive any legal power to forbid\ncircumvention of technological measures to the extent such circumvention\nis effected by exercising rights under this License with respect to\nthe covered work, and you disclaim any intention to limit operation or\nmodification of the work as a means of enforcing, against the work's\nusers, your or third parties' legal rights to forbid circumvention of\ntechnological measures.\n\n  4. Conveying Verbatim Copies.\n\n  You may convey verbatim copies of the Program's source code as you\nreceive it, in any medium, provided that you conspicuously and\nappropriately publish on each copy an appropriate copyright notice;\nkeep intact all notices stating that this License and any\nnon-permissive terms added in accord with section 7 apply to the code;\nkeep intact all notices of the absence of any warranty; and give all\nrecipients a copy of this License along with the Program.\n\n  You may charge any price or no price for each copy that you convey,\nand you may offer support or warranty protection for a fee.\n\n  5. Conveying Modified Source Versions.\n\n  You may convey a work based on the Program, or the modifications to\nproduce it from the Program, in the form of source code under the\nterms of section 4, provided that you also meet all of these conditions:\n\n    a) The work must carry prominent notices stating that you modified\n    it, and giving a relevant date.\n\n    b) The work must carry prominent notices stating that it is\n    released under this License and any conditions added under section\n    7.  This requirement modifies the requirement in section 4 to\n    \"keep intact all notices\".\n\n    c) You must license the entire work, as a whole, under this\n    License to anyone who comes into possession of a copy.  This\n    License will therefore apply, along with any applicable section 7\n    additional terms, to the whole of the work, and all its parts,\n    regardless of how they are packaged.  This License gives no\n    permission to license the work in any other way, but it does not\n    invalidate such permission if you have separately received it.\n\n    d) If the work has interactive user interfaces, each must display\n    Appropriate Legal Notices; however, if the Program has interactive\n    interfaces that do not display Appropriate Legal Notices, your\n    work need not make them do so.\n\n  A compilation of a covered work with other separate and independent\nworks, which are not by their nature extensions of the covered work,\nand which are not combined with it such as to form a larger program,\nin or on a volume of a storage or distribution medium, is called an\n\"aggregate\" if the compilation and its resulting copyright are not\nused to limit the access or legal rights of the compilation's users\nbeyond what the individual works permit.  Inclusion of a covered work\nin an aggregate does not cause this License to apply to the other\nparts of the aggregate.\n\n  6. Conveying Non-Source Forms.\n\n  You may convey a covered work in object code form under the terms\nof sections 4 and 5, provided that you also convey the\nmachine-readable Corresponding Source under the terms of this License,\nin one of these ways:\n\n    a) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by the\n    Corresponding Source fixed on a durable physical medium\n    customarily used for software interchange.\n\n    b) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by a\n    written offer, valid for at least three years and valid for as\n    long as you offer spare parts or customer support for that product\n    model, to give anyone who possesses the object code either (1) a\n    copy of the Corresponding Source for all the software in the\n    product that is covered by this License, on a durable physical\n    medium customarily used for software interchange, for a price no\n    more than your reasonable cost of physically performing this\n    conveying of source, or (2) access to copy the\n    Corresponding Source from a network server at no charge.\n\n    c) Convey individual copies of the object code with a copy of the\n    written offer to provide the Corresponding Source.  This\n    alternative is allowed only occasionally and noncommercially, and\n    only if you received the object code with such an offer, in accord\n    with subsection 6b.\n\n    d) Convey the object code by offering access from a designated\n    place (gratis or for a charge), and offer equivalent access to the\n    Corresponding Source in the same way through the same place at no\n    further charge.  You need not require recipients to copy the\n    Corresponding Source along with the object code.  If the place to\n    copy the object code is a network server, the Corresponding Source\n    may be on a different server (operated by you or a third party)\n    that supports equivalent copying facilities, provided you maintain\n    clear directions next to the object code saying where to find the\n    Corresponding Source.  Regardless of what server hosts the\n    Corresponding Source, you remain obligated to ensure that it is\n    available for as long as needed to satisfy these requirements.\n\n    e) Convey the object code using peer-to-peer transmission, provided\n    you inform other peers where the object code and Corresponding\n    Source of the work are being offered to the general public at no\n    charge under subsection 6d.\n\n  A separable portion of the object code, whose source code is excluded\nfrom the Corresponding Source as a System Library, need not be\nincluded in conveying the object code work.\n\n  A \"User Product\" is either (1) a \"consumer product\", which means any\ntangible personal property which is normally used for personal, family,\nor household purposes, or (2) anything designed or sold for incorporation\ninto a dwelling.  In determining whether a product is a consumer product,\ndoubtful cases shall be resolved in favor of coverage.  For a particular\nproduct received by a particular user, \"normally used\" refers to a\ntypical or common use of that class of product, regardless of the status\nof the particular user or of the way in which the particular user\nactually uses, or expects or is expected to use, the product.  A product\nis a consumer product regardless of whether the product has substantial\ncommercial, industrial or non-consumer uses, unless such uses represent\nthe only significant mode of use of the product.\n\n  \"Installation Information\" for a User Product means any methods,\nprocedures, authorization keys, or other information required to install\nand execute modified versions of a covered work in that User Product from\na modified version of its Corresponding Source.  The information must\nsuffice to ensure that the continued functioning of the modified object\ncode is in no case prevented or interfered with solely because\nmodification has been made.\n\n  If you convey an object code work under this section in, or with, or\nspecifically for use in, a User Product, and the conveying occurs as\npart of a transaction in which the right of possession and use of the\nUser Product is transferred to the recipient in perpetuity or for a\nfixed term (regardless of how the transaction is characterized), the\nCorresponding Source conveyed under this section must be accompanied\nby the Installation Information.  But this requirement does not apply\nif neither you nor any third party retains the ability to install\nmodified object code on the User Product (for example, the work has\nbeen installed in ROM).\n\n  The requirement to provide Installation Information does not include a\nrequirement to continue to provide support service, warranty, or updates\nfor a work that has been modified or installed by the recipient, or for\nthe User Product in which it has been modified or installed.  Access to a\nnetwork may be denied when the modification itself materially and\nadversely affects the operation of the network or violates the rules and\nprotocols for communication across the network.\n\n  Corresponding Source conveyed, and Installation Information provided,\nin accord with this section must be in a format that is publicly\ndocumented (and with an implementation available to the public in\nsource code form), and must require no special password or key for\nunpacking, reading or copying.\n\n  7. Additional Terms.\n\n  \"Additional permissions\" are terms that supplement the terms of this\nLicense by making exceptions from one or more of its conditions.\nAdditional permissions that are applicable to the entire Program shall\nbe treated as though they were included in this License, to the extent\nthat they are valid under applicable law.  If additional permissions\napply only to part of the Program, that part may be used separately\nunder those permissions, but the entire Program remains governed by\nthis License without regard to the additional permissions.\n\n  When you convey a copy of a covered work, you may at your option\nremove any additional permissions from that copy, or from any part of\nit.  (Additional permissions may be written to require their own\nremoval in certain cases when you modify the work.)  You may place\nadditional permissions on material, added by you to a covered work,\nfor which you have or can give appropriate copyright permission.\n\n  Notwithstanding any other provision of this License, for material you\nadd to a covered work, you may (if authorized by the copyright holders of\nthat material) supplement the terms of this License with terms:\n\n    a) Disclaiming warranty or limiting liability differently from the\n    terms of sections 15 and 16 of this License; or\n\n    b) Requiring preservation of specified reasonable legal notices or\n    author attributions in that material or in the Appropriate Legal\n    Notices displayed by works containing it; or\n\n    c) Prohibiting misrepresentation of the origin of that material, or\n    requiring that modified versions of such material be marked in\n    reasonable ways as different from the original version; or\n\n    d) Limiting the use for publicity purposes of names of licensors or\n    authors of the material; or\n\n    e) Declining to grant rights under trademark law for use of some\n    trade names, trademarks, or service marks; or\n\n    f) Requiring indemnification of licensors and authors of that\n    material by anyone who conveys the material (or modified versions of\n    it) with contractual assumptions of liability to the recipient, for\n    any liability that these contractual assumptions directly impose on\n    those licensors and authors.\n\n  All other non-permissive additional terms are considered \"further\nrestrictions\" within the meaning of section 10.  If the Program as you\nreceived it, or any part of it, contains a notice stating that it is\ngoverned by this License along with a term that is a further\nrestriction, you may remove that term.  If a license document contains\na further restriction but permits relicensing or conveying under this\nLicense, you may add to a covered work material governed by the terms\nof that license document, provided that the further restriction does\nnot survive such relicensing or conveying.\n\n  If you add terms to a covered work in accord with this section, you\nmust place, in the relevant source files, a statement of the\nadditional terms that apply to those files, or a notice indicating\nwhere to find the applicable terms.\n\n  Additional terms, permissive or non-permissive, may be stated in the\nform of a separately written license, or stated as exceptions;\nthe above requirements apply either way.\n\n  8. Termination.\n\n  You may not propagate or modify a covered work except as expressly\nprovided under this License.  Any attempt otherwise to propagate or\nmodify it is void, and will automatically terminate your rights under\nthis License (including any patent licenses granted under the third\nparagraph of section 11).\n\n  However, if you cease all violation of this License, then your\nlicense from a particular copyright holder is reinstated (a)\nprovisionally, unless and until the copyright holder explicitly and\nfinally terminates your license, and (b) permanently, if the copyright\nholder fails to notify you of the violation by some reasonable means\nprior to 60 days after the cessation.\n\n  Moreover, your license from a particular copyright holder is\nreinstated permanently if the copyright holder notifies you of the\nviolation by some reasonable means, this is the first time you have\nreceived notice of violation of this License (for any work) from that\ncopyright holder, and you cure the violation prior to 30 days after\nyour receipt of the notice.\n\n  Termination of your rights under this section does not terminate the\nlicenses of parties who have received copies or rights from you under\nthis License.  If your rights have been terminated and not permanently\nreinstated, you do not qualify to receive new licenses for the same\nmaterial under section 10.\n\n  9. Acceptance Not Required for Having Copies.\n\n  You are not required to accept this License in order to receive or\nrun a copy of the Program.  Ancillary propagation of a covered work\noccurring solely as a consequence of using peer-to-peer transmission\nto receive a copy likewise does not require acceptance.  However,\nnothing other than this License grants you permission to propagate or\nmodify any covered work.  These actions infringe copyright if you do\nnot accept this License.  Therefore, by modifying or propagating a\ncovered work, you indicate your acceptance of this License to do so.\n\n  10. Automatic Licensing of Downstream Recipients.\n\n  Each time you convey a covered work, the recipient automatically\nreceives a license from the original licensors, to run, modify and\npropagate that work, subject to this License.  You are not responsible\nfor enforcing compliance by third parties with this License.\n\n  An \"entity transaction\" is a transaction transferring control of an\norganization, or substantially all assets of one, or subdividing an\norganization, or merging organizations.  If propagation of a covered\nwork results from an entity transaction, each party to that\ntransaction who receives a copy of the work also receives whatever\nlicenses to the work the party's predecessor in interest had or could\ngive under the previous paragraph, plus a right to possession of the\nCorresponding Source of the work from the predecessor in interest, if\nthe predecessor has it or can get it with reasonable efforts.\n\n  You may not impose any further restrictions on the exercise of the\nrights granted or affirmed under this License.  For example, you may\nnot impose a license fee, royalty, or other charge for exercise of\nrights granted under this License, and you may not initiate litigation\n(including a cross-claim or counterclaim in a lawsuit) alleging that\nany patent claim is infringed by making, using, selling, offering for\nsale, or importing the Program or any portion of it.\n\n  11. Patents.\n\n  A \"contributor\" is a copyright holder who authorizes use under this\nLicense of the Program or a work on which the Program is based.  The\nwork thus licensed is called the contributor's \"contributor version\".\n\n  A contributor's \"essential patent claims\" are all patent claims\nowned or controlled by the contributor, whether already acquired or\nhereafter acquired, that would be infringed by some manner, permitted\nby this License, of making, using, or selling its contributor version,\nbut do not include claims that would be infringed only as a\nconsequence of further modification of the contributor version.  For\npurposes of this definition, \"control\" includes the right to grant\npatent sublicenses in a manner consistent with the requirements of\nthis License.\n\n  Each contributor grants you a non-exclusive, worldwide, royalty-free\npatent license under the contributor's essential patent claims, to\nmake, use, sell, offer for sale, import and otherwise run, modify and\npropagate the contents of its contributor version.\n\n  In the following three paragraphs, a \"patent license\" is any express\nagreement or commitment, however denominated, not to enforce a patent\n(such as an express permission to practice a patent or covenant not to\nsue for patent infringement).  To \"grant\" such a patent license to a\nparty means to make such an agreement or commitment not to enforce a\npatent against the party.\n\n  If you convey a covered work, knowingly relying on a patent license,\nand the Corresponding Source of the work is not available for anyone\nto copy, free of charge and under the terms of this License, through a\npublicly available network server or other readily accessible means,\nthen you must either (1) cause the Corresponding Source to be so\navailable, or (2) arrange to deprive yourself of the benefit of the\npatent license for this particular work, or (3) arrange, in a manner\nconsistent with the requirements of this License, to extend the patent\nlicense to downstream recipients.  \"Knowingly relying\" means you have\nactual knowledge that, but for the patent license, your conveying the\ncovered work in a country, or your recipient's use of the covered work\nin a country, would infringe one or more identifiable patents in that\ncountry that you have reason to believe are valid.\n\n  If, pursuant to or in connection with a single transaction or\narrangement, you convey, or propagate by procuring conveyance of, a\ncovered work, and grant a patent license to some of the parties\nreceiving the covered work authorizing them to use, propagate, modify\nor convey a specific copy of the covered work, then the patent license\nyou grant is automatically extended to all recipients of the covered\nwork and works based on it.\n\n  A patent license is \"discriminatory\" if it does not include within\nthe scope of its coverage, prohibits the exercise of, or is\nconditioned on the non-exercise of one or more of the rights that are\nspecifically granted under this License.  You may not convey a covered\nwork if you are a party to an arrangement with a third party that is\nin the business of distributing software, under which you make payment\nto the third party based on the extent of your activity of conveying\nthe work, and under which the third party grants, to any of the\nparties who would receive the covered work from you, a discriminatory\npatent license (a) in connection with copies of the covered work\nconveyed by you (or copies made from those copies), or (b) primarily\nfor and in connection with specific products or compilations that\ncontain the covered work, unless you entered into that arrangement,\nor that patent license was granted, prior to 28 March 2007.\n\n  Nothing in this License shall be construed as excluding or limiting\nany implied license or other defenses to infringement that may\notherwise be available to you under applicable patent law.\n\n  12. No Surrender of Others' Freedom.\n\n  If conditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot convey a\ncovered work so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you may\nnot convey it at all.  For example, if you agree to terms that obligate you\nto collect a royalty for further conveying from those to whom you convey\nthe Program, the only way you could satisfy both those terms and this\nLicense would be to refrain entirely from conveying the Program.\n\n  13. Remote Network Interaction; Use with the GNU General Public License.\n\n  Notwithstanding any other provision of this License, if you modify the\nProgram, your modified version must prominently offer all users\ninteracting with it remotely through a computer network (if your version\nsupports such interaction) an opportunity to receive the Corresponding\nSource of your version by providing access to the Corresponding Source\nfrom a network server at no charge, through some standard or customary\nmeans of facilitating copying of software.  This Corresponding Source\nshall include the Corresponding Source for any work covered by version 3\nof the GNU General Public License that is incorporated pursuant to the\nfollowing paragraph.\n\n  Notwithstanding any other provision of this License, you have\npermission to link or combine any covered work with a work licensed\nunder version 3 of the GNU General Public License into a single\ncombined work, and to convey the resulting work.  The terms of this\nLicense will continue to apply to the part which is the covered work,\nbut the work with which it is combined will remain governed by version\n3 of the GNU General Public License.\n\n  14. Revised Versions of this License.\n\n  The Free Software Foundation may publish revised and/or new versions of\nthe GNU Affero General Public License from time to time.  Such new versions\nwill be similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\n  Each version is given a distinguishing version number.  If the\nProgram specifies that a certain numbered version of the GNU Affero General\nPublic License \"or any later version\" applies to it, you have the\noption of following the terms and conditions either of that numbered\nversion or of any later version published by the Free Software\nFoundation.  If the Program does not specify a version number of the\nGNU Affero General Public License, you may choose any version ever published\nby the Free Software Foundation.\n\n  If the Program specifies that a proxy can decide which future\nversions of the GNU Affero General Public License can be used, that proxy's\npublic statement of acceptance of a version permanently authorizes you\nto choose that version for the Program.\n\n  Later license versions may give you additional or different\npermissions.  However, no additional obligations are imposed on any\nauthor or copyright holder as a result of your choosing to follow a\nlater version.\n\n  15. Disclaimer of Warranty.\n\n  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY\nAPPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT\nHOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY\nOF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,\nTHE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM\nIS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF\nALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n  16. Limitation of Liability.\n\n  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS\nTHE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY\nGENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE\nUSE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF\nDATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD\nPARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),\nEVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF\nSUCH DAMAGES.\n\n  17. Interpretation of Sections 15 and 16.\n\n  If the disclaimer of warranty and limitation of liability provided\nabove cannot be given local legal effect according to their terms,\nreviewing courts shall apply local law that most closely approximates\nan absolute waiver of all civil liability in connection with the\nProgram, unless a warranty or assumption of liability accompanies a\ncopy of the Program in return for a fee.\n\n                     END OF TERMS AND CONDITIONS\n\n            How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nstate the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the program's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This program is free software: you can redistribute it and/or modify\n    it under the terms of the GNU Affero General Public License as published\n    by the Free Software Foundation, either version 3 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU Affero General Public License for more details.\n\n    You should have received a copy of the GNU Affero General Public License\n    along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nAlso add information on how to contact you by electronic and paper mail.\n\n  If your software can interact with users remotely through a computer\nnetwork, you should also make sure that it provides a way for users to\nget its source.  For example, if your program is a web application, its\ninterface could display a \"Source\" link that leads users to an archive\nof the code.  There are many ways you could offer source, and different\nsolutions will be better for different programs; see section 13 for the\nspecific requirements.\n\n  You should also get your employer (if you work as a programmer) or school,\nif any, to sign a \"copyright disclaimer\" for the program, if necessary.\nFor more information on this, and how to apply and follow the GNU AGPL, see\n<https://www.gnu.org/licenses/>.\n"
  },
  {
    "path": "PULLREQUESTS.md",
    "content": "## The Importance of Small Pull Requests\n\n\nPull requests are an integral part of our workflow, but does the scope of your pull request matter?  In my opinion yes it does, and here’s why I think so\n\n### Smaller PRs make you spend more time thinking about your code before you write it\n\nSpend some time thinking about the PR you are going to open.  If you think about the scope of the PR you will be forced to limit the scope of your feature, and that will force you to plan your code out.\n\n### Smaller PRs are easier to review\n\nIf a PR is massive and complicated it is very difficult to review.  Reviewers are busy working on their own features and can quickly run into cognitive limits when a large PR comes in.  A PR should be simple enough that a busy dev can jump on the review without fatiguing themself.\n\n### Smaller PRs get better reviews\n\nThe smaller your PR, the greater the amount of quality feedback a reviewer can give you.  If you have 600 lines of codes you are not going to get decent feedback at line 500.  Try to limit your PRs to 200 lines of code at the most in order to get quality feedback from your reviewers.\n\n### Smaller PRs get reviewed faster and merged faster\n\nIf your PR is short and sweet your reviewers can get you feedback ASAP, this reduces the turnaround time for the whole pull request.  If it takes your reviewer a whole day to review your pull request you are looking at 2 days for the \n\n\tPull Request -> Review -> Revise -> Review -> Merge\n\nProcess.  If more revisions are required after the second review we’re looking at almost a week to get the feature reviewed, revised, and merged in.\n\n### Smaller PRs lead to better quality code\n\nIf PRs are small and manageable it is far more likely that a dev will catch bugs during the review process.  If our eyes glaze over at line 400 of a 700 line PR since we’ve reached our cognitive limit we’re not going to likely miss bugs in the last 300 lines of code.\n\n### Format your PRs for better readability\n\nEnsure you execute `npm run format` before submitting your pull requests in both the client and server directories. This command automatically applies our formatting structure, making the code easier to follow and review.\n\n### Keep PRs focused\n\nIt may be tempting to address a bug you suddenly remembered or make some tiny adjustments in some component that bothers you, but don’t!  Keep all commits in your pull request fully focused on the specific feature you are working on.  Open up another PR if you want to fix a big or work on another feature.\n"
  },
  {
    "path": "README.es.md",
    "content": "<p align=center> <a href=\"https://trendshift.io/repositories/12443\" target=\"_blank\"><img src=\"https://trendshift.io/api/badge/repositories/12443\" alt=\"bluewave-labs%2Fcheckmate | Trendshift\" style=\"width: 250px; height: 55px;\" width=\"250\" height=\"55\"/></a></p>\n\n![](https://img.shields.io/github/license/bluewave-labs/checkmate)\n![](https://img.shields.io/github/repo-size/bluewave-labs/checkmate)\n![](https://img.shields.io/github/commit-activity/m/bluewave-labs/checkmate)\n![](https://img.shields.io/github/last-commit/bluewave-labs/checkmate)\n![](https://img.shields.io/github/languages/top/bluewave-labs/checkmate)\n![](https://img.shields.io/github/issues/bluewave-labs/checkmate)\n![](https://img.shields.io/github/issues-pr/bluewave-labs/checkmate)\n[![OpenSSF Mejores Prácticas](https://www.bestpractices.dev/projects/9901/badge)](https://www.bestpractices.dev/projects/9901)\n[![Pregunta en DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/bluewave-labs/checkmate)\n\n<h1 align=\"center\"><a href=\"https://bluewavelabs.ca\" target=\"_blank\">Checkmate</a></h1>\n\n<p align=\"center\"><strong>Una aplicación de código abierto para monitoreo de infraestructura y tiempo de actividad</strong></p>\n\n<img width=\"1660\" alt=\"image\" src=\"https://github.com/user-attachments/assets/b748f36d-a271-4965-ad0a-18bf153bbee7\" />\n\nEste repositorio contiene tanto el frontend como el backend de Checkmate, una herramienta de monitoreo de código abierto y autoalojada para rastrear hardware de servidores, tiempo de actividad, tiempos de respuesta e incidentes en tiempo real con visualizaciones atractivas. Checkmate revisa regularmente si un servidor o sitio web es accesible y funciona de manera óptima, proporcionando alertas e informes en tiempo real sobre la disponibilidad, el tiempo de inactividad y el tiempo de respuesta de los servicios monitoreados.\n\nCheckmate también tiene un agente llamado [Capture](https://github.com/bluewave-labs/capture), para recuperar datos de servidores remotos. Aunque Capture no es obligatorio para ejecutar Checkmate, proporciona información adicional sobre el estado de la CPU, RAM, disco y temperatura de tus servidores.\n\nCheckmate ha sido probado con más de 1000 monitores activos sin problemas ni cuellos de botella de rendimiento.\n\n**Si deseas patrocinar una función, [visita este enlace](https://checkmate.so/sponsored-features).**\n\n## 📚 Tabla de contenidos\n\n- [📦 Demo](#demo)  \n- [🔗 Guía del usuario](#guía-del-usuario)  \n- [🛠️ Instalación](#instalación)\n- [🏁 Traducciones](#traducciones)  \n- [🚀 Rendimiento](#rendimiento)  \n- [💚 Preguntas e ideas](#preguntas-e-ideas)  \n- [🧩 Características](#características)  \n- [🏗️ Capturas de pantalla](#capturas-de-pantalla)  \n- [🏗️ Tecnologías](#tecnologías)  \n- [🔗 Enlaces útiles](#enlaces-útiles)  \n- [🤝 Contribuciones](#contribuciones)  \n- [💰 Patrocinadores](#patrocinadores)\n\n...\n\n**[Texto truncado para mantener la longitud del mensaje manejable]**\n\n## Demo\n\nPuedes ver la última versión de [Checkmate](https://checkmate-demo.bluewavelabs.ca/) en acción. El usuario es uptimedemo@demo.com y la contraseña es Demouser1! (ten en cuenta que actualizamos el servidor de demostración de vez en cuando, así que si no funciona para ti, por favor contáctanos en el canal de Discusiones).\n\n## Guía del usuario\n\nLas instrucciones de uso se pueden encontrar [aquí](https://docs.checkmate.so/checkmate-2.1). Todavía está en desarrollo y parte de la información puede estar desactualizada ya que continuamente añadimos funciones cada semana. ¡Ten por seguro que estamos haciendo lo mejor posible! :)\n\n## Instalación\n\nConsulta las instrucciones de instalación en el [portal de documentación de Checkmate](https://docs.checkmate.so/checkmate-2.1/users-guide/quickstart).\n\nAlternativamente, también puedes usar [Coolify](https://coolify.io/), [Elestio](https://elest.io/open-source/checkmate), [K8s](./charts/helm/checkmate/INSTALLATION.md) o [Pikapods](https://www.pikapods.com/) para desplegar rápidamente una instancia de Checkmate. Si deseas monitorear tu infraestructura de servidores, necesitarás el agente [Capture](https://github.com/bluewave-labs/capture). El repositorio de Capture también contiene las instrucciones de instalación.\n\n## Traducciones\n\nSi deseas usar Checkmate en tu idioma, por favor [ve a esta página](https://poeditor.com/join/project/lRUoGZFCsJ) y regístrate para el idioma al que te gustaría traducir Checkmate.\n\n## Rendimiento\n\nGracias a extensas optimizaciones, Checkmate opera con un uso de memoria excepcionalmente bajo, requiriendo recursos mínimos de memoria y CPU. Aquí está el uso de memoria de una instancia de Node.js ejecutándose en un servidor que monitorea 323 servidores cada minuto:\n\n![image](https://github.com/user-attachments/assets/37e04a75-d83a-488f-b25c-025511b492c9)\n\nTambién puedes ver el consumo de memoria de MongoDB y Redis en el mismo servidor (398Mb y 15Mb) para la misma cantidad de servidores:\n\n![image](https://github.com/user-attachments/assets/3b469e85-e675-4040-a162-3f24c1afc751)\n\n## Preguntas e Ideas\n\nSi tienes alguna pregunta, sugerencia o comentario, tienes varias opciones:\n\n- [Canal de Discord](https://discord.gg/NAb6H3UTjK)\n- [Discusiones en GitHub](https://github.com/bluewave-labs/bluewave-uptime/discussions)\n- [Grupo en Reddit](https://www.reddit.com/r/CheckmateMonitoring/)\n\n¡No dudes en hacer preguntas o compartir tus ideas, nos encantaría saber de ti!\n\n## Características\n\n- Completamente de código abierto, desplegable en tus propios servidores o dispositivos personales (por ejemplo, Raspberry Pi 4 o 5)\n- Monitoreo de sitios web\n- Monitoreo de velocidad de carga\n- Monitoreo de infraestructura (memoria, uso de disco, rendimiento de CPU, etc) - requiere el agente [Capture](https://github.com/bluewave-labs/capture)\n- Monitoreo de Docker\n- Monitoreo con ping\n- Monitoreo de certificados SSL\n- Monitoreo de puertos\n- Incidentes en una sola vista\n- Páginas de estado\n- Notificaciones por correo, Webhooks, Discord, Telegram, Slack\n- Mantenimiento programado\n- Monitoreo de consultas JSON\n- Soporte para múltiples idiomas\n\n**Hoja de ruta a corto plazo:** ([Milestone 2.2](https://github.com/bluewave-labs/Checkmate/milestone/8))\n\n- Mejores notificaciones\n- Monitoreo de red\n- ...y algunas funciones más\n\n## Capturas de pantalla\n\n<p>\n<img width=\"1628\" alt=\"image\" src=\"https://github.com/user-attachments/assets/2eff6464-0738-4a32-9312-26e1e8e86275\" />\n</p>\n<p>\n  <img width=\"1656\" alt=\"image\" src=\"https://github.com/user-attachments/assets/616c3563-c2a7-4ee4-af6c-7e6068955d1a\" />\n</p>\n<p>\n<img width=\"1652\" alt=\"image\" src=\"https://github.com/user-attachments/assets/7912d7cf-0d0e-4f26-aa5c-2ad7170b5c99\" />\n</p>\n<p>\n<img width=\"1652\" alt=\"image\" src=\"https://github.com/user-attachments/assets/08c2c6ac-3a2f-44d1-a229-d1746a3f9d16\" />\n</p>\n\n## Tecnologías\n\n- [ReactJs](https://react.dev/)\n- [MUI (framework de React)](https://mui.com/)\n- [Node.js](https://nodejs.org/en)\n- [MongoDB](https://mongodb.com)\n- [Recharts](https://recharts.org)\n- ¡Y muchos otros componentes de código abierto!\n\n## Enlaces útiles\n\n- Si deseas apoyarnos, por favor considera darle una ⭐ y haz clic en \"watch\".\n- ¿Tienes una pregunta o sugerencia para la hoja de ruta? Revisa nuestro [canal de Discord](https://discord.gg/NAb6H3UTjK) o el foro de [Discusiones](https://github.com/bluewave-labs/checkmate/discussions).\n- ¿Quieres saber cuándo hay una nueva versión? Usa [Newreleases](https://newreleases.io/), un servicio gratuito para seguir lanzamientos.\n- Mira un video de instalación y uso de Checkmate [aquí](https://www.youtube.com/watch?v=GfFOc0xHIwY)\n\n## Contribuciones\n\nSomos [Alex](http://github.com/ajhollid) (líder de equipo), [Vishnu](http://github.com/vishnusn77), [Mohadeseh](http://github.com/mohicody), [Gorkem](http://github.com/gorkem-bwl/), [Owaise](http://github.com/Owaiseimdad), [Aryaman](https://github.com/Br0wnHammer) y [Mert](https://github.com/mertssmnoglu), ayudando a personas y empresas a monitorear su infraestructura y servidores.\n\nNos enorgullecemos de construir conexiones fuertes con contribuyentes de todos los niveles. A pesar de ser un proyecto joven, Checkmate ya ha ganado más de 7000 estrellas y ha atraído a más de 90 contribuyentes de todo el mundo.\n\nNuestro repositorio ha sido marcado con estrella por empleados de **Google, Microsoft, Intel, Cisco, Tencent, Electronic Arts, ByteDance, JP Morgan Chase, Deloitte, Accenture, Foxconn, Broadcom, China Telecom, Barclays, Capgemini, Wipro, Cloudflare, Dassault Systèmes y NEC**, ¡así que no te detengas — participa, contribuye y aprende con nosotros!\n\nCómo contribuir:\n\n0. Dale una estrella al repositorio :)\n1. Revisa la [guía para contribuidores](https://github.com/bluewave-labs/Checkmate/blob/develop/CONTRIBUTING.md). Se anima a los nuevos a revisar las etiquetas `good-first-issue`.\n2. Consulta la [estructura del proyecto](https://docs.checkmate.so/checkmate-2.1/developers-guide/general-project-structure) y la [visión general](https://bluewavelabs.gitbook.io/checkmate/developers-guide/high-level-overview).\n3. Lee una estructura detallada de [Checkmate](https://deepwiki.com/bluewave-labs/Checkmate) si deseas profundizar en la arquitectura.\n4. Abre un issue si crees que has encontrado un error.\n5. Revisa los issues con la etiqueta `good-first-issue` si eres nuevo.\n6. Haz un pull request para añadir nuevas funciones, mejoras o correcciones.\n\n<a href=\"https://github.com/bluewave-labs/checkmate/graphs/contributors\">\n  <img src=\"https://contrib.rocks/image?repo=bluewave-labs/checkmate\" />\n</a>\n\n[![Historial de estrellas](https://api.star-history.com/svg?repos=bluewave-labs/checkmate&type=Date)](https://star-history.com/#bluewave-labs/bluewave-uptime&Date)\n\n## Patrocinadores\n\nGracias a [Gitbook](https://gitbook.io/) por darnos una cuenta gratuita para su plataforma de documentación, y a [Poeditor](https://poeditor.com/) por proporcionarnos una cuenta gratuita para servicios de traducción. Si deseas patrocinar Checkmate, por favor envía un correo a hello@bluewavelabs.ca\n\nSi deseas patrocinar una función, [visita esta página](https://checkmate.so/sponsored-features).\n\nTambién puedes revisar otros proyectos de BlueWave orientados a desarrolladores y contribuidores:\n\n- [VerifyWise](https://github.com/bluewave-labs/verifywise), la primera plataforma de gobernanza de IA de código abierto.\n- [DataRoom](https://github.com/bluewave-labs/bluewave-dataroom), una aplicación de intercambio de archivos seguro, también conocida como dataroom.\n- [Guidefox](https://github.com/bluewave-labs/guidefox), una app que ayuda a nuevos usuarios a aprender a usar tu producto mediante pistas, tours, popups y banners.\n"
  },
  {
    "path": "README.md",
    "content": "<p align=center> <a href=\"https://trendshift.io/repositories/12443\" target=\"_blank\"><img src=\"https://trendshift.io/api/badge/repositories/12443\" alt=\"bluewave-labs%2Fcheckmate | Trendshift\" style=\"width: 250px; height: 55px;\" width=\"250\" height=\"55\"/></a></p>\n  \n![](https://img.shields.io/github/license/bluewave-labs/checkmate)\n![](https://img.shields.io/github/repo-size/bluewave-labs/checkmate)\n![](https://img.shields.io/github/commit-activity/m/bluewave-labs/checkmate)\n![](https://img.shields.io/github/last-commit/bluewave-labs/checkmate)\n![](https://img.shields.io/github/languages/top/bluewave-labs/checkmate)\n![](https://img.shields.io/github/issues/bluewave-labs/checkmate)\n![](https://img.shields.io/github/issues-pr/bluewave-labs/checkmate)\n[![OpenSSF Best Practices](https://www.bestpractices.dev/projects/9901/badge)](https://www.bestpractices.dev/projects/9901)\n[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/bluewave-labs/checkmate)\n\n<h1 align=\"center\"><a href=\"https://bluewavelabs.ca\" target=\"_blank\">Checkmate</a></h1>\n\n<p align=\"center\"><strong>An open source uptime and infrastructure monitoring application</strong></p>\n\n<img width=\"1660\" alt=\"image\" src=\"https://github.com/user-attachments/assets/b748f36d-a271-4965-ad0a-18bf153bbee7\" />\n\nThis repository contains both the frontend and the backend of Checkmate, an open-source, self-hosted monitoring tool for tracking server hardware, uptime, response times, and incidents in real-time with beautiful visualizations. Checkmate regularly checks whether a server/website is accessible and performs optimally, providing real-time alerts and reports on the monitored services' availability, downtime, and response time.\n\nCheckmate also has an agent, called [Capture](https://github.com/bluewave-labs/capture), to retrieve data from remote servers. While Capture is not required to run Checkmate, it provides additional insights about your servers' CPU, RAM, disk, and temperature status. Capture can run on Linux, Windows, Mac, Raspberry Pi, or any device that can run Go.\n\nCheckmate has been stress-tested with 1000+ active monitors without any particular issues or performance bottlenecks.\n\n**If you would like to sponsor a feature, [see this link](https://checkmate.so/sponsored-features).**\n\n## 📚 Table of contents\n\n- [📦 Demo](#demo)  \n- [🔗 User's guide](#users-guide)  \n- [🛠️ Installation](#installation)\n- [🏁 Translations](#translations)  \n- [🚀 Performance](#performance)  \n- [💚 Questions & Ideas](#questions--ideas)  \n- [🧩 Features](#features)  \n- [🏗️ Screenshots](#screenshots)  \n- [🏗️ Tech stack](#tech-stack)  \n- [🔗 A few links](#a-few-links)  \n- [🤝 Contributing](#contributing)  \n- [💰 Our sponsors](#our-sponsors)\n\n\n## Demo\n\nYou can see the latest build of [Checkmate](https://checkmate-demo.bluewavelabs.ca/) in action. The username is demouser@demo.com and the password is Demouser1! (just a note that we update the demo server from time to time, so if it doesn't work for you, please ping us on the Discussions channel).\n\n## User's guide\n\nUsage instructions can be found [here](https://checkmate.so/docs). \n\n## Installation\n\nSee installation instructions in [Checkmate documentation portal](https://checkmate.so/docs). \n\nAlternatively, you can also use [Elestio](https://elest.io/open-source/checkmate), [K8s](./charts/helm/checkmate/INSTALLATION.md), [Sive Host](https://sive.host) (South Africa) or [Pikapods](https://www.pikapods.com/) to quickly spin off a Checkmate instance. If you would like to monitor your server infrastructure, you'll need [Capture agent](https://github.com/bluewave-labs/capture). Capture repository also contains the installation instructions.\n\n### Using a Custom CA\n\nIf you need to monitor internal HTTPS endpoints with certificates from private Certificate Authorities (like Smallstep), see our [Custom CA Trust Guide](./docs/custom-ca-trust.md) for Docker configuration options.\n\nFor more documentation, see the [docs directory](./docs/).\n\n\n## Translations\n\nIf you would like to use Checkmate in your language, please [go to this page](https://poeditor.com/join/project/lRUoGZFCsJ) and register for the language you would like to translate Checkmate to. \n\n## Performance\n\nThanks to extensive optimizations, Checkmate operates with an exceptionally small memory footprint, requiring minimal memory and CPU resources. Here’s the memory usage of a Node.js instance running on a server that monitors 323 servers every minute:\n\n![image](https://github.com/user-attachments/assets/37e04a75-d83a-488f-b25c-025511b492c9)\n\nYou can see the memory footprint of MongoDB and Redis on the same server (398Mb and 15Mb) for the same amount of servers:\n\n![image](https://github.com/user-attachments/assets/3b469e85-e675-4040-a162-3f24c1afc751)\n\n## Questions & Ideas\n\nIf you have any questions, suggestions or comments, you have several options: \n\n- [Discord channel](https://discord.gg/NAb6H3UTjK) (preferred)\n- [GitHub Discussions](https://github.com/bluewave-labs/bluewave-uptime/discussions) (we check here from time to time)\n\nFeel free to ask questions or share your ideas - we'd love to hear from you!\n\n## Features\n\n- Completely open source, deployable on your servers or home devices (e.g Raspberry Pi 4 or 5)\n- Website monitoring\n- Page speed monitoring\n- Infrastructure monitoring (memory, disk usage, CPU performance, network etc) - requires [Capture](https://github.com/bluewave-labs/capture) agent\n  - Selective disk monitoring with mountpoint selection\n- Docker monitoring\n- Ping monitoring\n- SSL monitoring\n- Port monitoring\n- Game server monitoring (3.0)\n- Incidents at a glance\n- Status pages\n- E-mail, Webhooks, Discord and Slack notifications\n- Scheduled maintenance\n- JSON query monitoring\n- Multi-language support for English, German, Japanese, Portuguese (Brazil), Russian, Turkish, Ukrainian, Vietnamese, Chinese (Traditional, Taiwan)\n\n**Short term roadmap:** \n\n- Plugins that will help Checkmate get any information from a remote service (e.g database, etc)\n- Better notifications\n- Network monitoring\n- ..and a few more features\n\nIf you would like to sponsor an additional feature, [see this page](https://checkmate.so/sponsored-features).\n\n## Screenshots\n\n<p>\n<img width=\"1628\" alt=\"image\" src=\"https://github.com/user-attachments/assets/2eff6464-0738-4a32-9312-26e1e8e86275\" />\n</p>\n<p>\n  <img width=\"1656\" alt=\"image\" src=\"https://github.com/user-attachments/assets/616c3563-c2a7-4ee4-af6c-7e6068955d1a\" />\n</p>\n<p>\n</p><img width=\"1652\" alt=\"image\" src=\"https://github.com/user-attachments/assets/7912d7cf-0d0e-4f26-aa5c-2ad7170b5c99\" />\n</p>\n<p>\n<img width=\"1652\" alt=\"image\" src=\"https://github.com/user-attachments/assets/08c2c6ac-3a2f-44d1-a229-d1746a3f9d16\" />\n</p>\n\n\n\n## Tech stack\n\n- [ReactJs](https://react.dev/)\n- [MUI (React framework)](https://mui.com/)\n- [Node.js](https://nodejs.org/en)\n- [MongoDB](https://mongodb.com)\n- [Recharts](https://recharts.org)\n- Lots of other open source components!\n\n## A few links\n\n- If you would like to support us, please consider giving it a ⭐ and click on \"watch\".\n- Have a question or suggestion for the roadmap/featureset? Check our [Discord channel](https://discord.gg/NAb6H3UTjK) or [Discussions](https://github.com/bluewave-labs/checkmate/discussions) forum.\n- Need a ping when there's a new release? Use [Newreleases](https://newreleases.io/), a free service to track releases.\n- Watch a Checkmate [installation and usage video](https://www.youtube.com/watch?v=GfFOc0xHIwY)\n\n## Contributing\n\nWe are [Alex](http://github.com/ajhollid) (team lead), [Gorkem](http://github.com/gorkem-bwl/), [Aryaman](https://github.com/Br0wnHammer), [Mert](https://github.com/mertssmnoglu) and [Karen](https://github.com/karenvicent) helping individuals and businesses monitor their infra and servers.\n\nWe pride ourselves on building strong connections with contributors at every level. Despite being a young project, Checkmate has already earned 7000+ stars and attracted 90+ contributors from around the globe.\n\nOur repo is starred by employees from **Google, Microsoft, Intel, Cisco, Tencent, Electronic Arts, ByteDance, JP Morgan Chase, Deloitte, Accenture, Foxconn, Broadcom, China Telecom, Barclays, Capgemini, Wipro, Cloudflare, Dassault Systèmes and NEC**, so don’t hold back — jump in, contribute and learn with us!\n\nHere's how you can contribute:\n\n0. Star this repo :)\n1. Check [Contributor's guideline](https://github.com/bluewave-labs/Checkmate/blob/develop/CONTRIBUTING.md). First timers are encouraged to check `good-first-issue` tag.\n2. Read a detailed structure of [Checkmate](https://deepwiki.com/bluewave-labs/Checkmate) if you would like to deep dive into the architecture.\n3. Open an issue if you believe you've encountered a bug.\n4. Check for good-first-issue's if you are a newcomer.\n5. Make a pull request to add new features/make quality-of-life improvements/fix bugs.\n6. Check out this interactive walkthrough of the `Checkmate` codebase on CodeCanvas [here](https://www.code-canvas.com/?session=unauthenticatedGithub&repo=Checkmate&owner=bluewave-labs&branch=develop&OnboardingTutorial=true). To refine existing dataflow simulation or create new ones, follow the quick tutorial [here](https://docs.code-canvas.com/updating-diagram).\n\n<a href=\"https://github.com/bluewave-labs/checkmate/graphs/contributors\">\n  <img src=\"https://contrib.rocks/image?repo=bluewave-labs/checkmate\" />\n</a>\n\n[![Star History Chart](https://api.star-history.com/svg?repos=bluewave-labs/checkmate&type=Date)](https://star-history.com/#bluewave-labs/bluewave-uptime&Date)\n\n## Our sponsors\n\nThanks to [Gitbook](https://gitbook.io/) for giving us a free tier for their documentation platform, and [Poeditor](https://poeditor.com/) providing us a free account to use their i18n services. If you would like to sponsor Checkmate, please send an email to hello@bluewavelabs.ca\n\nIf you would like to sponsor a feature, [see this page](https://checkmate.so/sponsored-features).\n"
  },
  {
    "path": "SECURITY.md",
    "content": "# Security Policy\n\nIf you find a vulnerability, [create an issue here](https://github.com/bluewave-labs/checkmate/security/advisories/new).\n\n"
  },
  {
    "path": "charts/helm/checkmate/.helmignore",
    "content": ".DS_Store\n.git/\n.gitignore\n.bzr/\n.bzrignore\n.hg/\n.hgignore\n.svn/\n*.swp\n*.bak\n*.tmp\n*.orig\n*~\n.project\n.idea/\n*.tmproj\n.vscode/\n"
  },
  {
    "path": "charts/helm/checkmate/Chart.yaml",
    "content": "apiVersion: v2\nname: checkmate-chart\ndescription: A Helm chart for Checkmate App\ntype: application\nversion: 0.1.0\nappVersion: \"2.3\"\n"
  },
  {
    "path": "charts/helm/checkmate/INSTALLATION.md",
    "content": "# Kubernetes Installation Guide for Checkmate\n\nThis guide walks you through deploying Checkmate on your Kubernetes cluster using Helm.\n\n## Prerequisites\n\n- A running Kubernetes cluster\n- Helm CLI installed and configured\n- `kubectl` configured to access your cluster\n\n## Steps\n\n### 1. Clone the repo and navigate to the Helm chart\n\n```bash\ngit clone https://github.com/bluewave-labs/checkmate.git\ncd checkmate/charts/helm/checkmate\n```\n\n### 2. Customize values.yaml\nEdit `values.yaml` to update:\n- `client.ingress.host` and `server.ingress.host` with your domain names\n- `server.protocol` (usually http or https)\n- **If upgrading**: Migrate persistence settings from flat structure to nested:\n  - Old: `persistence.mongodbSize` → New: `persistence.mongo.size`\n  - Old: `persistence.redisSize` → New: `persistence.redis.size`\n  - Add: `persistence.mongo.storageClass` and `persistence.redis.storageClass` (leave empty for default)\n- Secrets under the `secrets` section (`JWT_SECRET`, email credentials, API keys, etc.) — replace all change_me values\n- **For TLS/HTTPS**: Configure ingress TLS settings (see section below)\n\n### 3. Deploy the Helm chart\n```bash\nhelm install checkmate ./charts/helm/checkmate\n```\nThis will deploy the client, server, MongoDB, and Redis components.\n\n### 4. Verify the deployment\nCheck pods and services:\n```bash\nkubectl get pods\nkubectl get svc\n```\n\nOnce all pods are `Running` and `Ready`, you can access Checkmate via the configured ingress hosts.\n\n## Enabling TLS/HTTPS with cert-manager\n\nIf you have [cert-manager](https://cert-manager.io/) installed in your cluster, you can enable automatic TLS certificate provisioning using Let's Encrypt or other certificate issuers.\n\n### Prerequisites\n- cert-manager installed in your cluster\n- A ClusterIssuer or Issuer configured (e.g., `letsencrypt-prod`)\n\n### Configuration\n\nEdit `values.yaml` to enable TLS (and update protocols to https):\n\n```yaml\nclient:\n  protocol: https\n  ingress:\n    enabled: true\n    host: checkmate.example.com\n    className: nginx\n    annotations:\n      cert-manager.io/cluster-issuer: \"letsencrypt-prod\"\n    tls:\n      enabled: true\n      secretName: checkmate-client-tls\n\nserver:\n  protocol: https\n  ingress:\n    enabled: true\n    host: checkmate.example.com\n    className: nginx\n    annotations:\n      cert-manager.io/cluster-issuer: \"letsencrypt-prod\"\n    tls:\n      enabled: true\n      secretName: checkmate-server-tls\n```\n\n### Alternative: Using --set flags\n\nYou can also enable TLS during installation using Helm's `--set` flags:\n\n```bash\nhelm install checkmate ./charts/helm/checkmate \\\n  --set client.protocol=https \\\n  --set server.protocol=https \\\n  --set client.ingress.annotations.\"cert-manager\\.io/cluster-issuer\"=\"letsencrypt-prod\" \\\n  --set client.ingress.tls.enabled=true \\\n  --set client.ingress.tls.secretName=checkmate-client-tls \\\n  --set server.ingress.annotations.\"cert-manager\\.io/cluster-issuer\"=\"letsencrypt-prod\" \\\n  --set server.ingress.tls.enabled=true \\\n  --set server.ingress.tls.secretName=checkmate-server-tls\n```\n\n### Verification\n\nAfter deployment, cert-manager will automatically create the TLS secrets. You can verify the certificate status:\n\n```bash\n# Check certificates\nkubectl get certificates\n\n# Check certificate details\nkubectl describe certificate checkmate-client-tls\nkubectl describe certificate checkmate-server-tls\n\n# Verify the secrets were created\nkubectl get secrets | grep checkmate-tls\n```\n\nThe ingress will automatically use these secrets to enable HTTPS access to your Checkmate instance.\n"
  },
  {
    "path": "charts/helm/checkmate/templates/client-deployment.yaml",
    "content": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: checkmate-client\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: checkmate-client\n  template:\n    metadata:\n      labels:\n        app: checkmate-client\n    spec:\n    {{- with .Values.client.affinity }}\n      affinity:\n        {{- tpl ( . | toYaml) $ | nindent 8 }}\n    {{- end }}\n    {{- with .Values.client.tolerations }}\n      tolerations:\n        {{- tpl ( . | toYaml) $ | nindent 8 }}\n    {{- end }}\n      containers:\n        - name: client\n          image: {{ .Values.client.image }}\n          ports:\n            - containerPort: {{ .Values.client.port }}\n          env:\n            - name: UPTIME_APP_API_BASE_URL\n              value: \"{{ .Values.server.protocol }}://{{ .Values.server.ingress.host }}/api/v1\"\n            - name: UPTIME_APP_CLIENT_HOST\n              value: \"{{ .Values.client.protocol }}://{{ .Values.client.ingress.host }}\"\n          volumeMounts:\n            - name: config-volume\n              mountPath: /etc/nginx/conf.d/default.conf\n              subPath: default.conf\n          {{- with .Values.client.resources }}\n          resources:\n              {{- tpl ( . | toYaml) $ | nindent 12 }}\n          {{- end }}\n      volumes:\n        - name: config-volume\n          configMap:\n            name: checkmate-server-nginx-cm\n"
  },
  {
    "path": "charts/helm/checkmate/templates/client-ingress.yaml",
    "content": "{{- if .Values.client.ingress.enabled }}\napiVersion: networking.k8s.io/v1\nkind: Ingress\nmetadata:\n  name: checkmate-client-ingress\n  {{- if .Values.client.ingress.annotations }}\n  annotations:\n    {{- range $key, $value := .Values.client.ingress.annotations }}\n    {{ $key }}: {{ $value | quote }}\n    {{- end }}\n  {{- end }}\nspec:\n  ingressClassName: {{ .Values.client.ingress.className }}\n  {{- if .Values.client.ingress.tls.enabled }}\n  tls:\n    - hosts:\n        - {{ .Values.client.ingress.host }}\n      secretName: {{ default (printf \"%s-client-tls\" .Release.Name) .Values.client.ingress.tls.secretName }}\n  {{- end }}\n  rules:\n    - host: {{ .Values.client.ingress.host }}\n      http:\n        paths:\n          - path: /\n            pathType: Prefix\n            backend:\n              service:\n                name: checkmate-client\n                port:\n                  number: {{ .Values.client.port }}\n{{- end }}\n"
  },
  {
    "path": "charts/helm/checkmate/templates/client-service.yaml",
    "content": "apiVersion: v1\nkind: Service\nmetadata:\n  name: checkmate-client\nspec:\n  selector:\n    app: checkmate-client\n  ports:\n    - port: {{ .Values.client.port }}\n"
  },
  {
    "path": "charts/helm/checkmate/templates/mongodb-service.yaml",
    "content": "apiVersion: v1\nkind: Service\nmetadata:\n  name: checkmate-mongodb\nspec:\n  selector:\n    app: checkmate-mongodb\n  ports:\n    - port: {{ .Values.mongodb.port }}"
  },
  {
    "path": "charts/helm/checkmate/templates/mongodb-statefulsets.yaml",
    "content": "apiVersion: apps/v1\nkind: StatefulSet\nmetadata:\n  name: checkmate-mongodb\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: checkmate-mongodb\n  template:\n    metadata:\n      labels:\n        app: checkmate-mongodb\n    spec:\n    {{- with .Values.mongodb.affinity }}\n      affinity:\n        {{- tpl ( . | toYaml) $ | nindent 8 }}\n    {{- end }}\n    {{- with .Values.mongodb.tolerations }}\n      tolerations:\n        {{- tpl ( . | toYaml) $ | nindent 8 }}\n    {{- end }}\n      containers:\n        - name: mongodb\n          image: {{ .Values.mongodb.image }}\n          ports:\n            - containerPort: {{ .Values.mongodb.port }}\n          command: [\"mongod\", \"--quiet\", \"--bind_ip_all\"]\n          volumeMounts:\n            - name: checkmate-mongo-persistent-storage\n              mountPath: /data/db\n          {{- with .Values.mongodb.resources }}\n          resources:\n              {{- tpl ( . | toYaml) $ | nindent 12 }}\n          {{- end }}\n  volumeClaimTemplates:\n    - metadata:\n        name: checkmate-mongo-persistent-storage\n      spec:\n        storageClassName: {{ .Values.persistence.mongo.storageClass | quote }}\n        accessModes: [\"ReadWriteOnce\"]\n        resources:\n          requests:\n            storage: {{ .Values.persistence.mongo.size | default \"5Gi\" | quote }}"
  },
  {
    "path": "charts/helm/checkmate/templates/prechecks.yaml",
    "content": "{{- if eq .Values.client.ingress.host \"change_me\" }}\n  {{- fail \"client.ingress.host must be overridden and not set to 'change_me'\" }}\n{{- end }}\n\n{{- if eq .Values.server.ingress.host \"change_me\" }}\n  {{- fail \"server.ingress.host must be overridden and not set to 'change_me'\" }}\n{{- end }}\n\n{{- $serverProtocol := .Values.server.protocol }}\n{{- if not (or (eq $serverProtocol \"http\") (eq $serverProtocol \"https\")) }}\n  {{- fail \"server.protocol must be either 'http' or 'https'\" }}\n{{- end }}\n\n{{- $clientProtocol := .Values.client.protocol }}\n{{- if not (or (eq $clientProtocol \"http\") (eq $clientProtocol \"https\")) }}\n  {{- fail \"client.protocol must be either 'http' or 'https'\" }}\n{{- end }}\n\n{{/* Enforce protocol when TLS is enabled to avoid mixed-content */}}\n{{- if and .Values.client.ingress.tls.enabled (ne $clientProtocol \"https\") }}\n  {{- fail \"client.ingress.tls.enabled is true but client.protocol is not 'https'. Set client.protocol: https to avoid mixed content.\" }}\n{{- end }}\n\n{{- if and .Values.server.ingress.tls.enabled (ne $serverProtocol \"https\") }}\n  {{- fail \"server.ingress.tls.enabled is true but server.protocol is not 'https'. Set server.protocol: https to ensure correct API base URL.\" }}\n{{- end }}\n\n{{/* If client runs on https, API must also be https to avoid mixed content */}}\n{{- if and (eq $clientProtocol \"https\") (ne $serverProtocol \"https\") }}\n  {{- fail \"client.protocol is 'https' but server.protocol is not. Set server.protocol: https to prevent browser mixed-content issues.\" }}\n{{- end }}\n\n{{/* Fail early if TLS enabled without cert-manager annotations (cluster-issuer or issuer) */}}\n{{- $cAnn := .Values.client.ingress.annotations | default dict }}\n{{- $sAnn := .Values.server.ingress.annotations | default dict }}\n\n{{- $clientHasIssuer := or (hasKey $cAnn \"cert-manager.io/cluster-issuer\") (hasKey $cAnn \"cert-manager.io/issuer\") }}\n{{- $serverHasIssuer := or (hasKey $sAnn \"cert-manager.io/cluster-issuer\") (hasKey $sAnn \"cert-manager.io/issuer\") }}\n\n{{- if and .Values.client.ingress.tls.enabled (not $clientHasIssuer) }}\n  {{- fail \"client.ingress.tls.enabled is true but no cert-manager issuer annotation found. Add 'cert-manager.io/cluster-issuer' or 'cert-manager.io/issuer'.\" }}\n{{- end }}\n\n{{- if and .Values.server.ingress.tls.enabled (not $serverHasIssuer) }}\n  {{- fail \"server.ingress.tls.enabled is true but no cert-manager issuer annotation found. Add 'cert-manager.io/cluster-issuer' or 'cert-manager.io/issuer'.\" }}\n{{- end }}\n\n{{/* Secret name can be omitted; we default to <release>-client|server-tls in templates */}}\n"
  },
  {
    "path": "charts/helm/checkmate/templates/redis-service.yaml",
    "content": "{{- if .Values.redis.enabled }}\napiVersion: v1\nkind: Service\nmetadata:\n  name: checkmate-redis\nspec:\n  selector:\n    app: checkmate-redis\n  ports:\n    - port: {{ .Values.redis.port }}\n{{- end }}\n"
  },
  {
    "path": "charts/helm/checkmate/templates/redis-statefulsets.yaml",
    "content": "{{- if .Values.redis.enabled }}\napiVersion: apps/v1\nkind: StatefulSet\nmetadata:\n  name: checkmate-redis\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: checkmate-redis\n  template:\n    metadata:\n      labels:\n        app: checkmate-redis\n    spec:\n      containers:\n        - name: redis\n          image: {{ .Values.redis.image }}\n          ports:\n            - containerPort: {{ .Values.redis.port }}\n          volumeMounts:\n            - name: redis-data\n              mountPath: /data\n  volumeClaimTemplates:\n    - metadata:\n        name: checkmate-redis-persistent-storage\n      spec:\n        storageClassName: {{ .Values.persistence.redis.storageClass | quote }}\n        accessModes: [\"ReadWriteOnce\"]\n        resources:\n          requests:\n            storage: {{ .Values.persistence.redis.size | default \"1Gi\" | quote }}\n{{- end }}"
  },
  {
    "path": "charts/helm/checkmate/templates/secrets.yaml",
    "content": "{{- $secrets := .Values.secrets }}\n\n{{- if or (not $secrets.JWT_SECRET) (eq $secrets.JWT_SECRET \"change_me\") }}\n  {{- fail \"secrets.JWT_SECRET must be overridden and cannot be 'change_me'\" }}\n{{- end }}\n\napiVersion: v1\nkind: Secret\nmetadata:\n  name: checkmate-secrets\ntype: Opaque\nstringData:\n{{- range $key, $value := $secrets }}\n  {{ $key }}: {{ $value | quote }}\n{{- end }}"
  },
  {
    "path": "charts/helm/checkmate/templates/server-deployment.yaml",
    "content": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: checkmate-server\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: checkmate-server\n  template:\n    metadata:\n      labels:\n        app: checkmate-server\n    spec:\n    {{- with .Values.server.affinity }}\n      affinity:\n        {{- tpl ( . | toYaml) $ | nindent 8 }}\n    {{- end }}\n    {{- with .Values.server.tolerations }}\n      tolerations:\n        {{- tpl ( . | toYaml) $ | nindent 8 }}\n    {{- end }}\n      containers:\n        - name: server\n          image: {{ .Values.server.image }}\n          ports:\n            - containerPort: {{ .Values.server.port }}\n          envFrom:\n            - secretRef:\n                name: checkmate-secrets\n          {{- with .Values.server.resources }}\n          resources:\n              {{- tpl ( . | toYaml) $ | nindent 12 }}\n          {{- end }}\n          env:\n          - name: CLIENT_HOST\n            value: \"{{ .Values.client.protocol }}://{{ .Values.client.ingress.host }}\"\n"
  },
  {
    "path": "charts/helm/checkmate/templates/server-ingress.yaml",
    "content": "{{- if .Values.server.ingress.enabled }}\napiVersion: networking.k8s.io/v1\nkind: Ingress\nmetadata:\n  name: checkmate-server-ingress\n  {{- if .Values.server.ingress.annotations }}\n  annotations:\n    {{- range $key, $value := .Values.server.ingress.annotations }}\n    {{ $key }}: {{ $value | quote }}\n    {{- end }}\n  {{- end }}\n  {{/*#annotations:\n    #nginx.ingress.kubernetes.io/rewrite-target: /\n    #nginx.ingress.kubernetes.io/enable-cors: \"true\"\n    #nginx.ingress.kubernetes.io/cors-allow-origin: \"http://{{ .Values.client.ingress.host }},https://{{ .Values.client.ingress.host }}\"\n    #nginx.ingress.kubernetes.io/cors-allow-methods: \"GET, PUT, POST, DELETE, PATCH, OPTIONS\"\n    #nginx.ingress.kubernetes.io/cors-allow-headers: \"DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization\"\n    #nginx.ingress.kubernetes.io/cors-allow-credentials: \"true\"*/}}\nspec:\n  ingressClassName: {{ .Values.server.ingress.className }}\n  {{- if .Values.server.ingress.tls.enabled }}\n  tls:\n    - hosts:\n        - {{ .Values.server.ingress.host }}\n      secretName: {{ default (printf \"%s-server-tls\" .Release.Name) .Values.server.ingress.tls.secretName }}\n  {{- end }}\n  rules:\n    - host: {{ .Values.server.ingress.host }}\n      http:\n        paths:\n          - path: /api/v1\n            pathType: Prefix\n            backend:\n              service:\n                name: checkmate-server\n                port:\n                  number: {{ .Values.server.port }}\n{{- end }}\n"
  },
  {
    "path": "charts/helm/checkmate/templates/server-nginx-cm.yaml",
    "content": "apiVersion: v1\nkind: ConfigMap \nmetadata:\n  name: checkmate-server-nginx-cm\ndata:\n  default.conf: |\n    server {\n      listen       80;\n      listen  [::]:80;\n\n      server_name checkmate-demo.bluewavelabs.ca;\n      server_tokens off;\n\n      location /.well-known/acme-challenge/ {\n          root /var/www/certbot;\n      }\n\n      location / {\n          root   /usr/share/nginx/html;\n          index  index.html index.htm;\n          try_files $uri $uri/ /index.html;\n      }\n\n      # location /api/ {\n      #     proxy_pass http://{{ .Values.server.ingress.host }}:5000/api/;\n      #     proxy_http_version 1.1;\n      #     proxy_set_header Host $host;\n      #     proxy_set_header X-Real-IP $remote_addr;\n      #     proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n      #     proxy_set_header X-Forwarded-Proto $scheme;\n      # }\n\n      location /api-docs/ {\n          proxy_pass http://{{ .Values.server.ingress.host }}:5000/api-docs/;\n          proxy_http_version 1.1;\n          proxy_set_header Host $host;\n          proxy_set_header X-Real-IP $remote_addr;\n          proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n          proxy_set_header X-Forwarded-Proto $scheme;\n      }\n    }"
  },
  {
    "path": "charts/helm/checkmate/templates/server-service.yaml",
    "content": "apiVersion: v1\nkind: Service\nmetadata:\n  name: checkmate-server\nspec:\n  selector:\n    app: checkmate-server\n  ports:\n    - port: {{ .Values.server.port }}\n"
  },
  {
    "path": "charts/helm/checkmate/values.yaml",
    "content": "client:\n  image: ghcr.io/bluewave-labs/checkmate-client:v3.2.0\n  port: 80\n  protocol: http\n  ingress:\n    enabled: true\n    host: change_me\n    className: nginx\n    annotations: {}\n    # Example annotations for cert-manager:\n    # annotations:\n    #   cert-manager.io/cluster-issuer: \"letsencrypt-prod\"\n    tls:\n      enabled: false\n      # secretName: {{ .Release.Name }}-client-tls  # Optional; defaults to <release>-client-tls if omitted\n      # Note: when enabling TLS, also set client.protocol: https and add\n      # a cert-manager issuer annotation (e.g. cert-manager.io/cluster-issuer: \"letsencrypt-prod\").\n      # The secret will be automatically created by cert-manager when using the cert-manager.io/cluster-issuer annotation\n\nserver:\n  image: ghcr.io/bluewave-labs/checkmate-backend:v3.2.0\n  port: 52345\n  protocol: http\n  ingress:\n    enabled: true\n    host: change_me\n    className: nginx\n    annotations: {}\n    # Example annotations for cert-manager:\n    # annotations:\n    #   cert-manager.io/cluster-issuer: \"letsencrypt-prod\"\n    tls:\n      enabled: false\n      # secretName: {{ .Release.Name }}-server-tls  # Optional; defaults to <release>-server-tls if omitted\n      # Note: when enabling TLS, also set server.protocol: https and add\n      # a cert-manager issuer annotation (e.g. cert-manager.io/cluster-issuer: \"letsencrypt-prod\").\n      # The secret will be automatically created by cert-manager when using the cert-manager.io/cluster-issuer annotation\n\nredis:\n  enabled: false\n  image: redis:7.2\n  port: 6379\n\nmongodb:\n  image: ghcr.io/bluewave-labs/checkmate-mongo:v3.2.0\n  port: 27017\n\nsecrets:\n  JWT_SECRET: change_me\n#  REFRESH_TOKEN_SECRET: change_me\n#  SYSTEM_EMAIL_ADDRESS: test@example.com\n#  SYSTEM_EMAIL_PASSWORD: change_me\n#  SYSTEM_EMAIL_HOST: smtp.example.com\n#  SYSTEM_EMAIL_PORT: \"587\"\n#  PAGESPEED_API_KEY: change_me\n  DB_CONNECTION_STRING: mongodb://checkmate-mongodb.namespace.svc:27017/uptime_db\n  CLIENT_HOST: change_me\n#  REDIS_HOST: redis\n#  REDIS_PORT: \"6379\"\n#  DB_TYPE: MongoDB\n#  TOKEN_TTL: 99d\n#  REFRESH_TOKEN_TTL: 99d\n\npersistence:\n  mongo:\n    size: 5Gi\n    storageClass: \"\"\n  redis:\n    size: 1Gi\n    storageClass: \"\""
  },
  {
    "path": "client/.coderrabbit.yaml",
    "content": "language: \"en-CA\"\ntone_instructions: \"His palms are sweaty, knees weak, arms are heavy There’s vomit on his sweater already, mom’s spaghetti\"\nearly_access: false\nreviews:\n  profile: \"chill\"\n  request_changes_workflow: false\n  high_level_summary: false\n  poem: false\n  review_status: false\n  auto_review:\n    enabled: true\n    drafts: false\nchat:\n  auto_reply: false\n"
  },
  {
    "path": "client/.dockerignore",
    "content": "Client/node_modules/\nServer/node_modules/\nServer/*.env"
  },
  {
    "path": "client/.eslintrc.cjs",
    "content": "module.exports = {\n\troot: true,\n\tenv: { browser: true, es2020: true },\n\textends: [\n\t\t\"eslint:recommended\",\n\t\t\"plugin:react/recommended\",\n\t\t\"plugin:react/jsx-runtime\",\n\t\t\"plugin:react-hooks/recommended\",\n\t],\n\tignorePatterns: [\"dist\", \".eslintrc.cjs\"],\n\tparserOptions: { ecmaVersion: \"latest\", sourceType: \"module\" },\n\tsettings: { react: { version: \"18.2\" } },\n\tplugins: [\"react-refresh\"],\n\trules: {\n\t\t\"react/jsx-no-target-blank\": \"off\",\n\t\t\"react-refresh/only-export-components\": [\"warn\", { allowConstantExport: true }],\n\t\t\"react/no-unescaped-entities\": \"off\",\n\t},\n\tglobals: {\n\t\t__APP_VERSION__: \"readonly\",\n\t\tprocess: \"readonly\",\n\t},\n};\n"
  },
  {
    "path": "client/.gitignore",
    "content": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\npnpm-debug.log*\nlerna-debug.log*\n\nnode_modules\ndist\ndist-ssr\n*.local\n\n# Editor directories and files\n.vscode/*\n!.vscode/extensions.json\n.idea\n.DS_Store\n*.suo\n*.ntvs*\n*.njsproj\n*.sln\n*.sw?\n\n.env\n\n\n# Scripts\n*.sh\n!env.sh\n.env.development"
  },
  {
    "path": "client/.prettierrc",
    "content": "{\n\t\"printWidth\": 90,\n\t\"useTabs\": true,\n\t\"tabWidth\": 2,\n\t\"singleQuote\": false,\n\t\"bracketSpacing\": true,\n\t\"proseWrap\": \"preserve\",\n\t\"bracketSameLine\": false,\n\t\"singleAttributePerLine\": true,\n\t\"semi\": true,\n\t\"jsxSingleQuote\": false,\n\t\"quoteProps\": \"as-needed\",\n\t\"arrowParens\": \"always\",\n\t\"trailingComma\": \"es5\",\n\t\"htmlWhitespaceSensitivity\": \"css\"\n}\n"
  },
  {
    "path": "client/README.md",
    "content": "This directory contains the client side (frontend) of Checkmate.\n"
  },
  {
    "path": "client/env.sh",
    "content": "#!/bin/sh\nfor i in $(env | grep UPTIME_APP_)\ndo\n    key=$(echo $i | cut -d '=' -f 1)\n    value=$(echo $i | cut -d '=' -f 2-)\n    echo $key=$value\n    find /usr/share/nginx/html -type f \\( -name '*.js' -o -name '*.css' \\) -exec sed -i \"s|${key}|${value}|g\" '{}' +\ndone"
  },
  {
    "path": "client/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n\t<head>\n\t\t<meta charset=\"UTF-8\" />\n\t\t<link\n\t\t\trel=\"icon\"\n\t\t\thref=\"./checkmate_favicon.svg\"\n\t\t/>\n\t\t<meta\n\t\t\tname=\"viewport\"\n\t\t\tcontent=\"width=device-width, initial-scale=1.0\"\n\t\t/>\n\n\t\t<title>Checkmate</title>\n\t</head>\n\n\t<body>\n\t\t<div id=\"root\"></div>\n\t\t<script\n\t\t\ttype=\"module\"\n\t\t\tsrc=\"/src/main.tsx\"\n\t\t></script>\n\t</body>\n</html>\n"
  },
  {
    "path": "client/package.json",
    "content": "{\n\t\"name\": \"client\",\n\t\"private\": true,\n\t\"version\": \"0.0.0\",\n\t\"type\": \"module\",\n\t\"scripts\": {\n\t\t\"dev\": \"vite\",\n\t\t\"build\": \"tsc -b && vite build\",\n\t\t\"build-dev\": \"tsc -b && vite build --mode development\",\n\t\t\"lint\": \"eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0\",\n\t\t\"preview\": \"vite preview\",\n\t\t\"format\": \"prettier --write .\",\n\t\t\"format-check\": \"prettier --check .\"\n\t},\n\t\"lint-staged\": {\n\t\t\"**/*\": \"prettier --write\"\n\t},\n\t\"dependencies\": {\n\t\t\"@emotion/react\": \"^11.13.3\",\n\t\t\"@emotion/styled\": \"^11.13.0\",\n\t\t\"@hello-pangea/dnd\": \"^18.0.0\",\n\t\t\"@hookform/resolvers\": \"5.2.2\",\n\t\t\"@mui/lab\": \"7.0.0\",\n\t\t\"@mui/material\": \"7.3.7\",\n\t\t\"@mui/x-charts\": \"7.29.1\",\n\t\t\"@mui/x-date-pickers\": \"7.29.4\",\n\t\t\"@reduxjs/toolkit\": \"2.7.0\",\n\t\t\"@types/maplibre-gl\": \"^1.13.2\",\n\t\t\"axios\": \"^1.7.4\",\n\t\t\"dayjs\": \"1.11.13\",\n\t\t\"flag-icons\": \"7.3.2\",\n\t\t\"html2canvas\": \"^1.4.1\",\n\t\t\"human-interval\": \"2.0.1\",\n\t\t\"i18next\": \"25.4.2\",\n\t\t\"joi\": \"17.13.3\",\n\t\t\"lucide-react\": \"^0.562.0\",\n\t\t\"maplibre-gl\": \"^5.19.0\",\n\t\t\"mui-color-input\": \"^7.0.0\",\n\t\t\"pretty-bytes\": \"^7.1.0\",\n\t\t\"pretty-ms\": \"^9.3.0\",\n\t\t\"react\": \"18.3.1\",\n\t\t\"react-dom\": \"^18.2.0\",\n\t\t\"react-hook-form\": \"^7.63.0\",\n\t\t\"react-i18next\": \"^15.4.0\",\n\t\t\"react-icons\": \"5.5.0\",\n\t\t\"react-map-gl\": \"^8.1.0\",\n\t\t\"react-redux\": \"9.2.0\",\n\t\t\"react-router\": \"^6.23.0\",\n\t\t\"react-router-dom\": \"^6.23.1\",\n\t\t\"react-toastify\": \"^10.0.5\",\n\t\t\"recharts\": \"2.15.2\",\n\t\t\"redux-persist\": \"6.0.0\",\n\t\t\"swr\": \"^2.3.6\",\n\t\t\"vite-plugin-svgr\": \"^4.2.0\",\n\t\t\"zod\": \"^4.3.6\"\n\t},\n\t\"devDependencies\": {\n\t\t\"@types/node\": \"24.5.2\",\n\t\t\"@types/react\": \"^18.2.66\",\n\t\t\"@types/react-dom\": \"^18.2.22\",\n\t\t\"@vitejs/plugin-react\": \"^4.2.1\",\n\t\t\"eslint\": \"^8.57.0\",\n\t\t\"eslint-plugin-react\": \"^7.34.1\",\n\t\t\"eslint-plugin-react-hooks\": \"^5.0.0\",\n\t\t\"eslint-plugin-react-refresh\": \"^0.4.6\",\n\t\t\"lint-staged\": \"^16.2.7\",\n\t\t\"prettier\": \"^3.3.3\",\n\t\t\"typescript\": \"5.9.3\",\n\t\t\"vite\": \"6.4.1\"\n\t}\n}\n"
  },
  {
    "path": "client/public/bulk_import_monitors_sample.csv",
    "content": "type,name,url,interval,port,expectedValue,jsonPath,matchMethod\nhttp,HTTP Monitor,https://www.google.com,60000,,,,\nhttp,API Monitor,http://reqres.in/api/users/2,120000,,Janet,data.first_name,equal\nping,Ping monitor,127.0.0.1,60000,,,,\ndocker,Docker monitor,bbdd20b4e3757d63e070bc16e04d3f770c4a8f6e62e813de380f23b141e2ca01,60000,,,,\nport,Port monitor,127.0.0.1,60000,5000,,,"
  },
  {
    "path": "client/public/bulk_import_monitors_template.csv",
    "content": "type,name,url,interval,port,expectedValue,jsonPath,matchMethod"
  },
  {
    "path": "client/renovate.json",
    "content": "{\n\t\"$schema\": \"https://docs.renovatebot.com/renovate-schema.json\",\n\t\"extends\": [\"config:recommended\"],\n\t\"labels\": [\"dependencies\"]\n}\n"
  },
  {
    "path": "client/src/App.tsx",
    "content": "import { type CSSProperties } from \"react\";\nimport { useSelector } from \"react-redux\";\nimport \"react-toastify/dist/ReactToastify.css\";\nimport { ToastContainer } from \"react-toastify\";\nimport { ThemeProvider } from \"@emotion/react\";\nimport { CssBaseline, GlobalStyles } from \"@mui/material\";\nimport { SWRConfig } from \"swr\";\nimport { Routes } from \"./Routes\";\nimport AppLayout from \"@/Components/layout/AppLayout\";\nimport type { RootState } from \"@/Types/state\";\nimport { lightTheme, darkTheme } from \"@/Utils/Theme/Theme\";\n\nconst swrConfig = {\n\tdedupingInterval: 5000,\n\trevalidateOnFocus: false,\n\trevalidateOnReconnect: true,\n\tshouldRetryOnError: false,\n\terrorRetryCount: 2,\n\terrorRetryInterval: 1000,\n\tfocusThrottleInterval: 5000,\n};\n\nfunction App() {\n\tconst mode = useSelector((state: RootState) => state.ui.mode);\n\tconst theme = mode === \"light\" ? lightTheme : darkTheme;\n\n\treturn (\n\t\t<SWRConfig value={swrConfig}>\n\t\t\t<ThemeProvider theme={theme}>\n\t\t\t\t<CssBaseline />\n\t\t\t\t<GlobalStyles\n\t\t\t\t\tstyles={{\n\t\t\t\t\t\tbody: {\n\t\t\t\t\t\t\tbackgroundColor: theme.palette.background.default,\n\t\t\t\t\t\t},\n\t\t\t\t\t}}\n\t\t\t\t/>\n\t\t\t\t<AppLayout>\n\t\t\t\t\t<Routes />\n\t\t\t\t</AppLayout>\n\t\t\t\t<ToastContainer\n\t\t\t\t\tnewestOnTop={true}\n\t\t\t\t\ttheme={mode}\n\t\t\t\t\tstyle={\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"--toastify-color-progress-light\": \"#7C8BA1\",\n\t\t\t\t\t\t\t\"--toastify-color-progress-dark\": \"#7C8BA1\",\n\t\t\t\t\t\t} as CSSProperties\n\t\t\t\t\t}\n\t\t\t\t/>\n\t\t\t</ThemeProvider>\n\t\t</SWRConfig>\n\t);\n}\n\nexport default App;\n"
  },
  {
    "path": "client/src/Components/LanguageSelector.jsx",
    "content": "import { useTranslation } from \"react-i18next\";\nimport { Box, MenuItem, Select, Stack } from \"@mui/material\";\nimport { useTheme } from \"@emotion/react\";\nimport \"flag-icons/css/flag-icons.min.css\";\nimport { useSelector } from \"react-redux\";\nimport { useDispatch } from \"react-redux\";\nimport { setLanguage } from \"../Features/UI/uiSlice\";\n\nconst langMap = {\n\tcs: \"cz\",\n\tja: \"jp\",\n\tuk: \"ua\",\n\tvi: \"vn\",\n};\n\nconst LanguageSelector = () => {\n\tconst { i18n } = useTranslation();\n\tconst theme = useTheme();\n\tconst { language = \"en\" } = useSelector((state) => state.ui);\n\tconst dispatch = useDispatch();\n\tconst handleChange = (event) => {\n\t\tconst newLang = event.target.value;\n\t\tdispatch(setLanguage(newLang));\n\t};\n\n\tconst languages = Object.keys(i18n.options.resources || {});\n\n\treturn (\n\t\t<Select\n\t\t\tvalue={language}\n\t\t\tonChange={handleChange}\n\t\t\tsize=\"small\"\n\t\t\tsx={{\n\t\t\t\tminWidth: 80,\n\t\t\t\t\"& .MuiSelect-select\": {\n\t\t\t\t\tdisplay: \"flex\",\n\t\t\t\t\talignItems: \"center\",\n\t\t\t\t\tjustifyContent: \"center\",\n\t\t\t\t},\n\t\t\t\t\"& .MuiSelect-icon\": {\n\t\t\t\t\talignSelf: \"center\",\n\t\t\t\t},\n\t\t\t}}\n\t\t>\n\t\t\t{languages.map((lang) => {\n\t\t\t\tlet parsedLang = lang === \"en\" ? \"gb\" : lang;\n\n\t\t\t\tif (parsedLang.includes(\"-\")) {\n\t\t\t\t\tparsedLang = parsedLang.split(\"-\")[1].toLowerCase();\n\t\t\t\t}\n\n\t\t\t\tparsedLang = langMap[parsedLang] || parsedLang;\n\n\t\t\t\tconst flag = parsedLang ? `fi fi-${parsedLang}` : null;\n\n\t\t\t\treturn (\n\t\t\t\t\t<MenuItem\n\t\t\t\t\t\tkey={lang}\n\t\t\t\t\t\tvalue={lang}\n\t\t\t\t\t\tsx={{\n\t\t\t\t\t\t\tdisplay: \"flex\",\n\t\t\t\t\t\t\tjustifyContent: \"center\",\n\t\t\t\t\t\t\talignItems: \"center\",\n\t\t\t\t\t\t}}\n\t\t\t\t\t>\n\t\t\t\t\t\t<Stack\n\t\t\t\t\t\t\tdirection=\"row\"\n\t\t\t\t\t\t\tspacing={theme.spacing(2)}\n\t\t\t\t\t\t\talignItems=\"center\"\n\t\t\t\t\t\t\tjustifyContent=\"center\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<Box\n\t\t\t\t\t\t\t\tcomponent=\"span\"\n\t\t\t\t\t\t\t\tsx={{\n\t\t\t\t\t\t\t\t\tdisplay: \"flex\",\n\t\t\t\t\t\t\t\t\talignItems: \"center\",\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{flag && <span className={flag} />}\n\t\t\t\t\t\t\t</Box>\n\t\t\t\t\t\t\t<Box\n\t\t\t\t\t\t\t\tcomponent=\"span\"\n\t\t\t\t\t\t\t\tsx={{ textTransform: \"uppercase\" }}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{lang}\n\t\t\t\t\t\t\t</Box>\n\t\t\t\t\t\t</Stack>\n\t\t\t\t\t</MenuItem>\n\t\t\t\t);\n\t\t\t})}\n\t\t</Select>\n\t);\n};\n\nexport default LanguageSelector;\n"
  },
  {
    "path": "client/src/Components/actions-menu/index.tsx",
    "content": "import React, { useState } from \"react\";\nimport Menu from \"@mui/material/Menu\";\nimport MenuItem from \"@mui/material/MenuItem\";\nimport IconButton from \"@mui/material/IconButton\";\nimport { Settings } from \"lucide-react\";\n\nexport type ActionMenuItem = {\n\tid: number | string;\n\tlabel: React.ReactNode;\n\taction: Function;\n\tcloseMenu?: boolean;\n};\n\nexport const ActionsMenu = ({ items }: { items: ActionMenuItem[] }) => {\n\tconst [anchorEl, setAnchorEl] = useState<null | any>(null);\n\tconst open = Boolean(anchorEl);\n\n\tconst handleClick = (e: React.MouseEvent<any>) => {\n\t\te.stopPropagation();\n\t\tsetAnchorEl(e.currentTarget);\n\t};\n\n\tconst handleClose = (e: React.MouseEvent<any>) => {\n\t\te.stopPropagation();\n\t\tsetAnchorEl(null);\n\t};\n\n\treturn (\n\t\t<div>\n\t\t\t<IconButton onClick={handleClick}>\n\t\t\t\t<Settings\n\t\t\t\t\tsize={20}\n\t\t\t\t\tstrokeWidth={1.5}\n\t\t\t\t/>\n\t\t\t</IconButton>\n\t\t\t<Menu\n\t\t\t\tanchorEl={anchorEl}\n\t\t\t\topen={open}\n\t\t\t\tonClose={handleClose}\n\t\t\t>\n\t\t\t\t{items.map((item) => (\n\t\t\t\t\t<MenuItem\n\t\t\t\t\t\tkey={item.id}\n\t\t\t\t\t\tonClick={(e: React.MouseEvent<HTMLLIElement>) => {\n\t\t\t\t\t\t\te.stopPropagation();\n\t\t\t\t\t\t\tif (item.closeMenu) handleClose(e);\n\t\t\t\t\t\t\titem.action();\n\t\t\t\t\t\t}}\n\t\t\t\t\t>\n\t\t\t\t\t\t{item.label}\n\t\t\t\t\t</MenuItem>\n\t\t\t\t))}\n\t\t\t</Menu>\n\t\t</div>\n\t);\n};\n"
  },
  {
    "path": "client/src/Components/common/charts/HeatmapResponseTime.tsx",
    "content": "import Box from \"@mui/material/Box\";\nimport { useTheme } from \"@mui/material/styles\";\nimport type { CheckSnapshot } from \"@/Types/Check\";\nimport { getResponseColor } from \"@/Utils/DataUtils\";\nimport { HeatmapResponseTimeTooltip } from \"@/Components/common/charts/HeatmapResponseTimeTooltip\";\nimport type { SxProps } from \"@mui/material/styles\";\nimport type { ResponsiveStyleValue } from \"@mui/system\";\n\ninterface PlaceholderCheck {\n\tstatus: \"placeholder\";\n\tresponseTime: 0;\n\tcreatedAt: \"\";\n}\n\ninterface HeatmapResponseTimeProps {\n\tchecks: CheckSnapshot[];\n\tgap?: ResponsiveStyleValue<number | string>;\n\tavailabilityCellSx?: SxProps;\n\tresponseCellSx?: SxProps;\n}\n\nexport const HeatmapResponseTime = ({\n\tchecks,\n\tgap,\n\tavailabilityCellSx,\n\tresponseCellSx,\n}: HeatmapResponseTimeProps) => {\n\tconst theme = useTheme();\n\tif (!gap) {\n\t\tgap = theme.spacing(0.5);\n\t}\n\n\tif (!checks || checks.length === 0) return null;\n\n\tconst latestChecks = checks.slice(-25);\n\n\tlet data: Array<CheckSnapshot | PlaceholderCheck>;\n\tif (latestChecks.length !== 25) {\n\t\tconst placeholders = Array(25 - latestChecks.length).fill({\n\t\t\tstatus: \"placeholder\" as const,\n\t\t});\n\t\tdata = [...latestChecks, ...placeholders];\n\t} else {\n\t\tdata = latestChecks;\n\t}\n\treturn (\n\t\t<Box sx={{ width: \"100%\" }}>\n\t\t\t<Box\n\t\t\t\tsx={{\n\t\t\t\t\twidth: \"100%\",\n\t\t\t\t\tdisplay: \"grid\",\n\t\t\t\t\tgridTemplateColumns: \"repeat(25, 1fr)\",\n\t\t\t\t\tgap: gap,\n\t\t\t\t\talignItems: \"stretch\",\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t{data.map((check, index) => {\n\t\t\t\t\tconst statusBg =\n\t\t\t\t\t\tcheck.status === \"placeholder\"\n\t\t\t\t\t\t\t? theme.palette.action.hover\n\t\t\t\t\t\t\t: check.status === true\n\t\t\t\t\t\t\t\t? theme.palette.success.light\n\t\t\t\t\t\t\t\t: theme.palette.error.light;\n\t\t\t\t\tconst respBg =\n\t\t\t\t\t\tcheck.status === \"placeholder\"\n\t\t\t\t\t\t\t? theme.palette.action.hover\n\t\t\t\t\t\t\t: getResponseColor(check.responseTime || 0, {\n\t\t\t\t\t\t\t\t\tstart: theme.palette.success.main,\n\t\t\t\t\t\t\t\t\tmid: theme.palette.warning.main,\n\t\t\t\t\t\t\t\t\tend: theme.palette.error.main,\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\tconst statusBorder =\n\t\t\t\t\t\tcheck.status === \"placeholder\"\n\t\t\t\t\t\t\t? theme.palette.divider\n\t\t\t\t\t\t\t: check.status === true\n\t\t\t\t\t\t\t\t? theme.palette.success.main\n\t\t\t\t\t\t\t\t: theme.palette.error.main;\n\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<HeatmapResponseTimeTooltip\n\t\t\t\t\t\t\tkey={`${check}-${index}`}\n\t\t\t\t\t\t\tcheck={check}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<Box\n\t\t\t\t\t\t\t\tsx={{\n\t\t\t\t\t\t\t\t\tdisplay: \"grid\",\n\t\t\t\t\t\t\t\t\tgridTemplateRows: \"auto auto\",\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<Box\n\t\t\t\t\t\t\t\t\tsx={{\n\t\t\t\t\t\t\t\t\t\tdisplay: \"flex\",\n\t\t\t\t\t\t\t\t\t\tflexDirection: \"column\",\n\t\t\t\t\t\t\t\t\t\tgap: theme.spacing(2),\n\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<Box\n\t\t\t\t\t\t\t\t\t\tsx={{\n\t\t\t\t\t\t\t\t\t\t\tposition: \"relative\",\n\t\t\t\t\t\t\t\t\t\t\twidth: \"100%\",\n\t\t\t\t\t\t\t\t\t\t\taspectRatio: \"10\",\n\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<Box\n\t\t\t\t\t\t\t\t\t\t\tsx={{\n\t\t\t\t\t\t\t\t\t\t\t\tposition: \"absolute\",\n\t\t\t\t\t\t\t\t\t\t\t\tinset: 0,\n\t\t\t\t\t\t\t\t\t\t\t\tbgcolor: statusBg,\n\t\t\t\t\t\t\t\t\t\t\t\tborderRadius: theme.spacing(0.5),\n\t\t\t\t\t\t\t\t\t\t\t\t...availabilityCellSx,\n\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t<Box\n\t\t\t\t\t\t\t\t\t\t\tsx={{\n\t\t\t\t\t\t\t\t\t\t\t\tposition: \"absolute\",\n\t\t\t\t\t\t\t\t\t\t\t\tinset: 0,\n\t\t\t\t\t\t\t\t\t\t\t\tpointerEvents: \"none\",\n\t\t\t\t\t\t\t\t\t\t\t\tborderRadius: theme.spacing(0.5),\n\t\t\t\t\t\t\t\t\t\t\t\tboxShadow: `inset 0 0 0 2px ${statusBorder}`,\n\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t</Box>\n\t\t\t\t\t\t\t\t\t<Box\n\t\t\t\t\t\t\t\t\t\tsx={{\n\t\t\t\t\t\t\t\t\t\t\twidth: \"100%\",\n\t\t\t\t\t\t\t\t\t\t\taspectRatio: \"1 / 1\",\n\t\t\t\t\t\t\t\t\t\t\tbgcolor: respBg,\n\t\t\t\t\t\t\t\t\t\t\tborderRadius: theme.spacing(0.5),\n\t\t\t\t\t\t\t\t\t\t\t...responseCellSx,\n\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t</Box>\n\t\t\t\t\t\t\t</Box>\n\t\t\t\t\t\t</HeatmapResponseTimeTooltip>\n\t\t\t\t\t);\n\t\t\t\t})}\n\t\t\t</Box>\n\t\t</Box>\n\t);\n};\n"
  },
  {
    "path": "client/src/Components/common/charts/HeatmapResponseTimeTooltip.tsx",
    "content": "import Stack from \"@mui/material/Stack\";\nimport Tooltip from \"@mui/material/Tooltip\";\nimport Typography from \"@mui/material/Typography\";\nimport { formatDateWithTz } from \"@/Utils/TimeUtils\";\nimport type { CheckSnapshot } from \"@/Types/Check\";\nimport { useTheme } from \"@mui/material/styles\";\nimport { useSelector } from \"react-redux\";\nimport type { RootState } from \"@/Types/state\";\nimport { useTranslation } from \"react-i18next\";\n\ntype HeatmapCheck =\n\t| CheckSnapshot\n\t| { status: \"placeholder\"; responseTime: 0; createdAt: \"\" };\n\nexport const HeatmapResponseTimeTooltip = ({\n\tchildren,\n\tcheck,\n}: {\n\tchildren: React.ReactElement;\n\tcheck: HeatmapCheck;\n}) => {\n\tconst { t } = useTranslation();\n\tconst uiTimezone = useSelector((state: RootState) => state.ui.timezone);\n\tconst theme = useTheme();\n\n\tconst getColor = (status: boolean) => {\n\t\tif (status === true) return theme.palette.success.light;\n\t\tif (status === false) return theme.palette.error.light;\n\t};\n\n\tif (check.status === \"placeholder\") {\n\t\treturn children;\n\t}\n\n\treturn (\n\t\t<Tooltip\n\t\t\tslotProps={{\n\t\t\t\ttooltip: {\n\t\t\t\t\tsx: {\n\t\t\t\t\t\tbackgroundColor: \"transparent\",\n\t\t\t\t\t\tcolor: \"inherit\",\n\t\t\t\t\t\tboxShadow: \"none\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}}\n\t\t\ttitle={\n\t\t\t\t<Stack\n\t\t\t\t\tsx={{\n\t\t\t\t\t\tbackgroundColor: theme.palette.secondary.main,\n\t\t\t\t\t\tborder: 1,\n\t\t\t\t\t\tborderColor: theme.palette.divider,\n\t\t\t\t\t\tborderRadius: theme.shape.borderRadius,\n\t\t\t\t\t\tp: theme.spacing(4),\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t<Typography>\n\t\t\t\t\t\t{formatDateWithTz(check?.createdAt, \"ddd, MMMM D, YYYY, HH:mm A\", uiTimezone)}\n\t\t\t\t\t</Typography>\n\t\t\t\t\t<Typography>\n\t\t\t\t\t\t{t(\"common.labels.responseTime\")}:{\" \"}\n\t\t\t\t\t\t{check?.originalResponseTime?.toFixed() ?? \"N/A\"} ms\n\t\t\t\t\t</Typography>\n\t\t\t\t\t<Typography textTransform={\"capitalize\"}>\n\t\t\t\t\t\tStatus:{\" \"}\n\t\t\t\t\t\t<span style={{ color: getColor(check?.status) }}>\n\t\t\t\t\t\t\t{check?.status === true\n\t\t\t\t\t\t\t\t? t(\"pages.common.monitors.status.up\")\n\t\t\t\t\t\t\t\t: t(\"pages.common.monitors.status.down\")}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</Typography>\n\t\t\t\t</Stack>\n\t\t\t}\n\t\t>\n\t\t\t{children}\n\t\t</Tooltip>\n\t);\n};\n"
  },
  {
    "path": "client/src/Components/common/charts/HistogramResponseTime.tsx",
    "content": "import Box from \"@mui/material/Box\";\nimport Stack from \"@mui/material/Stack\";\nimport Typography from \"@mui/material/Typography\";\nimport { useTheme } from \"@mui/material/styles\";\nimport type { ResponsiveStyleValue } from \"@mui/system\";\nimport type { CheckSnapshot } from \"@/Types/Check\";\nimport { HeatmapResponseTimeTooltip } from \"./HeatmapResponseTimeTooltip\";\nimport { useMemo } from \"react\";\nimport { useTranslation } from \"react-i18next\";\n\ninterface HistogramResponseTimeProps {\n\tchecks: CheckSnapshot[];\n\theight?: ResponsiveStyleValue<number | string>;\n\tgap?: ResponsiveStyleValue<number | string>;\n\tshowStats?: boolean;\n\tstatsPosition?: \"left\" | \"right\";\n}\n\ninterface ResponseTimeStats {\n\tmax: number | string;\n\tavg: number | string;\n}\n\nconst DEFAULT_HEIGHT = 50;\n\nconst calculateResponseTimeStats = (checks: CheckSnapshot[]): ResponseTimeStats => {\n\tif (!Array.isArray(checks) || checks.length === 0) {\n\t\treturn { max: \"-\", avg: \"-\" };\n\t}\n\n\tconst validChecks = checks.filter((check) => check.originalResponseTime != null);\n\tif (validChecks.length === 0) {\n\t\treturn { max: \"-\", avg: \"-\" };\n\t}\n\n\tconst responseTimes = validChecks.map((check) => check.originalResponseTime);\n\tconst max = Math.max(...responseTimes);\n\tconst avg = Math.round(\n\t\tresponseTimes.reduce((sum, time) => sum + time, 0) / responseTimes.length\n\t);\n\n\treturn { max, avg };\n};\n\nexport const HistogramResponseTime = ({\n\tchecks,\n\theight = DEFAULT_HEIGHT,\n\tgap,\n\tshowStats = true,\n\tstatsPosition = \"right\",\n}: HistogramResponseTimeProps) => {\n\tconst theme = useTheme();\n\tconst { t } = useTranslation();\n\n\tconst stats = useMemo(() => calculateResponseTimeStats(checks), [checks]);\n\n\tif (!Array.isArray(checks) || checks.length === 0) return null;\n\n\tconst data =\n\t\tchecks.length !== 25\n\t\t\t? [...checks, ...Array(25 - checks.length).fill({ status: \"placeholder\" })]\n\t\t\t: checks;\n\n\tconst chartHeight = typeof height === \"number\" ? `${height}px` : height;\n\tconst gridGap = gap ?? theme.spacing(0.5);\n\n\tconst statsContent = showStats &&\n\t\t(typeof stats.max === \"number\" || typeof stats.avg === \"number\") && (\n\t\t\t<Stack\n\t\t\t\tjustifyContent=\"center\"\n\t\t\t\talignItems={statsPosition === \"left\" ? \"flex-end\" : \"flex-start\"}\n\t\t\t\tminWidth={70}\n\t\t\t\tpr={statsPosition === \"left\" ? theme.spacing(8) : 0}\n\t\t\t\tpl={statsPosition === \"right\" ? theme.spacing(8) : 0}\n\t\t\t>\n\t\t\t\t<Typography variant=\"body2\">\n\t\t\t\t\t{t(\"common.charts.histogram.avg\", { value: stats.avg })}\n\t\t\t\t</Typography>\n\t\t\t\t<Typography variant=\"body2\">\n\t\t\t\t\t{t(\"common.charts.histogram.max\", { value: stats.max })}\n\t\t\t\t</Typography>\n\t\t\t</Stack>\n\t\t);\n\n\treturn (\n\t\t<Stack\n\t\t\tdirection={statsPosition === \"left\" ? \"row-reverse\" : \"row\"}\n\t\t\talignItems=\"center\"\n\t\t\tsx={{ width: \"100%\" }}\n\t\t>\n\t\t\t<Box sx={{ flex: 1 }}>\n\t\t\t\t<Box\n\t\t\t\t\tsx={{\n\t\t\t\t\t\twidth: \"100%\",\n\t\t\t\t\t\tdisplay: \"grid\",\n\t\t\t\t\t\tgridTemplateColumns: \"repeat(25, 1fr)\",\n\t\t\t\t\t\tgap: gridGap,\n\t\t\t\t\t\talignItems: \"end\",\n\t\t\t\t\t\theight: chartHeight,\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t{data.map((check, index) => {\n\t\t\t\t\t\tconst isPlaceholder = (check as any).status === \"placeholder\";\n\t\t\t\t\t\tconst heightPct = `${Math.max(0, Math.min(100, (check as any).responseTime ?? 0))}%`;\n\t\t\t\t\t\tconst barColor =\n\t\t\t\t\t\t\tcheck.status === true\n\t\t\t\t\t\t\t\t? theme.palette.success.light\n\t\t\t\t\t\t\t\t: theme.palette.error.light;\n\t\t\t\t\t\tconst bar = (\n\t\t\t\t\t\t\t<Box\n\t\t\t\t\t\t\t\tsx={{\n\t\t\t\t\t\t\t\t\tposition: \"relative\",\n\t\t\t\t\t\t\t\t\twidth: \"100%\",\n\t\t\t\t\t\t\t\t\theight: \"100%\",\n\t\t\t\t\t\t\t\t\tborderRadius: theme.spacing(1),\n\t\t\t\t\t\t\t\t\tbgcolor: theme.palette.action.hover,\n\t\t\t\t\t\t\t\t\toverflow: \"hidden\",\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<Box\n\t\t\t\t\t\t\t\t\tsx={{\n\t\t\t\t\t\t\t\t\t\tposition: \"absolute\",\n\t\t\t\t\t\t\t\t\t\tbottom: 0,\n\t\t\t\t\t\t\t\t\t\tleft: 0,\n\t\t\t\t\t\t\t\t\t\twidth: \"100%\",\n\t\t\t\t\t\t\t\t\t\theight: isPlaceholder ? 0 : heightPct,\n\t\t\t\t\t\t\t\t\t\tbgcolor: barColor,\n\t\t\t\t\t\t\t\t\t\ttransition: \"height 500ms cubic-bezier(0.4, 0, 0.2, 1)\",\n\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t</Box>\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\treturn isPlaceholder ? (\n\t\t\t\t\t\t\t<Box\n\t\t\t\t\t\t\t\tkey={index}\n\t\t\t\t\t\t\t\tsx={{ height: \"100%\" }}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{bar}\n\t\t\t\t\t\t\t</Box>\n\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t<HeatmapResponseTimeTooltip\n\t\t\t\t\t\t\t\tkey={index}\n\t\t\t\t\t\t\t\tcheck={check}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{bar}\n\t\t\t\t\t\t\t</HeatmapResponseTimeTooltip>\n\t\t\t\t\t\t);\n\t\t\t\t\t})}\n\t\t\t\t</Box>\n\t\t\t</Box>\n\t\t\t{statsContent}\n\t\t</Stack>\n\t);\n};\n"
  },
  {
    "path": "client/src/Components/common/controls/HeaderCreate.tsx",
    "content": "import { Stack } from \"@mui/material\";\nimport { useNavigate } from \"react-router-dom\";\nimport { ButtonInput } from \"../../inputs/Button\";\nimport { useTranslation } from \"react-i18next\";\n\ninterface HeaderCreateProps {\n\tlabel?: string;\n\tpath: string;\n\tisLoading?: boolean;\n\tisAdmin?: boolean;\n}\n\nexport const HeaderCreate = ({\n\tlabel,\n\tpath,\n\tisLoading = false,\n\tisAdmin = false,\n}: HeaderCreateProps) => {\n\tconst navigate = useNavigate();\n\tconst { t } = useTranslation();\n\n\tif (!isAdmin) {\n\t\treturn null;\n\t}\n\n\tconst handleClick = () => {\n\t\tnavigate(path);\n\t};\n\n\treturn (\n\t\t<Stack\n\t\t\tdirection=\"row\"\n\t\t\tjustifyContent=\"flex-end\"\n\t\t\talignItems=\"center\"\n\t\t\twidth=\"100%\"\n\t\t>\n\t\t\t<ButtonInput\n\t\t\t\tvariant=\"contained\"\n\t\t\t\tcolor=\"primary\"\n\t\t\t\tonClick={handleClick}\n\t\t\t\tloading={isLoading}\n\t\t\t>\n\t\t\t\t{label || t(\"common.buttons.create\")}\n\t\t\t</ButtonInput>\n\t\t</Stack>\n\t);\n};\n"
  },
  {
    "path": "client/src/Components/common/controls/HeaderTimeRange.tsx",
    "content": "import Stack from \"@mui/material/Stack\";\nimport Box from \"@mui/material/Box\";\nimport Typography from \"@mui/material/Typography\";\nimport { ToggleButtonGroup, ToggleButton } from \"@/Components/inputs\";\nimport { useTheme } from \"@mui/material/styles\";\nimport CircularProgress from \"@mui/material/CircularProgress\";\nimport { useTranslation } from \"react-i18next\";\nimport { useMediaQuery } from \"@mui/material\";\n\ninterface MonitorTimeFrameHeaderProps {\n\tisLoading?: boolean;\n\thasDateRange?: boolean;\n\tdateRange: string;\n\tsetDateRange: (dateRange: string) => void;\n}\n\nexport const HeaderTimeRange = ({\n\tisLoading = false,\n\thasDateRange = true,\n\tdateRange,\n\tsetDateRange,\n}: MonitorTimeFrameHeaderProps) => {\n\tconst theme = useTheme();\n\tconst { t } = useTranslation();\n\tconst isSmallScreen = useMediaQuery(theme.breakpoints.down(\"md\"));\n\tconst handleChange = (\n\t\t_event: React.MouseEvent<HTMLElement>,\n\t\tnewValue: string | null\n\t) => {\n\t\tif (newValue !== null) {\n\t\t\tsetDateRange(newValue);\n\t\t}\n\t};\n\n\tlet timeFramePicker = null;\n\n\tif (hasDateRange) {\n\t\ttimeFramePicker = (\n\t\t\t<ToggleButtonGroup\n\t\t\t\torientation={isSmallScreen ? \"vertical\" : \"horizontal\"}\n\t\t\t\tvalue={dateRange}\n\t\t\t\texclusive\n\t\t\t\tonChange={handleChange}\n\t\t\t\tsize=\"small\"\n\t\t\t\tfullWidth={isSmallScreen}\n\t\t\t>\n\t\t\t\t<ToggleButton value=\"recent\">\n\t\t\t\t\t{t(\"components.headerTimeRange.labels.recent\")}\n\t\t\t\t</ToggleButton>\n\t\t\t\t<ToggleButton value=\"day\">\n\t\t\t\t\t{t(\"components.headerTimeRange.labels.day\")}\n\t\t\t\t</ToggleButton>\n\t\t\t\t<ToggleButton value=\"week\">\n\t\t\t\t\t{t(\"components.headerTimeRange.labels.week\")}\n\t\t\t\t</ToggleButton>\n\t\t\t\t<ToggleButton value=\"month\">\n\t\t\t\t\t{t(\"components.headerTimeRange.labels.month\")}\n\t\t\t\t</ToggleButton>\n\t\t\t</ToggleButtonGroup>\n\t\t);\n\t}\n\n\treturn (\n\t\t<Stack\n\t\t\tdirection={{ xs: \"column\", md: \"row\" }}\n\t\t\tjustifyContent=\"flex-end\"\n\t\t\talignItems=\"center\"\n\t\t\tgap={theme.spacing(4)}\n\t\t>\n\t\t\t<Box\n\t\t\t\twidth={16}\n\t\t\t\theight={16}\n\t\t\t>\n\t\t\t\t{isLoading && <CircularProgress size={16} />}\n\t\t\t</Box>\n\t\t\t<Typography variant=\"body2\">\n\t\t\t\t{t(`components.headerTimeRange.description.${dateRange}`)}\n\t\t\t</Typography>\n\t\t\t{timeFramePicker}\n\t\t</Stack>\n\t);\n};\n"
  },
  {
    "path": "client/src/Components/common/index.ts",
    "content": "export * from \"./charts/HistogramResponseTime\";\nexport * from \"./charts/HeatmapResponseTime\";\nexport * from \"./charts/HeatmapResponseTimeTooltip\";\nexport * from \"./controls/HeaderCreate\";\nexport * from \"./controls/HeaderTimeRange\";\n"
  },
  {
    "path": "client/src/Components/design-elements/Avatar.tsx",
    "content": "import { Avatar as MuiAvatar } from \"@mui/material\";\nimport { useSelector } from \"react-redux\";\nimport { useEffect, useState } from \"react\";\nimport { useTheme } from \"@mui/material\";\nimport type { RootState } from \"@/Types/state\";\n\ninterface AvatarProps {\n\tsrc?: string;\n\tsmall?: boolean;\n\tsx?: object;\n\tonClick?: (event: React.MouseEvent<HTMLDivElement>) => void;\n}\n\nexport const Avatar = ({ src, small, sx, onClick = () => {} }: AvatarProps) => {\n\tconst { user } = useSelector((state: RootState) => state.auth);\n\tconst theme = useTheme();\n\tif (!user) return null;\n\n\tconst style = small ? { width: 32, height: 32 } : { width: 64, height: 64 };\n\n\tconst [image, setImage] = useState<string>();\n\tuseEffect(() => {\n\t\tif (user.avatarImage) {\n\t\t\tsetImage(`data:image/png;base64,${user.avatarImage}`);\n\t\t}\n\t}, [user?.avatarImage]);\n\n\treturn (\n\t\t<MuiAvatar\n\t\t\tonClick={onClick}\n\t\t\talt={`${user?.firstName} ${user?.lastName}`}\n\t\t\tsrc={src ? src : user?.avatarImage ? image : undefined}\n\t\t\tsx={{\n\t\t\t\tcolor: theme.palette.primary.contrastText,\n\t\t\t\tfontSize: small ? \"16px\" : \"22px\",\n\t\t\t\tfontWeight: 400,\n\t\t\t\tbackgroundColor: theme.palette.primary.main,\n\t\t\t\tdisplay: \"inline-flex\",\n\n\t\t\t\t...style,\n\t\t\t\t...sx,\n\t\t\t}}\n\t\t>\n\t\t\t{user.firstName?.charAt(0)}\n\t\t\t{user.lastName?.charAt(0) || \"\"}\n\t\t</MuiAvatar>\n\t);\n};\n"
  },
  {
    "path": "client/src/Components/design-elements/BaseBox.tsx",
    "content": "import Box, { type BoxProps } from \"@mui/material/Box\";\nimport { useTheme } from \"@mui/material/styles\";\n\nexport const BaseBox = ({ sx, ...rest }: BoxProps) => {\n\tconst theme = useTheme();\n\treturn (\n\t\t<Box\n\t\t\t{...rest}\n\t\t\tsx={{\n\t\t\t\tbackgroundColor: theme.palette.background.paper,\n\t\t\t\tborder: 1,\n\t\t\t\tborderStyle: \"solid\",\n\t\t\t\tborderColor: theme.palette.divider,\n\t\t\t\tborderRadius: theme.shape.borderRadius,\n\t\t\t\t...sx,\n\t\t\t}}\n\t\t/>\n\t);\n};\n"
  },
  {
    "path": "client/src/Components/design-elements/BaseChart.tsx",
    "content": "import { BaseBox } from \".\";\nimport Stack from \"@mui/material/Stack\";\nimport Box from \"@mui/material/Box\";\nimport Typography from \"@mui/material/Typography\";\nimport { LAYOUT } from \"@/Utils/Theme/constants\";\nimport type { ResponsiveStyleValue } from \"@mui/system\";\n\nimport { useTheme } from \"@mui/material/styles\";\n\ntype BaseChartProps = React.PropsWithChildren<{\n\ticon: React.ReactNode;\n\ttitle: string;\n\twidth?: number | string;\n\tmaxWidth?: number | string;\n\tpadding?: number | string | ResponsiveStyleValue<number | string>;\n}>;\n\nexport const BaseChart = ({\n\tchildren,\n\ticon,\n\ttitle,\n\twidth = \"100%\",\n\tmaxWidth = \"100%\",\n\tpadding,\n}: BaseChartProps) => {\n\tconst theme = useTheme();\n\treturn (\n\t\t<BaseBox\n\t\t\tsx={{\n\t\t\t\tpadding: padding ?? theme.spacing(LAYOUT.MD),\n\t\t\t\tdisplay: \"flex\",\n\t\t\t\tflex: 1,\n\t\t\t\twidth: width,\n\t\t\t\tmaxWidth: maxWidth,\n\t\t\t}}\n\t\t>\n\t\t\t<Stack\n\t\t\t\tgap={theme.spacing(LAYOUT.MD)}\n\t\t\t\tflex={1}\n\t\t\t>\n\t\t\t\t<Stack\n\t\t\t\t\tdirection=\"row\"\n\t\t\t\t\talignItems={\"center\"}\n\t\t\t\t\tgap={theme.spacing(LAYOUT.XS)}\n\t\t\t\t>\n\t\t\t\t\t{icon && (\n\t\t\t\t\t\t<BaseBox\n\t\t\t\t\t\t\tsx={{\n\t\t\t\t\t\t\t\tdisplay: \"flex\",\n\t\t\t\t\t\t\t\talignItems: \"center\",\n\t\t\t\t\t\t\t\tjustifyContent: \"center\",\n\t\t\t\t\t\t\t\twidth: 34,\n\t\t\t\t\t\t\t\theight: 34,\n\t\t\t\t\t\t\t\tbackgroundColor: theme.palette.action.hover,\n\t\t\t\t\t\t\t\t\"& svg\": {\n\t\t\t\t\t\t\t\t\twidth: 20,\n\t\t\t\t\t\t\t\t\theight: 20,\n\t\t\t\t\t\t\t\t\t\"& path\": {\n\t\t\t\t\t\t\t\t\t\tstroke: theme.palette.text.secondary,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{icon}\n\t\t\t\t\t\t</BaseBox>\n\t\t\t\t\t)}\n\t\t\t\t\t<Typography variant=\"h2\">{title}</Typography>\n\t\t\t\t</Stack>\n\t\t\t\t<Box flex={1}>{children}</Box>\n\t\t\t</Stack>\n\t\t</BaseBox>\n\t);\n};\n"
  },
  {
    "path": "client/src/Components/design-elements/BasePage.tsx",
    "content": "import Logo from \"@/assets/icons/checkmate-icon.svg?react\";\nimport Stack from \"@mui/material/Stack\";\nimport Box from \"@mui/material/Box\";\nimport Alert from \"@mui/material/Alert\";\nimport Link from \"@mui/material/Link\";\nimport { LAYOUT, SPACING } from \"@/Utils/Theme/constants\";\nimport {\n\tErrorFallback,\n\tEmptyFallback,\n\tEmptyMonitorFallback,\n\tBaseFallback,\n} from \"@/Components/design-elements/Fallback\";\nimport { Breadcrumb } from \"@/Components/design-elements/Breadcrumb\";\nimport CircularProgress from \"@mui/material/CircularProgress\";\nimport { HeaderAuthControls } from \"@/Pages/Auth/components/HeaderAuthControls\";\n\nimport type { StackProps } from \"@mui/material/Stack\";\nimport { useTheme } from \"@mui/material/styles\";\nimport { Trans, useTranslation } from \"react-i18next\";\nimport { Link as RouterLink } from \"react-router-dom\";\nimport { Typography } from \"@mui/material\";\n\nexport const PageSpeedKeyPriorityFallback = () => {\n\treturn (\n\t\t<BaseFallback>\n\t\t\t<Alert\n\t\t\t\tseverity=\"warning\"\n\t\t\t\tsx={{\n\t\t\t\t\twidth: \"100%\",\n\t\t\t\t\tmaxWidth: 600,\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t<Typography>\n\t\t\t\t\t<Trans\n\t\t\t\t\t\ti18nKey=\"common.alerts.pageSpeedApiKey.content\"\n\t\t\t\t\t\tcomponents={{\n\t\t\t\t\t\t\tsettingsLink: (\n\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\tcomponent={RouterLink}\n\t\t\t\t\t\t\t\t\tto=\"/settings\"\n\t\t\t\t\t\t\t\t\tcolor=\"inherit\"\n\t\t\t\t\t\t\t\t\tfontWeight=\"inherit\"\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t}}\n\t\t\t\t\t/>\n\t\t\t\t</Typography>\n\t\t\t</Alert>\n\t\t</BaseFallback>\n\t);\n};\n\ninterface BasePageProps extends StackProps {\n\tloading?: boolean;\n\terror?: boolean;\n\tchildren: React.ReactNode;\n\tbreadcrumbOverride?: string[];\n}\n\nexport const BasePage = ({\n\tloading,\n\terror,\n\tchildren,\n\tbreadcrumbOverride,\n\t...props\n}: BasePageProps) => {\n\tconst theme = useTheme();\n\n\tif (loading) {\n\t\treturn (\n\t\t\t<Stack\n\t\t\t\talignItems=\"center\"\n\t\t\t\tjustifyContent=\"center\"\n\t\t\t\tsx={{ height: \"100%\" }}\n\t\t\t>\n\t\t\t\t<CircularProgress\n\t\t\t\t\tcolor=\"primary\"\n\t\t\t\t\tsize={28}\n\t\t\t\t/>\n\t\t\t</Stack>\n\t\t);\n\t}\n\n\tif (error) {\n\t\treturn (\n\t\t\t<ErrorFallback\n\t\t\t\ttitle=\"Something went wrong...\"\n\t\t\t\tsubtitle=\"Please try again later\"\n\t\t\t/>\n\t\t);\n\t}\n\n\treturn (\n\t\t<Stack\n\t\t\tspacing={theme.spacing(LAYOUT.LG)}\n\t\t\t{...props}\n\t\t>\n\t\t\t<Breadcrumb breadcrumbOverride={breadcrumbOverride} />\n\t\t\t{children}\n\t\t</Stack>\n\t);\n};\n\ninterface BasePageWithStatesProps extends StackProps {\n\tloading: boolean;\n\terror: any;\n\ttotalCount: number;\n\tbullets: string[] | unknown;\n\tpage: string;\n\tactionButtonText: string;\n\tactionLink: string;\n\tchildren: React.ReactNode;\n}\n\nexport const BasePageWithStates = ({\n\tloading,\n\terror,\n\ttotalCount,\n\tpage,\n\tbullets,\n\tactionButtonText,\n\tactionLink,\n\tchildren,\n\t...props\n}: BasePageWithStatesProps) => {\n\tconst showLoading = loading && totalCount === 0;\n\n\tif (!loading && totalCount === 0) {\n\t\treturn (\n\t\t\t<EmptyFallback\n\t\t\t\tbullets={bullets}\n\t\t\t\ttitle={page}\n\t\t\t\tactionButtonText={actionButtonText}\n\t\t\t\tactionLink={actionLink}\n\t\t\t/>\n\t\t);\n\t}\n\n\treturn (\n\t\t<BasePage\n\t\t\tloading={showLoading}\n\t\t\terror={error}\n\t\t\t{...props}\n\t\t>\n\t\t\t{children}\n\t\t</BasePage>\n\t);\n};\n\ninterface MonitorBasePageWithStatesProps extends StackProps {\n\tloading: boolean;\n\terror: any;\n\ttotalCount: number;\n\tpage: string;\n\tactionLink?: string;\n\tchildren: React.ReactNode;\n\tpriorityFallback?: React.ReactNode;\n}\n\nexport const MonitorBasePageWithStates = ({\n\tloading,\n\terror,\n\ttotalCount,\n\tpage,\n\tactionLink,\n\tchildren,\n\tpriorityFallback,\n\t...props\n}: MonitorBasePageWithStatesProps) => {\n\tconst { t } = useTranslation();\n\n\tconst showLoading = loading && totalCount === 0;\n\n\tif (priorityFallback) {\n\t\treturn (\n\t\t\t<BasePage\n\t\t\t\tloading={loading}\n\t\t\t\terror={error}\n\t\t\t\t{...props}\n\t\t\t>\n\t\t\t\t<Stack height={\"100%\"}>{priorityFallback}</Stack>\n\t\t\t</BasePage>\n\t\t);\n\t}\n\n\tif (!loading && totalCount === 0) {\n\t\treturn (\n\t\t\t<EmptyMonitorFallback\n\t\t\t\tpage={page}\n\t\t\t\ttitle={t(`pages.${page}.fallback.title`)}\n\t\t\t\tbullets={t(`pages.${page}.fallback.checks`, { returnObjects: true })}\n\t\t\t\tactionButtonText={t(`pages.${page}.fallback.actionButton`)}\n\t\t\t\tactionLink={actionLink || \"\"}\n\t\t\t/>\n\t\t);\n\t}\n\n\treturn (\n\t\t<BasePage\n\t\t\tloading={showLoading}\n\t\t\terror={error}\n\t\t\t{...props}\n\t\t>\n\t\t\t{children}\n\t\t</BasePage>\n\t);\n};\n\ninterface BaseAuthPageProps extends React.PropsWithChildren, StackProps {\n\ttitle: string;\n\tsubtitle: string;\n}\n\nexport const BaseAuthPage = ({\n\ttitle,\n\tsubtitle,\n\tchildren,\n\t...props\n}: BaseAuthPageProps) => {\n\tconst theme = useTheme();\n\treturn (\n\t\t<BasePage\n\t\t\tbreadcrumbOverride={[]}\n\t\t\tgap={theme.spacing(LAYOUT.MD)}\n\t\t\talignItems={\"center\"}\n\t\t\tjustifyContent={\"center\"}\n\t\t\tminHeight=\"100vh\"\n\t\t\tposition={\"relative\"}\n\t\t\t{...props}\n\t\t>\n\t\t\t<HeaderAuthControls\n\t\t\t\thideLogo\n\t\t\t\tpy={theme.spacing(LAYOUT.XS)}\n\t\t\t\tposition={\"absolute\"}\n\t\t\t\ttop={0}\n\t\t\t\tleft={0}\n\t\t\t/>\n\t\t\t<Box width={{ xs: 60, sm: 70, md: 80 }}>\n\t\t\t\t<Logo\n\t\t\t\t\twidth={\"100%\"}\n\t\t\t\t\theight={\"100%\"}\n\t\t\t\t/>\n\t\t\t</Box>\n\t\t\t<Stack alignItems={\"center\"}>\n\t\t\t\t<Typography\n\t\t\t\t\tvariant=\"h1\"\n\t\t\t\t\tmb={theme.spacing(SPACING.LG)}\n\t\t\t\t>\n\t\t\t\t\t{title}\n\t\t\t\t</Typography>\n\t\t\t\t<Typography variant=\"h2\">{subtitle}</Typography>\n\t\t\t</Stack>\n\t\t\t<Stack\n\t\t\t\tgap={theme.spacing(LAYOUT.MD)}\n\t\t\t\twidth={{\n\t\t\t\t\txs: \"80%\",\n\t\t\t\t\tmd: \"25%\",\n\t\t\t\t\tlg: \"15%\",\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t</Stack>\n\t\t</BasePage>\n\t);\n};\n"
  },
  {
    "path": "client/src/Components/design-elements/Breadcrumb.tsx",
    "content": "import MuiBreadcrumbs from \"@mui/material/Breadcrumbs\";\nimport Typography from \"@mui/material/Typography\";\nimport { Link, useLocation } from \"react-router-dom\";\nimport { useTheme } from \"@mui/material/styles\";\nimport { ChevronRight } from \"lucide-react\";\nimport { useTranslation } from \"react-i18next\";\nimport type { ReactNode } from \"react\";\n\nconst isId = (segment: string): boolean => {\n\treturn segment.length === 24 || /^[a-f0-9-]{36}$/.test(segment);\n};\n\nconst actionSegments = [\"create\", \"configure\"];\n\nconst BreadcrumbWrapper = ({ children }: { children: ReactNode }) => {\n\tconst theme = useTheme();\n\treturn (\n\t\t<MuiBreadcrumbs\n\t\t\tseparator={\n\t\t\t\t<ChevronRight\n\t\t\t\t\tsize={16}\n\t\t\t\t\tstrokeWidth={1.5}\n\t\t\t\t/>\n\t\t\t}\n\t\t\tsx={{\n\t\t\t\tfontSize: \"14px\",\n\t\t\t\tmarginBottom: theme.spacing(6),\n\t\t\t\t\"& .MuiBreadcrumbs-separator\": {\n\t\t\t\t\tcolor: theme.palette.text.secondary,\n\t\t\t\t},\n\t\t\t}}\n\t\t>\n\t\t\t{children}\n\t\t</MuiBreadcrumbs>\n\t);\n};\n\nexport const Breadcrumb = ({\n\tbreadcrumbOverride,\n}: {\n\tbreadcrumbOverride?: string[] | undefined;\n}) => {\n\tconst { t } = useTranslation();\n\tconst theme = useTheme();\n\tconst location = useLocation();\n\n\t// If override is an empty array, hide entirely\n\tif (breadcrumbOverride !== undefined && breadcrumbOverride.length === 0) {\n\t\treturn null;\n\t}\n\n\t// If override has items, render them directly\n\tif (breadcrumbOverride !== undefined && breadcrumbOverride.length > 0) {\n\t\treturn (\n\t\t\t<BreadcrumbWrapper>\n\t\t\t\t{breadcrumbOverride.map((item, index) => {\n\t\t\t\t\tconst isLast = index === breadcrumbOverride.length - 1;\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<Typography\n\t\t\t\t\t\t\tkey={index}\n\t\t\t\t\t\t\tsx={{\n\t\t\t\t\t\t\t\tfontSize: \"14px\",\n\t\t\t\t\t\t\t\tfontWeight: isLast ? 600 : 400,\n\t\t\t\t\t\t\t\tcolor: isLast ? theme.palette.primary.main : theme.palette.text.secondary,\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{item}\n\t\t\t\t\t\t</Typography>\n\t\t\t\t\t);\n\t\t\t\t})}\n\t\t\t</BreadcrumbWrapper>\n\t\t);\n\t}\n\n\t// Default behavior: use location pathname\n\tconst segments = location.pathname.split(\"/\").filter((x) => x);\n\n\tif (segments.length === 0) {\n\t\treturn null;\n\t}\n\n\t// Build simplified breadcrumb: \"uptime\" or \"uptime / details\" or \"uptime / create\"\n\tconst basePage = segments[0] || t(\"common.breadcrumbs.home\");\n\n\tconst secondSegment = segments[1];\n\tconst isActionPage = secondSegment && actionSegments.includes(secondSegment);\n\tconst isDetailsPage = secondSegment && isId(secondSegment);\n\tconst hasSubPage = isActionPage || isDetailsPage;\n\n\tconst getSubPageLabel = (): string => {\n\t\tif (isActionPage) {\n\t\t\treturn secondSegment.charAt(0).toUpperCase() + secondSegment.slice(1);\n\t\t}\n\t\treturn t(\"common.breadcrumbs.details\");\n\t};\n\n\treturn (\n\t\t<BreadcrumbWrapper>\n\t\t\t{hasSubPage ? (\n\t\t\t\t<Link\n\t\t\t\t\tto={`/${basePage}`}\n\t\t\t\t\tstyle={{ textDecoration: \"none\" }}\n\t\t\t\t>\n\t\t\t\t\t<Typography\n\t\t\t\t\t\tsx={{\n\t\t\t\t\t\t\tfontSize: \"14px\",\n\t\t\t\t\t\t\tcolor: theme.palette.text.secondary,\n\t\t\t\t\t\t\t\"&:hover\": {\n\t\t\t\t\t\t\t\tcolor: theme.palette.primary.main,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}}\n\t\t\t\t\t>\n\t\t\t\t\t\t{basePage.charAt(0).toUpperCase() + basePage.slice(1)}\n\t\t\t\t\t</Typography>\n\t\t\t\t</Link>\n\t\t\t) : (\n\t\t\t\t<Typography\n\t\t\t\t\tsx={{\n\t\t\t\t\t\tfontSize: \"14px\",\n\t\t\t\t\t\tfontWeight: 600,\n\t\t\t\t\t\tcolor: theme.palette.primary.main,\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t{basePage.charAt(0).toUpperCase() + basePage.slice(1)}\n\t\t\t\t</Typography>\n\t\t\t)}\n\t\t\t{hasSubPage && (\n\t\t\t\t<Typography\n\t\t\t\t\tsx={{\n\t\t\t\t\t\tfontSize: \"14px\",\n\t\t\t\t\t\tfontWeight: 600,\n\t\t\t\t\t\tcolor: theme.palette.primary.main,\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t{getSubPageLabel()}\n\t\t\t\t</Typography>\n\t\t\t)}\n\t\t</BreadcrumbWrapper>\n\t);\n};\n"
  },
  {
    "path": "client/src/Components/design-elements/BulletPointCheck.tsx",
    "content": "import Stack from \"@mui/material/Stack\";\nimport Typography from \"@mui/material/Typography\";\nimport { Check } from \"lucide-react\";\nimport { useTheme } from \"@mui/material/styles\";\nimport { LAYOUT } from \"@/Utils/Theme/constants\";\n\nexport const BulletPointCheck = ({\n\ttext,\n\tvariant = \"info\",\n}: {\n\ttext: string;\n\tnoHighlightText?: string;\n\tvariant?: \"success\" | \"error\" | \"info\";\n}) => {\n\tconst theme = useTheme();\n\tconst colors: Record<string, string | undefined> = {\n\t\tsuccess: theme.palette.success.main,\n\t\terror: theme.palette.error.main,\n\t\tinfo: theme.palette.text.secondary,\n\t};\n\n\treturn (\n\t\t<Stack\n\t\t\tdirection=\"row\"\n\t\t\tgap={theme.spacing(LAYOUT.SM)}\n\t\t\talignItems=\"center\"\n\t\t>\n\t\t\t<Check\n\t\t\t\tsize={16}\n\t\t\t\tstrokeWidth={1.5}\n\t\t\t\tcolor={variant === \"info\" ? theme.palette.text.secondary : colors[variant]}\n\t\t\t\tstyle={{\n\t\t\t\t\tflexShrink: 0,\n\t\t\t\t}}\n\t\t\t/>\n\t\t\t<Typography\n\t\t\t\tcomponent=\"span\"\n\t\t\t\tcolor={variant === \"info\" ? theme.palette.text.secondary : colors[variant]}\n\t\t\t\tfontWeight={450}\n\t\t\t\tsx={{\n\t\t\t\t\topacity: 0.9,\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t{text}\n\t\t\t</Typography>\n\t\t</Stack>\n\t);\n};\n"
  },
  {
    "path": "client/src/Components/design-elements/Dot.tsx",
    "content": "import type { CSSProperties } from \"react\";\n\ninterface DotProps {\n\tcolor?: string;\n\tsize?: string;\n\tstyle?: CSSProperties;\n}\n\nexport const Dot = ({ color = \"gray\", size = \"4px\", style }: DotProps) => {\n\treturn (\n\t\t<span\n\t\t\tstyle={{\n\t\t\t\tcontent: '\"\"',\n\t\t\t\twidth: size,\n\t\t\t\theight: size,\n\t\t\t\tborderRadius: \"50%\",\n\t\t\t\tbackgroundColor: color,\n\t\t\t\topacity: 0.8,\n\t\t\t\t...style,\n\t\t\t}}\n\t\t/>\n\t);\n};\n"
  },
  {
    "path": "client/src/Components/design-elements/Fallback.tsx",
    "content": "import Stack from \"@mui/material/Stack\";\nimport Typography from \"@mui/material/Typography\";\nimport { BulletPointCheck, SkeletonCard } from \"@/Components/design-elements\";\nimport { Button } from \"@/Components/inputs\";\nimport { SPACING, LAYOUT } from \"@/Utils/Theme/constants\";\n\nimport { useNavigate } from \"react-router\";\nimport useMediaQuery from \"@mui/material/useMediaQuery\";\nimport { useTheme } from \"@mui/material/styles\";\nimport type { StackProps } from \"@mui/material/Stack\";\n\ninterface BaseFallbackProps extends StackProps {\n\tchildren: React.ReactNode;\n}\n\nexport const BaseFallback = ({ children, ...props }: BaseFallbackProps) => {\n\tconst theme = useTheme();\n\tconst isSmall = useMediaQuery(theme.breakpoints.down(\"md\"));\n\n\treturn (\n\t\t<Stack\n\t\t\talignItems={\"center\"}\n\t\t\tmargin={isSmall ? \"inherit\" : \"auto\"}\n\t\t\tmarginTop={isSmall ? \"33%\" : \"10%\"}\n\t\t\twidth={{\n\t\t\t\tsm: \"90%\",\n\t\t\t\tmd: \"70%\",\n\t\t\t\tlg: \"50%\",\n\t\t\t\txl: \"40%\",\n\t\t\t}}\n\t\t\tpadding={{ xs: theme.spacing(LAYOUT.MD), md: theme.spacing(LAYOUT.XXL) }}\n\t\t\tbgcolor={theme.palette.background.paper}\n\t\t\tborder={1}\n\t\t\tborderColor={theme.palette.divider}\n\t\t\tborderRadius={theme.shape.borderRadius}\n\t\t\tsx={{\n\t\t\t\tborderStyle: \"dashed\",\n\t\t\t}}\n\t\t\t{...props}\n\t\t>\n\t\t\t<SkeletonCard showHalo={true} />\n\t\t\t{children}\n\t\t</Stack>\n\t);\n};\n\nexport const ErrorFallback = ({\n\ttitle,\n\tsubtitle,\n}: {\n\ttitle: string;\n\tsubtitle: string;\n}) => {\n\tconst theme = useTheme();\n\treturn (\n\t\t<BaseFallback>\n\t\t\t<Typography\n\t\t\t\tvariant=\"h1\"\n\t\t\t\tmarginY={theme.spacing(LAYOUT.XS)}\n\t\t\t\tcolor={theme.palette.text.secondary}\n\t\t\t>\n\t\t\t\t{title}\n\t\t\t</Typography>\n\t\t\t<Typography>{subtitle}</Typography>\n\t\t</BaseFallback>\n\t);\n};\n\nexport const EmptyFallback = ({\n\ttitle,\n\tbullets,\n\tactionButtonText,\n\tactionLink,\n}: {\n\ttitle: string;\n\tbullets: any;\n\tactionButtonText: string;\n\tactionLink: string;\n}) => {\n\tconst theme = useTheme();\n\tconst navigate = useNavigate();\n\treturn (\n\t\t<BaseFallback>\n\t\t\t<Stack\n\t\t\t\tgap={theme.spacing(LAYOUT.MD)}\n\t\t\t\tzIndex={1}\n\t\t\t\talignItems=\"center\"\n\t\t\t>\n\t\t\t\t<Typography component=\"h1\">{title}</Typography>\n\t\t\t\t<Stack\n\t\t\t\t\tsx={{\n\t\t\t\t\t\tflexWrap: \"wrap\",\n\t\t\t\t\t\tgap: theme.spacing(SPACING.MD),\n\t\t\t\t\t\tmaxWidth: \"1100px\",\n\t\t\t\t\t\twidth: \"100%\",\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t{Array.isArray(bullets) &&\n\t\t\t\t\t\tbullets?.map((bullet: string) => (\n\t\t\t\t\t\t\t<BulletPointCheck\n\t\t\t\t\t\t\t\ttext={bullet}\n\t\t\t\t\t\t\t\tkey={`${bullet}-${Math.random()}`}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t))}\n\t\t\t\t</Stack>\n\t\t\t\t<Stack>\n\t\t\t\t\t<Button\n\t\t\t\t\t\tvariant=\"contained\"\n\t\t\t\t\t\tcolor=\"primary\"\n\t\t\t\t\t\tonClick={() => navigate(actionLink)}\n\t\t\t\t\t>\n\t\t\t\t\t\t{actionButtonText}\n\t\t\t\t\t</Button>\n\t\t\t\t</Stack>\n\t\t\t</Stack>\n\t\t</BaseFallback>\n\t);\n};\n\nexport const EmptyMonitorFallback = ({\n\tpage,\n\ttitle,\n\tbullets,\n\tactionButtonText,\n\tactionLink,\n}: {\n\tpage: string;\n\ttitle: string;\n\tbullets: any;\n\tactionButtonText: string;\n\tactionLink: string;\n}) => {\n\tconst theme = useTheme();\n\tconst navigate = useNavigate();\n\treturn (\n\t\t<BaseFallback>\n\t\t\t<Stack\n\t\t\t\tgap={theme.spacing(LAYOUT.MD)}\n\t\t\t\tzIndex={1}\n\t\t\t\talignItems=\"center\"\n\t\t\t>\n\t\t\t\t<Typography\n\t\t\t\t\tcomponent=\"h1\"\n\t\t\t\t\tcolor={theme.palette.primary.contrastText}\n\t\t\t\t>\n\t\t\t\t\t{title}\n\t\t\t\t</Typography>\n\t\t\t\t<Stack\n\t\t\t\t\tsx={{\n\t\t\t\t\t\tflexWrap: \"wrap\",\n\t\t\t\t\t\tgap: theme.spacing(SPACING.MD),\n\t\t\t\t\t\tmaxWidth: \"1100px\",\n\t\t\t\t\t\twidth: \"100%\",\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t{Array.isArray(bullets) &&\n\t\t\t\t\t\tbullets?.map((bullet: string, index: number) => (\n\t\t\t\t\t\t\t<BulletPointCheck\n\t\t\t\t\t\t\t\ttext={bullet}\n\t\t\t\t\t\t\t\tkey={`${(page + \"Monitors\").trim().split(\" \")[0]}-${index}`}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t))}\n\t\t\t\t</Stack>\n\t\t\t\t<Stack>\n\t\t\t\t\t<Button\n\t\t\t\t\t\tvariant=\"contained\"\n\t\t\t\t\t\tcolor=\"primary\"\n\t\t\t\t\t\tonClick={() => navigate(actionLink)}\n\t\t\t\t\t>\n\t\t\t\t\t\t{actionButtonText}\n\t\t\t\t\t</Button>\n\t\t\t\t</Stack>\n\t\t\t</Stack>\n\t\t</BaseFallback>\n\t);\n};\n"
  },
  {
    "path": "client/src/Components/design-elements/Gauge.tsx",
    "content": "import { BaseChart } from \"@/Components/design-elements\";\nimport Stack from \"@mui/material/Stack\";\nimport Box from \"@mui/material/Box\";\nimport Typography from \"@mui/material/Typography\";\n\nimport { useTheme } from \"@mui/material/styles\";\nimport { useMemo, useState, useEffect } from \"react\";\nimport { getInfraGaugeColor } from \"@/Utils/MonitorUtils\";\n\nconst MINIMUM_VALUE = 0;\nconst MAXIMUM_VALUE = 100;\n\nexport const Gauge = ({\n\tisLoading = false,\n\tprogress = 0,\n\tradius = 70,\n\tstrokeWidth = 15,\n\tprecision = 1,\n\tunit = \"%\",\n}: {\n\tisLoading?: boolean;\n\tprogress?: number;\n\tradius?: number;\n\tstrokeWidth?: number;\n\tprecision?: number;\n\tunit?: string;\n}) => {\n\tconst theme = useTheme();\n\tconst progressWithinRange = Math.max(MINIMUM_VALUE, Math.min(progress, MAXIMUM_VALUE));\n\n\t// Calculate the length of the stroke for the circle\n\tconst { circumference, totalSize, strokeLength } = useMemo(\n\t\t() => ({\n\t\t\tcircumference: 2 * Math.PI * radius,\n\t\t\ttotalSize: radius * 2 + strokeWidth * 2,\n\t\t\tstrokeLength: (progress / 100) * (2 * Math.PI * radius),\n\t\t}),\n\t\t[radius, strokeWidth, progress]\n\t);\n\n\tconst [offset, setOffset] = useState(circumference);\n\tuseEffect(() => {\n\t\tsetOffset(circumference);\n\t\tconst timer = setTimeout(() => {\n\t\t\tsetOffset(circumference - strokeLength);\n\t\t}, 100);\n\n\t\treturn () => clearTimeout(timer);\n\t}, [progress, circumference, strokeLength]);\n\n\tconst fillColor = getInfraGaugeColor(progressWithinRange, theme);\n\n\tif (isLoading) {\n\t\treturn;\n\t}\n\n\treturn (\n\t\t<Box\n\t\t\tdisplay={\"inline-block\"}\n\t\t\tposition={\"relative\"}\n\t\t\twidth={radius}\n\t\t\theight={radius}\n\t\t\tbgcolor={theme.palette.background.paper}\n\t\t\tborderRadius={\"50%\"}\n\t\t>\n\t\t\t<svg\n\t\t\t\tviewBox={`0 0 ${totalSize} ${totalSize}`}\n\t\t\t\twidth={radius}\n\t\t\t\theight={radius}\n\t\t\t>\n\t\t\t\t<circle\n\t\t\t\t\tstroke={theme.palette.secondary.main}\n\t\t\t\t\tstrokeWidth={strokeWidth}\n\t\t\t\t\tfill=\"none\"\n\t\t\t\t\tcx={totalSize / 2}\n\t\t\t\t\tcy={totalSize / 2}\n\t\t\t\t\tr={radius}\n\t\t\t\t/>\n\t\t\t\t<circle\n\t\t\t\t\tstroke={fillColor}\n\t\t\t\t\tstrokeWidth={strokeWidth}\n\t\t\t\t\tstrokeDasharray={`${circumference} ${circumference}`}\n\t\t\t\t\tstrokeDashoffset={offset}\n\t\t\t\t\tfill=\"none\"\n\t\t\t\t\tcx={totalSize / 2}\n\t\t\t\t\tcy={totalSize / 2}\n\t\t\t\t\tr={radius}\n\t\t\t\t\tstyle={{\n\t\t\t\t\t\ttransform: \"rotate(-90deg)\",\n\t\t\t\t\t\ttransformOrigin: \"center\",\n\t\t\t\t\t\ttransition: \"stroke-dashoffset 1.5s ease-in-out\",\n\t\t\t\t\t}}\n\t\t\t\t/>\n\t\t\t</svg>\n\n\t\t\t<Typography\n\t\t\t\tstyle={{\n\t\t\t\t\tposition: \"absolute\",\n\t\t\t\t\ttop: \"50%\",\n\t\t\t\t\tleft: \"50%\",\n\t\t\t\t\ttransform: \"translate(-50%, -50%)\",\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t{`${progressWithinRange.toFixed(precision)}${unit}`}\n\t\t\t</Typography>\n\t\t</Box>\n\t);\n};\n\nexport const DetailGauge = ({\n\ttitle,\n\tprogress,\n\tupperLabel,\n\tupperValue,\n\tlowerLabel,\n\tlowerValue,\n}: {\n\ttitle: string;\n\tprogress: number;\n\tupperLabel?: string;\n\tupperValue?: string | number;\n\tlowerLabel?: string;\n\tlowerValue?: string | number;\n}) => {\n\tconst theme = useTheme();\n\treturn (\n\t\t<BaseChart\n\t\t\ticon={null}\n\t\t\ttitle={title}\n\t\t\tmaxWidth={225}\n\t\t>\n\t\t\t<Stack\n\t\t\t\talignItems={\"center\"}\n\t\t\t\tmb={theme.spacing(4)}\n\t\t\t\tgap={theme.spacing(4)}\n\t\t\t>\n\t\t\t\t<Gauge progress={progress} />\n\t\t\t</Stack>\n\t\t\t<Stack\n\t\t\t\tdirection={\"row\"}\n\t\t\t\tjustifyContent={\"space-between\"}\n\t\t\t>\n\t\t\t\t<Typography>{upperLabel}</Typography>\n\t\t\t\t<Typography>{upperValue}</Typography>\n\t\t\t</Stack>\n\t\t\t<Stack\n\t\t\t\tdirection={\"row\"}\n\t\t\t\tjustifyContent={\"space-between\"}\n\t\t\t>\n\t\t\t\t<Typography>{lowerLabel}</Typography>\n\t\t\t\t<Typography>{lowerValue}</Typography>\n\t\t\t</Stack>\n\t\t</BaseChart>\n\t);\n};\n"
  },
  {
    "path": "client/src/Components/design-elements/Icon.tsx",
    "content": "import type { LucideIcon } from \"lucide-react\";\n\ninterface IconProps {\n\ticon: LucideIcon;\n\tsize?: number;\n\tstrokeWidth?: number;\n\tstroke?: string;\n}\n\nconst Icon = ({ icon: Icon, size = 20, strokeWidth = 1.5 }: IconProps) => {\n\treturn (\n\t\t<Icon\n\t\t\tsize={size}\n\t\t\tstrokeWidth={strokeWidth}\n\t\t/>\n\t);\n};\n\nexport default Icon;\n"
  },
  {
    "path": "client/src/Components/design-elements/MonitorStatus.tsx",
    "content": "import type { Monitor } from \"@/Types/Monitor\";\nimport Stack from \"@mui/material/Stack\";\nimport Typography from \"@mui/material/Typography\";\nimport { PulseDot, Dot } from \"@/Components/design-elements\";\nimport { getStatusColor, formatUrl } from \"@/Utils/MonitorUtils\";\nimport { useTheme } from \"@mui/material/styles\";\nimport prettyMilliseconds from \"pretty-ms\";\nimport { typographyLevels } from \"@/Utils/Theme/Palette\";\nimport useMediaQuery from \"@mui/material/useMediaQuery\";\nexport const MonitorStatus = ({ monitor }: { monitor: Monitor }) => {\n\tconst theme = useTheme();\n\tconst isSmall = useMediaQuery(theme.breakpoints.down(\"md\"));\n\n\tif (!monitor) {\n\t\treturn null;\n\t}\n\treturn (\n\t\t<Stack>\n\t\t\t<Typography\n\t\t\t\tfontSize={typographyLevels.xl}\n\t\t\t\tfontWeight={500}\n\t\t\t\toverflow={\"hidden\"}\n\t\t\t\ttextOverflow={\"ellipsis\"}\n\t\t\t\twhiteSpace={\"nowrap\"}\n\t\t\t>\n\t\t\t\t{monitor.name}\n\t\t\t</Typography>\n\t\t\t<Stack\n\t\t\t\tdirection=\"row\"\n\t\t\t\talignItems={\"center\"}\n\t\t\t\tgap={theme.spacing(4)}\n\t\t\t>\n\t\t\t\t<PulseDot color={getStatusColor(monitor.status, theme)} />\n\t\t\t\t<Typography\n\t\t\t\t\tfontSize={typographyLevels.l}\n\t\t\t\t\tfontWeight={\"bolder\"}\n\t\t\t\t\tfontFamily={\"monospace\"}\n\t\t\t\t\toverflow={\"hidden\"}\n\t\t\t\t\ttextOverflow={\"ellipsis\"}\n\t\t\t\t\twhiteSpace={\"nowrap\"}\n\t\t\t\t>\n\t\t\t\t\t{formatUrl(monitor?.url)}\n\t\t\t\t</Typography>\n\t\t\t\t{!isSmall && (\n\t\t\t\t\t<>\n\t\t\t\t\t\t<Dot />\n\t\t\t\t\t\t<Typography>\n\t\t\t\t\t\t\tChecking every {prettyMilliseconds(monitor?.interval, { verbose: true })}\n\t\t\t\t\t\t</Typography>\n\t\t\t\t\t</>\n\t\t\t\t)}\n\t\t\t</Stack>\n\t\t</Stack>\n\t);\n};\n"
  },
  {
    "path": "client/src/Components/design-elements/OfflineBanner.tsx",
    "content": "import Box from \"@mui/material/Box\";\nimport Stack from \"@mui/material/Stack\";\nimport Typography from \"@mui/material/Typography\";\nimport { useTheme } from \"@mui/material/styles\";\nimport { useTranslation } from \"react-i18next\";\nimport { WifiOff } from \"lucide-react\";\nimport { useState, useEffect } from \"react\";\n\ninterface OfflineBannerProps {\n\tvisible: boolean;\n}\n\nexport const OfflineBanner = ({ visible }: OfflineBannerProps) => {\n\tconst theme = useTheme();\n\tconst { t } = useTranslation();\n\tconst [shouldRender, setShouldRender] = useState(visible);\n\tconst [isAnimating, setIsAnimating] = useState(false);\n\n\tuseEffect(() => {\n\t\tif (visible) {\n\t\t\tsetShouldRender(true);\n\t\t\trequestAnimationFrame(() => setIsAnimating(true));\n\t\t} else {\n\t\t\tsetIsAnimating(false);\n\t\t\tconst timer = setTimeout(() => setShouldRender(false), 1000);\n\t\t\treturn () => clearTimeout(timer);\n\t\t}\n\t}, [visible]);\n\n\tif (!shouldRender) return null;\n\n\treturn (\n\t\t<Box\n\t\t\tsx={{\n\t\t\t\tposition: \"fixed\",\n\t\t\t\ttop: isAnimating ? 0 : \"-100%\",\n\t\t\t\tleft: 0,\n\t\t\t\tright: 0,\n\t\t\t\tzIndex: theme.zIndex.snackbar,\n\t\t\t\tbackgroundColor: theme.palette.error.main,\n\t\t\t\tcolor: theme.palette.error.contrastText,\n\t\t\t\tpx: theme.spacing(8),\n\t\t\t\tpy: theme.spacing(4),\n\t\t\t\ttransition: \"top 1s ease-in-out\",\n\t\t\t}}\n\t\t>\n\t\t\t<Stack\n\t\t\t\tdirection=\"row\"\n\t\t\t\talignItems=\"center\"\n\t\t\t\tjustifyContent=\"center\"\n\t\t\t\tgap={theme.spacing(4)}\n\t\t\t>\n\t\t\t\t<WifiOff size={20} />\n\t\t\t\t<Typography\n\t\t\t\t\tvariant=\"body2\"\n\t\t\t\t\tfontWeight={500}\n\t\t\t\t>\n\t\t\t\t\t{t(\"components.offlineBanner.serverUnreachable\")}\n\t\t\t\t</Typography>\n\t\t\t</Stack>\n\t\t</Box>\n\t);\n};\n"
  },
  {
    "path": "client/src/Components/design-elements/PulseDot.tsx",
    "content": "import Box from \"@mui/material/Box\";\nimport Stack from \"@mui/material/Stack\";\nimport { useTheme, keyframes } from \"@mui/material\";\n\nconst ripple = keyframes`\n\tfrom {\n\t\topacity: 1;\n\t\ttransform: scale(0);\n\t}\n\tto {\n\t\topacity: 0;\n\t\ttransform: scale(2);\n\t}\n`;\n\ninterface PulseDotProps {\n\tcolor: string;\n}\n\nexport const PulseDot = ({ color }: PulseDotProps) => {\n\tconst theme = useTheme();\n\n\treturn (\n\t\t<Stack\n\t\t\twidth=\"26px\"\n\t\t\theight=\"24px\"\n\t\t\talignItems=\"center\"\n\t\t\tjustifyContent=\"center\"\n\t\t>\n\t\t\t<Box\n\t\t\t\tminWidth=\"18px\"\n\t\t\t\tminHeight=\"18px\"\n\t\t\t\tsx={{\n\t\t\t\t\tposition: \"relative\",\n\t\t\t\t\tbackgroundColor: color,\n\t\t\t\t\tborderRadius: \"50%\",\n\t\t\t\t\t\"&::before\": {\n\t\t\t\t\t\tcontent: `\"\"`,\n\t\t\t\t\t\tposition: \"absolute\",\n\t\t\t\t\t\twidth: \"100%\",\n\t\t\t\t\t\theight: \"100%\",\n\t\t\t\t\t\tbackgroundColor: \"inherit\",\n\t\t\t\t\t\tborderRadius: \"50%\",\n\t\t\t\t\t\tanimation: `${ripple} 1.8s ease-out infinite`,\n\t\t\t\t\t},\n\t\t\t\t\t\"&::after\": {\n\t\t\t\t\t\tcontent: `\"\"`,\n\t\t\t\t\t\tposition: \"absolute\",\n\t\t\t\t\t\twidth: \"7px\",\n\t\t\t\t\t\theight: \"7px\",\n\t\t\t\t\t\tborderRadius: \"50%\",\n\t\t\t\t\t\tbackgroundColor: theme.palette.background.paper,\n\t\t\t\t\t\ttop: \"50%\",\n\t\t\t\t\t\tleft: \"50%\",\n\t\t\t\t\t\ttransform: \"translate(-50%, -50%)\",\n\t\t\t\t\t},\n\t\t\t\t}}\n\t\t\t/>\n\t\t</Stack>\n\t);\n};\n"
  },
  {
    "path": "client/src/Components/design-elements/SkeletonCard.tsx",
    "content": "import { Box, Stack, useTheme } from \"@mui/material\";\n\ninterface SkeletonCardProps {\n\twidth?: number | string | { xs?: number | string; md?: number | string };\n\tshowHalo?: boolean;\n}\n\nexport const SkeletonCard = ({\n\twidth = { xs: 130, md: 216 },\n\tshowHalo = true,\n}: SkeletonCardProps) => {\n\tconst theme = useTheme();\n\tconst pulseAnimation = {\n\t\t\"@keyframes pulse\": {\n\t\t\t\"0%, 100%\": { opacity: 1 },\n\t\t\t\"50%\": { opacity: 0.72 },\n\t\t},\n\t};\n\n\tconst floatAnimation = {\n\t\t\"@keyframes float\": {\n\t\t\t\"0%, 100%\": { transform: \"rotate(5deg) translate(12px, -20px)\" },\n\t\t\t\"50%\": { transform: \"rotate(5deg) translate(12px, -24px)\" },\n\t\t},\n\t};\n\n\tconst cardStyle = {\n\t\twidth: width,\n\t\theight: 57,\n\t\tborderRadius: theme.shape.borderRadius,\n\t\tbackground:\n\t\t\ttheme.palette.mode === \"dark\"\n\t\t\t\t? theme.palette.secondary.dark\n\t\t\t\t: theme.palette.background.paper,\n\t\tboxShadow:\n\t\t\ttheme.palette.mode === \"dark\"\n\t\t\t\t? \"0 8px 30px rgba(0,0,0,.3), 0 0 0 1px rgba(255,255,255,.05) inset\"\n\t\t\t\t: \"0 8px 30px rgba(0,0,0,.08), 0 0 0 1px rgba(0,0,0,.05) inset\",\n\t\tdisplay: \"flex\",\n\t\tgap: theme.spacing(5),\n\t\talignItems: \"center\",\n\t\tpadding: theme.spacing(5),\n\t};\n\n\tconst blockStyle = {\n\t\twidth: 55,\n\t\theight: 34,\n\t\tborderRadius: theme.shape.borderRadius,\n\t\tbackground: theme.palette.secondary.main,\n\t\tborder: `1px solid ${theme.palette.divider}`,\n\t\tanimation: \"pulse 1.6s ease-in-out infinite\",\n\t\t...pulseAnimation,\n\t};\n\n\tconst lineStyle = {\n\t\theight: 7,\n\t\tborderRadius: theme.shape.borderRadius,\n\t\tbackground: theme.palette.secondary.main,\n\t\tborder: `1px solid ${theme.palette.divider}`,\n\t\tanimation: \"pulse 1.6s ease-in-out infinite\",\n\t\t...pulseAnimation,\n\t};\n\n\treturn (\n\t\t<Box\n\t\t\tposition={\"relative\"}\n\t\t\tmt={20}\n\t\t\tmb={20}\n\t\t>\n\t\t\t{showHalo && (\n\t\t\t\t<Box\n\t\t\t\t\tsx={{\n\t\t\t\t\t\tposition: \"absolute\",\n\t\t\t\t\t\tinset: 0,\n\t\t\t\t\t\tdisplay: \"grid\",\n\t\t\t\t\t\tplaceItems: \"center\",\n\t\t\t\t\t\tpointerEvents: \"none\",\n\t\t\t\t\t\t\"&::before\": {\n\t\t\t\t\t\t\tcontent: '\"\"',\n\t\t\t\t\t\t\twidth: \"260px\",\n\t\t\t\t\t\t\theight: \"260px\",\n\t\t\t\t\t\t\tborderRadius: \"999px\",\n\t\t\t\t\t\t\tbackground:\n\t\t\t\t\t\t\t\ttheme.palette.mode === \"dark\" ? \"rgba(255, 255, 255, 0.05)\" : \"#fff\",\n\t\t\t\t\t\t\tfilter: \"blur(60px)\",\n\t\t\t\t\t\t\topacity: 0.9,\n\t\t\t\t\t\t},\n\t\t\t\t\t}}\n\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t/>\n\t\t\t)}\n\n\t\t\t{/* Card stack */}\n\t\t\t<Box sx={{ position: \"relative\", zIndex: 1 }}>\n\t\t\t\t{/* Front card (now at bottom) */}\n\t\t\t\t<Box sx={cardStyle}>\n\t\t\t\t\t<Box sx={blockStyle} />\n\t\t\t\t\t<Stack sx={{ flex: 1, gap: \"12px\" }}>\n\t\t\t\t\t\t{/* Empty space to maintain card height */}\n\t\t\t\t\t</Stack>\n\t\t\t\t</Box>\n\n\t\t\t\t{/* Back card A */}\n\t\t\t\t<Box\n\t\t\t\t\tsx={{\n\t\t\t\t\t\t...cardStyle,\n\t\t\t\t\t\ttransform: \"rotate(-4deg) translate(-12px, -12px)\",\n\t\t\t\t\t\tfilter: \"blur(.2px)\",\n\t\t\t\t\t\tposition: \"absolute\",\n\t\t\t\t\t\tleft: 0,\n\t\t\t\t\t\ttop: 0,\n\t\t\t\t\t}}\n\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t>\n\t\t\t\t\t<Box sx={blockStyle} />\n\t\t\t\t\t<Stack sx={{ flex: 1, gap: \"12px\" }}>\n\t\t\t\t\t\t<Box sx={{ ...lineStyle, width: \"60%\" }} />\n\t\t\t\t\t\t<Box sx={{ ...lineStyle, width: \"80%\" }} />\n\t\t\t\t\t\t<Box sx={{ ...lineStyle, width: \"40%\" }} />\n\t\t\t\t\t</Stack>\n\t\t\t\t</Box>\n\n\t\t\t\t{/* Back card B */}\n\t\t\t\t<Box\n\t\t\t\t\tsx={{\n\t\t\t\t\t\t...cardStyle,\n\t\t\t\t\t\ttransform: \"rotate(5deg) translate(12px, -20px)\",\n\t\t\t\t\t\tfilter: \"blur(.3px)\",\n\t\t\t\t\t\tposition: \"absolute\",\n\t\t\t\t\t\tleft: 0,\n\t\t\t\t\t\ttop: 0,\n\t\t\t\t\t\tanimation: \"float 3s ease-in-out 5\",\n\t\t\t\t\t\t...floatAnimation,\n\t\t\t\t\t}}\n\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t>\n\t\t\t\t\t<Box sx={blockStyle} />\n\t\t\t\t\t<Stack sx={{ flex: 1, gap: \"12px\" }}>\n\t\t\t\t\t\t<Box sx={{ ...lineStyle, width: \"60%\" }} />\n\t\t\t\t\t\t<Box sx={{ ...lineStyle, width: \"80%\" }} />\n\t\t\t\t\t\t<Box sx={{ ...lineStyle, width: \"40%\" }} />\n\t\t\t\t\t</Stack>\n\t\t\t\t</Box>\n\t\t\t</Box>\n\t\t</Box>\n\t);\n};\n"
  },
  {
    "path": "client/src/Components/design-elements/SplitBox.tsx",
    "content": "import Stack from \"@mui/material/Stack\";\nimport Box from \"@mui/material/Box\";\nimport Typography from \"@mui/material/Typography\";\nimport { useTheme } from \"@mui/material/styles\";\nimport useMediaQuery from \"@mui/material/useMediaQuery\";\nimport { LAYOUT } from \"@/Utils/Theme/constants\";\nexport const SplitBox = ({\n\tleft,\n\tright,\n}: {\n\tleft: React.ReactNode;\n\tright: React.ReactNode;\n}) => {\n\tconst theme = useTheme();\n\tconst isSmall = useMediaQuery(theme.breakpoints.down(\"md\"));\n\treturn (\n\t\t<Stack\n\t\t\tdirection={isSmall ? \"column\" : \"row\"}\n\t\t\tbgcolor={theme.palette.background.paper}\n\t\t\tborder={1}\n\t\t\tborderColor={theme.palette.divider}\n\t\t\tborderRadius={theme.shape.borderRadius}\n\t\t>\n\t\t\t<Box\n\t\t\t\tpadding={theme.spacing(LAYOUT.XXL)}\n\t\t\t\tborderRight={isSmall ? 0 : 1}\n\t\t\t\tborderBottom={isSmall ? 1 : 0}\n\t\t\t\tborderColor={theme.palette.divider}\n\t\t\t\tflex={0.7}\n\t\t\t\tsx={{\n\t\t\t\t\tbackground:\n\t\t\t\t\t\ttheme.palette.mode === \"dark\"\n\t\t\t\t\t\t\t? \"linear-gradient(135deg, rgba(255, 255, 255, 0.01) 0%, rgba(255, 255, 255, 0.02) 100%)\"\n\t\t\t\t\t\t\t: \"linear-gradient(135deg, rgba(0, 0, 0, 0.01) 0%, rgba(0, 0, 0, 0.02) 100%)\",\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t{left}\n\t\t\t</Box>\n\t\t\t<Box\n\t\t\t\tflex={1}\n\t\t\t\tpadding={theme.spacing(LAYOUT.XXL)}\n\t\t\t>\n\t\t\t\t{right}\n\t\t\t</Box>\n\t\t</Stack>\n\t);\n};\n\nexport const ConfigBox = ({\n\ttitle,\n\tsubtitle,\n\tleftContent,\n\trightContent,\n}: {\n\ttitle: string;\n\tsubtitle: string;\n\tleftContent?: React.ReactNode;\n\trightContent: React.ReactNode;\n}) => {\n\tconst theme = useTheme();\n\treturn (\n\t\t<SplitBox\n\t\t\tleft={\n\t\t\t\t<Stack spacing={theme.spacing(LAYOUT.XS)}>\n\t\t\t\t\t<Typography\n\t\t\t\t\t\ttextTransform={\"capitalize\"}\n\t\t\t\t\t\tcomponent=\"h2\"\n\t\t\t\t\t\tvariant=\"h2\"\n\t\t\t\t\t>\n\t\t\t\t\t\t{title}\n\t\t\t\t\t</Typography>\n\t\t\t\t\t<Typography component=\"p\">{subtitle}</Typography>\n\t\t\t\t\t{leftContent}\n\t\t\t\t</Stack>\n\t\t\t}\n\t\t\tright={rightContent}\n\t\t/>\n\t);\n};\n"
  },
  {
    "path": "client/src/Components/design-elements/StatBox.tsx",
    "content": "import Stack from \"@mui/material/Stack\";\nimport Typography from \"@mui/material/Typography\";\nimport Box from \"@mui/material/Box\";\nimport { useTheme } from \"@mui/material/styles\";\nimport { lighten } from \"@mui/material/styles\";\nimport useMediaQuery from \"@mui/material/useMediaQuery\";\nimport type { PaletteKey } from \"@/Utils/Theme/Theme\";\nimport { BaseBox, TooltipWithInfo } from \"@/Components/design-elements\";\nimport type { SxProps } from \"@mui/material\";\n\ntype GradientBox = React.PropsWithChildren<{\n\tpalette?: PaletteKey;\n\tsx?: SxProps;\n}>;\n\nexport const GradientBox = ({ children, palette, sx }: GradientBox) => {\n\tconst theme = useTheme();\n\tconst isSmall = useMediaQuery(theme.breakpoints.down(\"md\"));\n\tconst isLight = theme.palette.mode === \"light\";\n\tconst paper = theme.palette.background.paper;\n\tconst paperStart = lighten(paper, isLight ? 0.06 : 0.08);\n\tconst paperEnd = paper;\n\tconst bg = palette\n\t\t? `linear-gradient(135deg, ${theme.palette[palette].light} 0%, ${theme.palette[palette].main} 100%)`\n\t\t: `linear-gradient(135deg, ${paperStart} 0%, ${paperEnd} 100%)`;\n\n\treturn (\n\t\t<BaseBox\n\t\t\tsx={{\n\t\t\t\tpadding: `${theme.spacing(4)} ${theme.spacing(8)}`,\n\t\t\t\twidth: isSmall ? `100%` : `calc(25% - (3 * ${theme.spacing(8)} / 4))`,\n\t\t\t\tbackground: bg,\n\t\t\t\t...sx,\n\t\t\t}}\n\t\t>\n\t\t\t{children}\n\t\t</BaseBox>\n\t);\n};\n\ntype StatBoxProps = React.PropsWithChildren<{\n\ttitle: string;\n\tsubtitle: string;\n\tpalette?: PaletteKey;\n\tsx?: SxProps;\n\ttooltip?: string;\n\tonClick?: () => void;\n}>;\n\nexport const StatBox = ({\n\ttitle,\n\tsubtitle,\n\tpalette,\n\tchildren,\n\tsx,\n\ttooltip,\n\tonClick,\n}: StatBoxProps) => {\n\tconst theme = useTheme();\n\tconst textColor = palette ? theme.palette[palette].contrastText : \"inherit\";\n\n\treturn (\n\t\t<GradientBox\n\t\t\tpalette={palette}\n\t\t\tsx={{\n\t\t\t\t...(sx as object),\n\t\t\t\t...(onClick ? { cursor: \"pointer\", \"&:hover\": { opacity: 0.95 } } : {}),\n\t\t\t}}\n\t\t>\n\t\t\t<Stack onClick={onClick}>\n\t\t\t\t<Box sx={{ display: \"flex\", alignItems: \"center\", gap: theme.spacing(2) }}>\n\t\t\t\t\t<Typography color={textColor}>{title}</Typography>\n\t\t\t\t\t{tooltip && (\n\t\t\t\t\t\t<TooltipWithInfo\n\t\t\t\t\t\t\ttitle={tooltip}\n\t\t\t\t\t\t\ticonColor={textColor as string}\n\t\t\t\t\t\t\ticonSize={14}\n\t\t\t\t\t\t/>\n\t\t\t\t\t)}\n\t\t\t\t</Box>\n\t\t\t\t<Typography color={textColor}>{subtitle}</Typography>\n\t\t\t\t{children}\n\t\t\t</Stack>\n\t\t</GradientBox>\n\t);\n};\n"
  },
  {
    "path": "client/src/Components/design-elements/StatusBox.tsx",
    "content": "import Stack from \"@mui/material/Stack\";\nimport Typography from \"@mui/material/Typography\";\nimport Box from \"@mui/material/Box\";\nimport { BaseBox } from \"@/Components/design-elements\";\nimport { useTranslation } from \"react-i18next\";\nimport type { SxProps } from \"@mui/material\";\n\nimport { useTheme } from \"@mui/material/styles\";\n\ntype StatusBoxProps = React.PropsWithChildren<{\n\tchildren: React.ReactNode;\n\tsx?: SxProps;\n}>;\n\nexport const BGBox = ({ children, sx }: StatusBoxProps) => {\n\tconst theme = useTheme();\n\treturn (\n\t\t<BaseBox\n\t\t\tsx={{\n\t\t\t\tbackgroundColor: theme.palette.background.default,\n\t\t\t\toverflow: \"hidden\",\n\t\t\t\tposition: \"relative\",\n\t\t\t\tflex: 1,\n\t\t\t\tpadding: theme.spacing(4),\n\t\t\t\t...sx,\n\t\t\t}}\n\t\t>\n\t\t\t<Box\n\t\t\t\tposition=\"absolute\"\n\t\t\t\ttop={0}\n\t\t\t\tleft={0}\n\t\t\t\tright={0}\n\t\t\t\tbottom={0}\n\t\t\t\tsx={{\n\t\t\t\t\tpointerEvents: \"none\",\n\t\t\t\t\tbackgroundImage: `\n\t\t\t\t\t\tlinear-gradient(${theme.palette.divider} 1px, transparent 1px),\n\t\t\t\t\t\tlinear-gradient(90deg, ${theme.palette.divider} 1px, transparent 1px)\n\t\t\t\t\t`,\n\t\t\t\t\tbackgroundSize: \"24px 24px\",\n\t\t\t\t\tmaskImage:\n\t\t\t\t\t\t\"linear-gradient(135deg, rgba(0,0,0,0) 0%, rgba(0,0,0,0) 30%, rgba(0,0,0,0.4) 100%)\",\n\t\t\t\t\tWebkitMaskImage:\n\t\t\t\t\t\t\"linear-gradient(135deg, rgba(0,0,0,0) 0%, rgba(0,0,0,0) 30%, rgba(0,0,0,0.4) 100%)\",\n\t\t\t\t}}\n\t\t\t/>\n\t\t\t{children}\n\t\t</BaseBox>\n\t);\n};\n\nconst StatusBox = ({\n\tlabel,\n\tn,\n\tcolor,\n\tsx,\n}: {\n\tlabel: string;\n\tn: number;\n\tcolor: string | undefined;\n\tsx?: SxProps;\n}) => {\n\tconst theme = useTheme();\n\treturn (\n\t\t<BGBox sx={sx}>\n\t\t\t<Stack spacing={theme.spacing(4)}>\n\t\t\t\t<Typography\n\t\t\t\t\tvariant={\"h2\"}\n\t\t\t\t\ttextTransform=\"uppercase\"\n\t\t\t\t\tcolor={theme.palette.text.secondary}\n\t\t\t\t>\n\t\t\t\t\t{label}\n\t\t\t\t</Typography>\n\t\t\t\t<Typography\n\t\t\t\t\tvariant=\"h1\"\n\t\t\t\t\tcolor={color}\n\t\t\t\t>\n\t\t\t\t\t{n}\n\t\t\t\t</Typography>\n\t\t\t</Stack>\n\t\t</BGBox>\n\t);\n};\n\nexport const UpStatusBox = ({ n }: { n: number }) => {\n\tconst theme = useTheme();\n\tconst { t } = useTranslation();\n\treturn (\n\t\t<StatusBox\n\t\t\tlabel={t(\"pages.common.monitors.status.up\")}\n\t\t\tn={n}\n\t\t\tcolor={theme.palette.success.light}\n\t\t/>\n\t);\n};\n\nexport const DownStatusBox = ({ n }: { n: number }) => {\n\tconst theme = useTheme();\n\tconst { t } = useTranslation();\n\treturn (\n\t\t<StatusBox\n\t\t\tlabel={t(\"pages.common.monitors.status.down\")}\n\t\t\tn={n}\n\t\t\tcolor={theme.palette.error.light}\n\t\t/>\n\t);\n};\n\nexport const PausedStatusBox = ({ n }: { n: number }) => {\n\tconst theme = useTheme();\n\tconst { t } = useTranslation();\n\treturn (\n\t\t<StatusBox\n\t\t\tlabel={t(\"pages.common.monitors.status.paused\")}\n\t\t\tn={n}\n\t\t\tcolor={theme.palette.warning.light}\n\t\t/>\n\t);\n};\nexport const MaintenanceStatusBox = ({ n }: { n: number }) => {\n\tconst theme = useTheme();\n\tconst { t } = useTranslation();\n\treturn (\n\t\t<StatusBox\n\t\t\tlabel={t(\"pages.common.monitors.status.maintenance\")}\n\t\t\tn={n}\n\t\t\tcolor={theme.palette.warning.light}\n\t\t/>\n\t);\n};\nexport const InitializingStatusBox = ({ n }: { n: number }) => {\n\tconst theme = useTheme();\n\tconst { t } = useTranslation();\n\treturn (\n\t\t<StatusBox\n\t\t\tlabel={t(\"pages.common.monitors.status.initializing\")}\n\t\t\tn={n}\n\t\t\tcolor={theme.palette.warning.light}\n\t\t/>\n\t);\n};\nexport const BreachedStatusBox = ({ n }: { n: number }) => {\n\tconst theme = useTheme();\n\tconst { t } = useTranslation();\n\treturn (\n\t\t<StatusBox\n\t\t\tlabel={t(\"pages.common.monitors.status.breached\")}\n\t\t\tn={n}\n\t\t\tcolor={theme.palette.warning.main}\n\t\t/>\n\t);\n};\n\nexport const TotalChecksBox = ({ n }: { n: number }) => {\n\tconst theme = useTheme();\n\tconst { t } = useTranslation();\n\treturn (\n\t\t<StatusBox\n\t\t\tlabel={t(\"pages.common.monitors.status.total\")}\n\t\t\tn={n}\n\t\t\tcolor={theme.palette.primary.light}\n\t\t/>\n\t);\n};\nexport const DownChecksBox = ({ n }: { n: number }) => {\n\tconst theme = useTheme();\n\tconst { t } = useTranslation();\n\treturn (\n\t\t<StatusBox\n\t\t\tlabel={t(\"pages.common.monitors.status.down\")}\n\t\t\tn={n}\n\t\t\tcolor={theme.palette.error.light}\n\t\t/>\n\t);\n};\nexport const UpChecksBox = ({ n }: { n: number }) => {\n\tconst theme = useTheme();\n\tconst { t } = useTranslation();\n\treturn (\n\t\t<StatusBox\n\t\t\tlabel={t(\"pages.common.monitors.status.up\")}\n\t\t\tn={n}\n\t\t\tcolor={theme.palette.success.light}\n\t\t/>\n\t);\n};\n"
  },
  {
    "path": "client/src/Components/design-elements/StatusLabel.tsx",
    "content": "import Box from \"@mui/material/Box\";\nimport { BaseBox } from \"@/Components/design-elements\";\nimport Typography from \"@mui/material/Typography\";\n\nimport type { MonitorStatus } from \"@/Types/Monitor\";\nimport type { SxProps } from \"@mui/material/styles\";\nimport { getStatusPalette, getValuePalette } from \"@/Utils/MonitorUtils\";\nimport { useTheme } from \"@mui/material/styles\";\nimport { useTranslation } from \"react-i18next\";\n\nexport const ValueTypes = [\"positive\", \"negative\", \"neutral\"] as const;\nexport type ValueType = (typeof ValueTypes)[number];\n\nexport const StatusLabel = ({ status, sx }: { status: MonitorStatus; sx?: SxProps }) => {\n\tconst { t } = useTranslation();\n\tconst theme = useTheme();\n\tconst palette = getStatusPalette(status);\n\n\tconst determineStatus = (status: MonitorStatus): string => {\n\t\tif (status === \"up\") {\n\t\t\treturn t(\"pages.common.monitors.status.up\");\n\t\t} else if (status === \"down\") {\n\t\t\treturn t(\"pages.common.monitors.status.down\");\n\t\t} else if (status === \"breached\") {\n\t\t\treturn t(\"pages.common.monitors.status.breached\");\n\t\t} else if (status === \"maintenance\") {\n\t\t\treturn t(\"pages.common.monitors.status.maintenance\");\n\t\t} else if (status === \"paused\") {\n\t\t\treturn t(\"pages.common.monitors.status.paused\");\n\t\t} else if (status === \"initializing\") {\n\t\t\treturn t(\"pages.common.monitors.status.initializing\");\n\t\t}\n\n\t\treturn t(\"pages.common.monitors.status.initializing\");\n\t};\n\n\treturn (\n\t\t<BaseBox\n\t\t\tsx={{\n\t\t\t\tdisplay: \"inline-flex\",\n\t\t\t\tflexDirection: \"row\",\n\t\t\t\talignItems: \"center\",\n\t\t\t\tjustifyContent: \"center\",\n\t\t\t\tpadding: theme.spacing(3, 5),\n\t\t\t\tcolor: theme.palette[palette].main,\n\t\t\t\tborderColor:\n\t\t\t\t\ttheme.palette.mode === \"dark\"\n\t\t\t\t\t\t? \"rgba(255, 255, 255, 0.08)\"\n\t\t\t\t\t\t: \"rgba(0, 0, 0, 0.08)\",\n\t\t\t\t...sx,\n\t\t\t}}\n\t\t>\n\t\t\t<Box\n\t\t\t\twidth={7}\n\t\t\t\theight={7}\n\t\t\t\tbgcolor={theme.palette[palette].light}\n\t\t\t\tborderRadius=\"50%\"\n\t\t\t\tmarginRight=\"5px\"\n\t\t\t/>\n\t\t\t<Typography textTransform={\"capitalize\"}>{determineStatus(status)}</Typography>\n\t\t</BaseBox>\n\t);\n};\n\nexport const ValueLabel = ({ value, text }: { value: ValueType; text: string }) => {\n\tconst theme = useTheme();\n\tconst palette = getValuePalette(value);\n\tconst transformedText = text.charAt(0).toUpperCase() + text.slice(1).toLowerCase();\n\n\treturn (\n\t\t<BaseBox\n\t\t\tsx={{\n\t\t\t\tdisplay: \"inline-flex\",\n\t\t\t\tflexDirection: \"row\",\n\t\t\t\talignItems: \"center\",\n\t\t\t\tjustifyContent: \"center\",\n\t\t\t\tpadding: theme.spacing(3, 5),\n\t\t\t\tcolor: theme.palette[palette].main,\n\t\t\t\tborderColor:\n\t\t\t\t\ttheme.palette.mode === \"dark\"\n\t\t\t\t\t\t? \"rgba(255, 255, 255, 0.08)\"\n\t\t\t\t\t\t: \"rgba(0, 0, 0, 0.08)\",\n\t\t\t}}\n\t\t>\n\t\t\t<Box\n\t\t\t\twidth={7}\n\t\t\t\theight={7}\n\t\t\t\tbgcolor={theme.palette[palette].light}\n\t\t\t\tborderRadius=\"50%\"\n\t\t\t\tmarginRight=\"5px\"\n\t\t\t/>\n\t\t\t<Typography>{transformedText}</Typography>\n\t\t</BaseBox>\n\t);\n};\n"
  },
  {
    "path": "client/src/Components/design-elements/Table.tsx",
    "content": "import Stack from \"@mui/material/Stack\";\nimport Grid2 from \"@mui/material/Grid\";\nimport Box from \"@mui/material/Box\";\nimport Typography from \"@mui/material/Typography\";\nimport Paper from \"@mui/material/Paper\";\nimport Table from \"@mui/material/Table\";\nimport TableBody from \"@mui/material/TableBody\";\nimport TableCell from \"@mui/material/TableCell\";\nimport TableContainer from \"@mui/material/TableContainer\";\nimport TableHead from \"@mui/material/TableHead\";\nimport TableRow from \"@mui/material/TableRow\";\nimport Collapse from \"@mui/material/Collapse\";\nimport Tooltip from \"@mui/material/Tooltip\";\n\nimport IconButton from \"@mui/material/IconButton\";\nimport {\n\tChevronsLeft,\n\tChevronsRight,\n\tChevronLeft,\n\tChevronRight,\n\tCoffee,\n\tEllipsis,\n\tPartyPopper,\n} from \"lucide-react\";\n\nimport TablePagination from \"@mui/material/TablePagination\";\nimport type { TablePaginationOwnProps } from \"@mui/material/TablePagination\";\n\nimport { useTranslation } from \"react-i18next\";\nimport { useState, Fragment, useEffect } from \"react\";\nimport { useTheme } from \"@mui/material/styles\";\nimport { SPACING, LAYOUT } from \"@/Utils/Theme/constants\";\nimport type { SxProps, Theme } from \"@mui/material/styles\";\nimport useMediaQuery from \"@mui/material/useMediaQuery\";\n\nexport type Header<T> = {\n\tid: number | string;\n\tcontent: React.ReactNode;\n\tonClick?: (event: React.MouseEvent<HTMLTableCellElement | null>, row: T) => void;\n\trender: (row: T) => React.ReactNode;\n};\n\ntype DataTableProps<T extends { id?: string | number; _id?: string | number }> = {\n\theaders: Header<T>[];\n\tdata: T[];\n\tonRowClick?: (row: T) => void;\n\tcardsOnSmallScreens?: boolean;\n\texpandableRows?: boolean;\n\trenderExpandedContent?: (row: T) => React.ReactNode;\n\temptyViewText?: string;\n\temptyViewPositive?: boolean;\n\tgetRowSx?: (row: T) => SxProps<Theme>;\n};\n\nexport function DataTable<\n\tT extends {\n\t\tid?: string | number;\n\t\t_id?: string | number;\n\t\tonRowClick?: (row: T) => void;\n\t},\n>({\n\theaders,\n\tdata,\n\tonRowClick,\n\tcardsOnSmallScreens = true,\n\texpandableRows = false,\n\trenderExpandedContent,\n\temptyViewText,\n\temptyViewPositive,\n\tgetRowSx,\n}: DataTableProps<T>) {\n\tconst theme = useTheme();\n\tconst [expanded, setExpanded] = useState<(string | number) | null>(null);\n\tconst handleExpand = (row: T) => {\n\t\tconst key = row.id || row._id || null;\n\t\tsetExpanded(expanded === key ? null : key);\n\t};\n\n\tconst isSmall = useMediaQuery(theme.breakpoints.down(\"md\"));\n\n\tif (data.length === 0 || headers.length === 0) {\n\t\treturn (\n\t\t\t<EmptyView\n\t\t\t\ttext={emptyViewText}\n\t\t\t\tpositive={emptyViewPositive}\n\t\t\t/>\n\t\t);\n\t}\n\n\tconst keys = [];\n\t// Return stack of cards for small screens\n\tif (isSmall && cardsOnSmallScreens) {\n\t\treturn (\n\t\t\t<Stack spacing={theme.spacing(LAYOUT.XS)}>\n\t\t\t\t{data.map((row) => {\n\t\t\t\t\tconst key = row.id || row._id || Math.random();\n\t\t\t\t\tkeys.push(key);\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<Stack\n\t\t\t\t\t\t\tonClick={() => (onRowClick ? onRowClick(row) : null)}\n\t\t\t\t\t\t\tspacing={theme.spacing(LAYOUT.XS)}\n\t\t\t\t\t\t\tsx={{\n\t\t\t\t\t\t\t\tborderStyle: \"solid\",\n\t\t\t\t\t\t\t\tborderWidth: 1,\n\t\t\t\t\t\t\t\tborderColor: theme.palette.divider,\n\t\t\t\t\t\t\t\tborderRadius: theme.shape.borderRadius,\n\t\t\t\t\t\t\t\tpadding: theme.spacing(LAYOUT.XS),\n\t\t\t\t\t\t\t\tcursor: onRowClick ? \"pointer\" : \"default\",\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\tkey={key}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{headers.map((header) => {\n\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t<Grid2\n\t\t\t\t\t\t\t\t\t\tcontainer\n\t\t\t\t\t\t\t\t\t\tkey={header.id}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<Grid2\n\t\t\t\t\t\t\t\t\t\t\tsize={5}\n\t\t\t\t\t\t\t\t\t\t\tdisplay={\"flex\"}\n\t\t\t\t\t\t\t\t\t\t\talignItems={\"center\"}\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t<Typography\n\t\t\t\t\t\t\t\t\t\t\t\tcomponent=\"div\"\n\t\t\t\t\t\t\t\t\t\t\t\tcolor={theme.palette.text.primary}\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t{header.content}\n\t\t\t\t\t\t\t\t\t\t\t</Typography>\n\t\t\t\t\t\t\t\t\t\t</Grid2>\n\t\t\t\t\t\t\t\t\t\t<Grid2\n\t\t\t\t\t\t\t\t\t\t\tsize={7}\n\t\t\t\t\t\t\t\t\t\t\tdisplay=\"flex\"\n\t\t\t\t\t\t\t\t\t\t\talignItems={\"center\"}\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t{header.render(row)}{\" \"}\n\t\t\t\t\t\t\t\t\t\t</Grid2>\n\t\t\t\t\t\t\t\t\t</Grid2>\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\t{expandableRows && renderExpandedContent && renderExpandedContent(row) && (\n\t\t\t\t\t\t\t\t<Grid2 size={12}>{renderExpandedContent(row)}</Grid2>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</Stack>\n\t\t\t\t\t);\n\t\t\t\t})}\n\t\t\t</Stack>\n\t\t);\n\t}\n\n\treturn (\n\t\t<TableContainer\n\t\t\tcomponent={Paper}\n\t\t\televation={0}\n\t\t\tsx={{ boxShadow: \"none\", overflowX: \"hidden\" }}\n\t\t>\n\t\t\t<Table\n\t\t\t\tsx={{\n\t\t\t\t\t\"&.MuiTable-root  :is(.MuiTableHead-root, .MuiTableBody-root) :is(th, td)\": {\n\t\t\t\t\t\tpaddingLeft: theme.spacing(LAYOUT.MD),\n\t\t\t\t\t},\n\t\t\t\t\t\"& .MuiTableCell-root\": {\n\t\t\t\t\t\tborderBottom: `1px solid ${theme.palette.divider}`,\n\t\t\t\t\t},\n\t\t\t\t\t\"& .MuiTableHead-root .MuiTableRow-root\": {\n\t\t\t\t\t\theight: \"28px\",\n\t\t\t\t\t},\n\t\t\t\t\t\"& :is(th)\": {\n\t\t\t\t\t\tbackgroundColor: theme.palette.background.paper,\n\t\t\t\t\t\tcolor: theme.palette.text.secondary,\n\t\t\t\t\t\tfontWeight: 500,\n\t\t\t\t\t\ttextTransform: \"uppercase\",\n\t\t\t\t\t\tpadding: `${theme.spacing(SPACING.LG)} ${theme.spacing(LAYOUT.MD)}`,\n\t\t\t\t\t\tfontSize: theme.typography.fontSize,\n\t\t\t\t\t},\n\t\t\t\t\t\"& :is(td)\": {\n\t\t\t\t\t\tbackgroundColor: theme.palette.background.paper,\n\t\t\t\t\t\tcolor: theme.palette.text.secondary,\n\t\t\t\t\t\tpadding: `${theme.spacing(LAYOUT.MD)} ${theme.spacing(LAYOUT.MD)}`,\n\t\t\t\t\t\tfontSize: theme.typography.fontSize,\n\t\t\t\t\t\toverflowX: \"hidden\",\n\t\t\t\t\t},\n\t\t\t\t\t\"& .MuiTableBody-root .MuiTableRow-root:last-child .MuiTableCell-root\": {\n\t\t\t\t\t\tborderBottom: \"none\",\n\t\t\t\t\t},\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t<TableHead>\n\t\t\t\t\t<TableRow>\n\t\t\t\t\t\t{headers.map((header, idx) => {\n\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t<TableCell\n\t\t\t\t\t\t\t\t\talign={idx === 0 ? \"left\" : \"center\"}\n\t\t\t\t\t\t\t\t\tkey={header.id}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t{header.content}\n\t\t\t\t\t\t\t\t</TableCell>\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t})}\n\t\t\t\t\t</TableRow>\n\t\t\t\t</TableHead>\n\t\t\t\t<TableBody>\n\t\t\t\t\t{data.map((row) => {\n\t\t\t\t\t\tconst key = row.id || row._id || Math.random();\n\t\t\t\t\t\tconst isExpanded = expanded === key;\n\n\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t<Fragment key={key}>\n\t\t\t\t\t\t\t\t<TableRow\n\t\t\t\t\t\t\t\t\tsx={{\n\t\t\t\t\t\t\t\t\t\tcursor: onRowClick ? \"pointer\" : \"default\",\n\t\t\t\t\t\t\t\t\t\t...(getRowSx?.(row) as object),\n\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\t\t\t\t\tif (expandableRows) handleExpand(row);\n\t\t\t\t\t\t\t\t\t\telse if (onRowClick) onRowClick(row);\n\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t{headers.map((header, index) => {\n\t\t\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t\t\t<TableCell\n\t\t\t\t\t\t\t\t\t\t\t\talign={index === 0 ? \"left\" : \"center\"}\n\t\t\t\t\t\t\t\t\t\t\t\tkey={header.id}\n\t\t\t\t\t\t\t\t\t\t\t\tonClick={\n\t\t\t\t\t\t\t\t\t\t\t\t\theader.onClick ? (e) => header.onClick!(e, row) : undefined\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t{header.render(row)}\n\t\t\t\t\t\t\t\t\t\t\t</TableCell>\n\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\t\t</TableRow>\n\t\t\t\t\t\t\t\t{expandableRows &&\n\t\t\t\t\t\t\t\t\trenderExpandedContent &&\n\t\t\t\t\t\t\t\t\trenderExpandedContent(row) && (\n\t\t\t\t\t\t\t\t\t\t<TableRow>\n\t\t\t\t\t\t\t\t\t\t\t<TableCell\n\t\t\t\t\t\t\t\t\t\t\t\tcolSpan={headers.length}\n\t\t\t\t\t\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\t\t\t\t\t\tborderBottom: isExpanded ? undefined : \"none\",\n\t\t\t\t\t\t\t\t\t\t\t\t\tpaddingTop: 0,\n\t\t\t\t\t\t\t\t\t\t\t\t\tpaddingBottom: 0,\n\t\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t<Collapse\n\t\t\t\t\t\t\t\t\t\t\t\t\tin={isExpanded}\n\t\t\t\t\t\t\t\t\t\t\t\t\ttimeout=\"auto\"\n\t\t\t\t\t\t\t\t\t\t\t\t\tunmountOnExit\n\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<Box sx={{ pt: 4, pb: 4 }}>{renderExpandedContent(row)}</Box>\n\t\t\t\t\t\t\t\t\t\t\t\t</Collapse>\n\t\t\t\t\t\t\t\t\t\t\t</TableCell>\n\t\t\t\t\t\t\t\t\t\t</TableRow>\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t</Fragment>\n\t\t\t\t\t\t);\n\t\t\t\t\t})}\n\t\t\t\t</TableBody>\n\t\t\t</Table>\n\t\t</TableContainer>\n\t);\n}\n\ninterface TablePaginationActionsProps {\n\tcount: number;\n\tpage: number;\n\trowsPerPage: number;\n\tonPageChange: (event: React.MouseEvent<HTMLButtonElement>, newPage: number) => void;\n}\n\nfunction TablePaginationActions(props: TablePaginationActionsProps) {\n\tconst theme = useTheme();\n\tconst { count, page, rowsPerPage, onPageChange } = props;\n\n\tconst handleFirstPageButtonClick = (event: React.MouseEvent<HTMLButtonElement>) => {\n\t\tonPageChange(event, 0);\n\t};\n\n\tconst handleBackButtonClick = (event: React.MouseEvent<HTMLButtonElement>) => {\n\t\tonPageChange(event, page - 1);\n\t};\n\n\tconst handleNextButtonClick = (event: React.MouseEvent<HTMLButtonElement>) => {\n\t\tonPageChange(event, page + 1);\n\t};\n\n\tconst handleLastPageButtonClick = (event: React.MouseEvent<HTMLButtonElement>) => {\n\t\tonPageChange(event, Math.max(0, Math.ceil(count / rowsPerPage) - 1));\n\t};\n\n\treturn (\n\t\t<Box\n\t\t\tsx={{ flexShrink: 0, ml: { xs: 0, md: 2.5 } }}\n\t\t\tclassName=\"table-pagination-actions\"\n\t\t>\n\t\t\t<IconButton\n\t\t\t\tonClick={handleFirstPageButtonClick}\n\t\t\t\tdisabled={page === 0}\n\t\t\t\taria-label=\"first page\"\n\t\t\t>\n\t\t\t\t{theme.direction === \"rtl\" ? (\n\t\t\t\t\t<ChevronsRight\n\t\t\t\t\t\tsize={20}\n\t\t\t\t\t\tstrokeWidth={1.5}\n\t\t\t\t\t/>\n\t\t\t\t) : (\n\t\t\t\t\t<ChevronsLeft\n\t\t\t\t\t\tsize={20}\n\t\t\t\t\t\tstrokeWidth={1.5}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\t\t\t</IconButton>\n\t\t\t<IconButton\n\t\t\t\tonClick={handleBackButtonClick}\n\t\t\t\tdisabled={page === 0}\n\t\t\t\taria-label=\"previous page\"\n\t\t\t>\n\t\t\t\t{theme.direction === \"rtl\" ? (\n\t\t\t\t\t<ChevronRight\n\t\t\t\t\t\tsize={20}\n\t\t\t\t\t\tstrokeWidth={1.5}\n\t\t\t\t\t/>\n\t\t\t\t) : (\n\t\t\t\t\t<ChevronLeft\n\t\t\t\t\t\tsize={20}\n\t\t\t\t\t\tstrokeWidth={1.5}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\t\t\t</IconButton>\n\t\t\t<IconButton\n\t\t\t\tonClick={handleNextButtonClick}\n\t\t\t\tdisabled={page >= Math.ceil(count / rowsPerPage) - 1}\n\t\t\t\taria-label=\"next page\"\n\t\t\t>\n\t\t\t\t{theme.direction === \"rtl\" ? (\n\t\t\t\t\t<ChevronLeft\n\t\t\t\t\t\tsize={20}\n\t\t\t\t\t\tstrokeWidth={1.5}\n\t\t\t\t\t/>\n\t\t\t\t) : (\n\t\t\t\t\t<ChevronRight\n\t\t\t\t\t\tsize={20}\n\t\t\t\t\t\tstrokeWidth={1.5}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\t\t\t</IconButton>\n\t\t\t<IconButton\n\t\t\t\tonClick={handleLastPageButtonClick}\n\t\t\t\tdisabled={page >= Math.ceil(count / rowsPerPage) - 1}\n\t\t\t\taria-label=\"last page\"\n\t\t\t>\n\t\t\t\t{theme.direction === \"rtl\" ? (\n\t\t\t\t\t<ChevronsLeft\n\t\t\t\t\t\tsize={20}\n\t\t\t\t\t\tstrokeWidth={1.5}\n\t\t\t\t\t/>\n\t\t\t\t) : (\n\t\t\t\t\t<ChevronsRight\n\t\t\t\t\t\tsize={20}\n\t\t\t\t\t\tstrokeWidth={1.5}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\t\t\t</IconButton>\n\t\t</Box>\n\t);\n}\n\ninterface HasMoreTablePaginationActionsProps {\n\thasMore?: boolean;\n\tpage: number;\n\tonPageChange: (event: React.MouseEvent<HTMLButtonElement>, newPage: number) => void;\n}\nfunction HasMoreTablePaginationActions(props: HasMoreTablePaginationActionsProps) {\n\tconst theme = useTheme();\n\tconst { hasMore, page, onPageChange } = props;\n\n\tconst handleFirstPageButtonClick = (event: React.MouseEvent<HTMLButtonElement>) => {\n\t\tonPageChange(event, 0);\n\t};\n\n\tconst handleBackButtonClick = (event: React.MouseEvent<HTMLButtonElement>) => {\n\t\tonPageChange(event, page - 1);\n\t};\n\n\tconst handleNextButtonClick = (event: React.MouseEvent<HTMLButtonElement>) => {\n\t\tonPageChange(event, page + 1);\n\t};\n\n\treturn (\n\t\t<Box\n\t\t\tsx={{ flexShrink: 0, ml: { xs: 0, md: 2.5 } }}\n\t\t\tclassName=\"table-pagination-actions\"\n\t\t>\n\t\t\t<IconButton\n\t\t\t\tonClick={handleFirstPageButtonClick}\n\t\t\t\tdisabled={page === 0}\n\t\t\t\taria-label=\"first page\"\n\t\t\t>\n\t\t\t\t{theme.direction === \"rtl\" ? (\n\t\t\t\t\t<ChevronsRight\n\t\t\t\t\t\tsize={20}\n\t\t\t\t\t\tstrokeWidth={1.5}\n\t\t\t\t\t/>\n\t\t\t\t) : (\n\t\t\t\t\t<ChevronsLeft\n\t\t\t\t\t\tsize={20}\n\t\t\t\t\t\tstrokeWidth={1.5}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\t\t\t</IconButton>\n\t\t\t<IconButton\n\t\t\t\tonClick={handleBackButtonClick}\n\t\t\t\tdisabled={page === 0}\n\t\t\t\taria-label=\"previous page\"\n\t\t\t>\n\t\t\t\t{theme.direction === \"rtl\" ? (\n\t\t\t\t\t<ChevronRight\n\t\t\t\t\t\tsize={20}\n\t\t\t\t\t\tstrokeWidth={1.5}\n\t\t\t\t\t/>\n\t\t\t\t) : (\n\t\t\t\t\t<ChevronLeft\n\t\t\t\t\t\tsize={20}\n\t\t\t\t\t\tstrokeWidth={1.5}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\t\t\t</IconButton>\n\t\t\t<IconButton\n\t\t\t\tonClick={handleNextButtonClick}\n\t\t\t\tdisabled={hasMore === false}\n\t\t\t\taria-label=\"next page\"\n\t\t\t>\n\t\t\t\t{theme.direction === \"rtl\" ? (\n\t\t\t\t\t<ChevronLeft\n\t\t\t\t\t\tsize={20}\n\t\t\t\t\t\tstrokeWidth={1.5}\n\t\t\t\t\t/>\n\t\t\t\t) : (\n\t\t\t\t\t<ChevronRight\n\t\t\t\t\t\tsize={20}\n\t\t\t\t\t\tstrokeWidth={1.5}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\t\t\t</IconButton>\n\t\t\t<Tooltip title={hasMore === true ? \"More pages available\" : \"No more pages\"}>\n\t\t\t\t<IconButton\n\t\t\t\t\tdisabled={hasMore === false}\n\t\t\t\t\taria-label=\"next page\"\n\t\t\t\t>\n\t\t\t\t\t<Ellipsis\n\t\t\t\t\t\tsize={20}\n\t\t\t\t\t\tstrokeWidth={1.5}\n\t\t\t\t\t/>\n\t\t\t\t</IconButton>\n\t\t\t</Tooltip>\n\t\t</Box>\n\t);\n}\n\ninterface PaginationProps extends TablePaginationOwnProps {\n\tcomponent?: React.ElementType;\n\thasMore?: boolean;\n\titemsOnPage?: number;\n}\n\nexport const Pagination = ({ ...props }: PaginationProps) => {\n\tconst { hasMore, itemsOnPage, ...rest } = props;\n\tconst isSmall = useMediaQuery((theme: any) => theme.breakpoints.down(\"sm\"));\n\tconst theme = useTheme();\n\n\tuseEffect(() => {\n\t\tif (\n\t\t\ttypeof itemsOnPage === \"number\" &&\n\t\t\titemsOnPage === 0 &&\n\t\t\trest.count > 0 &&\n\t\t\trest.page > 0 &&\n\t\t\trest.onPageChange\n\t\t) {\n\t\t\trest.onPageChange(null, rest.page - 1);\n\t\t}\n\t}, [itemsOnPage, rest.count, rest.page, rest.onPageChange]);\n\n\tconst labelDisplayedRows = ({\n\t\tfrom,\n\t\tto,\n\t\tcount,\n\t}: {\n\t\tfrom: number;\n\t\tto: number;\n\t\tcount: number;\n\t}) => {\n\t\tif (hasMore) {\n\t\t\treturn to === 0 ? \"\" : `${from}–${to}`;\n\t\t}\n\t\treturn `${from}–${to} of ${count}`;\n\t};\n\n\treturn (\n\t\t<TablePagination\n\t\t\tActionsComponent={(props) =>\n\t\t\t\ttypeof hasMore === \"boolean\" ? (\n\t\t\t\t\t<HasMoreTablePaginationActions\n\t\t\t\t\t\t{...props}\n\t\t\t\t\t\thasMore={hasMore}\n\t\t\t\t\t/>\n\t\t\t\t) : (\n\t\t\t\t\t<TablePaginationActions {...props} />\n\t\t\t\t)\n\t\t\t}\n\t\t\trowsPerPageOptions={[5, 10, 25]}\n\t\t\tlabelDisplayedRows={labelDisplayedRows}\n\t\t\t{...rest}\n\t\t\tsx={{\n\t\t\t\t\"& .MuiTablePagination-toolbar\": isSmall\n\t\t\t\t\t? {\n\t\t\t\t\t\t\tdisplay: \"grid\",\n\t\t\t\t\t\t\tgridTemplateColumns: \"1fr 1fr\",\n\t\t\t\t\t\t\tgridAutoRows: \"auto\",\n\t\t\t\t\t\t\trowGap: theme.spacing(SPACING.SM),\n\t\t\t\t\t\t\talignItems: \"center\",\n\t\t\t\t\t\t\tjustifyItems: \"center\",\n\t\t\t\t\t\t\tpaddingLeft: 0,\n\t\t\t\t\t\t\tpaddingRight: 0,\n\t\t\t\t\t\t}\n\t\t\t\t\t: { display: \"flex\", alignItems: \"center\" },\n\t\t\t\t\"& .MuiTablePagination-selectLabel\": {\n\t\t\t\t\tgridColumn: \"1\",\n\t\t\t\t\tgridRow: \"1\",\n\t\t\t\t\tjustifySelf: \"center\",\n\t\t\t\t},\n\t\t\t\t\"& .MuiTablePagination-select\": {\n\t\t\t\t\tgridColumn: \"2\",\n\t\t\t\t\tgridRow: \"1\",\n\t\t\t\t\tjustifySelf: \"center\",\n\t\t\t\t},\n\t\t\t\t\"& .MuiTablePagination-displayedRows\": isSmall\n\t\t\t\t\t? { gridColumn: \"1 / span 2\", gridRow: \"2\", justifySelf: \"center\" }\n\t\t\t\t\t: {},\n\t\t\t\t\"& .table-pagination-actions\": isSmall\n\t\t\t\t\t? { gridColumn: \"1 / span 2\", gridRow: \"3\", justifySelf: \"center\" }\n\t\t\t\t\t: {},\n\t\t\t\t\"& .MuiSelect-select\": {\n\t\t\t\t\tborder: 1,\n\t\t\t\t\tborderColor: theme.palette.divider,\n\t\t\t\t\tborderRadius: theme.shape.borderRadius,\n\t\t\t\t},\n\t\t\t}}\n\t\t/>\n\t);\n};\n\nconst EmptyView = ({ text, positive }: { text?: string; positive?: boolean }) => {\n\tconst theme = useTheme();\n\tconst { t } = useTranslation();\n\tconst Icon = positive ? PartyPopper : Coffee;\n\treturn (\n\t\t<Stack\n\t\t\talignItems={\"center\"}\n\t\t\tjustifyContent={\"center\"}\n\t\t\tsx={{\n\t\t\t\tpy: theme.spacing(LAYOUT.XL),\n\t\t\t\tpx: theme.spacing(LAYOUT.XS),\n\t\t\t\tborderWidth: 1,\n\t\t\t\tborderStyle: \"solid\",\n\t\t\t\tborderColor: theme.palette.divider,\n\t\t\t\tborderRadius: theme.shape.borderRadius,\n\t\t\t\ttextAlign: \"center\",\n\t\t\t}}\n\t\t>\n\t\t\t<Box\n\t\t\t\tsx={{\n\t\t\t\t\twidth: 64,\n\t\t\t\t\theight: 64,\n\t\t\t\t\tborderRadius: \"50%\",\n\t\t\t\t\tbackgroundColor: theme.palette.action.hover,\n\t\t\t\t\tdisplay: \"flex\",\n\t\t\t\t\talignItems: \"center\",\n\t\t\t\t\tjustifyContent: \"center\",\n\t\t\t\t\tmb: theme.spacing(SPACING.LG),\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t<Icon\n\t\t\t\t\tsize={28}\n\t\t\t\t\tstrokeWidth={1}\n\t\t\t\t\tcolor={theme.palette.text.secondary}\n\t\t\t\t/>\n\t\t\t</Box>\n\t\t\t<Typography\n\t\t\t\tvariant=\"subtitle1\"\n\t\t\t\tcolor={theme.palette.text.primary}\n\t\t\t\tsx={{ fontWeight: 500 }}\n\t\t\t>\n\t\t\t\t{text ?? t(\"common.table.empty\")}\n\t\t\t</Typography>\n\t\t</Stack>\n\t);\n};\n"
  },
  {
    "path": "client/src/Components/design-elements/Tabs.tsx",
    "content": "import MuiTabs from \"@mui/material/Tabs\";\nimport type { TabsProps } from \"@mui/material/Tabs\";\nimport { useTheme } from \"@mui/material/styles\";\ninterface CustomTabsProps extends TabsProps {}\n\nexport const Tabs = (props: CustomTabsProps) => {\n\tconst theme = useTheme();\n\treturn (\n\t\t<MuiTabs\n\t\t\tsx={{\n\t\t\t\tminHeight: 34,\n\t\t\t\tborderBottom: `1px solid ${theme.palette.divider}`,\n\t\t\t\t\"& .MuiTabs-indicator\": {\n\t\t\t\t\tbackgroundColor: theme.palette.primary.main,\n\t\t\t\t\theight: 2,\n\t\t\t\t\tbottom: 0,\n\t\t\t\t},\n\t\t\t\t\"& .MuiTabs-flexContainer\": {\n\t\t\t\t\tgap: theme.spacing(16),\n\t\t\t\t},\n\t\t\t}}\n\t\t\t{...props}\n\t\t>\n\t\t\t{props.children}\n\t\t</MuiTabs>\n\t);\n};\n\nimport MuiTab from \"@mui/material/Tab\";\nimport type { TabProps } from \"@mui/material/Tab\";\ninterface CustomTabProps extends TabProps {}\n\nexport const Tab = (props: CustomTabProps) => {\n\tconst theme = useTheme();\n\treturn (\n\t\t<MuiTab\n\t\t\tdisableRipple\n\t\t\ticonPosition=\"start\"\n\t\t\tsx={{\n\t\t\t\ttextTransform: \"none\",\n\t\t\t\tfontSize: 14,\n\t\t\t\tfontWeight: 500,\n\t\t\t\tminHeight: 34,\n\t\t\t\tpadding: theme.spacing(1, 0),\n\t\t\t\tpaddingBottom: 0,\n\t\t\t\tminWidth: \"auto\",\n\t\t\t\talignItems: \"flex-start\",\n\t\t\t\tcolor: theme.palette.text.secondary,\n\t\t\t\t\"&.Mui-selected\": {\n\t\t\t\t\tcolor: theme.palette.primary.main,\n\t\t\t\t\tfontWeight: 600,\n\t\t\t\t},\n\t\t\t\t\"&:hover\": {\n\t\t\t\t\tcolor: theme.palette.text.secondary,\n\t\t\t\t},\n\t\t\t\t\"& .MuiTab-iconWrapper\": {\n\t\t\t\t\tmarginRight: theme.spacing(2),\n\t\t\t\t\tmarginBottom: 0,\n\t\t\t\t},\n\t\t\t}}\n\t\t\t{...props}\n\t\t/>\n\t);\n};\n"
  },
  {
    "path": "client/src/Components/design-elements/TextLink.tsx",
    "content": "import Typography from \"@mui/material/Typography\";\nimport Stack from \"@mui/material/Stack\";\nimport type { StackProps } from \"@mui/material/Stack\";\nimport Link from \"@mui/material/Link\";\nimport { Link as RouterLink } from \"react-router-dom\";\n\nimport { useTheme } from \"@mui/material/styles\";\n\ninterface TextLinkProps extends StackProps {\n\ttext: string;\n\tlinkText: string;\n\thref: string;\n\ttarget?: \"_self\" | \"_blank\" | \"_parent\" | \"_top\";\n}\n\nexport const TextLink = ({\n\ttext,\n\tlinkText,\n\thref,\n\ttarget = \"_self\",\n\t...props\n}: TextLinkProps) => {\n\tconst theme = useTheme();\n\n\treturn (\n\t\t<Stack\n\t\t\tdirection=\"row\"\n\t\t\tgap={theme.spacing(4)}\n\t\t\t{...props}\n\t\t>\n\t\t\t<Typography>{text}</Typography>\n\t\t\t<Link\n\t\t\t\tcolor=\"primary\"\n\t\t\t\tto={href}\n\t\t\t\tcomponent={RouterLink}\n\t\t\t\ttarget={target}\n\t\t\t\t{...(target === \"_blank\" && { rel: \"noopener noreferrer\" })}\n\t\t\t>\n\t\t\t\t{linkText}\n\t\t\t</Link>\n\t\t</Stack>\n\t);\n};\n"
  },
  {
    "path": "client/src/Components/design-elements/Tooltip.tsx",
    "content": "import MuiTooltip from \"@mui/material/Tooltip\";\nimport { useTheme } from \"@mui/material/styles\";\nimport { Info } from \"lucide-react\";\n\nimport type { TooltipProps } from \"@mui/material/Tooltip\";\n\ntype StyledTooltipProps = TooltipProps;\n\nexport const Tooltip = ({ placement = \"top\", ...props }: StyledTooltipProps) => {\n\tconst theme = useTheme();\n\n\treturn (\n\t\t<MuiTooltip\n\t\t\ttitle={props.title}\n\t\t\tplacement={placement}\n\t\t\tslotProps={{\n\t\t\t\ttooltip: {\n\t\t\t\t\tsx: {\n\t\t\t\t\t\tbackground:\n\t\t\t\t\t\t\ttheme.palette.mode === \"dark\"\n\t\t\t\t\t\t\t\t? \"linear-gradient(135deg, #1a1a2e 0%, #16213e 100%)\"\n\t\t\t\t\t\t\t\t: \"linear-gradient(135deg, #2c3e50 0%, #1a252f 100%)\",\n\t\t\t\t\t\tbackgroundColor: \"transparent\",\n\t\t\t\t\t\tcolor: \"#ffffff\",\n\t\t\t\t\t\tfontSize: \"13px\",\n\t\t\t\t\t\tpadding: `${theme.spacing(4)} ${theme.spacing(5)}`,\n\t\t\t\t\t\tborderRadius: `${theme.shape.borderRadius}px`,\n\t\t\t\t\t\tboxShadow: \"0 8px 24px rgba(0, 0, 0, 0.4)\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}}\n\t\t>\n\t\t\t{props.children}\n\t\t</MuiTooltip>\n\t);\n};\n\nexport interface TooltipWithInfoProps extends Omit<StyledTooltipProps, \"children\"> {\n\ticonSize?: number;\n\ticonColor?: string;\n}\n\nexport const TooltipWithInfo = ({\n\ticonSize = 14,\n\ticonColor,\n\t...props\n}: TooltipWithInfoProps) => {\n\tconst theme = useTheme();\n\n\tconst defaultColor = theme.palette.text.secondary;\n\n\treturn (\n\t\t<Tooltip {...props}>\n\t\t\t<span\n\t\t\t\tstyle={{\n\t\t\t\t\tdisplay: \"inline-flex\",\n\t\t\t\t\talignItems: \"center\",\n\t\t\t\t\tcursor: \"help\",\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t<Info\n\t\t\t\t\tsize={iconSize}\n\t\t\t\t\tstrokeWidth={1.5}\n\t\t\t\t\tstyle={{\n\t\t\t\t\t\topacity: 0.7,\n\t\t\t\t\t\tcolor: iconColor || defaultColor,\n\t\t\t\t\t\ttransition: \"opacity 0.2s ease\",\n\t\t\t\t\t}}\n\t\t\t\t\tonMouseEnter={(e) => {\n\t\t\t\t\t\te.currentTarget.style.opacity = \"1\";\n\t\t\t\t\t}}\n\t\t\t\t\tonMouseLeave={(e) => {\n\t\t\t\t\t\te.currentTarget.style.opacity = \"0.7\";\n\t\t\t\t\t}}\n\t\t\t\t/>\n\t\t\t</span>\n\t\t</Tooltip>\n\t);\n};\n"
  },
  {
    "path": "client/src/Components/design-elements/index.tsx",
    "content": "export * from \"./Breadcrumb\";\nexport * from \"./BasePage\";\nexport * from \"./Fallback\";\nexport * from \"./SkeletonCard\";\nexport * from \"./BulletPointCheck\";\nexport * from \"./StatusBox\";\nexport * from \"./BaseBox\";\nexport * from \"./Table\";\nexport { DataTable as Table } from \"./Table\";\nexport * from \"./StatusLabel\";\nexport * from \"./PulseDot\";\nexport * from \"./Dot\";\nexport * from \"./MonitorStatus\";\nexport { default as Icon } from \"./Icon\";\nexport * from \"./Tooltip\";\nexport * from \"./StatBox\";\nexport * from \"./BaseChart\";\nexport * from \"./Gauge\";\nexport * from \"./Tabs\";\nexport * from \"./SplitBox\";\nexport * from \"./TextLink\";\nexport * from \"./OfflineBanner\";\nexport * from \"./Avatar\";\n"
  },
  {
    "path": "client/src/Components/i18nLoader/index.tsx",
    "content": "import i18n from \"@/Utils/i18n.js\";\nimport { useSelector } from \"react-redux\";\nimport { useEffect } from \"react\";\nimport type { RootState } from \"@/store\";\nconst I18nLoader = () => {\n\tconst language = useSelector((state: RootState) => state.ui.language ?? \"en\");\n\n\tuseEffect(() => {\n\t\tif (language && i18n.language !== language) {\n\t\t\ti18n.changeLanguage(language);\n\t\t}\n\t}, [language]);\n\n\treturn null;\n};\n\nexport default I18nLoader;\n"
  },
  {
    "path": "client/src/Components/inputs/AutoComplete.tsx",
    "content": "import Autocomplete from \"@mui/material/Autocomplete\";\nimport type { AutocompleteProps } from \"@mui/material/Autocomplete\";\nimport { TextField, Checkbox } from \"@/Components/inputs\";\nimport ListItem from \"@mui/material/ListItem\";\nimport Stack from \"@mui/material/Stack\";\nimport { useTheme } from \"@mui/material/styles\";\nimport { FieldLabel } from \"./FieldLabel\";\nimport { ChevronDown } from \"lucide-react\";\n\ntype AutoCompleteInputProps = Omit<\n\tAutocompleteProps<any, boolean, boolean, boolean>,\n\t\"renderInput\"\n> & {\n\trenderInput?: AutocompleteProps<any, boolean, boolean, boolean>[\"renderInput\"];\n\tfieldLabel?: string;\n\trequired?: boolean;\n};\n\nexport const AutoCompleteInput = ({\n\tfieldLabel,\n\trequired,\n\trenderInput,\n\t...props\n}: AutoCompleteInputProps) => {\n\tconst theme = useTheme();\n\tconst multiple = props.multiple;\n\n\tconst defaultRenderInput = (params: any) => (\n\t\t<TextField\n\t\t\t{...params}\n\t\t\tplaceholder=\"Type to search\"\n\t\t/>\n\t);\n\n\tconst autocomplete = (\n\t\t<Autocomplete\n\t\t\t{...props}\n\t\t\tdisableCloseOnSelect={!!multiple}\n\t\t\tpopupIcon={\n\t\t\t\t<ChevronDown\n\t\t\t\t\tsize={18}\n\t\t\t\t\tstrokeWidth={1.5}\n\t\t\t\t\tstyle={{ marginRight: theme.spacing(3) }}\n\t\t\t\t/>\n\t\t\t}\n\t\t\trenderInput={renderInput || defaultRenderInput}\n\t\t\tgetOptionKey={(option) => option.id}\n\t\t\trenderTags={() => null}\n\t\t\trenderOption={(props, option, { selected }) => {\n\t\t\t\tconst { key, ...optionProps } = props;\n\t\t\t\treturn (\n\t\t\t\t\t<ListItem\n\t\t\t\t\t\tkey={key}\n\t\t\t\t\t\t{...optionProps}\n\t\t\t\t\t>\n\t\t\t\t\t\t<Stack\n\t\t\t\t\t\t\tdirection={\"row\"}\n\t\t\t\t\t\t\talignItems={\"center\"}\n\t\t\t\t\t\t\tgap={theme.spacing(2)}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{multiple && <Checkbox checked={selected} />}\n\t\t\t\t\t\t\t{option.name}\n\t\t\t\t\t\t</Stack>\n\t\t\t\t\t</ListItem>\n\t\t\t\t);\n\t\t\t}}\n\t\t\tsx={{\n\t\t\t\t\"&.MuiAutocomplete-root .MuiAutocomplete-input\": {\n\t\t\t\t\tpadding: `0 ${theme.spacing(5)}`,\n\t\t\t\t},\n\t\t\t\t\"& .MuiInputBase-root .MuiAutocomplete-endAdornment\": {\n\t\t\t\t\tright: theme.spacing(3),\n\t\t\t\t},\n\t\t\t}}\n\t\t/>\n\t);\n\n\tif (fieldLabel) {\n\t\treturn (\n\t\t\t<Stack spacing={theme.spacing(2)}>\n\t\t\t\t<FieldLabel required={required}>{fieldLabel}</FieldLabel>\n\t\t\t\t{autocomplete}\n\t\t\t</Stack>\n\t\t);\n\t}\n\n\treturn autocomplete;\n};\n"
  },
  {
    "path": "client/src/Components/inputs/Button.tsx",
    "content": "import Button from \"@mui/material/Button\";\nimport type { ButtonProps } from \"@mui/material/Button\";\nimport { useTheme } from \"@mui/material/styles\";\n\nexport const ButtonInput = ({ sx, ...props }: ButtonProps) => {\n\tconst theme = useTheme();\n\tconst outlinedSx =\n\t\tprops.variant === \"outlined\"\n\t\t\t? {\n\t\t\t\t\tcolor: theme.palette.text.primary,\n\t\t\t\t\tborderColor: theme.palette.divider,\n\t\t\t\t\t\"&:hover\": {\n\t\t\t\t\t\tborderColor: theme.palette.text.secondary,\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t: {};\n\treturn (\n\t\t<Button\n\t\t\t{...props}\n\t\t\tsx={{\n\t\t\t\ttextTransform: \"none\",\n\t\t\t\theight: 34,\n\t\t\t\tfontWeight: 400,\n\t\t\t\tborderRadius: 2,\n\t\t\t\twhiteSpace: \"nowrap\",\n\t\t\t\ttextOverflow: \"ellipsis\",\n\t\t\t\toverflow: \"hidden\",\n\t\t\t\tboxShadow: \"none\",\n\t\t\t\t\"&:hover\": {\n\t\t\t\t\tboxShadow: \"none\",\n\t\t\t\t},\n\t\t\t\t...outlinedSx,\n\t\t\t\t...sx,\n\t\t\t}}\n\t\t/>\n\t);\n};\n"
  },
  {
    "path": "client/src/Components/inputs/Checkbox.tsx",
    "content": "import { forwardRef } from \"react\";\nimport Checkbox from \"@mui/material/Checkbox\";\nimport type { CheckboxProps } from \"@mui/material/Checkbox\";\nimport { Square, SquareCheck } from \"lucide-react\";\nimport { useTheme } from \"@mui/material/styles\";\n\ntype CheckboxInputProps = CheckboxProps & {\n\tlabel?: string;\n};\nexport const CheckboxInput = forwardRef<HTMLInputElement, CheckboxInputProps>(\n\tfunction CheckboxInput(\n\t\t{ sx, ...props }: CheckboxInputProps,\n\t\tref: React.Ref<HTMLInputElement>\n\t) {\n\t\tconst theme = useTheme();\n\t\treturn (\n\t\t\t<Checkbox\n\t\t\t\t{...props}\n\t\t\t\taria-label={props.label}\n\t\t\t\tslotProps={{\n\t\t\t\t\tinput: {\n\t\t\t\t\t\tref: ref,\n\t\t\t\t\t},\n\t\t\t\t}}\n\t\t\t\ticon={\n\t\t\t\t\t<Square\n\t\t\t\t\t\tsize={16}\n\t\t\t\t\t\tstrokeWidth={1.5}\n\t\t\t\t\t/>\n\t\t\t\t}\n\t\t\t\tcheckedIcon={\n\t\t\t\t\t<SquareCheck\n\t\t\t\t\t\tsize={16}\n\t\t\t\t\t\tstrokeWidth={1.5}\n\t\t\t\t\t/>\n\t\t\t\t}\n\t\t\t\tsx={{\n\t\t\t\t\tcolor: theme.palette.text.secondary,\n\t\t\t\t\t\"&.Mui-checked\": {\n\t\t\t\t\t\tcolor: theme.palette.primary.main,\n\t\t\t\t\t},\n\t\t\t\t\t\"&:hover\": { backgroundColor: \"transparent\" },\n\t\t\t\t\t\"& svg\": {\n\t\t\t\t\t\tstroke: \"currentColor\",\n\t\t\t\t\t},\n\t\t\t\t\t\"& svg path, & svg line, & svg polyline, & svg rect\": {\n\t\t\t\t\t\tstroke: \"currentColor\",\n\t\t\t\t\t\tfill: \"none\",\n\t\t\t\t\t},\n\n\t\t\t\t\t...sx,\n\t\t\t\t}}\n\t\t\t/>\n\t\t);\n\t}\n);\n"
  },
  {
    "path": "client/src/Components/inputs/ColorPicker.tsx",
    "content": "import { MuiColorInput } from \"mui-color-input\";\nimport type { MuiColorInputProps } from \"mui-color-input\";\nimport { typographyLevels } from \"@/Utils/Theme/Palette\";\nimport { useTheme } from \"@mui/material\";\nimport Stack from \"@mui/material/Stack\";\nimport { FieldLabel } from \"@/Components/inputs/FieldLabel\";\n\ninterface ColorPickerProps extends MuiColorInputProps {\n\tfieldLabel?: string;\n\trequired?: boolean;\n}\n\nexport const ColorInput = ({ fieldLabel, required, ...props }: ColorPickerProps) => {\n\tconst theme = useTheme();\n\tconst input = (\n\t\t<MuiColorInput\n\t\t\t{...props}\n\t\t\tsx={{\n\t\t\t\t\"& .MuiOutlinedInput-root\": {\n\t\t\t\t\tborderRadius: theme.shape.borderRadius,\n\t\t\t\t\theight: 34,\n\t\t\t\t\tfontSize: typographyLevels.base,\n\t\t\t\t},\n\t\t\t\t\"& .MuiOutlinedInput-notchedOutline\": {\n\t\t\t\t\tborderColor: theme.palette.divider,\n\t\t\t\t},\n\t\t\t\t\"&:hover .MuiOutlinedInput-notchedOutline\": {\n\t\t\t\t\tborderColor: theme.palette.divider,\n\t\t\t\t},\n\t\t\t\t\"& .MuiFormHelperText-root\": {\n\t\t\t\t\tmarginLeft: 0,\n\t\t\t\t\tmarginRight: 0,\n\t\t\t\t\tmarginTop: theme.spacing(1),\n\t\t\t\t},\n\t\t\t}}\n\t\t/>\n\t);\n\tif (fieldLabel) {\n\t\treturn (\n\t\t\t<Stack spacing={theme.spacing(2)}>\n\t\t\t\t<FieldLabel required={required}>{fieldLabel}</FieldLabel>\n\t\t\t\t{input}\n\t\t\t</Stack>\n\t\t);\n\t}\n\n\treturn input;\n};\n"
  },
  {
    "path": "client/src/Components/inputs/DatePicker.tsx",
    "content": "import { DatePicker } from \"@mui/x-date-pickers/DatePicker\";\nimport type { DatePickerProps } from \"@mui/x-date-pickers/DatePicker\";\nimport type { Dayjs } from \"dayjs\";\nimport { useTheme } from \"@mui/material/styles\";\nimport Stack from \"@mui/material/Stack\";\nimport Typography from \"@mui/material/Typography\";\nimport { FieldLabel } from \"./FieldLabel\";\nimport { Calendar } from \"lucide-react\";\nimport { AdapterDayjs } from \"@mui/x-date-pickers/AdapterDayjs\";\nimport { LocalizationProvider } from \"@mui/x-date-pickers\";\n\ninterface DatePickerComponentProps extends Omit<DatePickerProps<Dayjs>, \"label\"> {\n\tfieldLabel?: string;\n\trequired?: boolean;\n\terror?: boolean;\n\thelperText?: string;\n}\n\nexport const DatePickerComponent = ({\n\tfieldLabel,\n\trequired,\n\terror,\n\thelperText,\n\t...props\n}: DatePickerComponentProps) => {\n\tconst theme = useTheme();\n\n\tconst picker = (\n\t\t<LocalizationProvider dateAdapter={AdapterDayjs}>\n\t\t\t<DatePicker\n\t\t\t\t{...props}\n\t\t\t\tslots={{\n\t\t\t\t\topenPickerIcon: () => (\n\t\t\t\t\t\t<Calendar\n\t\t\t\t\t\t\tsize={20}\n\t\t\t\t\t\t\tstroke={theme.palette.text.secondary}\n\t\t\t\t\t\t/>\n\t\t\t\t\t),\n\t\t\t\t\t...props.slots,\n\t\t\t\t}}\n\t\t\t\tslotProps={{\n\t\t\t\t\tswitchViewButton: { sx: { display: \"none\" } },\n\t\t\t\t\tnextIconButton: { sx: { ml: theme.spacing(2) } },\n\t\t\t\t\tday: {\n\t\t\t\t\t\tsx: {\n\t\t\t\t\t\t\t\"&.MuiPickersDay-root.Mui-disabled\": {\n\t\t\t\t\t\t\t\tcolor: theme.palette.text.disabled,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tfield: {\n\t\t\t\t\t\tsx: {\n\t\t\t\t\t\t\twidth: \"fit-content\",\n\t\t\t\t\t\t\t\"& > .MuiOutlinedInput-root\": {\n\t\t\t\t\t\t\t\tflexDirection: \"row-reverse\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"& input\": {\n\t\t\t\t\t\t\t\tminHeight: 34,\n\t\t\t\t\t\t\t\tp: 0,\n\t\t\t\t\t\t\t\tpl: theme.spacing(3),\n\t\t\t\t\t\t\t\tpr: theme.spacing(5),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"& fieldset\": {\n\t\t\t\t\t\t\t\tborderColor: error ? theme.palette.error.main : theme.palette.divider,\n\t\t\t\t\t\t\t\tborderRadius: theme.shape.borderRadius,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"&:not(:has(.Mui-disabled)):not(:has(.Mui-error)) .MuiOutlinedInput-root:not(:has(input:focus)):hover fieldset\":\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tborderColor: error ? theme.palette.error.main : theme.palette.divider,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tinputAdornment: { sx: { ml: 0 } },\n\t\t\t\t\topenPickerButton: {\n\t\t\t\t\t\tsx: {\n\t\t\t\t\t\t\tpy: 0,\n\t\t\t\t\t\t\tmr: 0,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t...props.slotProps,\n\t\t\t\t}}\n\t\t\t/>\n\t\t</LocalizationProvider>\n\t);\n\n\treturn (\n\t\t<Stack spacing={theme.spacing(2)}>\n\t\t\t{fieldLabel && <FieldLabel required={required}>{fieldLabel}</FieldLabel>}\n\t\t\t{picker}\n\t\t\t{helperText && (\n\t\t\t\t<Typography\n\t\t\t\t\tvariant=\"caption\"\n\t\t\t\t\tcolor={error ? \"error\" : \"text.secondary\"}\n\t\t\t\t>\n\t\t\t\t\t{helperText}\n\t\t\t\t</Typography>\n\t\t\t)}\n\t\t</Stack>\n\t);\n};\n"
  },
  {
    "path": "client/src/Components/inputs/Dialog.tsx",
    "content": "import Dialog from \"@mui/material/Dialog\";\nimport type { DialogProps } from \"@mui/material/Dialog\";\nimport DialogActions from \"@mui/material/DialogActions\";\nimport DialogContent from \"@mui/material/DialogContent\";\nimport DialogContentText from \"@mui/material/DialogContentText\";\nimport DialogTitle from \"@mui/material/DialogTitle\";\nimport { Button } from \"@/Components/inputs\";\nimport { typographyLevels } from \"@/Utils/Theme/Palette\";\nimport { useTranslation } from \"react-i18next\";\nimport type { ReactNode } from \"react\";\n\nexport const DialogInput = ({\n\topen,\n\ttitle,\n\tcontent,\n\tonConfirm,\n\tonCancel,\n\tconfirmColor = \"primary\",\n\tcancelColor = \"error\",\n\tloading = false,\n\tcancelText,\n\tconfirmText,\n\tchildren,\n\tmaxWidth,\n\tfullWidth = false,\n\tadditionalButtons,\n}: {\n\topen: boolean;\n\ttitle?: string;\n\tcontent?: string;\n\tonConfirm?(item: any): any;\n\tonCancel?(item: any): any;\n\tconfirmColor?: \"error\" | \"primary\";\n\tcancelColor?: \"error\" | \"primary\";\n\tloading?: boolean;\n\tcancelText?: string;\n\tconfirmText?: string;\n\tchildren?: ReactNode;\n\tmaxWidth?: DialogProps[\"maxWidth\"];\n\tfullWidth?: boolean;\n\tadditionalButtons?: ReactNode;\n}) => {\n\tconst { t } = useTranslation();\n\treturn (\n\t\t<Dialog\n\t\t\topen={open}\n\t\t\tmaxWidth={maxWidth}\n\t\t\tfullWidth={fullWidth}\n\t\t>\n\t\t\t{title && <DialogTitle sx={{ fontSize: typographyLevels.l }}>{title}</DialogTitle>}\n\t\t\t<DialogContent>\n\t\t\t\t{content && <DialogContentText>{content}</DialogContentText>}\n\t\t\t\t{children}\n\t\t\t</DialogContent>\n\t\t\t<DialogActions>\n\t\t\t\t<Button\n\t\t\t\t\tloading={loading}\n\t\t\t\t\tvariant=\"contained\"\n\t\t\t\t\tcolor={cancelColor}\n\t\t\t\t\tonClick={onCancel}\n\t\t\t\t>\n\t\t\t\t\t{cancelText ?? t(\"common.buttons.cancel\")}\n\t\t\t\t</Button>\n\t\t\t\t{additionalButtons}\n\t\t\t\t{onConfirm && (\n\t\t\t\t\t<Button\n\t\t\t\t\t\tloading={loading}\n\t\t\t\t\t\tvariant=\"contained\"\n\t\t\t\t\t\tcolor={confirmColor}\n\t\t\t\t\t\tonClick={onConfirm}\n\t\t\t\t\t>\n\t\t\t\t\t\t{confirmText ?? t(\"common.buttons.confirm\")}\n\t\t\t\t\t</Button>\n\t\t\t\t)}\n\t\t\t</DialogActions>\n\t\t</Dialog>\n\t);\n};\n"
  },
  {
    "path": "client/src/Components/inputs/FieldLabel.tsx",
    "content": "import Typography from \"@mui/material/Typography\";\nimport { useTheme } from \"@mui/material/styles\";\n\ninterface FieldLabelProps {\n\tchildren: React.ReactNode;\n\trequired?: boolean;\n\thtmlFor?: string;\n}\n\nexport const FieldLabel = ({ children, required = false, htmlFor }: FieldLabelProps) => {\n\tconst theme = useTheme();\n\tif (children === \" \") {\n\t\tchildren = \"\\u00A0\";\n\t}\n\treturn (\n\t\t<Typography\n\t\t\tcomponent=\"label\"\n\t\t\thtmlFor={htmlFor}\n\t\t\tsx={{\n\t\t\t\tfontSize: \"14px\",\n\t\t\t\tfontWeight: 500,\n\t\t\t\tcolor: theme.palette.text.secondary,\n\t\t\t\tmarginBottom: theme.spacing(2),\n\t\t\t\tdisplay: \"block\",\n\t\t\t}}\n\t\t>\n\t\t\t{children}\n\t\t\t{required && (\n\t\t\t\t<span\n\t\t\t\t\tstyle={{\n\t\t\t\t\t\tcolor: theme.palette.error.main,\n\t\t\t\t\t\tmarginLeft: theme.spacing(2),\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t*\n\t\t\t\t</span>\n\t\t\t)}\n\t\t</Typography>\n\t);\n};\n"
  },
  {
    "path": "client/src/Components/inputs/ImageUpload.tsx",
    "content": "import { Box, Stack, Typography, IconButton } from \"@mui/material\";\nimport { useTheme } from \"@mui/material/styles\";\nimport { Upload, X } from \"lucide-react\";\nimport { useState, useRef, useCallback } from \"react\";\nimport { useTranslation } from \"react-i18next\";\n\ninterface FileObject {\n\tsrc: string;\n\tname: string;\n\tfile: File;\n}\n\ninterface ImageUploadProps {\n\tsrc?: string;\n\tonChange?: (file: FileObject | undefined) => void;\n\tmaxSize?: number;\n\taccept?: string[];\n\terror?: string;\n}\n\nexport const ImageUpload = ({\n\tsrc,\n\tonChange,\n\tmaxSize = 3 * 1024 * 1024,\n\taccept = [\"jpg\", \"jpeg\", \"png\"],\n\terror,\n}: ImageUploadProps) => {\n\tconst theme = useTheme();\n\tconst { t } = useTranslation();\n\tconst inputRef = useRef<HTMLInputElement>(null);\n\tconst [isDragging, setIsDragging] = useState(false);\n\tconst [localError, setLocalError] = useState<string | null>(null);\n\tconst [preview, setPreview] = useState<FileObject | null>(null);\n\n\tconst handleFile = useCallback(\n\t\t(file: File | undefined) => {\n\t\t\tif (!file) return;\n\t\t\tconst isValidType = accept.some((type) => file.type.includes(type));\n\t\t\tconst isValidSize = file.size <= maxSize;\n\t\t\tif (!isValidType) {\n\t\t\t\tsetLocalError(t(\"components.imageUpload.errors.invalidFileFormat\"));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (!isValidSize) {\n\t\t\t\tsetLocalError(t(\"components.imageUpload.errors.invalidFileSize\"));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tsetLocalError(null);\n\t\t\tconst fileObj: FileObject = {\n\t\t\t\tsrc: URL.createObjectURL(file),\n\t\t\t\tname: file.name,\n\t\t\t\tfile,\n\t\t\t};\n\t\t\tsetPreview(fileObj);\n\t\t\tonChange?.(fileObj);\n\t\t},\n\t\t[maxSize, accept, onChange, t]\n\t);\n\n\tconst handleClear = () => {\n\t\tsetPreview(null);\n\t\tsetLocalError(null);\n\t\tonChange?.(undefined);\n\t\tif (inputRef.current) inputRef.current.value = \"\";\n\t};\n\n\tconst displaySrc = src || preview?.src;\n\tconst displayError = localError || error;\n\n\treturn (\n\t\t<Stack sx={{ width: \"100%\", maxWidth: 500 }}>\n\t\t\t{displaySrc ? (\n\t\t\t\t<Stack\n\t\t\t\t\talignItems=\"center\"\n\t\t\t\t\tgap={1}\n\t\t\t\t>\n\t\t\t\t\t<Box\n\t\t\t\t\t\tcomponent=\"img\"\n\t\t\t\t\t\tsrc={displaySrc}\n\t\t\t\t\t\talt=\"Preview\"\n\t\t\t\t\t\tsx={{ maxWidth: 250, maxHeight: 250, objectFit: \"contain\", borderRadius: 1 }}\n\t\t\t\t\t/>\n\t\t\t\t\t<IconButton\n\t\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t\tonClick={handleClear}\n\t\t\t\t\t\tsx={{ color: theme.palette.error.main }}\n\t\t\t\t\t>\n\t\t\t\t\t\t<X size={18} />\n\t\t\t\t\t</IconButton>\n\t\t\t\t</Stack>\n\t\t\t) : (\n\t\t\t\t<Stack\n\t\t\t\t\tonDragOver={(e) => {\n\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\tsetIsDragging(true);\n\t\t\t\t\t}}\n\t\t\t\t\tonDragLeave={() => setIsDragging(false)}\n\t\t\t\t\tonDrop={(e) => {\n\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\tsetIsDragging(false);\n\t\t\t\t\t\thandleFile(e.dataTransfer.files?.[0]);\n\t\t\t\t\t}}\n\t\t\t\t\talignItems=\"center\"\n\t\t\t\t\tjustifyContent=\"center\"\n\t\t\t\t\tgap={1}\n\t\t\t\t\tsx={{\n\t\t\t\t\t\tposition: \"relative\",\n\t\t\t\t\t\twidth: \"100%\",\n\t\t\t\t\t\tminHeight: 150,\n\t\t\t\t\t\tborder: \"2px dashed\",\n\t\t\t\t\t\tborderRadius: 1,\n\t\t\t\t\t\tborderColor: isDragging ? theme.palette.primary.main : theme.palette.divider,\n\t\t\t\t\t\tbackgroundColor: isDragging ? theme.palette.action.hover : \"transparent\",\n\t\t\t\t\t\ttransition: \"0.2s\",\n\t\t\t\t\t\tcursor: \"pointer\",\n\t\t\t\t\t\t\"&:hover\": {\n\t\t\t\t\t\t\tborderColor: theme.palette.primary.main,\n\t\t\t\t\t\t\tbackgroundColor: theme.palette.action.hover,\n\t\t\t\t\t\t},\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t<input\n\t\t\t\t\t\tref={inputRef}\n\t\t\t\t\t\ttype=\"file\"\n\t\t\t\t\t\taccept={accept.map((ext) => `.${ext}`).join(\",\")}\n\t\t\t\t\t\tonChange={(e) => handleFile(e.target.files?.[0])}\n\t\t\t\t\t\tstyle={{ position: \"absolute\", inset: 0, opacity: 0, cursor: \"pointer\" }}\n\t\t\t\t\t/>\n\t\t\t\t\t<Upload size={24} />\n\t\t\t\t\t<Typography\n\t\t\t\t\t\tvariant=\"body2\"\n\t\t\t\t\t\tcolor=\"text.secondary\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<Typography\n\t\t\t\t\t\t\tcomponent=\"span\"\n\t\t\t\t\t\t\tvariant=\"body2\"\n\t\t\t\t\t\t\tcolor=\"primary\"\n\t\t\t\t\t\t\tfontWeight={500}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{t(\"components.imageUpload.clickToUpload\")}\n\t\t\t\t\t\t</Typography>{\" \"}\n\t\t\t\t\t\t{t(\"components.imageUpload.orDragAndDrop\")}\n\t\t\t\t\t</Typography>\n\t\t\t\t\t<Typography\n\t\t\t\t\t\tvariant=\"caption\"\n\t\t\t\t\t\tcolor=\"text.disabled\"\n\t\t\t\t\t>\n\t\t\t\t\t\t{accept.join(\", \").toUpperCase()} • {t(\"components.imageUpload.maxSize\")}{\" \"}\n\t\t\t\t\t\t{Math.round(maxSize / 1024 / 1024)}MB\n\t\t\t\t\t</Typography>\n\t\t\t\t</Stack>\n\t\t\t)}\n\t\t\t{displayError && (\n\t\t\t\t<Typography\n\t\t\t\t\tvariant=\"caption\"\n\t\t\t\t\tcolor=\"error\"\n\t\t\t\t\tsx={{ mt: 1 }}\n\t\t\t\t>\n\t\t\t\t\t{displayError}\n\t\t\t\t</Typography>\n\t\t\t)}\n\t\t</Stack>\n\t);\n};\n"
  },
  {
    "path": "client/src/Components/inputs/LanguageSelector.tsx",
    "content": "import Stack from \"@mui/material/Stack\";\nimport Box from \"@mui/material/Box\";\nimport MenuItem from \"@mui/material/MenuItem\";\nimport { Select } from \"@/Components/inputs\";\nimport \"flag-icons/css/flag-icons.min.css\";\n\nimport { useTranslation } from \"react-i18next\";\nimport { useTheme } from \"@mui/material\";\nimport { useSelector } from \"react-redux\";\nimport { useDispatch } from \"react-redux\";\nimport { setLanguage } from \"@/Features/UI/uiSlice\";\nimport type { RootState } from \"@/Types/state\";\n\nconst langMap: Record<string, string> = {\n\tcs: \"cz\",\n\tja: \"jp\",\n\tuk: \"ua\",\n\tvi: \"vn\",\n};\n\nexport const LanguageSelector = () => {\n\tconst { i18n } = useTranslation();\n\tconst theme = useTheme();\n\tconst { language = \"en\" } = useSelector((state: RootState) => state.ui);\n\tconst dispatch = useDispatch();\n\tconst handleChange = (event: any) => {\n\t\tconst newLang = event.target.value;\n\t\tdispatch(setLanguage(newLang));\n\t};\n\n\tconst languages = Object.keys(i18n.options.resources || {});\n\n\treturn (\n\t\t<Select\n\t\t\tvalue={language}\n\t\t\tonChange={handleChange}\n\t\t\tsize=\"small\"\n\t\t\t// sx={{\n\t\t\t// \tminWidth: 80,\n\t\t\t// \t\"& .MuiSelect-select\": {\n\t\t\t// \t\tdisplay: \"flex\",\n\t\t\t// \t\talignItems: \"center\",\n\t\t\t// \t\tjustifyContent: \"center\",\n\t\t\t// \t},\n\t\t\t// \t\"& .MuiSelect-icon\": {\n\t\t\t// \t\talignSelf: \"center\",\n\t\t\t// \t},\n\t\t\t// }}\n\t\t>\n\t\t\t{languages.map((lang) => {\n\t\t\t\tlet parsedLang = lang === \"en\" ? \"gb\" : lang;\n\n\t\t\t\tif (parsedLang.includes(\"-\")) {\n\t\t\t\t\tparsedLang = parsedLang.split(\"-\")[1].toLowerCase();\n\t\t\t\t}\n\n\t\t\t\tparsedLang = langMap[parsedLang] || parsedLang;\n\n\t\t\t\tconst flag = parsedLang ? `fi fi-${parsedLang}` : null;\n\n\t\t\t\treturn (\n\t\t\t\t\t<MenuItem\n\t\t\t\t\t\tkey={lang}\n\t\t\t\t\t\tvalue={lang}\n\t\t\t\t\t\tsx={{\n\t\t\t\t\t\t\tdisplay: \"flex\",\n\t\t\t\t\t\t\tjustifyContent: \"center\",\n\t\t\t\t\t\t\talignItems: \"center\",\n\t\t\t\t\t\t}}\n\t\t\t\t\t>\n\t\t\t\t\t\t<Stack\n\t\t\t\t\t\t\tdirection=\"row\"\n\t\t\t\t\t\t\tspacing={theme.spacing(2)}\n\t\t\t\t\t\t\talignItems=\"center\"\n\t\t\t\t\t\t\tjustifyContent=\"center\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<Box\n\t\t\t\t\t\t\t\tcomponent=\"span\"\n\t\t\t\t\t\t\t\tsx={{\n\t\t\t\t\t\t\t\t\tdisplay: \"flex\",\n\t\t\t\t\t\t\t\t\talignItems: \"center\",\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{flag && <span className={flag} />}\n\t\t\t\t\t\t\t</Box>\n\t\t\t\t\t\t\t<Box\n\t\t\t\t\t\t\t\tcomponent=\"span\"\n\t\t\t\t\t\t\t\tsx={{ textTransform: \"uppercase\" }}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{lang}\n\t\t\t\t\t\t\t</Box>\n\t\t\t\t\t\t</Stack>\n\t\t\t\t\t</MenuItem>\n\t\t\t\t);\n\t\t\t})}\n\t\t</Select>\n\t);\n};\n\nexport default LanguageSelector;\n"
  },
  {
    "path": "client/src/Components/inputs/Radio.tsx",
    "content": "import Radio from \"@mui/material/Radio\";\nimport type { RadioProps } from \"@mui/material/Radio\";\nimport { useTheme } from \"@mui/material/styles\";\nimport { Circle, CircleDot } from \"lucide-react\";\nimport FormControlLabel from \"@mui/material/FormControlLabel\";\nimport Typography from \"@mui/material/Typography\";\n\ninterface RadioInputProps extends RadioProps {}\n\nexport const RadioInput = ({ ...props }: RadioInputProps) => {\n\tconst theme = useTheme();\n\treturn (\n\t\t<Radio\n\t\t\t{...props}\n\t\t\ticon={\n\t\t\t\t<Circle\n\t\t\t\t\tsize={16}\n\t\t\t\t\tstrokeWidth={1.5}\n\t\t\t\t/>\n\t\t\t}\n\t\t\tcheckedIcon={\n\t\t\t\t<CircleDot\n\t\t\t\t\tsize={14}\n\t\t\t\t\tstrokeWidth={1.5}\n\t\t\t\t/>\n\t\t\t}\n\t\t\tsx={{\n\t\t\t\tpadding: 0,\n\t\t\t\tmt: theme.spacing(0.5),\n\t\t\t\tcolor: theme.palette.text.secondary,\n\t\t\t\t\"&.Mui-checked\": {\n\t\t\t\t\tcolor: theme.palette.primary.main,\n\t\t\t\t\t\"& svg circle\": {\n\t\t\t\t\t\tfill: theme.palette.primary.main,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t\"& .MuiSvgIcon-root\": {\n\t\t\t\t\tfontSize: 16,\n\t\t\t\t},\n\t\t\t\t\"& svg\": {\n\t\t\t\t\tstroke: \"currentColor\",\n\t\t\t\t},\n\t\t\t\t\"& svg path, & svg line, & svg polyline, & svg rect, & svg circle\": {\n\t\t\t\t\tstroke: \"currentColor\",\n\t\t\t\t\tfill: \"none\",\n\t\t\t\t},\n\t\t\t}}\n\t\t/>\n\t);\n};\n\nexport const RadioWithDescription = ({\n\tlabel,\n\tdescription,\n\t...props\n}: RadioInputProps & { label: string; description: string }) => {\n\tconst theme = useTheme();\n\treturn (\n\t\t<FormControlLabel\n\t\t\tcontrol={<RadioInput {...props} />}\n\t\t\tlabel={\n\t\t\t\t<>\n\t\t\t\t\t<Typography component=\"p\">{label}</Typography>\n\t\t\t\t\t<Typography\n\t\t\t\t\t\tcomponent=\"h6\"\n\t\t\t\t\t\tcolor={theme.palette.text.secondary}\n\t\t\t\t\t>\n\t\t\t\t\t\t{description}\n\t\t\t\t\t</Typography>\n\t\t\t\t</>\n\t\t\t}\n\t\t\tsx={{\n\t\t\t\talignItems: \"flex-start\",\n\t\t\t\tp: theme.spacing(2.5),\n\t\t\t\tm: theme.spacing(-2.5),\n\t\t\t\tborderRadius: theme.shape.borderRadius,\n\n\t\t\t\t\"&:hover\": {\n\t\t\t\t\tbackgroundColor: theme.palette.background.paper,\n\t\t\t\t},\n\t\t\t\t\"& .MuiButtonBase-root\": {\n\t\t\t\t\tp: 0,\n\t\t\t\t\tmr: theme.spacing(6),\n\t\t\t\t},\n\t\t\t}}\n\t\t/>\n\t);\n};\n"
  },
  {
    "path": "client/src/Components/inputs/Select.tsx",
    "content": "import Select from \"@mui/material/Select\";\nimport type { SelectProps } from \"@mui/material/Select\";\nimport React, { forwardRef } from \"react\";\nimport { useTheme } from \"@mui/material/styles\";\nimport Stack from \"@mui/material/Stack\";\nimport { FieldLabel } from \"./FieldLabel\";\nimport { ChevronDown } from \"lucide-react\";\nimport Typography from \"@mui/material/Typography\";\n\ninterface SelectInputProps<T> extends Omit<SelectProps<T>, \"label\"> {\n\tfieldLabel?: string;\n\trequired?: boolean;\n\tplaceholder?: string;\n\tplaceholderColor?: string;\n}\n\nconst SelectInputInner = <T,>(\n\t{ fieldLabel, required, placeholder, placeholderColor, ...props }: SelectInputProps<T>,\n\tref: React.ForwardedRef<HTMLDivElement>\n) => {\n\tconst theme = useTheme();\n\tconst emptyPlaceholderColor = placeholderColor || theme.palette.text.disabled;\n\n\tconst renderValue = (selected: unknown) => {\n\t\tconst isMultiple = Boolean((props as { multiple?: boolean }).multiple);\n\t\tconst isEmpty = isMultiple\n\t\t\t? !Array.isArray(selected) || selected.length === 0\n\t\t\t: selected === undefined || selected === null || selected === \"\";\n\n\t\tif (isEmpty && placeholder) {\n\t\t\treturn <Typography sx={{ color: emptyPlaceholderColor }}>{placeholder}</Typography>;\n\t\t}\n\n\t\tif (isMultiple) {\n\t\t\tconst items: string[] = Array.isArray(selected) ? selected : [];\n\t\t\tconst capitalized = items.map(\n\t\t\t\t(item) => item.charAt(0).toUpperCase() + item.slice(1)\n\t\t\t);\n\t\t\treturn <Typography>{capitalized.join(\" | \")}</Typography>;\n\t\t}\n\n\t\tconst nodes = React.Children.toArray(props.children as React.ReactNode);\n\t\tfor (const node of nodes) {\n\t\t\tif (!React.isValidElement(node)) continue;\n\t\t\tconst el = node as React.ReactElement<{\n\t\t\t\tvalue?: unknown;\n\t\t\t\tchildren?: React.ReactNode;\n\t\t\t}>;\n\t\t\tif (el.props?.value === selected) {\n\t\t\t\treturn (el.props.children ?? selected) as React.ReactNode;\n\t\t\t}\n\t\t}\n\t\treturn selected as React.ReactNode;\n\t};\n\n\tconst select = (\n\t\t<Select<T>\n\t\t\t{...props}\n\t\t\tref={ref}\n\t\t\tdisplayEmpty\n\t\t\trenderValue={renderValue}\n\t\t\tinputProps={{\n\t\t\t\t...(props.inputProps || {}),\n\t\t\t\t\"aria-placeholder\": placeholder,\n\t\t\t}}\n\t\t\tIconComponent={() => (\n\t\t\t\t<ChevronDown\n\t\t\t\t\tsize={18}\n\t\t\t\t\tstrokeWidth={1.5}\n\t\t\t\t\tstyle={{ marginRight: theme.spacing(3) }}\n\t\t\t\t/>\n\t\t\t)}\n\t\t\tsx={{\n\t\t\t\theight: \"34px\",\n\t\t\t\t\"& .MuiSelect-select\": {\n\t\t\t\t\tdisplay: \"flex\",\n\t\t\t\t\talignItems: \"center\",\n\t\t\t\t\theight: \"100%\",\n\t\t\t\t\tboxSizing: \"border-box\",\n\t\t\t\t},\n\t\t\t\t\"& .MuiSelect-icon\": {\n\t\t\t\t\tright: theme.spacing(3),\n\t\t\t\t},\n\t\t\t\t\"& .MuiOutlinedInput-notchedOutline\": {\n\t\t\t\t\tborderRadius: theme.shape.borderRadius,\n\t\t\t\t\tborderColor: theme.palette.divider,\n\t\t\t\t},\n\t\t\t\t\"&:hover .MuiOutlinedInput-notchedOutline\": {\n\t\t\t\t\tborderColor: theme.palette.divider,\n\t\t\t\t},\n\t\t\t\t...props.sx,\n\t\t\t}}\n\t\t/>\n\t);\n\n\tif (fieldLabel) {\n\t\treturn (\n\t\t\t<Stack spacing={theme.spacing(2)}>\n\t\t\t\t<FieldLabel required={required}>{fieldLabel}</FieldLabel>\n\t\t\t\t{select}\n\t\t\t</Stack>\n\t\t);\n\t}\n\n\treturn select;\n};\n\nexport const SelectInput = forwardRef(SelectInputInner) as <T>(\n\tprops: SelectInputProps<T> & { ref?: React.ForwardedRef<HTMLDivElement> }\n) => React.ReactElement;\n"
  },
  {
    "path": "client/src/Components/inputs/Slider.tsx",
    "content": "import Typography from \"@mui/material/Typography\";\nimport { forwardRef } from \"react\";\nimport Slider from \"@mui/material/Slider\";\nimport type { SliderProps } from \"@mui/material/Slider\";\nimport { useTheme } from \"@mui/material/styles\";\nimport Stack from \"@mui/material/Stack\";\nimport { FieldLabel } from \"./FieldLabel\";\nimport Box from \"@mui/material/Box\";\nimport type { ResponsiveStyleValue } from \"@mui/system\";\n\ninterface SliderInputProps extends SliderProps {\n\tsx?: SliderProps[\"sx\"];\n\tshowValue?: boolean;\n\tformatDisplayValue?: (value: number) => string;\n}\n\nexport const SliderInput = forwardRef<HTMLSpanElement, SliderInputProps>(\n\t({ sx, showValue = false, formatDisplayValue, ...props }, ref) => {\n\t\tconst theme = useTheme();\n\t\tconst additionalSx = Array.isArray(sx) ? sx : sx ? [sx] : [];\n\n\t\tconst displayValue =\n\t\t\tshowValue && formatDisplayValue && typeof props.value === \"number\"\n\t\t\t\t? formatDisplayValue(props.value)\n\t\t\t\t: props.value;\n\n\t\treturn (\n\t\t\t<Stack\n\t\t\t\tgap={theme.spacing(8)}\n\t\t\t\tdirection={\"row\"}\n\t\t\t\talignItems={\"center\"}\n\t\t\t>\n\t\t\t\t{showValue && <Typography>{displayValue}</Typography>}\n\t\t\t\t<Slider\n\t\t\t\t\t{...props}\n\t\t\t\t\tref={ref}\n\t\t\t\t\tsx={[\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"& .MuiSlider-track\": {\n\t\t\t\t\t\t\t\tbackgroundColor: theme.palette.primary.main,\n\t\t\t\t\t\t\t\tborder: \"none\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"& .MuiSlider-rail\": {\n\t\t\t\t\t\t\t\tbackgroundColor: theme.palette.grey[300],\n\t\t\t\t\t\t\t\topacity: 1,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"& .MuiSlider-thumb\": {\n\t\t\t\t\t\t\t\tbackgroundColor: \"#fff\",\n\t\t\t\t\t\t\t\t\"&:hover, &.Mui-focusVisible\": {\n\t\t\t\t\t\t\t\t\tboxShadow: \"none\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\"&:active\": {\n\t\t\t\t\t\t\t\t\tboxShadow: \"none\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"& .MuiSlider-valueLabel\": {\n\t\t\t\t\t\t\t\tbackgroundColor: theme.palette.primary.main,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t...additionalSx,\n\t\t\t\t\t]}\n\t\t\t\t/>\n\t\t\t</Stack>\n\t\t);\n\t}\n);\n\ninterface SliderWithLabelProps extends SliderProps {\n\tfieldLabel?: string;\n\trequired?: boolean;\n\tshowValue?: boolean;\n\tformatDisplayValue?: (value: number) => string;\n\tsliderMaxWidth?: ResponsiveStyleValue<number | string>;\n}\n\nexport const SliderWithLabel = forwardRef<HTMLSpanElement, SliderWithLabelProps>(\n\t(\n\t\t{\n\t\t\tfieldLabel,\n\t\t\trequired,\n\t\t\tshowValue = true,\n\t\t\tformatDisplayValue,\n\t\t\tvalue,\n\t\t\tsliderMaxWidth = \"100%\",\n\t\t\t...props\n\t\t},\n\t\tref\n\t) => {\n\t\tconst theme = useTheme();\n\n\t\tconst labelText = fieldLabel;\n\n\t\treturn (\n\t\t\t<Stack spacing={theme.spacing(2)}>\n\t\t\t\t{fieldLabel && <FieldLabel required={required}>{labelText}</FieldLabel>}\n\t\t\t\t<Box maxWidth={sliderMaxWidth}>\n\t\t\t\t\t<SliderInput\n\t\t\t\t\t\t{...props}\n\t\t\t\t\t\tshowValue={showValue}\n\t\t\t\t\t\tformatDisplayValue={formatDisplayValue}\n\t\t\t\t\t\tvalue={value}\n\t\t\t\t\t\tref={ref}\n\t\t\t\t\t/>\n\t\t\t\t</Box>\n\t\t\t</Stack>\n\t\t);\n\t}\n);\n"
  },
  {
    "path": "client/src/Components/inputs/Switch.tsx",
    "content": "import { forwardRef } from \"react\";\nimport Switch from \"@mui/material/Switch\";\nimport type { SwitchProps } from \"@mui/material/Switch\";\nimport { useTheme } from \"@mui/material/styles\";\n\ninterface SwitchComponentProps extends SwitchProps {\n\tdualOption?: boolean;\n}\n\nexport const SwitchComponent = forwardRef<HTMLInputElement, SwitchComponentProps>(\n\tfunction SwitchComponent({ sx, dualOption = false, ...props }, ref) {\n\t\tconst theme = useTheme();\n\t\tconst additionalSx = Array.isArray(sx) ? sx : sx ? [sx] : [];\n\n\t\treturn (\n\t\t\t<Switch\n\t\t\t\t{...props}\n\t\t\t\tslotProps={{\n\t\t\t\t\tinput: {\n\t\t\t\t\t\tref: ref,\n\t\t\t\t\t},\n\t\t\t\t}}\n\t\t\t\tsx={[\n\t\t\t\t\t{\n\t\t\t\t\t\t\"& .MuiSwitch-switchBase\": {\n\t\t\t\t\t\t\t\"&.Mui-checked\": {\n\t\t\t\t\t\t\t\tcolor: \"#E0E0E0\",\n\t\t\t\t\t\t\t\t\"& + .MuiSwitch-track\": {\n\t\t\t\t\t\t\t\t\tbackgroundColor: theme.palette.primary.main,\n\t\t\t\t\t\t\t\t\topacity: 1,\n\t\t\t\t\t\t\t\t\tborder: 0,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t...(dualOption && {\n\t\t\t\t\t\t\t\"& .MuiSwitch-track\": {\n\t\t\t\t\t\t\t\tbackgroundColor: theme.palette.primary.main,\n\t\t\t\t\t\t\t\topacity: 1,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}),\n\t\t\t\t\t},\n\t\t\t\t\t...additionalSx,\n\t\t\t\t]}\n\t\t\t/>\n\t\t);\n\t}\n);\n"
  },
  {
    "path": "client/src/Components/inputs/SwitchTheme.tsx",
    "content": "import IconButton from \"@mui/material/IconButton\";\n\nimport { Moon, Sun } from \"lucide-react\";\n\nimport { setMode } from \"@/Features/UI/uiSlice.js\";\nimport { useTheme } from \"@mui/material\";\nimport { useDispatch, useSelector } from \"react-redux\";\nimport type { RootState } from \"@/Types/state\";\n\nexport const SwitchTheme = () => {\n\tconst mode = useSelector((state: RootState) => state.ui.mode);\n\tconst dispatch = useDispatch();\n\tconst theme = useTheme();\n\n\tconst handleChange = () => {\n\t\tdispatch(setMode(mode === \"light\" ? \"dark\" : \"light\"));\n\t};\n\treturn (\n\t\t<IconButton\n\t\t\tid=\"theme-toggle\"\n\t\t\tonClick={handleChange}\n\t\t\tsx={{\n\t\t\t\tdisplay: \"flex\",\n\t\t\t\talignItems: \"center\",\n\t\t\t\tjustifyContent: \"center\",\n\t\t\t\t\"& svg\": {\n\t\t\t\t\ttransition: \"stroke 0.2s ease\",\n\t\t\t\t},\n\t\t\t\t\"&:hover svg path, &:hover svg line, &:hover svg polyline, &:hover svg rect, &:hover svg circle\":\n\t\t\t\t\t{\n\t\t\t\t\t\tstroke: theme.palette.primary.main,\n\t\t\t\t\t},\n\t\t\t}}\n\t\t>\n\t\t\t{mode === \"light\" ? (\n\t\t\t\t<Moon\n\t\t\t\t\tsize={16}\n\t\t\t\t\tstrokeWidth={1.5}\n\t\t\t\t/>\n\t\t\t) : (\n\t\t\t\t<Sun\n\t\t\t\t\tsize={16}\n\t\t\t\t\tstrokeWidth={1.5}\n\t\t\t\t/>\n\t\t\t)}\n\t\t</IconButton>\n\t);\n};\n"
  },
  {
    "path": "client/src/Components/inputs/TextInput.tsx",
    "content": "import { forwardRef } from \"react\";\nimport TextField from \"@mui/material/TextField\";\nimport type { TextFieldProps } from \"@mui/material\";\nimport { typographyLevels } from \"@/Utils/Theme/Palette\";\nimport { useTheme } from \"@mui/material/styles\";\nimport Stack from \"@mui/material/Stack\";\nimport { FieldLabel } from \"./FieldLabel\";\n\ninterface TextInputProps extends Omit<TextFieldProps, \"label\"> {\n\tfieldLabel?: string;\n\trequired?: boolean;\n}\n\nexport const TextInput = forwardRef<HTMLInputElement, TextInputProps>(function TextInput(\n\t{ fieldLabel, required, ...props },\n\tref\n) {\n\tconst theme = useTheme();\n\n\tconst input = (\n\t\t<TextField\n\t\t\t{...props}\n\t\t\tinputRef={ref}\n\t\t\tsx={{\n\t\t\t\t\"& .MuiOutlinedInput-root\": {\n\t\t\t\t\tborderRadius: theme.shape.borderRadius,\n\t\t\t\t\theight: 34,\n\t\t\t\t\tfontSize: typographyLevels.base,\n\t\t\t\t},\n\t\t\t\t\"& .MuiOutlinedInput-notchedOutline\": {\n\t\t\t\t\tborderColor: theme.palette.divider,\n\t\t\t\t},\n\t\t\t\t\"&:hover .MuiOutlinedInput-notchedOutline\": {\n\t\t\t\t\tborderColor: theme.palette.divider,\n\t\t\t\t},\n\t\t\t\t\"& .MuiFormHelperText-root\": {\n\t\t\t\t\tmarginLeft: 0,\n\t\t\t\t\tmarginRight: 0,\n\t\t\t\t\tmarginTop: theme.spacing(1),\n\t\t\t\t},\n\t\t\t}}\n\t\t/>\n\t);\n\n\tif (fieldLabel) {\n\t\treturn (\n\t\t\t<Stack spacing={theme.spacing(2)}>\n\t\t\t\t<FieldLabel required={required}>{fieldLabel}</FieldLabel>\n\t\t\t\t{input}\n\t\t\t</Stack>\n\t\t);\n\t}\n\n\treturn input;\n});\nTextInput.displayName = \"TextInput\";\n"
  },
  {
    "path": "client/src/Components/inputs/TimePicker.tsx",
    "content": "import { MobileTimePicker } from \"@mui/x-date-pickers/MobileTimePicker\";\nimport type { MobileTimePickerProps } from \"@mui/x-date-pickers/MobileTimePicker\";\nimport type { Dayjs } from \"dayjs\";\nimport { useTheme } from \"@mui/material/styles\";\nimport Stack from \"@mui/material/Stack\";\nimport { FieldLabel } from \"./FieldLabel\";\nimport { AdapterDayjs } from \"@mui/x-date-pickers/AdapterDayjs\";\nimport { LocalizationProvider } from \"@mui/x-date-pickers\";\n\ninterface TimePickerComponentProps extends Omit<MobileTimePickerProps<Dayjs>, \"label\"> {\n\tfieldLabel?: string;\n\trequired?: boolean;\n}\n\nexport const TimePickerComponent = ({\n\tfieldLabel,\n\trequired,\n\t...props\n}: TimePickerComponentProps) => {\n\tconst theme = useTheme();\n\n\tconst picker = (\n\t\t<LocalizationProvider dateAdapter={AdapterDayjs}>\n\t\t\t<MobileTimePicker\n\t\t\t\t{...props}\n\t\t\t\tslotProps={{\n\t\t\t\t\tfield: {\n\t\t\t\t\t\tsx: {\n\t\t\t\t\t\t\twidth: \"fit-content\",\n\t\t\t\t\t\t\t\"& input\": {\n\t\t\t\t\t\t\t\tminHeight: 34,\n\t\t\t\t\t\t\t\tp: 0,\n\t\t\t\t\t\t\t\tpx: theme.spacing(5),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"& fieldset\": {\n\t\t\t\t\t\t\t\tborderColor: theme.palette.divider,\n\t\t\t\t\t\t\t\tborderRadius: theme.shape.borderRadius,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"&:not(:has(.Mui-disabled)):not(:has(.Mui-error)) .MuiOutlinedInput-root:not(:has(input:focus)):hover fieldset\":\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tborderColor: theme.palette.divider,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t...props.slotProps,\n\t\t\t\t}}\n\t\t\t/>\n\t\t</LocalizationProvider>\n\t);\n\n\tif (fieldLabel) {\n\t\treturn (\n\t\t\t<Stack spacing={theme.spacing(2)}>\n\t\t\t\t<FieldLabel required={required}>{fieldLabel}</FieldLabel>\n\t\t\t\t{picker}\n\t\t\t</Stack>\n\t\t);\n\t}\n\n\treturn picker;\n};\n"
  },
  {
    "path": "client/src/Components/inputs/ToggleButton.tsx",
    "content": "import ToggleButton from \"@mui/material/ToggleButton\";\nimport ToggleButtonGroup from \"@mui/material/ToggleButtonGroup\";\nimport type { ToggleButtonProps } from \"@mui/material/ToggleButton\";\nimport type { ToggleButtonGroupProps } from \"@mui/material/ToggleButtonGroup\";\nimport { useTheme } from \"@mui/material/styles\";\n\nexport const ToggleButtonInput = ({ sx, ...props }: ToggleButtonProps) => {\n\treturn (\n\t\t<ToggleButton\n\t\t\t{...props}\n\t\t\tsx={{\n\t\t\t\tpx: 8,\n\t\t\t\ttextTransform: \"none\",\n\t\t\t\theight: 34,\n\t\t\t\tfontWeight: 400,\n\t\t\t\twhiteSpace: \"nowrap\",\n\t\t\t\ttextOverflow: \"ellipsis\",\n\t\t\t\toverflow: \"hidden\",\n\t\t\t\tboxShadow: \"none\",\n\t\t\t\t\"&:hover\": {\n\t\t\t\t\tboxShadow: \"none\",\n\t\t\t\t},\n\t\t\t\t...sx,\n\t\t\t}}\n\t\t/>\n\t);\n};\n\nexport const ToggleButtonGroupInput = ({ sx, ...props }: ToggleButtonGroupProps) => {\n\tconst theme = useTheme();\n\treturn (\n\t\t<ToggleButtonGroup\n\t\t\t{...props}\n\t\t\tsx={{\n\t\t\t\t\"& .MuiToggleButtonGroup-grouped\": {\n\t\t\t\t\tborderColor: theme.palette.divider,\n\n\t\t\t\t\tborderRadius: 0,\n\t\t\t\t\t\"&:first-of-type\": {\n\t\t\t\t\t\tborderTopLeftRadius: 2,\n\t\t\t\t\t\tborderBottomLeftRadius: 2,\n\t\t\t\t\t},\n\t\t\t\t\t\"&:last-of-type\": {\n\t\t\t\t\t\tborderTopRightRadius: 2,\n\t\t\t\t\t\tborderBottomRightRadius: 2,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t...sx,\n\t\t\t}}\n\t\t/>\n\t);\n};\n"
  },
  {
    "path": "client/src/Components/inputs/index.tsx",
    "content": "export { ButtonInput as Button } from \"./Button\";\nexport * from \"./FieldLabel\";\nexport { SelectInput as Select } from \"./Select\";\nexport { CheckboxInput as Checkbox } from \"./Checkbox\";\nexport { AutoCompleteInput as Autocomplete } from \"./AutoComplete\";\nexport { TextInput as TextField } from \"./TextInput\";\nexport {\n\tToggleButtonInput as ToggleButton,\n\tToggleButtonGroupInput as ToggleButtonGroup,\n} from \"./ToggleButton\";\nexport { DialogInput as Dialog } from \"./Dialog\";\nexport * from \"./Radio\";\nexport * from \"./Switch\";\nexport * from \"./Slider\";\nexport * from \"./ImageUpload\";\nexport * from \"./ColorPicker\";\nexport { DatePickerComponent as DatePicker } from \"./DatePicker\";\nexport { TimePickerComponent as TimePicker } from \"./TimePicker\";\nexport * from \"./LanguageSelector\";\nexport * from \"./SwitchTheme\";\n"
  },
  {
    "path": "client/src/Components/layout/AppLayout.tsx",
    "content": "import Box from \"@mui/material/Box\";\nimport { useState, useEffect, useRef } from \"react\";\nimport { useTheme } from \"@mui/material/styles\";\nimport { OfflineBanner } from \"@/Components/design-elements\";\nimport { setServerUnreachableCallback, get } from \"@/Utils/ApiClient\";\n\ninterface AppLayoutProps {\n\tchildren: React.ReactNode;\n}\n\nconst AppLayout = ({ children }: AppLayoutProps) => {\n\tconst theme = useTheme();\n\tconst [serverUnreachable, setServerUnreachable] = useState(false);\n\tconst retryIntervalRef = useRef<number | null>(null);\n\n\tuseEffect(() => {\n\t\tsetServerUnreachableCallback(setServerUnreachable);\n\t}, []);\n\n\tuseEffect(() => {\n\t\tif (serverUnreachable) {\n\t\t\tretryIntervalRef.current = window.setInterval(async () => {\n\t\t\t\ttry {\n\t\t\t\t\tawait get(\"/health\", { timeout: 5000 });\n\t\t\t\t} catch {\n\t\t\t\t\t// NO_OP\n\t\t\t\t}\n\t\t\t}, 5000);\n\t\t} else if (retryIntervalRef.current) {\n\t\t\tclearInterval(retryIntervalRef.current);\n\t\t\tretryIntervalRef.current = null;\n\t\t}\n\n\t\treturn () => {\n\t\t\tif (retryIntervalRef.current) {\n\t\t\t\tclearInterval(retryIntervalRef.current);\n\t\t\t}\n\t\t};\n\t}, [serverUnreachable]);\n\n\treturn (\n\t\t<Box\n\t\t\tsx={{\n\t\t\t\tminHeight: \"100vh\",\n\t\t\t\tbackgroundColor: theme.palette.background.default,\n\t\t\t}}\n\t\t>\n\t\t\t<OfflineBanner visible={serverUnreachable} />\n\t\t\t{children}\n\t\t</Box>\n\t);\n};\n\nexport default AppLayout;\n"
  },
  {
    "path": "client/src/Components/layout/RootLayout.tsx",
    "content": "import { Sidebar } from \"@/Components/sidebar\";\nimport { Outlet } from \"react-router\";\nimport Stack from \"@mui/material/Stack\";\nimport { useMediaQuery } from \"@mui/material\";\nimport { useSidebar } from \"@/Hooks/useSidebar\";\n\nimport { useTheme } from \"@mui/material\";\n\nconst RootLayout = () => {\n\tconst theme = useTheme();\n\tconst isSmall = useMediaQuery(theme.breakpoints.down(\"md\"));\n\tconst { collapsedWidth } = useSidebar();\n\n\treturn (\n\t\t<Stack flexDirection=\"row\">\n\t\t\t<Sidebar />\n\t\t\t<Stack\n\t\t\t\tflex={1}\n\t\t\t\tpadding={6}\n\t\t\t\toverflow={\"hidden\"}\n\t\t\t\tsx={{\n\t\t\t\t\tbackgroundColor:\n\t\t\t\t\t\ttheme.palette.mode === \"dark\"\n\t\t\t\t\t\t\t? \"rgba(255, 255, 255, 0.01)\"\n\t\t\t\t\t\t\t: \"rgba(0, 0, 0, 0.01)\",\n\t\t\t\t\tdisplay: \"flex\",\n\t\t\t\t\talignItems: \"center\",\n\t\t\t\t\tpaddingLeft: isSmall ? `${collapsedWidth + 12}px` : 12,\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t<Stack\n\t\t\t\t\tmaxWidth={1280}\n\t\t\t\t\twidth=\"100%\"\n\t\t\t\t\tpaddingY={theme.spacing(6)}\n\t\t\t\t\tflex={1}\n\t\t\t\t>\n\t\t\t\t\t<Outlet />\n\t\t\t\t</Stack>\n\t\t\t</Stack>\n\t\t</Stack>\n\t);\n};\n\nexport default RootLayout;\n"
  },
  {
    "path": "client/src/Components/monitors/ControlsFilter.tsx",
    "content": "import Stack from \"@mui/material/Stack\";\nimport { Select, Button } from \"@/Components/inputs\";\nimport MenuItem from \"@mui/material/MenuItem\";\nimport useMediaQuery from \"@mui/material/useMediaQuery\";\n\nimport type { MonitorType } from \"@/Types/Monitor\";\nimport { Typography, useTheme } from \"@mui/material\";\nimport { useTranslation } from \"react-i18next\";\n\nconst types = [\"http\", \"ping\", \"port\", \"docker\", \"game\", \"grpc\", \"websocket\"];\nconst typeDisplayNames: Record<string, string> = {\n\thttp: \"HTTP\",\n\tping: \"Ping\",\n\tport: \"Port\",\n\tdocker: \"Docker\",\n\tgame: \"Game\",\n\tgrpc: \"gRPC\",\n\twebsocket: \"WebSocket\",\n};\nconst statuses = [\"up\", \"down\"];\nconst states = [\"active\", \"paused\"];\n\nexport const ControlsFilter = ({\n\tshowTypes = true,\n\tselectedTypes,\n\tsetSelectedTypes,\n\tselectedStatus,\n\tsetSelectedStatus,\n\tselectedState,\n\tsetSelectedState,\n\tonClearFilters,\n}: {\n\tshowTypes?: boolean;\n\tselectedTypes?: MonitorType[];\n\tsetSelectedTypes?: React.Dispatch<React.SetStateAction<MonitorType[]>>;\n\tselectedStatus: string;\n\tsetSelectedStatus: React.Dispatch<React.SetStateAction<string>>;\n\tselectedState: string;\n\tsetSelectedState: React.Dispatch<React.SetStateAction<string>>;\n\tonClearFilters: () => void;\n}) => {\n\tconst theme = useTheme();\n\tconst { t } = useTranslation();\n\tconst isSmall = useMediaQuery(theme.breakpoints.down(\"md\"));\n\tconst isFilterActive =\n\t\t(selectedTypes?.length ?? 0) > 0 || selectedStatus !== \"\" || selectedState !== \"\";\n\treturn (\n\t\t<Stack\n\t\t\tdirection={isSmall ? \"column\" : \"row\"}\n\t\t\tgap={theme.spacing(2)}\n\t\t>\n\t\t\t{showTypes && setSelectedTypes && (\n\t\t\t\t<Select\n\t\t\t\t\tmultiple\n\t\t\t\t\tplaceholder=\"Type\"\n\t\t\t\t\tvalue={selectedTypes ?? []}\n\t\t\t\t\tonChange={(e) => setSelectedTypes(e.target.value as MonitorType[])}\n\t\t\t\t>\n\t\t\t\t\t{types.map((type) => (\n\t\t\t\t\t\t<MenuItem\n\t\t\t\t\t\t\tkey={type}\n\t\t\t\t\t\t\tvalue={type}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<Typography>{typeDisplayNames[type] ?? type}</Typography>\n\t\t\t\t\t\t</MenuItem>\n\t\t\t\t\t))}\n\t\t\t\t</Select>\n\t\t\t)}\n\t\t\t<Select\n\t\t\t\tplaceholder=\"Status\"\n\t\t\t\tvalue={selectedStatus}\n\t\t\t\tonChange={(e) => setSelectedStatus(e.target.value)}\n\t\t\t>\n\t\t\t\t{statuses.map((status) => (\n\t\t\t\t\t<MenuItem\n\t\t\t\t\t\tkey={status}\n\t\t\t\t\t\tvalue={status}\n\t\t\t\t\t>\n\t\t\t\t\t\t<Typography textTransform={\"capitalize\"}>{status}</Typography>\n\t\t\t\t\t</MenuItem>\n\t\t\t\t))}\n\t\t\t</Select>\n\t\t\t<Select\n\t\t\t\tplaceholder=\"State\"\n\t\t\t\tvalue={selectedState}\n\t\t\t\tonChange={(e) => setSelectedState(e.target.value)}\n\t\t\t>\n\t\t\t\t{states.map((state) => (\n\t\t\t\t\t<MenuItem\n\t\t\t\t\t\tkey={state}\n\t\t\t\t\t\tvalue={state}\n\t\t\t\t\t>\n\t\t\t\t\t\t<Typography textTransform={\"capitalize\"}>{state}</Typography>\n\t\t\t\t\t</MenuItem>\n\t\t\t\t))}\n\t\t\t</Select>\n\t\t\t{isFilterActive && (\n\t\t\t\t<Button\n\t\t\t\t\tvariant=\"contained\"\n\t\t\t\t\tonClick={onClearFilters}\n\t\t\t\t>\n\t\t\t\t\t{t(\"common.buttons.clearFilters\")}\n\t\t\t\t</Button>\n\t\t\t)}\n\t\t</Stack>\n\t);\n};\n"
  },
  {
    "path": "client/src/Components/monitors/GeoChecksMap.tsx",
    "content": "import { useRef, useEffect, useState } from \"react\";\nimport { Box, Typography, Stack, useTheme, GlobalStyles } from \"@mui/material\";\nimport Map, { Marker, Popup } from \"react-map-gl/maplibre\";\nimport type { MapRef } from \"react-map-gl/maplibre\";\nimport type { FlatGeoCheck } from \"@/Types/GeoCheck\";\nimport \"maplibre-gl/dist/maplibre-gl.css\";\n\ninterface GeoChecksMapProps {\n\tgeoChecks: FlatGeoCheck[];\n}\n\nexport const GeoChecksMap = ({ geoChecks }: GeoChecksMapProps) => {\n\tconst mapRef = useRef<MapRef>(null);\n\tconst [selectedCheck, setSelectedCheck] = useState<FlatGeoCheck | null>(null);\n\tconst theme = useTheme();\n\tconst isDarkMode = theme.palette.mode === \"dark\";\n\n\tconst mapPopupStyles = (\n\t\t<GlobalStyles\n\t\t\tstyles={{\n\t\t\t\t\".maplibregl-popup-content\": {\n\t\t\t\t\tbackground: \"transparent !important\",\n\t\t\t\t\tpadding: \"0 !important\",\n\t\t\t\t\tboxShadow: \"none !important\",\n\t\t\t\t},\n\t\t\t\t\".maplibregl-popup-tip\": {\n\t\t\t\t\tdisplay: \"none\",\n\t\t\t\t},\n\t\t\t\t\".maplibregl-ctrl-attrib\": {\n\t\t\t\t\tdisplay: \"none\",\n\t\t\t\t},\n\t\t\t\t\".maplibregl-ctrl-logo\": {\n\t\t\t\t\tdisplay: \"none\",\n\t\t\t\t},\n\t\t\t\t\".maplibregl-popup-close-button\": {\n\t\t\t\t\tcolor: theme.palette.text.primary,\n\t\t\t\t\tbackground: \"transparent\",\n\t\t\t\t\tfontSize: \"20px\",\n\t\t\t\t\tpadding: \"4px\",\n\t\t\t\t\t\"&:hover\": {\n\t\t\t\t\t\tbackgroundColor: theme.palette.action.hover,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}}\n\t\t/>\n\t);\n\n\tuseEffect(() => {\n\t\tif (geoChecks.length === 0 || !mapRef.current) return;\n\n\t\tconst bounds = geoChecks.reduce(\n\t\t\t(acc, check) => {\n\t\t\t\treturn {\n\t\t\t\t\tminLng: Math.min(acc.minLng, check.location.longitude),\n\t\t\t\t\tmaxLng: Math.max(acc.maxLng, check.location.longitude),\n\t\t\t\t\tminLat: Math.min(acc.minLat, check.location.latitude),\n\t\t\t\t\tmaxLat: Math.max(acc.maxLat, check.location.latitude),\n\t\t\t\t};\n\t\t\t},\n\t\t\t{\n\t\t\t\tminLng: Infinity,\n\t\t\t\tmaxLng: -Infinity,\n\t\t\t\tminLat: Infinity,\n\t\t\t\tmaxLat: -Infinity,\n\t\t\t}\n\t\t);\n\n\t\tif (bounds.minLng !== Infinity) {\n\t\t\tmapRef.current.fitBounds(\n\t\t\t\t[\n\t\t\t\t\t[bounds.minLng, bounds.minLat],\n\t\t\t\t\t[bounds.maxLng, bounds.maxLat],\n\t\t\t\t],\n\t\t\t\t{ padding: 50, duration: 1000 }\n\t\t\t);\n\t\t}\n\t}, [geoChecks]);\n\n\tconst getMarkerColor = (status: boolean): string => {\n\t\treturn status ? theme.palette.success.main : theme.palette.error.main;\n\t};\n\n\tconst formatResponseTime = (timing: number): string => {\n\t\treturn `${timing.toFixed(0)}ms`;\n\t};\n\n\treturn (\n\t\t<>\n\t\t\t{mapPopupStyles}\n\t\t\t<Box\n\t\t\t\theight={500}\n\t\t\t\twidth={\"100%\"}\n\t\t\t\tborderRadius={theme.shape.borderRadius}\n\t\t\t\toverflow={\"hidden\"}\n\t\t\t>\n\t\t\t\t<Map\n\t\t\t\t\tref={mapRef}\n\t\t\t\t\tinitialViewState={{\n\t\t\t\t\t\tlongitude: 0,\n\t\t\t\t\t\tlatitude: 20,\n\t\t\t\t\t\tzoom: 1.5,\n\t\t\t\t\t}}\n\t\t\t\t\tstyle={{ height: \"100%\", width: \"100%\" }}\n\t\t\t\t\tmapStyle={\n\t\t\t\t\t\tisDarkMode\n\t\t\t\t\t\t\t? \"https://basemaps.cartocdn.com/gl/dark-matter-gl-style/style.json\"\n\t\t\t\t\t\t\t: \"https://basemaps.cartocdn.com/gl/positron-gl-style/style.json\"\n\t\t\t\t\t}\n\t\t\t\t>\n\t\t\t\t\t{geoChecks.map((check, index) => (\n\t\t\t\t\t\t<Marker\n\t\t\t\t\t\t\tkey={`${check.id}-${index}`}\n\t\t\t\t\t\t\tlongitude={check.location.longitude}\n\t\t\t\t\t\t\tlatitude={check.location.latitude}\n\t\t\t\t\t\t\tanchor=\"bottom\"\n\t\t\t\t\t\t\tonClick={(e: any) => {\n\t\t\t\t\t\t\t\te.originalEvent.stopPropagation();\n\t\t\t\t\t\t\t\tsetSelectedCheck(check);\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\t\twidth: \"10px\",\n\t\t\t\t\t\t\t\t\theight: \"10px\",\n\t\t\t\t\t\t\t\t\tborderRadius: \"50%\",\n\t\t\t\t\t\t\t\t\tbackgroundColor: getMarkerColor(check.status),\n\t\t\t\t\t\t\t\t\tboxShadow: \"0 2px 4px rgba(0,0,0,0.3)\",\n\t\t\t\t\t\t\t\t\tcursor: \"pointer\",\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</Marker>\n\t\t\t\t\t))}\n\n\t\t\t\t\t{selectedCheck && (\n\t\t\t\t\t\t<Popup\n\t\t\t\t\t\t\tlongitude={selectedCheck.location.longitude}\n\t\t\t\t\t\t\tlatitude={selectedCheck.location.latitude}\n\t\t\t\t\t\t\tanchor=\"top\"\n\t\t\t\t\t\t\tonClose={() => setSelectedCheck(null)}\n\t\t\t\t\t\t\tcloseOnClick={false}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<Box\n\t\t\t\t\t\t\t\tsx={{\n\t\t\t\t\t\t\t\t\tminWidth: 200,\n\t\t\t\t\t\t\t\t\tp: theme.spacing(4),\n\t\t\t\t\t\t\t\t\tbgcolor: theme.palette.background.paper,\n\t\t\t\t\t\t\t\t\tborderWidth: 1,\n\t\t\t\t\t\t\t\t\tborderStyle: \"solid\",\n\t\t\t\t\t\t\t\t\tborderColor: theme.palette.divider,\n\t\t\t\t\t\t\t\t\tborderRadius: 1,\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<Typography\n\t\t\t\t\t\t\t\t\tvariant=\"subtitle1\"\n\t\t\t\t\t\t\t\t\tfontWeight=\"bold\"\n\t\t\t\t\t\t\t\t\tgutterBottom\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t{selectedCheck.location.city}, {selectedCheck.location.country}\n\t\t\t\t\t\t\t\t</Typography>\n\t\t\t\t\t\t\t\t<Stack spacing={0.5}>\n\t\t\t\t\t\t\t\t\t<Typography variant=\"body2\">\n\t\t\t\t\t\t\t\t\t\t<Typography\n\t\t\t\t\t\t\t\t\t\t\tcomponent=\"span\"\n\t\t\t\t\t\t\t\t\t\t\tfontWeight=\"medium\"\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\tStatus:\n\t\t\t\t\t\t\t\t\t\t</Typography>{\" \"}\n\t\t\t\t\t\t\t\t\t\t{selectedCheck.status ? \"Up\" : \"Down\"}\n\t\t\t\t\t\t\t\t\t</Typography>\n\t\t\t\t\t\t\t\t\t<Typography variant=\"body2\">\n\t\t\t\t\t\t\t\t\t\t<Typography\n\t\t\t\t\t\t\t\t\t\t\tcomponent=\"span\"\n\t\t\t\t\t\t\t\t\t\t\tfontWeight=\"medium\"\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\tStatus Code:\n\t\t\t\t\t\t\t\t\t\t</Typography>{\" \"}\n\t\t\t\t\t\t\t\t\t\t{selectedCheck.statusCode}\n\t\t\t\t\t\t\t\t\t</Typography>\n\t\t\t\t\t\t\t\t\t<Typography variant=\"body2\">\n\t\t\t\t\t\t\t\t\t\t<Typography\n\t\t\t\t\t\t\t\t\t\t\tcomponent=\"span\"\n\t\t\t\t\t\t\t\t\t\t\tfontWeight=\"medium\"\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\tResponse Time:\n\t\t\t\t\t\t\t\t\t\t</Typography>{\" \"}\n\t\t\t\t\t\t\t\t\t\t{formatResponseTime(selectedCheck.timings.total)}\n\t\t\t\t\t\t\t\t\t</Typography>\n\t\t\t\t\t\t\t\t\t<Typography\n\t\t\t\t\t\t\t\t\t\tvariant=\"caption\"\n\t\t\t\t\t\t\t\t\t\tcolor=\"text.secondary\"\n\t\t\t\t\t\t\t\t\t\tsx={{ mt: 0.5 }}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t{new Date(selectedCheck.createdAt).toLocaleString()}\n\t\t\t\t\t\t\t\t\t</Typography>\n\t\t\t\t\t\t\t\t</Stack>\n\t\t\t\t\t\t\t</Box>\n\t\t\t\t\t\t</Popup>\n\t\t\t\t\t)}\n\t\t\t\t</Map>\n\t\t\t</Box>\n\t\t</>\n\t);\n};\n"
  },
  {
    "path": "client/src/Components/monitors/HeaderGeoTabs.tsx",
    "content": "import Stack from \"@mui/material/Stack\";\nimport { Tabs, Tab } from \"@/Components/design-elements\";\nimport { useTheme } from \"@mui/material/styles\";\nimport { useTranslation } from \"react-i18next\";\nimport type { GeoContinent } from \"@/Types/GeoCheck\";\n\ninterface HeaderGeoTabsProps {\n\tgeoCheckEnabled: boolean;\n\tlocations: GeoContinent[] | undefined;\n\tselectedLocation: GeoContinent;\n\tonLocationChange: (location: GeoContinent) => void;\n}\n\nexport const HeaderGeoTabs = ({\n\tgeoCheckEnabled,\n\tlocations,\n\tselectedLocation,\n\tonLocationChange,\n}: HeaderGeoTabsProps) => {\n\tconst { t } = useTranslation();\n\tconst theme = useTheme();\n\n\tif (!geoCheckEnabled || !locations || locations.length === 0) {\n\t\treturn null;\n\t}\n\n\tconst handleChange = (_event: React.SyntheticEvent, newValue: GeoContinent) => {\n\t\tonLocationChange(newValue);\n\t};\n\n\treturn (\n\t\t<Stack\n\t\t\tspacing={{ xs: theme.spacing(8), md: 0 }}\n\t\t\tdirection={{ xs: \"column\", md: \"row\" }}\n\t\t\talignItems={\"center\"}\n\t\t\tjustifyContent={\"flex-start\"}\n\t\t>\n\t\t\t<Tabs\n\t\t\t\tvalue={selectedLocation}\n\t\t\t\tonChange={handleChange}\n\t\t\t>\n\t\t\t\t{locations.map((location) => (\n\t\t\t\t\t<Tab\n\t\t\t\t\t\tkey={location}\n\t\t\t\t\t\tlabel={t(\n\t\t\t\t\t\t\t`pages.createMonitor.form.geoChecks.option.locations.options.${location}`\n\t\t\t\t\t\t)}\n\t\t\t\t\t\tvalue={location}\n\t\t\t\t\t/>\n\t\t\t\t))}\n\t\t\t</Tabs>\n\t\t</Stack>\n\t);\n};\n"
  },
  {
    "path": "client/src/Components/monitors/HeaderMonitorControls.tsx",
    "content": "import Stack from \"@mui/material/Stack\";\nimport { Icon, MonitorStatus } from \"@/Components/design-elements\";\nimport { Button } from \"@/Components/inputs\";\nimport { Settings, Pause, Play, Mail, Bug, Trash } from \"lucide-react\";\n\nimport { useTranslation } from \"react-i18next\";\nimport { useNavigate } from \"react-router-dom\";\nimport { useTheme } from \"@mui/material/styles\";\nimport { usePost } from \"@/Hooks/UseApi\";\n\nimport type { Monitor } from \"@/Types/Monitor.js\";\ninterface BaseHeaderProps {\n\tmonitor: Monitor;\n}\n\nconst BaseHeader = ({ monitor, children }: React.PropsWithChildren<BaseHeaderProps>) => {\n\tconst theme = useTheme();\n\treturn (\n\t\t<Stack\n\t\t\tspacing={{ xs: theme.spacing(8), md: 0 }}\n\t\t\tdirection={{ xs: \"column\", md: \"row\" }}\n\t\t\talignItems={\"center\"}\n\t\t\tjustifyContent={\"space-between\"}\n\t\t>\n\t\t\t<MonitorStatus monitor={monitor} />\n\t\t\t{children}\n\t\t</Stack>\n\t);\n};\n\ninterface HeaderMonitorControlsProps {\n\tpath: string;\n\tmonitor?: Monitor | null;\n\tisAdmin: boolean;\n\trefetch: Function;\n}\n\nexport const HeaderMonitorControls = ({\n\tpath,\n\tmonitor,\n\tisAdmin,\n\trefetch,\n}: HeaderMonitorControlsProps) => {\n\tconst { t } = useTranslation();\n\tconst theme = useTheme();\n\tconst navigate = useNavigate();\n\tconst {\n\t\tpost,\n\t\tloading: isPosting,\n\t\t// error: postError,\n\t} = usePost<any, Monitor>();\n\n\tif (!monitor) {\n\t\treturn null;\n\t}\n\treturn (\n\t\t<BaseHeader monitor={monitor}>\n\t\t\t<Stack\n\t\t\t\twidth={{ xs: \"100%\", md: \"auto\" }}\n\t\t\t\tdirection={{ xs: \"column\", md: \"row\" }}\n\t\t\t\tgap={theme.spacing(2)}\n\t\t\t>\n\t\t\t\t<Button\n\t\t\t\t\tvariant=\"contained\"\n\t\t\t\t\tcolor=\"secondary\"\n\t\t\t\t\tloading={isPosting}\n\t\t\t\t\tstartIcon={<Icon icon={Mail} />}\n\t\t\t\t\tonClick={async () => {\n\t\t\t\t\t\tawait post(`/notifications/test/all`, { monitorId: monitor.id });\n\t\t\t\t\t}}\n\t\t\t\t\tsx={{\n\t\t\t\t\t\twhiteSpace: \"nowrap\",\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t{t(\"common.buttons.testNotifications\")}\n\t\t\t\t</Button>\n\t\t\t\t<Button\n\t\t\t\t\tvariant=\"contained\"\n\t\t\t\t\tcolor=\"secondary\"\n\t\t\t\t\tstartIcon={<Icon icon={Bug} />}\n\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\tnavigate(`/incidents/${monitor?.id}`);\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t{t(\"common.buttons.incidents\")}\n\t\t\t\t</Button>\n\t\t\t\t{isAdmin && (\n\t\t\t\t\t<Button\n\t\t\t\t\t\tvariant=\"contained\"\n\t\t\t\t\t\tcolor=\"secondary\"\n\t\t\t\t\t\tloading={isPosting}\n\t\t\t\t\t\tstartIcon={monitor?.isActive ? <Icon icon={Pause} /> : <Icon icon={Play} />}\n\t\t\t\t\t\tonClick={async () => {\n\t\t\t\t\t\t\tawait post(`/monitors/pause/${monitor.id}`, {});\n\t\t\t\t\t\t\tawait refetch();\n\t\t\t\t\t\t}}\n\t\t\t\t\t>\n\t\t\t\t\t\t{monitor?.isActive ? t(\"common.buttons.pause\") : t(\"common.buttons.resume\")}\n\t\t\t\t\t</Button>\n\t\t\t\t)}\n\t\t\t\t{isAdmin && (\n\t\t\t\t\t<Button\n\t\t\t\t\t\tvariant=\"contained\"\n\t\t\t\t\t\tcolor=\"secondary\"\n\t\t\t\t\t\tstartIcon={<Icon icon={Settings} />}\n\t\t\t\t\t\tonClick={() => navigate(`/${path}/configure/${monitor.id}`)}\n\t\t\t\t\t>\n\t\t\t\t\t\t{t(\"common.buttons.configure\")}\n\t\t\t\t\t</Button>\n\t\t\t\t)}\n\t\t\t</Stack>\n\t\t</BaseHeader>\n\t);\n};\n\ninterface HeaderDeleteControlsProps {\n\tmonitor?: Monitor | null;\n\tisAdmin: boolean;\n\trefetch: Function;\n\tonDelete?: () => void;\n}\n\nexport const HeaderDeleteControls = ({\n\tmonitor,\n\tisAdmin,\n\trefetch,\n\tonDelete,\n}: HeaderDeleteControlsProps) => {\n\tconst { t } = useTranslation();\n\tconst theme = useTheme();\n\tconst {\n\t\tpost,\n\t\tloading: isPosting,\n\t\t// error: postError,\n\t} = usePost<any, Monitor>();\n\n\tif (!monitor) {\n\t\treturn null;\n\t}\n\treturn (\n\t\t<BaseHeader monitor={monitor}>\n\t\t\t<Stack\n\t\t\t\twidth={{ xs: \"100%\", md: \"auto\" }}\n\t\t\t\tdirection={{ xs: \"column\", md: \"row\" }}\n\t\t\t\tgap={theme.spacing(2)}\n\t\t\t>\n\t\t\t\t{isAdmin && (\n\t\t\t\t\t<Button\n\t\t\t\t\t\tvariant=\"contained\"\n\t\t\t\t\t\tcolor=\"secondary\"\n\t\t\t\t\t\tloading={isPosting}\n\t\t\t\t\t\tstartIcon={monitor?.isActive ? <Icon icon={Pause} /> : <Icon icon={Play} />}\n\t\t\t\t\t\tonClick={async () => {\n\t\t\t\t\t\t\tawait post(`/monitors/pause/${monitor.id}`, {});\n\t\t\t\t\t\t\tawait refetch();\n\t\t\t\t\t\t}}\n\t\t\t\t\t>\n\t\t\t\t\t\t{monitor?.isActive ? t(\"common.buttons.pause\") : t(\"common.buttons.resume\")}\n\t\t\t\t\t</Button>\n\t\t\t\t)}\n\t\t\t\t{isAdmin && (\n\t\t\t\t\t<Button\n\t\t\t\t\t\tvariant=\"contained\"\n\t\t\t\t\t\tcolor=\"error\"\n\t\t\t\t\t\tstartIcon={<Icon icon={Trash} />}\n\t\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\t\tonDelete?.();\n\t\t\t\t\t\t}}\n\t\t\t\t\t>\n\t\t\t\t\t\t{t(\"common.buttons.delete\")}\n\t\t\t\t\t</Button>\n\t\t\t\t)}\n\t\t\t</Stack>\n\t\t</BaseHeader>\n\t);\n};\n"
  },
  {
    "path": "client/src/Components/monitors/HeaderMonitorsSummary.tsx",
    "content": "import {\n\tUpStatusBox,\n\tDownStatusBox,\n\tPausedStatusBox,\n\tInitializingStatusBox,\n\tBreachedStatusBox,\n} from \"@/Components/design-elements\";\nimport Stack from \"@mui/material/Stack\";\n\nimport type { MonitorsSummary } from \"@/Types/Monitor\";\nimport { useTheme } from \"@mui/material\";\n\ninterface MonitorsSummaryProps {\n\tsummary: MonitorsSummary | null;\n\tshowBreached?: boolean;\n}\n\nexport const HeaderMonitorsSummary = ({\n\tsummary,\n\tshowBreached = false,\n}: MonitorsSummaryProps) => {\n\tconst theme = useTheme();\n\treturn (\n\t\t<Stack\n\t\t\tdirection={{ xs: \"column\", md: \"row\" }}\n\t\t\tgap={theme.spacing(8)}\n\t\t>\n\t\t\t<UpStatusBox n={summary?.upMonitors || 0} />\n\t\t\t<DownStatusBox n={summary?.downMonitors || 0} />\n\t\t\t{showBreached && <BreachedStatusBox n={summary?.breachedMonitors || 0} />}\n\t\t\t<PausedStatusBox n={summary?.pausedMonitors || 0} />\n\t\t\t<InitializingStatusBox n={summary?.initializingMonitors || 0} />\n\t\t</Stack>\n\t);\n};\n"
  },
  {
    "path": "client/src/Components/monitors/MonitorStatBoxes.tsx",
    "content": "import Stack from \"@mui/material/Stack\";\nimport { StatBox } from \"@/Components/design-elements\";\n\nimport prettyMilliseconds from \"pretty-ms\";\nimport { useTheme } from \"@mui/material/styles\";\nimport type { MonitorStats, Monitor } from \"@/Types/Monitor\";\nimport { getStatusPalette } from \"@/Utils/MonitorUtils\";\nimport { useTranslation } from \"react-i18next\";\n\ninterface MonitorStatBoxesProps {\n\tmonitor?: Monitor;\n\tmonitorStats: MonitorStats | null;\n\tcertificateExpiry?: string;\n}\n\nexport const MonitorStatBoxes = ({\n\tmonitor,\n\tmonitorStats,\n\tcertificateExpiry,\n}: MonitorStatBoxesProps) => {\n\tconst theme = useTheme();\n\tconst { t } = useTranslation();\n\tif (!monitorStats || !monitor) {\n\t\treturn null;\n\t}\n\n\tconst timeOfLastFailure = monitorStats?.timeOfLastFailure || 0;\n\tconst timeSinceLastFailure =\n\t\ttimeOfLastFailure > 0\n\t\t\t? Date.now() - timeOfLastFailure\n\t\t\t: Date.now() - new Date(monitorStats?.createdAt || 0).getTime();\n\n\t// Determine time since last check\n\tconst timeOfLastCheck = monitorStats?.lastCheckTimestamp || 0;\n\tconst timeSinceLastCheck = Date.now() - timeOfLastCheck || 0;\n\n\tconst options = {\n\t\tsecondsDecimalDigits: 0,\n\t\tmillisecondsDecimalDigits: 0,\n\t};\n\n\tconst streakTime = prettyMilliseconds(timeSinceLastFailure, options);\n\n\tconst lastCheckTime = prettyMilliseconds(timeSinceLastCheck, options);\n\tconst palette = getStatusPalette(monitor?.status);\n\n\treturn (\n\t\t<Stack\n\t\t\tdirection={{ xs: \"column\", md: \"row\" }}\n\t\t\tgap={theme.spacing(8)}\n\t\t>\n\t\t\t<StatBox\n\t\t\t\tpalette={palette}\n\t\t\t\ttitle={t(\"pages.common.monitors.statBoxes.activeFor\")}\n\t\t\t\tsubtitle={streakTime}\n\t\t\t/>\n\t\t\t<StatBox\n\t\t\t\ttitle={t(\"pages.common.monitors.statBoxes.lastCheck\")}\n\t\t\t\tsubtitle={lastCheckTime}\n\t\t\t/>\n\t\t\t<StatBox\n\t\t\t\ttitle={t(\"pages.common.monitors.statBoxes.lastResponseTime\")}\n\t\t\t\tsubtitle={prettyMilliseconds(monitorStats?.lastResponseTime ?? 0)}\n\t\t\t/>\n\n\t\t\t{monitor?.type === \"http\" && (\n\t\t\t\t<StatBox\n\t\t\t\t\ttitle={t(\"pages.common.monitors.statBoxes.certificateExpiry\")}\n\t\t\t\t\tsubtitle={certificateExpiry || \"N/A\"}\n\t\t\t\t/>\n\t\t\t)}\n\t\t</Stack>\n\t);\n};\n"
  },
  {
    "path": "client/src/Components/monitors/charts/HistogramDetails.tsx",
    "content": "import { BaseChart, BaseBox } from \"@/Components/design-elements\";\nimport { Clock } from \"lucide-react\";\nimport {\n\tAreaChart,\n\tArea,\n\tXAxis,\n\tTooltip,\n\tCartesianGrid,\n\tResponsiveContainer,\n\tText,\n} from \"recharts\";\nimport Typography from \"@mui/material/Typography\";\n\nimport { useSelector } from \"react-redux\";\nimport {\n\tformatDateWithTz,\n\ttickDateFormatLookup,\n\ttooltipDateFormatLookup,\n} from \"@/Utils/TimeUtils\";\nimport { useTheme } from \"@mui/material/styles\";\nimport type { GroupedCheck } from \"@/Types/Check\";\nimport type { RootState } from \"@/Types/state\";\n\ntype XTickProps = {\n\tx: number;\n\ty: number;\n\tpayload: { value: any };\n\trange: string;\n};\n\nexport const XTick = ({ x, y, payload, range }: XTickProps) => {\n\tconst format = tickDateFormatLookup(range);\n\tconst theme = useTheme();\n\tconst uiTimezone = useSelector((state: RootState) => state.ui.timezone);\n\treturn (\n\t\t<Text\n\t\t\tx={x}\n\t\t\ty={y + 10}\n\t\t\ttextAnchor=\"middle\"\n\t\t\tfill={theme.palette.text.secondary}\n\t\t\tfontSize={11}\n\t\t\tfontWeight={400}\n\t\t>\n\t\t\t{formatDateWithTz(payload?.value, format, uiTimezone)}\n\t\t</Text>\n\t);\n};\n\ntype ResponseTimeToolTipProps = {\n\tactive?: boolean | undefined;\n\tpayload?: any[];\n\tlabel?: string | number;\n\trange: string;\n\ttheme: any;\n\tuiTimezone: string;\n};\n\nconst ResponseTimeToolTip = ({\n\tactive,\n\tpayload,\n\tlabel,\n\trange,\n\ttheme,\n\tuiTimezone,\n}: ResponseTimeToolTipProps) => {\n\tif (!label) return null;\n\tif (!payload) return null;\n\tif (!active) return null;\n\n\tconst format = tooltipDateFormatLookup(range);\n\tconst responseTime = Math.floor(payload?.[0]?.payload?.avgResponseTime || 0);\n\treturn (\n\t\t<BaseBox sx={{ py: theme.spacing(2), px: theme.spacing(4) }}>\n\t\t\t<Typography>{formatDateWithTz(String(label), format, uiTimezone)}</Typography>\n\t\t\t<Typography>Response time: {responseTime} ms</Typography>\n\t\t</BaseBox>\n\t);\n};\n\nexport const HistogramDetails = ({\n\tchecks,\n\trange,\n}: {\n\tchecks: GroupedCheck[];\n\trange: string;\n}) => {\n\tconst theme = useTheme();\n\tconst uiTimezone = useSelector((state: RootState) => state.ui.timezone);\n\treturn (\n\t\t<BaseChart\n\t\t\ticon={\n\t\t\t\t<Clock\n\t\t\t\t\tsize={20}\n\t\t\t\t\tstrokeWidth={1.5}\n\t\t\t\t/>\n\t\t\t}\n\t\t\ttitle=\"Response times\"\n\t\t>\n\t\t\t<ResponsiveContainer\n\t\t\t\twidth=\"100%\"\n\t\t\t\theight={300}\n\t\t\t>\n\t\t\t\t<AreaChart data={checks?.slice()}>\n\t\t\t\t\t<CartesianGrid\n\t\t\t\t\t\tstroke={theme.palette.divider}\n\t\t\t\t\t\tstrokeWidth={1}\n\t\t\t\t\t\tstrokeOpacity={1}\n\t\t\t\t\t\tfill=\"transparent\"\n\t\t\t\t\t\tvertical={false}\n\t\t\t\t\t/>\n\t\t\t\t\t<defs>\n\t\t\t\t\t\t<linearGradient\n\t\t\t\t\t\t\tid=\"colorUv\"\n\t\t\t\t\t\t\tx1=\"0\"\n\t\t\t\t\t\t\ty1=\"0\"\n\t\t\t\t\t\t\tx2=\"0\"\n\t\t\t\t\t\t\ty2=\"1\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<stop\n\t\t\t\t\t\t\t\toffset=\"0%\"\n\t\t\t\t\t\t\t\tstopColor={theme.palette.primary.main}\n\t\t\t\t\t\t\t\tstopOpacity={0.8}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t<stop\n\t\t\t\t\t\t\t\toffset=\"100%\"\n\t\t\t\t\t\t\t\tstopColor={theme.palette.primary.light}\n\t\t\t\t\t\t\t\tstopOpacity={0}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</linearGradient>\n\t\t\t\t\t</defs>\n\t\t\t\t\t<XAxis\n\t\t\t\t\t\taxisLine={false}\n\t\t\t\t\t\ttickLine={false}\n\t\t\t\t\t\tdataKey=\"bucketDate\"\n\t\t\t\t\t\ttick={(props) => (\n\t\t\t\t\t\t\t<XTick\n\t\t\t\t\t\t\t\t{...props}\n\t\t\t\t\t\t\t\trange={range}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t)}\n\t\t\t\t\t/>\n\n\t\t\t\t\t<Tooltip\n\t\t\t\t\t\tcontent={(props) => (\n\t\t\t\t\t\t\t<ResponseTimeToolTip\n\t\t\t\t\t\t\t\t{...props}\n\t\t\t\t\t\t\t\trange={range}\n\t\t\t\t\t\t\t\ttheme={theme}\n\t\t\t\t\t\t\t\tuiTimezone={uiTimezone}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t)}\n\t\t\t\t\t/>\n\t\t\t\t\t<Area\n\t\t\t\t\t\ttype=\"monotone\"\n\t\t\t\t\t\tdataKey=\"avgResponseTime\"\n\t\t\t\t\t\tstroke={theme.palette.primary.main}\n\t\t\t\t\t\tfill=\"url(#colorUv)\"\n\t\t\t\t\t/>\n\t\t\t\t</AreaChart>\n\t\t\t</ResponsiveContainer>\n\t\t</BaseChart>\n\t);\n};\n"
  },
  {
    "path": "client/src/Components/monitors/charts/HistogramInfrastructure.tsx",
    "content": "import { BaseChart } from \"@/Components/design-elements\";\nimport {\n\tAreaChart,\n\tArea,\n\tXAxis,\n\tYAxis,\n\tCartesianGrid,\n\tResponsiveContainer,\n} from \"recharts\";\nimport { Fragment, useId } from \"react\";\nimport { XTick } from \"@/Components/monitors\";\n\nimport { useTheme } from \"@mui/material/styles\";\nimport type { HardwareCheckStats } from \"@/Types/Monitor\";\n\nconst AREA_COLORS = [\n\t// Blues\n\t\"#3182bd\", // Deep blue\n\t\"#6baed6\", // Medium blue\n\t\"#9ecae1\", // Light blue\n\n\t// Greens\n\t\"#74c476\", // Soft green\n\t\"#a1d99b\", // Light green\n\t\"#c7e9c0\", // Pale green\n\n\t// Oranges\n\t\"#fdae6b\", // Warm orange\n\t\"#fdd0a2\", // Light orange\n\t\"#feedde\", // Pale orange\n\n\t// Purples\n\t\"#9467bd\", // Lavender\n\t\"#a55194\", // Deep magenta\n\t\"#c994c7\", // Soft magenta\n\n\t// Reds\n\t\"#ff9896\", // Soft red\n\t\"#de2d26\", // Deep red\n\t\"#fc9272\", // Medium red\n\n\t// Cyans/Teals\n\t\"#17becf\", // Cyan\n\t\"#7fcdbb\", // Teal\n\t\"#a1dab4\", // Light teal\n\n\t// Yellows\n\t\"#fec44f\", // Mustard\n\t\"#fee391\", // Light yellow\n\t\"#ffffd4\", // Pale yellow\n\n\t// Additional colors\n\t\"#e377c2\", // Soft pink\n\t\"#bcbd22\", // Olive\n\t\"#2ca02c\", // Vibrant green\n];\n\nconst createGradient = ({\n\tid,\n\tstartColor,\n\tendColor,\n\tstartOpacity = 0.8,\n\tendOpacity = 0,\n\tdirection = \"vertical\",\n}: {\n\tid: string;\n\tstartColor: string;\n\tendColor: string;\n\tstartOpacity?: number;\n\tendOpacity?: number;\n\tdirection?: \"vertical\" | \"horizontal\";\n}) => (\n\t<defs>\n\t\t<linearGradient\n\t\t\tid={id}\n\t\t\tx1={direction === \"vertical\" ? \"0\" : \"0\"}\n\t\t\ty1={direction === \"vertical\" ? \"0\" : \"0\"}\n\t\t\tx2={direction === \"vertical\" ? \"0\" : \"1\"}\n\t\t\ty2={direction === \"vertical\" ? \"1\" : \"0\"}\n\t\t>\n\t\t\t<stop\n\t\t\t\toffset=\"0%\"\n\t\t\t\tstopColor={startColor}\n\t\t\t\tstopOpacity={startOpacity}\n\t\t\t/>\n\t\t\t<stop\n\t\t\t\toffset=\"100%\"\n\t\t\t\tstopColor={endColor}\n\t\t\t\tstopOpacity={endOpacity}\n\t\t\t/>\n\t\t</linearGradient>\n\t</defs>\n);\n\nexport const HistogramInfrastructure = ({\n\tdateRange,\n\ttitle,\n\ttype,\n\tidx: _idx,\n\tchecks,\n\txKey,\n\tyDomain,\n\tdataKeys,\n\tgradient = false,\n\tgradientDirection = \"vertical\",\n\tgradientStartColor,\n\tgradientEndColor,\n\tstrokeColor,\n\tfillColor,\n\tyAxisFormatter,\n}: {\n\tdateRange: string;\n\ttitle: string;\n\ttype: string;\n\tidx: number | null;\n\tchecks: HardwareCheckStats[];\n\txKey: string;\n\tyDomain?: number[];\n\tdataKeys: string[];\n\tgradient?: boolean;\n\tgradientDirection?: \"vertical\" | \"horizontal\";\n\tgradientStartColor?: string;\n\tgradientEndColor?: string;\n\tstrokeColor: string;\n\tfillColor?: string;\n\tyAxisFormatter?: (value: number) => string;\n}) => {\n\tconst theme = useTheme();\n\tconst uniqueId = useId();\n\tconst data = checks;\n\n\tlet avgTemps: { bucketDate: string; avg_temp: number | null }[] = [];\n\tlet tempYDomain: number[] = [];\n\tif (type === \"temp\") {\n\t\tavgTemps = data.map((check) => {\n\t\t\tconst temps = check.avgTemperature || [];\n\t\t\tif (temps.length === 0) return { bucketDate: check.bucketDate, avg_temp: null };\n\t\t\tconst totalTemp = temps.reduce((sum, temp) => sum + (temp || 0), 0);\n\t\t\tconst avgTemp = totalTemp / temps.length;\n\t\t\treturn { bucketDate: check.bucketDate, avg_temp: avgTemp };\n\t\t});\n\n\t\tconst maxTemp: number = avgTemps.reduce((max, item) => {\n\t\t\treturn item.avg_temp && item.avg_temp > max ? item.avg_temp : max;\n\t\t}, 0);\n\n\t\ttempYDomain = [0, Math.ceil((maxTemp * 1.3) / 10) * 10];\n\t}\n\n\treturn (\n\t\t<BaseChart\n\t\t\ticon={null}\n\t\t\ttitle={title}\n\t\t>\n\t\t\t<ResponsiveContainer\n\t\t\t\twidth=\"100%\"\n\t\t\t\theight={200}\n\t\t\t>\n\t\t\t\t<AreaChart data={type === \"temp\" ? avgTemps : data}>\n\t\t\t\t\t<XAxis\n\t\t\t\t\t\tdataKey={xKey}\n\t\t\t\t\t\ttick={(props) => (\n\t\t\t\t\t\t\t<XTick\n\t\t\t\t\t\t\t\t{...props}\n\t\t\t\t\t\t\t\trange={dateRange}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t)}\n\t\t\t\t\t/>\n\t\t\t\t\t<YAxis\n\t\t\t\t\t\tdomain={type === \"temp\" ? tempYDomain : yDomain}\n\t\t\t\t\t\ttickFormatter={yAxisFormatter}\n\t\t\t\t\t/>\n\n\t\t\t\t\t<CartesianGrid\n\t\t\t\t\t\tstroke={theme.palette.divider}\n\t\t\t\t\t\tstrokeWidth={1}\n\t\t\t\t\t\tstrokeOpacity={1}\n\t\t\t\t\t\tfill=\"transparent\"\n\t\t\t\t\t\tvertical={false}\n\t\t\t\t\t/>\n\t\t\t\t\t{dataKeys?.map((dataKey, index) => {\n\t\t\t\t\t\tconst gradientId = `gradient-${uniqueId}-${index}`;\n\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t<Fragment key={`${dataKey}-${index}`}>\n\t\t\t\t\t\t\t\t{gradient === true &&\n\t\t\t\t\t\t\t\t\tcreateGradient({\n\t\t\t\t\t\t\t\t\t\tid: gradientId,\n\t\t\t\t\t\t\t\t\t\tstartColor: gradientStartColor || AREA_COLORS[index],\n\t\t\t\t\t\t\t\t\t\tendColor: gradientEndColor || \"transparent\",\n\t\t\t\t\t\t\t\t\t\tdirection: gradientDirection,\n\t\t\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\t\t<Area\n\t\t\t\t\t\t\t\t\tkey={dataKey}\n\t\t\t\t\t\t\t\t\ttype=\"monotone\"\n\t\t\t\t\t\t\t\t\tdataKey={dataKey}\n\t\t\t\t\t\t\t\t\tstroke={strokeColor || AREA_COLORS[index]}\n\t\t\t\t\t\t\t\t\tfill={gradient === true ? `url(#${gradientId})` : fillColor}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t</Fragment>\n\t\t\t\t\t\t);\n\t\t\t\t\t})}\n\t\t\t\t</AreaChart>\n\t\t\t</ResponsiveContainer>\n\t\t</BaseChart>\n\t);\n};\n"
  },
  {
    "path": "client/src/Components/monitors/charts/HistogramPageSpeed.tsx",
    "content": "import Stack from \"@mui/material/Stack\";\nimport { Area, AreaChart, CartesianGrid, ResponsiveContainer, Tooltip } from \"recharts\";\nimport { HistogramPageSpeedTooltip } from \"@/Components/monitors/charts/HistogramPageSpeedTooltip\";\nimport { useTheme } from \"@mui/material/styles\";\nimport type { CheckSnapshot } from \"@/Types/Check\";\nimport type { MonitorStatus } from \"@/Types/Monitor\";\n\nimport { getStatusColor } from \"@/Utils/MonitorUtils\";\n\nconst processData = (checks: CheckSnapshot[]) => {\n\tif (checks.length === 0) return [];\n\tconst formattedData: { score: number; date: string }[] = [];\n\n\tconst calculateScore = (entry: CheckSnapshot) => {\n\t\tconst accessibility = entry?.accessibility || 0;\n\t\tconst bestPractices = entry?.bestPractices || 0;\n\t\tconst performance = entry?.performance || 0;\n\t\tconst seo = entry?.seo || 0;\n\t\treturn Math.floor((accessibility + bestPractices + performance + seo) / 4);\n\t};\n\n\tchecks.forEach((entry) => {\n\t\tconst score = calculateScore(entry);\n\t\tconst date = entry.createdAt;\n\t\tformattedData.push({ score, date });\n\t});\n\n\treturn formattedData;\n};\n\nexport const HistogramPageSpeed = ({\n\tchecks,\n\tstatus,\n}: {\n\tchecks: CheckSnapshot[];\n\tstatus: MonitorStatus;\n}) => {\n\tconst theme = useTheme();\n\tconst scores = processData(checks ?? []);\n\tconst color = getStatusColor(status, theme);\n\treturn (\n\t\t<Stack\n\t\t\tdirection=\"row\"\n\t\t\tflexWrap=\"nowrap\"\n\t\t\tgap={theme.spacing(1.5)}\n\t\t\theight=\"100px\"\n\t\t\tmaxWidth=\"400px\"\n\t\t\twidth=\"100%\"\n\t\t\tonClick={(event) => event.stopPropagation()}\n\t\t\toverflow={\"hidden\"}\n\t\t\tsx={{\n\t\t\t\tcursor: \"default\",\n\t\t\t\tposition: \"relative\",\n\t\t\t}}\n\t\t>\n\t\t\t<ResponsiveContainer\n\t\t\t\twidth=\"100%\"\n\t\t\t\theight={\"100%\"}\n\t\t\t>\n\t\t\t\t<AreaChart\n\t\t\t\t\tdata={scores}\n\t\t\t\t\tmargin={{ top: 10, bottom: -5 }}\n\t\t\t\t\tstyle={{ cursor: \"pointer\" }}\n\t\t\t\t>\n\t\t\t\t\t<CartesianGrid\n\t\t\t\t\t\tstroke={theme.palette.divider}\n\t\t\t\t\t\tstrokeWidth={1}\n\t\t\t\t\t\tstrokeOpacity={1}\n\t\t\t\t\t\tfill=\"transparent\"\n\t\t\t\t\t\tvertical={false}\n\t\t\t\t\t/>\n\t\t\t\t\t<Tooltip\n\t\t\t\t\t\tcursor={{ stroke: theme.palette.divider }}\n\t\t\t\t\t\tcontent={<HistogramPageSpeedTooltip />}\n\t\t\t\t\t/>\n\t\t\t\t\t<defs>\n\t\t\t\t\t\t<linearGradient\n\t\t\t\t\t\t\tid={`pagespeed-chart-${status}`}\n\t\t\t\t\t\t\tx1=\"0\"\n\t\t\t\t\t\t\ty1=\"0\"\n\t\t\t\t\t\t\tx2=\"0\"\n\t\t\t\t\t\t\ty2=\"1\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<stop\n\t\t\t\t\t\t\t\toffset=\"0%\"\n\t\t\t\t\t\t\t\tstopColor={color}\n\t\t\t\t\t\t\t\tstopOpacity={0.8}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t<stop\n\t\t\t\t\t\t\t\toffset=\"100%\"\n\t\t\t\t\t\t\t\tstopColor={color}\n\t\t\t\t\t\t\t\tstopOpacity={0}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</linearGradient>\n\t\t\t\t\t</defs>\n\t\t\t\t\t<Area\n\t\t\t\t\t\ttype=\"monotone\"\n\t\t\t\t\t\tdataKey=\"score\"\n\t\t\t\t\t\tstroke={color}\n\t\t\t\t\t\tfill={`url(#pagespeed-chart-${status})`}\n\t\t\t\t\t/>\n\t\t\t\t</AreaChart>\n\t\t\t</ResponsiveContainer>\n\t\t</Stack>\n\t);\n};\n"
  },
  {
    "path": "client/src/Components/monitors/charts/HistogramPageSpeedDetails.tsx",
    "content": "import { BaseChart } from \"@/Components/design-elements\";\nimport { TrendingUp } from \"lucide-react\";\nimport { XTick } from \"@/Components/monitors\";\nimport {\n\tXAxis,\n\tAreaChart,\n\tArea,\n\tTooltip,\n\tCartesianGrid,\n\tResponsiveContainer,\n} from \"recharts\";\nimport { HistogramPageSpeedScoresTooltip } from \"@/Components/monitors\";\n\nimport { useTheme } from \"@mui/material/styles\";\nimport type { PageSpeedGroupedCheck } from \"@/Types/Check\";\nimport type { Palette } from \"@mui/material/styles\";\ntype PaletteColorKey = Extract<\n\tkeyof Palette,\n\t\"primary\" | \"error\" | \"success\" | \"warning\"\n>;\n\nexport interface ConfigItem {\n\tid: string;\n\ttext: string;\n\tpalette: PaletteColorKey;\n}\n\nconst config: Record<string, ConfigItem> = {\n\tseo: {\n\t\tid: \"seo\",\n\t\ttext: \"SEO\",\n\t\tpalette: \"primary\",\n\t},\n\tperformance: {\n\t\tid: \"performance\",\n\t\ttext: \"performance\",\n\t\tpalette: \"success\",\n\t},\n\tbestPractices: {\n\t\tid: \"bestPractices\",\n\t\ttext: \"best practices\",\n\t\tpalette: \"warning\",\n\t},\n\taccessibility: {\n\t\tid: \"accessibility\",\n\t\ttext: \"accessibility\",\n\t\tpalette: \"error\",\n\t},\n};\n\nexport const HistogramPageSpeedDetails = ({\n\tchecks,\n\trange,\n}: {\n\tchecks: PageSpeedGroupedCheck[];\n\trange: string;\n}) => {\n\tconst theme = useTheme();\n\treturn (\n\t\t<BaseChart\n\t\t\ticon={\n\t\t\t\t<TrendingUp\n\t\t\t\t\tsize={20}\n\t\t\t\t\tstrokeWidth={1.5}\n\t\t\t\t/>\n\t\t\t}\n\t\t\ttitle=\"Score history\"\n\t\t>\n\t\t\t<ResponsiveContainer\n\t\t\t\twidth=\"100%\"\n\t\t\t\tminWidth={25}\n\t\t\t\theight={215}\n\t\t\t>\n\t\t\t\t<AreaChart data={checks}>\n\t\t\t\t\t<XAxis\n\t\t\t\t\t\tdataKey={\"bucketDate\"}\n\t\t\t\t\t\ttick={(props) => (\n\t\t\t\t\t\t\t<XTick\n\t\t\t\t\t\t\t\t{...props}\n\t\t\t\t\t\t\t\trange={range}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t)}\n\t\t\t\t\t/>\n\t\t\t\t\t<CartesianGrid\n\t\t\t\t\t\tstroke={theme.palette.divider}\n\t\t\t\t\t\tstrokeWidth={1}\n\t\t\t\t\t\tstrokeOpacity={1}\n\t\t\t\t\t\tfill=\"transparent\"\n\t\t\t\t\t\tvertical={false}\n\t\t\t\t\t/>\n\t\t\t\t\t<Tooltip\n\t\t\t\t\t\tcursor={{ stroke: theme.palette.divider }}\n\t\t\t\t\t\tcontent={<HistogramPageSpeedScoresTooltip config={config} />}\n\t\t\t\t\t/>\n\t\t\t\t\t<defs>\n\t\t\t\t\t\t{Object.values(config).map(({ id, palette }) => {\n\t\t\t\t\t\t\tconst startColor = theme.palette[palette].main;\n\t\t\t\t\t\t\tconst endColor = theme.palette[palette].light;\n\n\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t<linearGradient\n\t\t\t\t\t\t\t\t\tid={id}\n\t\t\t\t\t\t\t\t\tx1=\"0\"\n\t\t\t\t\t\t\t\t\ty1=\"0\"\n\t\t\t\t\t\t\t\t\tx2=\"0\"\n\t\t\t\t\t\t\t\t\ty2=\"1\"\n\t\t\t\t\t\t\t\t\tkey={id}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<stop\n\t\t\t\t\t\t\t\t\t\toffset=\"0%\"\n\t\t\t\t\t\t\t\t\t\tstopColor={startColor}\n\t\t\t\t\t\t\t\t\t\tstopOpacity={0.8}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t<stop\n\t\t\t\t\t\t\t\t\t\toffset=\"100%\"\n\t\t\t\t\t\t\t\t\t\tstopColor={endColor}\n\t\t\t\t\t\t\t\t\t\tstopOpacity={0}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t</linearGradient>\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t})}\n\t\t\t\t\t</defs>\n\t\t\t\t\t{Object.keys(config).map((key) => {\n\t\t\t\t\t\tconst { palette } = config[key];\n\t\t\t\t\t\tconst strokeColor = theme.palette[palette].main;\n\t\t\t\t\t\tconst bgColor = theme.palette.primary.main;\n\n\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t<Area\n\t\t\t\t\t\t\t\tconnectNulls\n\t\t\t\t\t\t\t\tkey={key}\n\t\t\t\t\t\t\t\tdataKey={key}\n\t\t\t\t\t\t\t\tstackId={1}\n\t\t\t\t\t\t\t\tstroke={strokeColor}\n\t\t\t\t\t\t\t\tfill={`url(#${config[key].id})`}\n\t\t\t\t\t\t\t\tactiveDot={{ stroke: bgColor, fill: strokeColor, r: 4.5 }}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t);\n\t\t\t\t\t})}\n\t\t\t\t</AreaChart>\n\t\t\t</ResponsiveContainer>\n\t\t</BaseChart>\n\t);\n};\n"
  },
  {
    "path": "client/src/Components/monitors/charts/HistogramPageSpeedDetailsTooltip.tsx",
    "content": "import Box from \"@mui/material/Box\";\nimport Stack from \"@mui/material/Stack\";\nimport Typography from \"@mui/material/Typography\";\nimport { useTheme } from \"@mui/material/styles\";\nimport { SPACING, LAYOUT } from \"@/Utils/Theme/constants\";\nimport { formatDateWithTz } from \"@/Utils/TimeUtils\";\nimport type { ConfigItem } from \"@/Components/monitors\";\nimport type { TooltipProps } from \"recharts\";\nimport { useSelector } from \"react-redux\";\nimport type { RootState } from \"@/Types/state\";\n\ninterface HistogramPageSpeedScoresTooltipProps extends Partial<\n\tTooltipProps<number, string>\n> {\n\tconfig: Record<string, ConfigItem>;\n}\nexport const HistogramPageSpeedScoresTooltip = ({\n\tactive,\n\tpayload,\n\tlabel,\n\tconfig,\n}: HistogramPageSpeedScoresTooltipProps) => {\n\tconst theme = useTheme();\n\tconst uiTimezone = useSelector((state: RootState) => state.ui.timezone);\n\n\tif (active && payload && payload.length) {\n\t\treturn (\n\t\t\t<Box\n\t\t\t\tsx={{\n\t\t\t\t\tbackgroundColor: theme.palette.background.paper,\n\t\t\t\t\tborder: 1,\n\t\t\t\t\tborderColor: theme.palette.divider,\n\t\t\t\t\tborderRadius: theme.shape.borderRadius,\n\t\t\t\t\tpy: theme.spacing(SPACING.LG),\n\t\t\t\t\tpx: theme.spacing(LAYOUT.XS),\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t<Typography\n\t\t\t\t\tsx={{\n\t\t\t\t\t\tcolor: theme.palette.text.secondary,\n\t\t\t\t\t\tfontSize: 12,\n\t\t\t\t\t\tfontWeight: 500,\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t{formatDateWithTz(label, \"ddd, MMMM D, YYYY, h:mm A\", uiTimezone)}\n\t\t\t\t</Typography>\n\t\t\t\t{Object.keys(config)\n\t\t\t\t\t.reverse()\n\t\t\t\t\t.map((key) => {\n\t\t\t\t\t\tconst { palette } = config[key];\n\t\t\t\t\t\tconst dotColor = theme.palette[palette].main;\n\n\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t<Stack\n\t\t\t\t\t\t\t\tkey={`${key}-tooltip`}\n\t\t\t\t\t\t\t\tdirection=\"row\"\n\t\t\t\t\t\t\t\talignItems=\"center\"\n\t\t\t\t\t\t\t\tgap={theme.spacing(SPACING.XXL)}\n\t\t\t\t\t\t\t\tmt={theme.spacing(SPACING.SM)}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<Box\n\t\t\t\t\t\t\t\t\twidth={theme.spacing(LAYOUT.XS)}\n\t\t\t\t\t\t\t\t\theight={theme.spacing(LAYOUT.XS)}\n\t\t\t\t\t\t\t\t\tsx={{ borderRadius: \"50%\", backgroundColor: dotColor }}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t<Typography\n\t\t\t\t\t\t\t\t\ttextTransform=\"capitalize\"\n\t\t\t\t\t\t\t\t\tsx={{ opacity: 0.8 }}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t{config[key].text}\n\t\t\t\t\t\t\t\t</Typography>\n\t\t\t\t\t\t\t\t<Typography>{Math.floor(payload[0].payload[key])}</Typography>\n\t\t\t\t\t\t\t</Stack>\n\t\t\t\t\t\t);\n\t\t\t\t\t})}\n\t\t\t</Box>\n\t\t);\n\t}\n\treturn null;\n};\n"
  },
  {
    "path": "client/src/Components/monitors/charts/HistogramPageSpeedTooltip.tsx",
    "content": "import Stack from \"@mui/material/Stack\";\nimport Typography from \"@mui/material/Typography\";\nimport { formatDateWithTz } from \"@/Utils/TimeUtils\";\nimport type { TooltipProps } from \"recharts\";\nimport { useTheme } from \"@mui/material/styles\";\nimport { useSelector } from \"react-redux\";\nimport type { RootState } from \"@/Types/state\";\n\nexport const HistogramPageSpeedTooltip = ({\n\tactive,\n\tpayload,\n}: TooltipProps<number, string>) => {\n\tconst uiTimezone = useSelector((state: RootState) => state.ui.timezone);\n\tconst theme = useTheme();\n\n\tif (!active || !payload || payload.length === 0) {\n\t\treturn null;\n\t}\n\n\tconst data = payload[0]?.payload;\n\n\treturn (\n\t\t<Stack\n\t\t\talignItems=\"flex-start\"\n\t\t\tsx={{\n\t\t\t\tbackgroundColor: theme.palette.secondary.main,\n\t\t\t\tborder: 1,\n\t\t\t\tborderColor: theme.palette.divider,\n\t\t\t\tborderRadius: theme.shape.borderRadius,\n\t\t\t\tp: theme.spacing(4),\n\t\t\t}}\n\t\t>\n\t\t\t<Typography>\n\t\t\t\t{formatDateWithTz(data?.date, \"ddd, MMMM D, YYYY, HH:mm A\", uiTimezone)}\n\t\t\t</Typography>\n\t\t\t<Typography>Score: {data?.score}</Typography>\n\t\t</Stack>\n\t);\n};\n"
  },
  {
    "path": "client/src/Components/monitors/charts/HistogramStatus.tsx",
    "content": "import Stack from \"@mui/material/Stack\";\nimport Typography from \"@mui/material/Typography\";\nimport { BaseChart } from \"@/Components/design-elements\";\nimport { useTheme } from \"@mui/material/styles\";\nimport { useSelector } from \"react-redux\";\nimport { formatDateWithTz } from \"@/Utils/TimeUtils\";\nimport { useTranslation } from \"react-i18next\";\nimport { ResponsiveContainer, BarChart, XAxis, Bar, Cell, Tooltip } from \"recharts\";\nimport { getResponseTimeColor } from \"@/Utils/MonitorUtils\";\nimport type { GroupedCheck } from \"@/Types/Check\";\nimport type { RootState } from \"@/Types/state\";\n\ninterface XLabelProps {\n\tp1: GroupedCheck;\n\tp2: GroupedCheck;\n\trange: string;\n}\n\nconst XLabel = ({ p1, p2, range }: XLabelProps) => {\n\tconst theme = useTheme();\n\tconst uiTimezone = useSelector((state: RootState) => state.ui.timezone);\n\tconst dateFormat = range === \"day\" ? \"MMM D, h:mm A\" : \"MMM D\";\n\treturn (\n\t\t<>\n\t\t\t<text\n\t\t\t\tx={0}\n\t\t\t\ty=\"100%\"\n\t\t\t\tdy={-3}\n\t\t\t\ttextAnchor=\"start\"\n\t\t\t\tfontSize={11}\n\t\t\t\tfill={theme.palette.text.secondary}\n\t\t\t>\n\t\t\t\t{formatDateWithTz(p1.bucketDate, dateFormat, uiTimezone)}\n\t\t\t</text>\n\t\t\t<text\n\t\t\t\tx=\"100%\"\n\t\t\t\ty=\"100%\"\n\t\t\t\tdy={-3}\n\t\t\t\ttextAnchor=\"end\"\n\t\t\t\tfontSize={11}\n\t\t\t\tfill={theme.palette.text.secondary}\n\t\t\t>\n\t\t\t\t{formatDateWithTz(p2.bucketDate, dateFormat, uiTimezone)}\n\t\t\t</text>\n\t\t</>\n\t);\n};\n\ninterface HistogramStatusProps {\n\ttitle: string;\n\ticon: React.ReactNode;\n\tchecks?: GroupedCheck[];\n\trange: string;\n}\n\nexport const HistogramStatus = ({\n\ttitle,\n\ticon,\n\tchecks = [],\n\trange,\n}: HistogramStatusProps) => {\n\tconst { t } = useTranslation();\n\tconst theme = useTheme();\n\tconst CustomTooltip = ({\n\t\tactive,\n\t\tpayload,\n\t}: {\n\t\tactive?: boolean;\n\t\tpayload?: Array<{ payload: GroupedCheck }>;\n\t}) => {\n\t\tconst uiTimezone = useSelector((state: RootState) => state.ui.timezone);\n\t\tif (!active || !payload?.length) return null;\n\t\tconst d = payload[0]?.payload;\n\t\tconst avg = d?.avgResponseTime ?? 0;\n\t\tconst titleText = t(\"common.charts.labels.averageResponseTime\");\n\t\tconst fmt = range === \"30d\" ? \"MMM D, YYYY\" : \"ddd, MMM D, YYYY, h:mm A\";\n\t\tlet dateLabel = \"\";\n\t\tif (d?.bucketDate) {\n\t\t\tconst base = new Date(d.bucketDate);\n\t\t\tconst midBucket =\n\t\t\t\trange === \"30d\" ? new Date(base.getTime() + 12 * 60 * 60 * 1000) : base;\n\t\t\tdateLabel = formatDateWithTz(midBucket.toISOString(), fmt, uiTimezone);\n\t\t}\n\t\treturn (\n\t\t\t<Stack\n\t\t\t\tsx={{\n\t\t\t\t\tp: 1,\n\t\t\t\t\tbgcolor: \"background.paper\",\n\t\t\t\t\tborder: 1,\n\t\t\t\t\tborderColor: \"divider\",\n\t\t\t\t\tborderRadius: 1,\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t{dateLabel ? (\n\t\t\t\t\t<Typography\n\t\t\t\t\t\tsx={{ color: \"text.secondary\" }}\n\t\t\t\t\t\tvariant=\"caption\"\n\t\t\t\t\t>\n\t\t\t\t\t\t{dateLabel}\n\t\t\t\t\t</Typography>\n\t\t\t\t) : null}\n\t\t\t\t<Typography variant=\"caption\">{titleText}</Typography>\n\t\t\t\t<Typography variant=\"body2\">{Math.floor(avg)} ms</Typography>\n\t\t\t</Stack>\n\t\t);\n\t};\n\n\tconst totalChecks = checks.reduce((acc, check) => acc + (check.totalChecks || 0), 0);\n\n\treturn (\n\t\t<BaseChart\n\t\t\ticon={icon}\n\t\t\ttitle={title}\n\t\t>\n\t\t\t<Stack gap={theme.spacing(8)}>\n\t\t\t\t<Stack\n\t\t\t\t\tposition=\"relative\"\n\t\t\t\t\tdirection=\"row\"\n\t\t\t\t\tjustifyContent=\"space-between\"\n\t\t\t\t>\n\t\t\t\t\t<Stack>\n\t\t\t\t\t\t<Typography>Total checks: {totalChecks}</Typography>\n\t\t\t\t\t</Stack>\n\t\t\t\t</Stack>\n\t\t\t\t<ResponsiveContainer\n\t\t\t\t\twidth=\"100%\"\n\t\t\t\t\theight={155}\n\t\t\t\t>\n\t\t\t\t\t<BarChart data={checks}>\n\t\t\t\t\t\t<XAxis\n\t\t\t\t\t\t\tstroke={theme.palette.divider}\n\t\t\t\t\t\t\theight={15}\n\t\t\t\t\t\t\ttick={false}\n\t\t\t\t\t\t\tlabel={\n\t\t\t\t\t\t\t\t<XLabel\n\t\t\t\t\t\t\t\t\tp1={checks[0]}\n\t\t\t\t\t\t\t\t\tp2={checks[checks.length - 1]}\n\t\t\t\t\t\t\t\t\trange={range}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<Tooltip\n\t\t\t\t\t\t\tcursor={false}\n\t\t\t\t\t\t\tcontent={<CustomTooltip />}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<Bar\n\t\t\t\t\t\t\tdataKey=\"avgResponseTime\"\n\t\t\t\t\t\t\tmaxBarSize={7}\n\t\t\t\t\t\t\tbackground={{ fill: \"transparent\" }}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{checks?.map((groupedCheck, index) => {\n\t\t\t\t\t\t\t\tconst fillColor = getResponseTimeColor(groupedCheck.avgResponseTime);\n\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t<Cell\n\t\t\t\t\t\t\t\t\t\tkey={groupedCheck.bucketDate || `check-${index}`}\n\t\t\t\t\t\t\t\t\t\tfill={theme.palette[fillColor].main}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t</Bar>\n\t\t\t\t\t</BarChart>\n\t\t\t\t</ResponsiveContainer>\n\t\t\t</Stack>\n\t\t</BaseChart>\n\t);\n};\n"
  },
  {
    "path": "client/src/Components/monitors/charts/PiePageSpeed.tsx",
    "content": "import { BaseChart } from \"@/Components/design-elements\";\nimport { FileText } from \"lucide-react\";\nimport type { CheckAudits, CheckSnapshot } from \"@/Types/Check\";\nimport { Pie, PieChart, ResponsiveContainer, Label } from \"recharts\";\nimport Typography from \"@mui/material/Typography\";\nimport Box from \"@mui/material/Box\";\nimport { getPageSpeedPalette } from \"@/Utils/MonitorUtils\";\nimport { useTheme } from \"@mui/material/styles\";\nimport { alpha } from \"@mui/material/styles\";\nimport { useState } from \"react\";\nimport Tooltip from \"@mui/material/Tooltip\";\nimport { useTranslation } from \"react-i18next\";\n\nconst CenterLabel = ({ viewBox, value }: any) => {\n\tconst { cx, cy } = viewBox;\n\treturn (\n\t\t<foreignObject\n\t\t\tx={cx - 25}\n\t\t\ty={cy - 10}\n\t\t\twidth={50}\n\t\t\theight={50}\n\t\t>\n\t\t\t<Typography\n\t\t\t\tvariant=\"h1\"\n\t\t\t\talign=\"center\"\n\t\t\t>\n\t\t\t\t{value}\n\t\t\t</Typography>\n\t\t</foreignObject>\n\t);\n};\n\nexport const PiePageSpeed = ({ latestCheck }: { latestCheck?: CheckSnapshot }) => {\n\tconst { t } = useTranslation();\n\tconst theme = useTheme();\n\tconst [hoverTitle, setHoverTitle] = useState<string | null>(null);\n\n\tif (!latestCheck) return null;\n\tconst LABELS: Record<string, string> = {\n\t\tFCP: t(\"pages.pageSpeed.charts.common.fcp\"),\n\t\tSI: t(\"pages.pageSpeed.charts.common.si\"),\n\t\tLCP: t(\"pages.pageSpeed.charts.common.lcp\"),\n\t\tTBT: t(\"pages.pageSpeed.charts.common.tbt\"),\n\t\tCLS: t(\"pages.pageSpeed.charts.common.cls\"),\n\t};\n\tconst metrics: { key: keyof CheckAudits; color: string; weight: number }[] = [\n\t\t{ key: \"fcp\", color: alpha(\"#1DE9B6\", 0.6), weight: 0.1 },\n\t\t{ key: \"si\", color: alpha(\"#7C4DFF\", 0.6), weight: 0.1 },\n\t\t{ key: \"lcp\", color: alpha(\"#FFB200\", 0.6), weight: 0.25 },\n\t\t{ key: \"tbt\", color: alpha(\"#00AFFE\", 0.6), weight: 0.3 },\n\t\t{ key: \"cls\", color: alpha(\"#FF4181\", 0.6), weight: 0.25 },\n\t];\n\n\tconst scores = metrics.flatMap(({ key, color, weight }) => {\n\t\tconst audit = latestCheck?.audits?.[key];\n\t\tconst val = Math.floor((audit?.score ?? 0) * 100);\n\t\tconst inverse = 100 - val;\n\t\treturn [\n\t\t\t{\n\t\t\t\tname: `${key.toUpperCase()} Inverse`,\n\t\t\t\tvalue: inverse * weight,\n\t\t\t\tfill: \"transparent\",\n\t\t\t\tstroke: color,\n\t\t\t\tweight,\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: key.toUpperCase(),\n\t\t\t\tvalue: val * weight,\n\t\t\t\tfill: color,\n\t\t\t\tstroke: color,\n\t\t\t\tweight,\n\t\t\t},\n\t\t];\n\t});\n\n\tconst totalScore =\n\t\t(latestCheck.audits?.fcp?.score || 0) * 0.1 +\n\t\t(latestCheck.audits?.si?.score || 0) * 0.1 +\n\t\t(latestCheck.audits?.lcp?.score || 0) * 0.25 +\n\t\t(latestCheck.audits?.tbt?.score || 0) * 0.3 +\n\t\t(latestCheck.audits?.cls?.score || 0) * 0.25;\n\tconst pageSpeedPalette = getPageSpeedPalette(Math.floor(totalScore * 100));\n\n\tconst score = [\n\t\t{\n\t\t\tvalue: 100,\n\t\t\tfill: alpha(theme.palette[pageSpeedPalette].light || \"#ffffff\", 0.6),\n\t\t\tstroke: \"none\",\n\t\t},\n\t];\n\n\treturn (\n\t\t<BaseChart\n\t\t\ticon={\n\t\t\t\t<FileText\n\t\t\t\t\tsize={20}\n\t\t\t\t\tstrokeWidth={1.5}\n\t\t\t\t/>\n\t\t\t}\n\t\t\ttitle={t(\"pages.pageSpeed.charts.pie.title\")}\n\t\t>\n\t\t\t<Tooltip\n\t\t\t\topen={Boolean(hoverTitle)}\n\t\t\t\ttitle={hoverTitle || \"\"}\n\t\t\t\tarrow\n\t\t\t\tfollowCursor\n\t\t\t\tplacement=\"top\"\n\t\t\t>\n\t\t\t\t<Box\n\t\t\t\t\tsx={{\n\t\t\t\t\t\t\"& .recharts-wrapper:focus, & .recharts-surface:focus\": {\n\t\t\t\t\t\t\toutline: \"none\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"& .recharts-wrapper *:focus\": { outline: \"none\" },\n\t\t\t\t\t\t\"& svg:focus, & g:focus, & path:focus\": { outline: \"none\" },\n\t\t\t\t\t\tposition: \"relative\",\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t<ResponsiveContainer\n\t\t\t\t\t\twidth=\"100%\"\n\t\t\t\t\t\theight={250}\n\t\t\t\t\t>\n\t\t\t\t\t\t<PieChart>\n\t\t\t\t\t\t\t<Pie\n\t\t\t\t\t\t\t\tdata={score}\n\t\t\t\t\t\t\t\tdataKey=\"value\"\n\t\t\t\t\t\t\t\tcx=\"50%\"\n\t\t\t\t\t\t\t\tcy=\"50%\"\n\t\t\t\t\t\t\t\touterRadius=\"65%\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<Label\n\t\t\t\t\t\t\t\t\tposition={\"center\"}\n\t\t\t\t\t\t\t\t\tcontent={<CenterLabel value={Math.floor(totalScore * 100)} />}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t</Pie>\n\t\t\t\t\t\t\t<Pie\n\t\t\t\t\t\t\t\tdata={scores}\n\t\t\t\t\t\t\t\tinnerRadius=\"70%\"\n\t\t\t\t\t\t\t\touterRadius=\"80%\"\n\t\t\t\t\t\t\t\tlabel={({ name, value }) => `${name}: ${Math.round(value)}`}\n\t\t\t\t\t\t\t\tdataKey=\"value\"\n\t\t\t\t\t\t\t\tstroke=\"none\"\n\t\t\t\t\t\t\t\tonMouseEnter={(_, index: number) => {\n\t\t\t\t\t\t\t\t\tconst d = scores[index];\n\t\t\t\t\t\t\t\t\tif (!d) return;\n\t\t\t\t\t\t\t\t\tconst isInverse = String(d.name).includes(\"Inverse\");\n\t\t\t\t\t\t\t\t\tconst pair = isInverse && scores[index + 1] ? scores[index + 1] : d;\n\t\t\t\t\t\t\t\t\tconst base = String(pair.name).replace(\" Inverse\", \"\");\n\t\t\t\t\t\t\t\t\tconst full = LABELS[base] ?? base;\n\t\t\t\t\t\t\t\t\tconst displayVal = Math.round(Number(pair.value) || 0);\n\t\t\t\t\t\t\t\t\tsetHoverTitle(`${full}: ${displayVal}`);\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\tonMouseLeave={() => setHoverTitle(null)}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</PieChart>\n\t\t\t\t\t</ResponsiveContainer>\n\t\t\t\t</Box>\n\t\t\t</Tooltip>\n\t\t</BaseChart>\n\t);\n};\n"
  },
  {
    "path": "client/src/Components/monitors/charts/PiePageSpeedLegend.tsx",
    "content": "import Stack from \"@mui/material/Stack\";\nimport Box from \"@mui/material/Box\";\nimport { BarChart3 } from \"lucide-react\";\nimport { BaseChart } from \"@/Components/design-elements\";\nimport Typography from \"@mui/material/Typography\";\n\nimport type { CheckSnapshot } from \"@/Types/Check\";\nimport { useTranslation } from \"react-i18next\";\nimport { getPageSpeedPalette } from \"@/Utils/MonitorUtils\";\nimport { useTheme } from \"@mui/material/styles\";\n\nconst MetricBox = ({\n\tlabel,\n\tvalue,\n\tweight,\n}: {\n\tlabel: string;\n\tvalue: number;\n\tweight: number;\n}) => {\n\tconst { t } = useTranslation();\n\tconst theme = useTheme();\n\tconst palette = getPageSpeedPalette(value);\n\treturn (\n\t\t<Stack\n\t\t\tdirection={\"row\"}\n\t\t\tsx={{\n\t\t\t\tborder: 1,\n\t\t\t\tborderStyle: \"solid\",\n\t\t\t\tborderColor: theme.palette.divider,\n\t\t\t\tborderRadius: theme.shape.borderRadius,\n\t\t\t}}\n\t\t>\n\t\t\t<Stack\n\t\t\t\tflex={1}\n\t\t\t\tp={theme.spacing(4)}\n\t\t\t>\n\t\t\t\t<Typography textTransform={\"uppercase\"}>{label}</Typography>\n\t\t\t\t<Stack\n\t\t\t\t\tdirection=\"row\"\n\t\t\t\t\tjustifyContent={\"space-between\"}\n\t\t\t\t>\n\t\t\t\t\t<Typography>{`${value}%`}</Typography>\n\t\t\t\t\t<Typography>{`${t(\"pages.pageSpeed.charts.legend.weight\")}: ${weight}%`}</Typography>\n\t\t\t\t</Stack>\n\t\t\t</Stack>\n\t\t\t<Box\n\t\t\t\twidth={4}\n\t\t\t\tbgcolor={theme.palette[palette].light}\n\t\t\t\tsx={{\n\t\t\t\t\tborderTopRightRadius: theme.shape.borderRadius,\n\t\t\t\t\tborderBottomRightRadius: theme.shape.borderRadius,\n\t\t\t\t}}\n\t\t\t/>\n\t\t</Stack>\n\t);\n};\n\nexport const PiePageSpeedLegend = ({ latestCheck }: { latestCheck?: CheckSnapshot }) => {\n\tconst theme = useTheme();\n\tconst { t } = useTranslation();\n\n\tif (!latestCheck) {\n\t\treturn null;\n\t}\n\treturn (\n\t\t<BaseChart\n\t\t\ticon={\n\t\t\t\t<BarChart3\n\t\t\t\t\tsize={20}\n\t\t\t\t\tstrokeWidth={1.5}\n\t\t\t\t/>\n\t\t\t}\n\t\t\ttitle={t(\"pages.pageSpeed.charts.legend.title\")}\n\t\t>\n\t\t\t<Stack gap={theme.spacing(4)}>\n\t\t\t\t<MetricBox\n\t\t\t\t\tlabel={t(\"pages.pageSpeed.charts.common.si\")}\n\t\t\t\t\tvalue={Math.floor((latestCheck.audits?.si?.score || 0) * 100)}\n\t\t\t\t\tweight={10}\n\t\t\t\t/>\n\t\t\t\t<MetricBox\n\t\t\t\t\tlabel={t(\"pages.pageSpeed.charts.common.fcp\")}\n\t\t\t\t\tvalue={Math.floor((latestCheck.audits?.fcp?.score || 0) * 100)}\n\t\t\t\t\tweight={10}\n\t\t\t\t/>\n\t\t\t\t<MetricBox\n\t\t\t\t\tlabel={t(\"pages.pageSpeed.charts.common.cls\")}\n\t\t\t\t\tvalue={Math.floor((latestCheck.audits?.cls?.score || 0) * 100)}\n\t\t\t\t\tweight={25}\n\t\t\t\t/>\n\t\t\t\t<MetricBox\n\t\t\t\t\tlabel={t(\"pages.pageSpeed.charts.common.tbt\")}\n\t\t\t\t\tvalue={Math.floor((latestCheck.audits?.tbt?.score || 0) * 100)}\n\t\t\t\t\tweight={30}\n\t\t\t\t/>\n\t\t\t\t<MetricBox\n\t\t\t\t\tlabel={t(\"pages.pageSpeed.charts.common.lcp\")}\n\t\t\t\t\tvalue={Math.floor((latestCheck.audits?.lcp?.score || 0) * 100)}\n\t\t\t\t\tweight={25}\n\t\t\t\t/>\n\t\t\t</Stack>\n\t\t</BaseChart>\n\t);\n};\n"
  },
  {
    "path": "client/src/Components/monitors/charts/RadialAvgResponse.tsx",
    "content": "import { BaseChart } from \"@/Components/design-elements\";\nimport Stack from \"@mui/material/Stack\";\nimport Typography from \"@mui/material/Typography\";\nimport { Gauge } from \"lucide-react\";\nimport { Cell, RadialBarChart, RadialBar, ResponsiveContainer } from \"recharts\";\n\nimport { useTranslation } from \"react-i18next\";\nimport { getResponseTimeColor } from \"@/Utils/MonitorUtils\";\nimport { useTheme } from \"@mui/material/styles\";\n\nexport const RadialAvgResponse = ({ avg, max }: { avg: number; max: number }) => {\n\tconst { t } = useTranslation();\n\tconst theme = useTheme();\n\tconst chartData = [\n\t\t{ name: \"max\", value: max - avg, color: \"transparent\" },\n\t\t{ name: \"avg\", value: avg, color: \"red\" },\n\t];\n\n\tconst palette = getResponseTimeColor(avg);\n\tconst msg: Record<string, string> = {\n\t\tsuccess: \"Excellent\",\n\t\twarning: \"Average\",\n\t\tdanger: \"Poor\",\n\t};\n\n\treturn (\n\t\t<BaseChart\n\t\t\ticon={\n\t\t\t\t<Gauge\n\t\t\t\t\tsize={20}\n\t\t\t\t\tstrokeWidth={1.5}\n\t\t\t\t/>\n\t\t\t}\n\t\t\ttitle={t(\"common.charts.labels.averageResponseTime\")}\n\t\t>\n\t\t\t<Stack\n\t\t\t\theight=\"100%\"\n\t\t\t\tposition={\"relative\"}\n\t\t\t\tjustifyContent={\"flex-end\"}\n\t\t\t>\n\t\t\t\t<ResponsiveContainer\n\t\t\t\t\twidth=\"100%\"\n\t\t\t\t\theight={155}\n\t\t\t\t>\n\t\t\t\t\t<RadialBarChart\n\t\t\t\t\t\tcy=\"100%\"\n\t\t\t\t\t\tdata={chartData}\n\t\t\t\t\t\tstartAngle={180}\n\t\t\t\t\t\tendAngle={0}\n\t\t\t\t\t\tinnerRadius={\"120%\"}\n\t\t\t\t\t\touterRadius={\"200%\"}\n\t\t\t\t\t>\n\t\t\t\t\t\t<RadialBar\n\t\t\t\t\t\t\tdataKey=\"value\"\n\t\t\t\t\t\t\tbackground={{ fill: theme.palette[palette].light }}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<Cell visibility={\"hidden\"} />\n\t\t\t\t\t\t\t<Cell fill={theme.palette[palette].main} />\n\t\t\t\t\t\t</RadialBar>\n\t\t\t\t\t</RadialBarChart>\n\t\t\t\t</ResponsiveContainer>\n\t\t\t\t<Stack\n\t\t\t\t\tdirection={\"row\"}\n\t\t\t\t\tjustifyContent={\"space-between\"}\n\t\t\t\t>\n\t\t\t\t\t<Typography variant=\"body2\">{t(\"common.charts.labels.low\")}</Typography>\n\t\t\t\t\t<Typography variant=\"body2\">{t(\"common.charts.labels.high\")}</Typography>\n\t\t\t\t</Stack>\n\t\t\t\t<Stack\n\t\t\t\t\tposition=\"absolute\"\n\t\t\t\t\ttop={\"50%\"}\n\t\t\t\t\tright={\"50%\"}\n\t\t\t\t\tsx={{\n\t\t\t\t\t\ttransform: \"translate(50%, 0%)\",\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t<Typography\n\t\t\t\t\t\tvariant=\"h6\"\n\t\t\t\t\t\ttextAlign={\"center\"}\n\t\t\t\t\t>\n\t\t\t\t\t\t{msg[palette]}\n\t\t\t\t\t</Typography>\n\t\t\t\t\t<Typography\n\t\t\t\t\t\tvariant=\"h6\"\n\t\t\t\t\t\ttextAlign={\"center\"}\n\t\t\t\t\t>{`${avg?.toFixed()}ms`}</Typography>\n\t\t\t\t</Stack>\n\t\t\t</Stack>\n\t\t</BaseChart>\n\t);\n};\n"
  },
  {
    "path": "client/src/Components/monitors/index.tsx",
    "content": "export * from \"./ControlsFilter\";\nexport * from \"./MonitorStatBoxes\";\nexport * from \"./HeaderMonitorControls\";\nexport * from \"./HeaderGeoTabs\";\nexport * from \"./GeoChecksMap\";\nexport * from \"./charts/HistogramStatus\";\nexport * from \"./charts/RadialAvgResponse\";\nexport * from \"./charts/HistogramDetails\";\nexport * from \"./charts/HistogramPageSpeed\";\nexport * from \"./charts/HistogramPageSpeedTooltip\";\nexport * from \"./charts/PiePageSpeed\";\nexport * from \"./charts/PiePageSpeedLegend\";\nexport * from \"./charts/HistogramPageSpeedDetails\";\nexport * from \"./charts/HistogramPageSpeedDetailsTooltip\";\nexport * from \"./charts/HistogramInfrastructure\";\nexport * from \"./HeaderMonitorsSummary\";\n"
  },
  {
    "path": "client/src/Components/routing/RouteProtected.tsx",
    "content": "import { Navigate } from \"react-router-dom\";\nimport { useSelector } from \"react-redux\";\nimport type { RootState } from \"@/Types/state\";\nimport type { UserRole } from \"@/Types/User\";\n\ninterface ProtectedRouteProps {\n\tchildren: React.ReactNode;\n}\n\nexport const ProtectedRoute = ({ children }: ProtectedRouteProps) => {\n\tconst authState = useSelector((state: RootState) => state.auth);\n\n\treturn authState.authToken ? (\n\t\tchildren\n\t) : (\n\t\t<Navigate\n\t\t\tto=\"/login\"\n\t\t\treplace\n\t\t/>\n\t);\n};\n\ninterface RoleProtectedRouteProps {\n\troles: UserRole[];\n\tchildren: React.ReactNode;\n}\n\nexport const RoleProtectedRoute = ({ roles, children }: RoleProtectedRouteProps) => {\n\tconst authState = useSelector((state: RootState) => state.auth);\n\tconst userRoles = authState?.user?.role || [];\n\tconst canAccess = userRoles.some((role) => roles.includes(role));\n\n\treturn canAccess ? (\n\t\tchildren\n\t) : (\n\t\t<Navigate\n\t\t\tto=\"/uptime\"\n\t\t\treplace\n\t\t/>\n\t);\n};\n"
  },
  {
    "path": "client/src/Components/sidebar/Authfooter.tsx",
    "content": "import Stack from \"@mui/material/Stack\";\nimport Box from \"@mui/material/Box\";\nimport Typography from \"@mui/material/Typography\";\nimport IconButton from \"@mui/material/IconButton\";\nimport Menu from \"@mui/material/Menu\";\nimport MenuItem from \"@mui/material/MenuItem\";\nimport { useTheme } from \"@mui/material\";\nimport { SPACING, LAYOUT } from \"@/Utils/Theme/constants\";\nimport { useSelector, useDispatch } from \"react-redux\";\nimport { useTranslation } from \"react-i18next\";\nimport { useState } from \"react\";\nimport { useNavigate } from \"react-router\";\nimport { MoreVertical, LogOut } from \"lucide-react\";\nimport { Avatar, Icon } from \"@/Components/design-elements\";\nimport { clearAuthState } from \"@/Features/Auth/authSlice.js\";\nimport type { RootState } from \"@/Types/state.js\";\n\ninterface AuthFooterProps {\n\tcollapsed: boolean;\n\taccountMenuItems: Array<{\n\t\tname: string;\n\t\tpath: string;\n\t\ticon: React.ReactNode;\n\t}>;\n}\n\nexport const AuthFooter = ({ collapsed, accountMenuItems }: AuthFooterProps) => {\n\tconst { t } = useTranslation();\n\tconst theme = useTheme();\n\tconst user = useSelector((state: RootState) => state.auth.user);\n\tconst navigate = useNavigate();\n\tconst dispatch = useDispatch();\n\tconst [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);\n\n\tconst menuOpen = Boolean(anchorEl);\n\tconst handleMenuOpen = (e: React.MouseEvent<HTMLElement>) =>\n\t\tsetAnchorEl(e.currentTarget);\n\tconst handleMenuClose = () => setAnchorEl(null);\n\n\tconst handleNavigate = (path: string) => {\n\t\thandleMenuClose();\n\t\tnavigate(path);\n\t};\n\n\tconst handleLogout = () => {\n\t\tdispatch(clearAuthState());\n\t\tnavigate(\"/login\");\n\t};\n\n\tconst getRoleText = () => {\n\t\tconst role = user?.role ?? \"\";\n\t\tif (role.includes(\"superadmin\"))\n\t\t\treturn t(\"components.sidebar.authFooter.roles.superAdmin\");\n\t\tif (role.includes(\"admin\")) return t(\"components.sidebar.authFooter.roles.admin\");\n\t\tif (role.includes(\"user\")) return t(\"components.sidebar.authFooter.roles.user\");\n\t\tif (role.includes(\"demo\")) return t(\"components.sidebar.authFooter.roles.demoUser\");\n\t\treturn role;\n\t};\n\n\tconst filteredMenuItems = accountMenuItems.filter((item) => {\n\t\tif (!user) return false;\n\t\tif (item.name === \"Password\" && user.role?.includes(\"demo\")) return false;\n\t\tif (item.name === \"Team\" && !user.role?.includes(\"superadmin\")) return false;\n\t\treturn true;\n\t});\n\n\tconst menuItemSx = {\n\t\tgap: theme.spacing(LAYOUT.MD),\n\t\tborderRadius: theme.shape.borderRadius,\n\t\tpl: theme.spacing(LAYOUT.XS),\n\t\t\"& svg\": { stroke: theme.palette.text.secondary },\n\t};\n\n\treturn (\n\t\t<Stack\n\t\t\tdirection=\"row\"\n\t\t\talignItems=\"center\"\n\t\t\tpy={theme.spacing(LAYOUT.XS)}\n\t\t\tpx={theme.spacing(LAYOUT.MD)}\n\t\t\tgap={theme.spacing(LAYOUT.MD)}\n\t\t>\n\t\t\t<Avatar\n\t\t\t\tsmall\n\t\t\t\tonClick={collapsed ? handleMenuOpen : undefined}\n\t\t\t\tsx={{ cursor: collapsed ? \"pointer\" : \"default\" }}\n\t\t\t/>\n\n\t\t\t{!collapsed && (\n\t\t\t\t<Stack\n\t\t\t\t\tdirection=\"row\"\n\t\t\t\t\talignItems=\"center\"\n\t\t\t\t\tgap={theme.spacing(SPACING.MD)}\n\t\t\t\t\tminWidth={0}\n\t\t\t\t\tflex={1}\n\t\t\t\t>\n\t\t\t\t\t<Stack\n\t\t\t\t\t\tminWidth={0}\n\t\t\t\t\t\tflex={1}\n\t\t\t\t\t>\n\t\t\t\t\t\t<Typography\n\t\t\t\t\t\t\tfontWeight={500}\n\t\t\t\t\t\t\tnoWrap\n\t\t\t\t\t\t\tsx={{ color: theme.palette.text.primary }}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{user?.firstName} {user?.lastName}\n\t\t\t\t\t\t</Typography>\n\t\t\t\t\t\t<Typography\n\t\t\t\t\t\t\tnoWrap\n\t\t\t\t\t\t\tsx={{ textTransform: \"capitalize\", color: theme.palette.text.secondary }}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{getRoleText()}\n\t\t\t\t\t\t</Typography>\n\t\t\t\t\t</Stack>\n\t\t\t\t\t<IconButton\n\t\t\t\t\t\tonClick={handleMenuOpen}\n\t\t\t\t\t\tsx={{\n\t\t\t\t\t\t\t\"&:focus\": { outline: \"none\" },\n\t\t\t\t\t\t\t\"& svg\": { stroke: theme.palette.text.secondary },\n\t\t\t\t\t\t}}\n\t\t\t\t\t>\n\t\t\t\t\t\t<Icon\n\t\t\t\t\t\t\ticon={MoreVertical}\n\t\t\t\t\t\t\tsize={22}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</IconButton>\n\t\t\t\t</Stack>\n\t\t\t)}\n\n\t\t\t<Menu\n\t\t\t\tanchorEl={anchorEl}\n\t\t\t\topen={menuOpen}\n\t\t\t\tonClose={handleMenuClose}\n\t\t\t\tdisableScrollLock\n\t\t\t\tanchorOrigin={{ vertical: \"top\", horizontal: \"right\" }}\n\t\t\t\tslotProps={{\n\t\t\t\t\tpaper: {\n\t\t\t\t\t\tsx: {\n\t\t\t\t\t\t\tmt: theme.spacing(-LAYOUT.XS),\n\t\t\t\t\t\t\tml: collapsed ? theme.spacing(SPACING.LG) : 0,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t}}\n\t\t\t\tMenuListProps={{ sx: { p: 2, \"& li\": { m: 0 } } }}\n\t\t\t\tsx={{ ml: theme.spacing(LAYOUT.XS) }}\n\t\t\t>\n\t\t\t\t{collapsed && (\n\t\t\t\t\t<Box\n\t\t\t\t\t\tpx={2}\n\t\t\t\t\t\tpb={2}\n\t\t\t\t\t\tsx={{ pointerEvents: \"none\" }}\n\t\t\t\t\t>\n\t\t\t\t\t\t<Typography\n\t\t\t\t\t\t\tfontWeight={500}\n\t\t\t\t\t\t\tfontSize={13}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{user?.firstName} {user?.lastName}\n\t\t\t\t\t\t</Typography>\n\t\t\t\t\t\t<Typography\n\t\t\t\t\t\t\tfontSize={12}\n\t\t\t\t\t\t\tsx={{ textTransform: \"capitalize\" }}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{getRoleText()}\n\t\t\t\t\t\t</Typography>\n\t\t\t\t\t</Box>\n\t\t\t\t)}\n\t\t\t\t{filteredMenuItems.map((item) => (\n\t\t\t\t\t<MenuItem\n\t\t\t\t\t\tkey={item.name}\n\t\t\t\t\t\tonClick={() => handleNavigate(item.path)}\n\t\t\t\t\t\tsx={menuItemSx}\n\t\t\t\t\t>\n\t\t\t\t\t\t{item.icon}\n\t\t\t\t\t\t{item.name}\n\t\t\t\t\t</MenuItem>\n\t\t\t\t))}\n\t\t\t\t<MenuItem\n\t\t\t\t\tonClick={handleLogout}\n\t\t\t\t\tsx={menuItemSx}\n\t\t\t\t>\n\t\t\t\t\t<Icon\n\t\t\t\t\t\ticon={LogOut}\n\t\t\t\t\t\tsize={20}\n\t\t\t\t\t/>\n\t\t\t\t\t{t(\"components.sidebar.authFooter.logOut\")}\n\t\t\t\t</MenuItem>\n\t\t\t</Menu>\n\t\t</Stack>\n\t);\n};\n"
  },
  {
    "path": "client/src/Components/sidebar/Logo.tsx",
    "content": "import Stack, { type StackProps } from \"@mui/material/Stack\";\nimport Box from \"@mui/material/Box\";\nimport Typography from \"@mui/material/Typography\";\nimport { useTheme } from \"@mui/material/styles\";\nimport { toggleSidebar } from \"@/Features/UI/uiSlice.js\";\nimport { useDispatch } from \"react-redux\";\nimport { useTranslation } from \"react-i18next\";\nimport useSidebar from \"@/Hooks/useSidebar\";\n\nexport const Logo = (props: StackProps) => {\n\tconst { t } = useTranslation();\n\tconst theme = useTheme();\n\tconst dispatch = useDispatch();\n\tconst { collapsed } = useSidebar();\n\treturn (\n\t\t<Stack\n\t\t\tdirection=\"row\"\n\t\t\talignItems=\"center\"\n\t\t\tgap={theme.spacing(4)}\n\t\t\tonClick={() => {\n\t\t\t\tdispatch(toggleSidebar());\n\t\t\t}}\n\t\t\tsx={{ cursor: \"pointer\" }}\n\t\t\t{...props}\n\t\t>\n\t\t\t<Typography\n\t\t\t\tminWidth={theme.spacing(16)}\n\t\t\t\tminHeight={theme.spacing(16)}\n\t\t\t\tdisplay={\"flex\"}\n\t\t\t\tjustifyContent={\"center\"}\n\t\t\t\talignItems={\"center\"}\n\t\t\t\tbgcolor={theme.palette.primary.main}\n\t\t\t\tborderRadius={theme.shape.borderRadius}\n\t\t\t\tcolor={theme.palette.primary.contrastText}\n\t\t\t\tfontSize={18}\n\t\t\t>\n\t\t\t\tC\n\t\t\t</Typography>\n\t\t\t<Box\n\t\t\t\toverflow={\"hidden\"}\n\t\t\t\tsx={{\n\t\t\t\t\ttransition: \"opacity 900ms ease, width 900ms ease\",\n\t\t\t\t\topacity: collapsed ? 0 : 1,\n\t\t\t\t\twhiteSpace: \"nowrap\",\n\t\t\t\t\twidth: collapsed ? 0 : \"100%\",\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t{\" \"}\n\t\t\t\t<Typography\n\t\t\t\t\tlineHeight={1}\n\t\t\t\t\tmt={theme.spacing(2)}\n\t\t\t\t\tvariant=\"h2\"\n\t\t\t\t\tfontWeight={500}\n\t\t\t\t>\n\t\t\t\t\t{t(\"common.appName\")}\n\t\t\t\t</Typography>\n\t\t\t</Box>\n\t\t</Stack>\n\t);\n};\n"
  },
  {
    "path": "client/src/Components/sidebar/Menu.tsx",
    "content": "import { Icon } from \"@/Components/design-elements\";\n\nimport {\n\tGlobe,\n\tGauge,\n\tLink,\n\tBell,\n\tFileText,\n\tAlertTriangle,\n\tWifi,\n\tWrench,\n\tDatabase,\n\tSettings,\n\tHelpCircle,\n\tMessageCircle,\n\tCode,\n\tUser,\n\tLock,\n\tUsers,\n} from \"lucide-react\";\n\nexport const getMenu = (t: Function) => {\n\treturn [\n\t\t{\n\t\t\tname: t(\"components.sidebar.menu.uptime\"),\n\t\t\tpath: \"uptime\",\n\t\t\ticon: <Icon icon={Globe} />,\n\t\t},\n\t\t{\n\t\t\tname: t(\"components.sidebar.menu.pagespeed\"),\n\t\t\tpath: \"pagespeed\",\n\t\t\ticon: <Icon icon={Gauge} />,\n\t\t},\n\t\t{\n\t\t\tname: t(\"components.sidebar.menu.infrastructure\"),\n\t\t\tpath: \"infrastructure\",\n\t\t\ticon: <Icon icon={Link} />,\n\t\t},\n\t\t{\n\t\t\tname: t(\"components.sidebar.menu.notifications\"),\n\t\t\tpath: \"notifications\",\n\t\t\ticon: <Icon icon={Bell} />,\n\t\t},\n\t\t{\n\t\t\tname: t(\"components.sidebar.menu.checks\"),\n\t\t\tpath: \"checks\",\n\t\t\ticon: <Icon icon={FileText} />,\n\t\t},\n\t\t{\n\t\t\tname: t(\"components.sidebar.menu.incidents\"),\n\t\t\tpath: \"incidents\",\n\t\t\ticon: <Icon icon={AlertTriangle} />,\n\t\t},\n\t\t{\n\t\t\tname: t(\"components.sidebar.menu.statusPages\"),\n\t\t\tpath: \"status\",\n\t\t\ticon: <Icon icon={Wifi} />,\n\t\t},\n\t\t{\n\t\t\tname: t(\"components.sidebar.menu.maintenance\"),\n\t\t\tpath: \"maintenance\",\n\t\t\ticon: <Icon icon={Wrench} />,\n\t\t},\n\t\t{\n\t\t\tname: t(\"components.sidebar.menu.logs\"),\n\t\t\tpath: \"logs\",\n\t\t\ticon: <Icon icon={Database} />,\n\t\t},\n\t\t{\n\t\t\tname: t(\"components.sidebar.menu.settings\"),\n\t\t\ticon: <Icon icon={Settings} />,\n\t\t\tpath: \"settings\",\n\t\t},\n\t];\n};\n\nexport const getBottomMenu = (t: Function) => {\n\treturn [\n\t\t{\n\t\t\tname: t(\"components.sidebar.bottomMenu.support\"),\n\t\t\tpath: \"support\",\n\t\t\ticon: <Icon icon={HelpCircle} />,\n\t\t},\n\t\t{\n\t\t\tname: t(\"components.sidebar.bottomMenu.discussions\"),\n\t\t\tpath: \"discussions\",\n\t\t\ticon: <Icon icon={MessageCircle} />,\n\t\t},\n\t\t{\n\t\t\tname: t(\"components.sidebar.bottomMenu.docs\"),\n\t\t\tpath: \"docs\",\n\t\t\ticon: <Icon icon={FileText} />,\n\t\t},\n\t\t{\n\t\t\tname: t(\"components.sidebar.bottomMenu.changelog\"),\n\t\t\tpath: \"changelog\",\n\t\t\ticon: <Icon icon={Code} />,\n\t\t},\n\t];\n};\n\nexport const getAccountMenu = (t: Function) => {\n\treturn [\n\t\t{\n\t\t\tname: t(\"components.sidebar.accountMenu.profile\"),\n\t\t\tpath: \"account/profile\",\n\t\t\ticon: <Icon icon={User} />,\n\t\t},\n\t\t{\n\t\t\tname: t(\"components.sidebar.accountMenu.password\"),\n\t\t\tpath: \"account/password\",\n\t\t\ticon: <Icon icon={Lock} />,\n\t\t},\n\t\t{\n\t\t\tname: t(\"components.sidebar.accountMenu.team\"),\n\t\t\tpath: \"account/team\",\n\t\t\ticon: <Icon icon={Users} />,\n\t\t},\n\t];\n};\n"
  },
  {
    "path": "client/src/Components/sidebar/NavItem.tsx",
    "content": "import Tooltip from \"@mui/material/Tooltip\";\nimport ListItemButton from \"@mui/material/ListItemButton\";\nimport ListItemIcon from \"@mui/material/ListItemIcon\";\nimport Box from \"@mui/material/Box\";\nimport Typography from \"@mui/material/Typography\";\nimport { useTheme } from \"@mui/material/styles\";\nimport useSidebar from \"@/Hooks/useSidebar\";\n\nexport interface NavData {\n\tname: string;\n\ticon: React.ReactElement;\n}\n\nexport const NavItem = ({\n\titem,\n\tselected,\n\tonClick,\n}: {\n\titem: NavData;\n\tselected: boolean;\n\tonClick: (event: React.MouseEvent) => void;\n}) => {\n\tconst { collapsed } = useSidebar();\n\tconst theme = useTheme();\n\tconst iconStroke = selected ? theme.palette.primary.main : theme.palette.text.secondary;\n\n\tconst buttonBgColor = selected ? theme.palette.action.selected : \"transparent\";\n\tconst buttonBgHoverColor = selected\n\t\t? theme.palette.action.selected\n\t\t: theme.palette.action.hover;\n\tconst fontWeight = selected ? 600 : 400;\n\treturn (\n\t\t<Tooltip\n\t\t\tplacement=\"right\"\n\t\t\ttitle={collapsed ? item.name : \"\"}\n\t\t\tslotProps={{\n\t\t\t\tpopper: {\n\t\t\t\t\tmodifiers: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tname: \"offset\",\n\t\t\t\t\t\t\toptions: {\n\t\t\t\t\t\t\t\toffset: [0, -16],\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t},\n\t\t\t}}\n\t\t\tdisableInteractive\n\t\t>\n\t\t\t<ListItemButton\n\t\t\t\tsx={{\n\t\t\t\t\tbackgroundColor: buttonBgColor,\n\t\t\t\t\tbackgroundImage: \"none\",\n\t\t\t\t\tborder: 1,\n\t\t\t\t\tborderColor: \"transparent\",\n\t\t\t\t\t\"&:hover\": {\n\t\t\t\t\t\tbackgroundColor: buttonBgHoverColor,\n\t\t\t\t\t\tbackgroundImage: \"none\",\n\t\t\t\t\t},\n\t\t\t\t\theight: 32,\n\t\t\t\t\tgap: theme.spacing(4),\n\t\t\t\t\tborderRadius: theme.shape.borderRadius,\n\t\t\t\t\tpx: theme.spacing(4),\n\t\t\t\t\tpl: theme.spacing(5),\n\t\t\t\t}}\n\t\t\t\tonClick={onClick}\n\t\t\t>\n\t\t\t\t<ListItemIcon\n\t\t\t\t\tsx={{\n\t\t\t\t\t\tminWidth: 0,\n\t\t\t\t\t\t\"& svg\": {\n\t\t\t\t\t\t\theight: 16,\n\t\t\t\t\t\t\twidth: 16,\n\t\t\t\t\t\t\topacity: 0.81,\n\t\t\t\t\t\t\ttransition: \"stroke 0.2s ease\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"& svg path, & svg line, & svg polyline, & svg rect, & svg circle\": {\n\t\t\t\t\t\t\tstroke: iconStroke,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\".MuiListItemButton-root:hover &\": {\n\t\t\t\t\t\t\t\"& svg path, & svg line, & svg polyline, & svg rect, & svg circle\": {\n\t\t\t\t\t\t\t\tstroke: theme.palette.primary.main,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t{item.icon}\n\t\t\t\t</ListItemIcon>\n\t\t\t\t<Box\n\t\t\t\t\tsx={{\n\t\t\t\t\t\toverflow: \"hidden\",\n\t\t\t\t\t\ttransition: \"opacity 900ms ease\",\n\t\t\t\t\t\topacity: collapsed ? 0 : 1,\n\t\t\t\t\t\twhiteSpace: \"nowrap\",\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t<Typography\n\t\t\t\t\t\tvariant=\"body1\"\n\t\t\t\t\t\tsx={{\n\t\t\t\t\t\t\tfontWeight: fontWeight,\n\t\t\t\t\t\t\topacity: 0.9,\n\t\t\t\t\t\t}}\n\t\t\t\t\t>\n\t\t\t\t\t\t{item.name}\n\t\t\t\t\t</Typography>\n\t\t\t\t</Box>\n\t\t\t</ListItemButton>\n\t\t</Tooltip>\n\t);\n};\n"
  },
  {
    "path": "client/src/Components/sidebar/StarPrompt.tsx",
    "content": "import { Typography, IconButton, Stack, Box } from \"@mui/material\";\nimport { Icon } from \"@/Components/design-elements\";\nimport { X } from \"lucide-react\";\nimport { SPACING, LAYOUT } from \"@/Utils/Theme/constants\";\n\nimport { useTheme } from \"@mui/material\";\nimport { useSelector, useDispatch } from \"react-redux\";\nimport { useTranslation } from \"react-i18next\";\nimport { setStarPromptOpen } from \"@/Features/UI/uiSlice.js\";\nimport type { RootState } from \"@/Types/state.js\";\nimport useSidebar from \"@/Hooks/useSidebar.js\";\n\nexport const StarPrompt = ({\n\trepoUrl = \"https://github.com/bluewave-labs/checkmate\",\n}: {\n\trepoUrl?: string;\n}) => {\n\tconst theme = useTheme();\n\tconst dispatch = useDispatch();\n\tconst { t } = useTranslation();\n\tconst isOpen = useSelector((state: RootState) => state.ui?.starPromptOpen ?? true);\n\tconst mode = useSelector((state: RootState) => state.ui.mode);\n\tconst { collapsed } = useSidebar();\n\tconst handleClose = () => {\n\t\tdispatch(setStarPromptOpen(false));\n\t};\n\n\tconst handleStarClick = () => {\n\t\twindow.open(repoUrl, \"_blank\");\n\t};\n\n\tif (collapsed) return null;\n\tif (!isOpen) return null;\n\n\treturn (\n\t\t<Stack\n\t\t\tdirection=\"column\"\n\t\t\tgap={theme.spacing(LAYOUT.MD)}\n\t\t\tpadding={theme.spacing(LAYOUT.SM)}\n\t\t\twidth={\"100%\"}\n\t\t\tborderTop={`1px solid ${theme.palette.divider}`}\n\t\t\tborderBottom={`1px solid ${theme.palette.divider}`}\n\t\t>\n\t\t\t<Stack\n\t\t\t\tdirection=\"row\"\n\t\t\t\tjustifyContent=\"space-between\"\n\t\t\t\talignItems=\"center\"\n\t\t\t\twidth=\"100%\"\n\t\t\t\tpl={theme.spacing(LAYOUT.XS)}\n\t\t\t>\n\t\t\t\t<Typography\n\t\t\t\t\tvariant=\"subtitle2\"\n\t\t\t\t\tmt={theme.spacing(SPACING.XXL)}\n\t\t\t\t>\n\t\t\t\t\t{t(\"components.sidebar.starPrompt.title\")}\n\t\t\t\t</Typography>\n\t\t\t\t<IconButton\n\t\t\t\t\tonClick={handleClose}\n\t\t\t\t\tsize=\"small\"\n\t\t\t\t\tsx={{\n\t\t\t\t\t\tcolor: theme.palette.text.primary,\n\t\t\t\t\t\tpadding: 0,\n\t\t\t\t\t\t\"&:hover\": {\n\t\t\t\t\t\t\tbackgroundColor: \"transparent\",\n\t\t\t\t\t\t\topacity: 0.8,\n\t\t\t\t\t\t},\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t<Icon\n\t\t\t\t\t\ticon={X}\n\t\t\t\t\t\tsize={20}\n\t\t\t\t\t/>\n\t\t\t\t</IconButton>\n\t\t\t</Stack>\n\n\t\t\t<Typography\n\t\t\t\tsx={{\n\t\t\t\t\tmb: 1,\n\t\t\t\t\tpx: theme.spacing(LAYOUT.XS),\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t{t(\"components.sidebar.starPrompt.description\")}\n\t\t\t</Typography>\n\n\t\t\t<Box\n\t\t\t\tcomponent=\"img\"\n\t\t\t\tsrc={`https://img.shields.io/github/stars/bluewave-labs/checkmate?label=checkmate&style=social${mode === \"dark\" ? \"&color=white\" : \"\"}`}\n\t\t\t\talt=\"GitHub stars\"\n\t\t\t\tonClick={handleStarClick}\n\t\t\t\tsx={{\n\t\t\t\t\tcursor: \"pointer\",\n\t\t\t\t\ttransform: \"scale(0.65)\",\n\t\t\t\t\ttransformOrigin: \"left center\",\n\t\t\t\t\t\"&:hover\": {\n\t\t\t\t\t\topacity: 0.8,\n\t\t\t\t\t},\n\t\t\t\t\tpl: theme.spacing(LAYOUT.XS),\n\t\t\t\t\tfilter: mode === \"dark\" ? \"invert(1)\" : \"none\",\n\t\t\t\t}}\n\t\t\t/>\n\t\t</Stack>\n\t);\n};\n"
  },
  {
    "path": "client/src/Components/sidebar/index.tsx",
    "content": "import { useEffect } from \"react\";\nimport Backdrop from \"@mui/material/Backdrop\";\nimport Stack from \"@mui/material/Stack\";\nimport List from \"@mui/material/List\";\nimport Divider from \"@mui/material/Divider\";\nimport { LAYOUT } from \"@/Utils/Theme/constants\";\nimport { useSidebar } from \"@/Hooks/useSidebar.js\";\nimport { Logo } from \"@/Components/sidebar/Logo\";\nimport { getMenu, getBottomMenu, getAccountMenu } from \"@/Components/sidebar/Menu\";\nimport { NavItem } from \"@/Components/sidebar/NavItem\";\nimport { StarPrompt } from \"@/Components/sidebar/StarPrompt\";\nimport { AuthFooter } from \"@/Components/sidebar/Authfooter\";\n\nimport { useNavigate, useLocation } from \"react-router\";\nimport { useTranslation } from \"react-i18next\";\nimport { useTheme, useMediaQuery } from \"@mui/material\";\nimport { useDispatch } from \"react-redux\";\nimport { setCollapsed } from \"@/Features/UI/uiSlice\";\n\nconst URL_MAP: Record<string, string> = {\n\tsupport: \"https://discord.com/invite/NAb6H3UTjK\",\n\tdiscussions: \"https://github.com/bluewave-labs/checkmate/discussions\",\n\tdocs: \"https://bluewavelabs.gitbook.io/checkmate\",\n\tchangelog: \"https://github.com/bluewave-labs/checkmate/releases\",\n};\n\nexport const Sidebar = () => {\n\tconst dispatch = useDispatch();\n\tconst navigate = useNavigate();\n\tconst location = useLocation();\n\tconst { t } = useTranslation();\n\tconst { width, transition, collapsed } = useSidebar();\n\tconst theme = useTheme();\n\tconst isSmall = useMediaQuery(theme.breakpoints.down(\"md\"));\n\tconst menu = getMenu(t);\n\tconst bottomMenu = getBottomMenu(t);\n\tconst accountMenu = getAccountMenu(t);\n\n\tuseEffect(() => {\n\t\tdispatch(setCollapsed({ collapsed: isSmall }));\n\t}, [isSmall, dispatch]);\n\n\tconst handleNavClick = (path: string) => {\n\t\tconst url = URL_MAP[path];\n\t\tif (url) {\n\t\t\twindow.open(url, \"_blank\", \"noreferrer\");\n\t\t} else {\n\t\t\tnavigate(`/${path}`);\n\t\t}\n\t\tif (isSmall) {\n\t\t\tdispatch(setCollapsed({ collapsed: true }));\n\t\t}\n\t};\n\n\treturn (\n\t\t<>\n\t\t\t<Backdrop\n\t\t\t\topen={!collapsed && isSmall}\n\t\t\t\tonClick={() => dispatch(setCollapsed({ collapsed: true }))}\n\t\t\t\tsx={{ zIndex: 999 }}\n\t\t\t/>\n\t\t\t<Stack\n\t\t\t\tcomponent=\"aside\"\n\t\t\t\tposition={isSmall ? \"fixed\" : \"sticky\"}\n\t\t\t\ttop={0}\n\t\t\t\tleft={0}\n\t\t\t\tminHeight={\"100vh\"}\n\t\t\t\tmaxHeight={\"100vh\"}\n\t\t\t\tpaddingTop={theme.spacing(LAYOUT.SM)}\n\t\t\t\tpaddingBottom={theme.spacing(LAYOUT.SM)}\n\t\t\t\tgap={theme.spacing(LAYOUT.SM)}\n\t\t\t\tborderRight={`1px solid ${theme.palette.divider}`}\n\t\t\t\twidth={width}\n\t\t\t\tsx={{\n\t\t\t\t\ttouchAction: \"none\",\n\t\t\t\t\ttransition: transition,\n\t\t\t\t\tzIndex: 1000,\n\t\t\t\t\tbackdropFilter: \"blur(8px)\",\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t<List\n\t\t\t\t\tcomponent=\"nav\"\n\t\t\t\t\tdisablePadding\n\t\t\t\t\tsx={{\n\t\t\t\t\t\tpx: theme.spacing(LAYOUT.SM),\n\t\t\t\t\t\tflex: 1,\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t<Logo\n\t\t\t\t\t\tpt={theme.spacing(LAYOUT.MD)}\n\t\t\t\t\t\tpb={theme.spacing(LAYOUT.MD)}\n\t\t\t\t\t/>\n\t\t\t\t\t{menu.map((item) => {\n\t\t\t\t\t\tconst selected = location.pathname.startsWith(`/${item.path}`);\n\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t<NavItem\n\t\t\t\t\t\t\t\tkey={item.path}\n\t\t\t\t\t\t\t\titem={item}\n\t\t\t\t\t\t\t\tselected={selected}\n\t\t\t\t\t\t\t\tonClick={() => handleNavClick(item.path)}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t);\n\t\t\t\t\t})}\n\t\t\t\t</List>\n\t\t\t\t<StarPrompt />\n\t\t\t\t<List\n\t\t\t\t\tcomponent=\"nav\"\n\t\t\t\t\tdisablePadding\n\t\t\t\t\tsx={{ px: theme.spacing(LAYOUT.SM) }}\n\t\t\t\t>\n\t\t\t\t\t{bottomMenu.map((item) => {\n\t\t\t\t\t\tconst selected = location.pathname.startsWith(`/${item.path}`);\n\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t<NavItem\n\t\t\t\t\t\t\t\tkey={item.path}\n\t\t\t\t\t\t\t\titem={item}\n\t\t\t\t\t\t\t\tselected={selected}\n\t\t\t\t\t\t\t\tonClick={() => handleNavClick(item.path)}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t);\n\t\t\t\t\t})}\n\t\t\t\t</List>\n\t\t\t\t<Divider sx={{ borderColor: theme.palette.divider }} />\n\n\t\t\t\t<AuthFooter\n\t\t\t\t\tcollapsed={collapsed}\n\t\t\t\t\taccountMenuItems={accountMenu}\n\t\t\t\t/>\n\t\t\t</Stack>\n\t\t</>\n\t);\n};\n"
  },
  {
    "path": "client/src/Features/Auth/authSlice.ts",
    "content": "import { createSlice, type PayloadAction } from \"@reduxjs/toolkit\";\nimport type { User } from \"@/Types/User\";\n\ninterface AuthState {\n\tisLoading: boolean;\n\tauthToken: string;\n\tuser: User | null;\n\tsuccess: boolean | null;\n\tmsg: string | null;\n}\n\nconst initialState: AuthState = {\n\tisLoading: false,\n\tauthToken: \"\",\n\tuser: null,\n\tsuccess: null,\n\tmsg: null,\n};\n\nconst authSlice = createSlice({\n\tname: \"auth\",\n\tinitialState,\n\treducers: {\n\t\tclearAuthState: (state) => {\n\t\t\tstate.authToken = \"\";\n\t\t\tstate.user = null;\n\t\t\tstate.isLoading = false;\n\t\t\tstate.success = true;\n\t\t\tstate.msg = \"Logged out successfully\";\n\t\t},\n\t\tsetAuthState: (\n\t\t\tstate,\n\t\t\taction: PayloadAction<{\n\t\t\t\tsuccess: boolean;\n\t\t\t\tmsg: string;\n\t\t\t\tdata: { token: string; user: User };\n\t\t\t}>\n\t\t) => {\n\t\t\tstate.isLoading = false;\n\t\t\tstate.success = action.payload.success;\n\t\t\tstate.msg = action.payload.msg;\n\t\t\tstate.authToken = action.payload.data.token;\n\t\t\tstate.user = action.payload.data.user;\n\t\t},\n\t\tsetUser: (state, action: PayloadAction<User>) => {\n\t\t\tstate.user = action.payload;\n\t\t},\n\t},\n});\n\nexport type { AuthState };\nexport default authSlice.reducer;\nexport const { clearAuthState, setAuthState, setUser } = authSlice.actions;\n"
  },
  {
    "path": "client/src/Features/UI/uiSlice.ts",
    "content": "import { createSlice, type PayloadAction } from \"@reduxjs/toolkit\";\n\ntype ThemeMode = \"light\" | \"dark\";\ntype ChartType = \"histogram\" | \"line\";\ntype TableName = \"monitors\" | \"team\" | \"maintenance\" | \"infrastructure\" | \"logs\";\n\ninterface TableState {\n\trowsPerPage: number;\n}\n\ninterface SidebarState {\n\tcollapsed: boolean;\n}\n\ninterface UIState {\n\tmonitors: TableState;\n\tteam: TableState;\n\tmaintenance: TableState;\n\tinfrastructure: TableState;\n\tlogs: TableState;\n\tsidebar: SidebarState;\n\tmode: ThemeMode;\n\tshowURL: boolean;\n\ttimezone: string;\n\tdistributedUptimeEnabled: boolean;\n\tlanguage: string;\n\tstarPromptOpen: boolean;\n\tchartType: ChartType;\n}\n\nconst initialMode: ThemeMode = window?.matchMedia?.(\"(prefers-color-scheme: dark)\")\n\t?.matches\n\t? \"dark\"\n\t: \"light\";\n\nconst initialState: UIState = {\n\tmonitors: {\n\t\trowsPerPage: 10,\n\t},\n\tteam: {\n\t\trowsPerPage: 5,\n\t},\n\tmaintenance: {\n\t\trowsPerPage: 5,\n\t},\n\tinfrastructure: {\n\t\trowsPerPage: 5,\n\t},\n\tlogs: {\n\t\trowsPerPage: 15,\n\t},\n\tsidebar: {\n\t\tcollapsed: false,\n\t},\n\tmode: initialMode,\n\tshowURL: false,\n\ttimezone: \"America/Toronto\",\n\tdistributedUptimeEnabled: false,\n\tlanguage: \"en\",\n\tstarPromptOpen: true,\n\tchartType: \"histogram\",\n};\n\nconst uiSlice = createSlice({\n\tname: \"ui\",\n\tinitialState,\n\treducers: {\n\t\tsetDistributedUptimeEnabled: (state, action: PayloadAction<boolean>) => {\n\t\t\tstate.distributedUptimeEnabled = action.payload;\n\t\t},\n\t\tsetRowsPerPage: (\n\t\t\tstate,\n\t\t\taction: PayloadAction<{ table: TableName; value: number }>\n\t\t) => {\n\t\t\tconst { table, value } = action.payload;\n\t\t\tstate[table].rowsPerPage = value;\n\t\t},\n\t\ttoggleSidebar: (state) => {\n\t\t\tstate.sidebar.collapsed = !state.sidebar.collapsed;\n\t\t},\n\t\tsetCollapsed: (state, action: PayloadAction<{ collapsed: boolean }>) => {\n\t\t\tstate.sidebar.collapsed = action.payload.collapsed;\n\t\t},\n\t\tsetMode: (state, action: PayloadAction<ThemeMode>) => {\n\t\t\tstate.mode = action.payload;\n\t\t},\n\t\tsetShowURL: (state, action: PayloadAction<boolean>) => {\n\t\t\tstate.showURL = action.payload;\n\t\t},\n\n\t\tsetTimezone: (state, action: PayloadAction<{ timezone: string }>) => {\n\t\t\tstate.timezone = action.payload.timezone;\n\t\t},\n\t\tsetLanguage: (state, action: PayloadAction<string>) => {\n\t\t\tstate.language = action.payload;\n\t\t},\n\t\tsetStarPromptOpen: (state, action: PayloadAction<boolean>) => {\n\t\t\tstate.starPromptOpen = action.payload;\n\t\t},\n\t\tsetChartType: (state, action: PayloadAction<ChartType>) => {\n\t\t\tstate.chartType = action.payload;\n\t\t},\n\t},\n});\n\nexport type { UIState, ThemeMode, ChartType, TableName };\nexport default uiSlice.reducer;\nexport const {\n\tsetRowsPerPage,\n\ttoggleSidebar,\n\tsetCollapsed,\n\tsetMode,\n\tsetShowURL,\n\tsetTimezone,\n\tsetDistributedUptimeEnabled,\n\tsetLanguage,\n\tsetStarPromptOpen,\n\tsetChartType,\n} = uiSlice.actions;\n"
  },
  {
    "path": "client/src/Hooks/UseApi.ts",
    "content": "import useSWR from \"swr\";\nimport type { SWRConfiguration } from \"swr\";\nimport type { AxiosRequestConfig } from \"axios\";\nimport { get, patch, post, put, deleteOp } from \"@/Utils/ApiClient\";\nimport { useState } from \"react\";\nimport { useToast } from \"@/Hooks/UseToast\";\nimport { logger } from \"@/Utils/logger\";\n\ninterface ApiResponse<T> {\n\tsuccess: boolean;\n\tmsg: string;\n\tdata: T;\n}\n\nconst fetcher = async <T>(url: string, config?: AxiosRequestConfig) => {\n\tconst res = await get<ApiResponse<T>>(url, config);\n\treturn res.data;\n};\n\nexport const useGet = <T>(\n\turl: string | null | undefined,\n\taxiosConfig?: AxiosRequestConfig,\n\tswrConfig?: SWRConfiguration\n) => {\n\tconst { data, error, isLoading, isValidating, mutate } = useSWR<ApiResponse<T>>(\n\t\turl,\n\t\t(url: string) => fetcher<T>(url, axiosConfig),\n\t\tswrConfig\n\t);\n\n\treturn {\n\t\tdata: data?.data ?? null,\n\t\tisLoading,\n\t\tisValidating,\n\t\terror,\n\t\trefetch: mutate,\n\t};\n};\n\nexport const usePost = <B = any, R = any>() => {\n\tconst [loading, setLoading] = useState(false);\n\tconst [error, setError] = useState<string | null>(null);\n\tconst { toastError, toastSuccess } = useToast();\n\n\tconst postFn = async (\n\t\tendpoint: string,\n\t\tbody: B,\n\t\tconfig?: AxiosRequestConfig\n\t): Promise<ApiResponse<R> | null> => {\n\t\tsetLoading(true);\n\t\tsetError(null);\n\n\t\ttry {\n\t\t\tconst res = await post<ApiResponse<R>>(endpoint, body, {\n\t\t\t\t...config,\n\t\t\t\theaders: {\n\t\t\t\t\t...config?.headers,\n\t\t\t\t},\n\t\t\t});\n\t\t\ttoastSuccess(res.data?.msg || \"Operation successful\");\n\n\t\t\treturn res.data;\n\t\t} catch (err: any) {\n\t\t\tconst errMsg = err?.response?.data?.msg || err.message || \"An error occurred\";\n\t\t\tlogger.error(\"POST request failed\", err, { endpoint, body });\n\t\t\ttoastError(errMsg);\n\t\t\tsetError(errMsg);\n\t\t\treturn null;\n\t\t} finally {\n\t\t\tsetLoading(false);\n\t\t}\n\t};\n\n\treturn { post: postFn, loading, error };\n};\n\nexport const usePatch = <B = any, R = any>() => {\n\tconst [loading, setLoading] = useState(false);\n\tconst [error, setError] = useState<string | null>(null);\n\tconst { toastError, toastSuccess } = useToast();\n\n\tconst patchFn = async (\n\t\tendpoint: string,\n\t\tbody?: B,\n\t\tconfig?: AxiosRequestConfig\n\t): Promise<ApiResponse<R> | null> => {\n\t\tsetLoading(true);\n\t\tsetError(null);\n\n\t\ttry {\n\t\t\tconst res = await patch<ApiResponse<R>>(endpoint, body, {\n\t\t\t\t...config,\n\t\t\t\theaders: {\n\t\t\t\t\t...config?.headers,\n\t\t\t\t},\n\t\t\t});\n\t\t\ttoastSuccess(res.data?.msg || \"Operation successful\");\n\t\t\treturn res.data;\n\t\t} catch (err: any) {\n\t\t\tlogger.error(\"PATCH request failed\", err, { endpoint, body });\n\t\t\tconst errMsg = err?.response?.data?.msg || err.message || \"An error occurred\";\n\t\t\ttoastError(errMsg);\n\t\t\tsetError(errMsg);\n\t\t\treturn null;\n\t\t} finally {\n\t\t\tsetLoading(false);\n\t\t}\n\t};\n\n\treturn { patch: patchFn, loading, error };\n};\n\nexport const usePut = <B = any, R = any>() => {\n\tconst [loading, setLoading] = useState(false);\n\tconst [error, setError] = useState<string | null>(null);\n\tconst { toastError, toastSuccess } = useToast();\n\n\tconst putFn = async (\n\t\tendpoint: string,\n\t\tbody?: B,\n\t\tconfig?: AxiosRequestConfig\n\t): Promise<ApiResponse<R> | null> => {\n\t\tsetLoading(true);\n\t\tsetError(null);\n\n\t\ttry {\n\t\t\tconst res = await put<ApiResponse<R>>(endpoint, body, {\n\t\t\t\t...config,\n\t\t\t\theaders: {\n\t\t\t\t\t...config?.headers,\n\t\t\t\t},\n\t\t\t});\n\t\t\ttoastSuccess(res.data?.msg || \"Operation successful\");\n\t\t\treturn res.data;\n\t\t} catch (err: any) {\n\t\t\tlogger.error(\"PUT request failed\", err, { endpoint, body });\n\t\t\tconst errMsg = err?.response?.data?.msg || err.message || \"An error occurred\";\n\t\t\ttoastError(errMsg);\n\t\t\tsetError(errMsg);\n\t\t\treturn null;\n\t\t} finally {\n\t\t\tsetLoading(false);\n\t\t}\n\t};\n\n\treturn { put: putFn, loading, error };\n};\n\nexport const useDelete = <R = any>() => {\n\tconst [loading, setLoading] = useState(false);\n\tconst [error, setError] = useState<string | null>(null);\n\tconst { toastError, toastSuccess } = useToast();\n\n\tconst deleteFn = async (\n\t\tendpoint: string,\n\t\tconfig?: AxiosRequestConfig\n\t): Promise<ApiResponse<R> | null> => {\n\t\tsetLoading(true);\n\t\tsetError(null);\n\n\t\ttry {\n\t\t\tconst res = await deleteOp<ApiResponse<R>>(endpoint, {\n\t\t\t\t...config,\n\t\t\t\theaders: {\n\t\t\t\t\t...config?.headers,\n\t\t\t\t},\n\t\t\t});\n\t\t\ttoastSuccess(res.data?.msg || \"Operation successful\");\n\t\t\treturn res.data;\n\t\t} catch (err: any) {\n\t\t\tlogger.error(\"DELETE request failed\", err, { endpoint });\n\t\t\tconst errMsg = err?.response?.data?.message || err.message || \"An error occurred\";\n\t\t\ttoastError(errMsg);\n\t\t\tsetError(errMsg);\n\t\t\treturn null;\n\t\t} finally {\n\t\t\tsetLoading(false);\n\t\t}\n\t};\n\n\treturn { deleteFn, loading, error };\n};\n\nexport const useLazyGet = <R = any>() => {\n\tconst [loading, setLoading] = useState(false);\n\tconst [error, setError] = useState<string | null>(null);\n\tconst { toastError } = useToast();\n\n\tconst getFn = async (\n\t\tendpoint: string,\n\t\tconfig?: AxiosRequestConfig\n\t): Promise<ApiResponse<R> | null> => {\n\t\tsetLoading(true);\n\t\tsetError(null);\n\n\t\ttry {\n\t\t\tconst res = await get<ApiResponse<R>>(endpoint, {\n\t\t\t\t...config,\n\t\t\t\theaders: {\n\t\t\t\t\t...config?.headers,\n\t\t\t\t},\n\t\t\t});\n\t\t\treturn res.data;\n\t\t} catch (err: any) {\n\t\t\tlogger.error(\"GET request failed\", err, { endpoint });\n\t\t\tconst errMsg = err?.response?.data?.msg || err.message || \"An error occurred\";\n\t\t\ttoastError(errMsg);\n\t\t\tsetError(errMsg);\n\t\t\treturn null;\n\t\t} finally {\n\t\t\tsetLoading(false);\n\t\t}\n\t};\n\n\treturn { get: getFn, loading, error };\n};\n"
  },
  {
    "path": "client/src/Hooks/UseToast.ts",
    "content": "import { toast, type ToastOptions } from \"react-toastify\";\n\nexport const useToast = () => {\n\tconst showToast = (message: string, options?: ToastOptions) => {\n\t\ttoast.dismiss();\n\t\tconst baseStyle: React.CSSProperties = {\n\t\t\twhiteSpace: \"pre-line\",\n\t\t\twordBreak: \"break-word\",\n\t\t};\n\t\ttoast(message, {\n\t\t\t...options,\n\t\t\tstyle: { ...baseStyle, ...(options?.style || {}) },\n\t\t});\n\t};\n\n\tconst toastSuccess = (msg: string, opts?: ToastOptions) =>\n\t\tshowToast(msg, { ...opts, type: \"success\" });\n\tconst toastError = (msg: string, opts?: ToastOptions) =>\n\t\tshowToast(msg, { ...opts, type: \"error\" });\n\tconst toastInfo = (msg: string, opts?: ToastOptions) =>\n\t\tshowToast(msg, { ...opts, type: \"info\" });\n\n\treturn { showToast, toastSuccess, toastError, toastInfo };\n};\n"
  },
  {
    "path": "client/src/Hooks/useAddTeamMemberForm.ts",
    "content": "import {\n\taddTeamMemberSchema,\n\ttype AddTeamMemberFormData,\n} from \"@/Validation/addTeamMember\";\n\nexport const useAddTeamMemberForm = () => {\n\tconst defaults: AddTeamMemberFormData = {\n\t\tfirstName: \"\",\n\t\tlastName: \"\",\n\t\temail: \"\",\n\t\tpassword: \"\",\n\t\tconfirm: \"\",\n\t\trole: [\"user\"],\n\t};\n\n\treturn {\n\t\tschema: addTeamMemberSchema,\n\t\tdefaults,\n\t};\n};\n"
  },
  {
    "path": "client/src/Hooks/useDebounce.ts",
    "content": "import { useState, useEffect } from \"react\";\n\nconst useDebounce = <T>(value: T, delay: number): T => {\n\tconst [debouncedValue, setDebouncedValue] = useState<T>(value);\n\n\tuseEffect(() => {\n\t\tconst handler = setTimeout(() => {\n\t\t\tsetDebouncedValue(value);\n\t\t}, delay);\n\n\t\treturn () => {\n\t\t\tclearTimeout(handler);\n\t\t};\n\t}, [value, delay]);\n\n\treturn debouncedValue;\n};\n\nexport default useDebounce;\n"
  },
  {
    "path": "client/src/Hooks/useEditUserForm.ts",
    "content": "import { zodResolver } from \"@hookform/resolvers/zod\";\nimport { editUserSchema, type EditUserFormData } from \"@/Validation/editUser\";\n\nexport const useEditUserForm = () => {\n\treturn {\n\t\tresolver: zodResolver(editUserSchema),\n\t\tdefaults: {\n\t\t\tfirstName: \"\",\n\t\t\tlastName: \"\",\n\t\t\trole: [],\n\t\t} as EditUserFormData,\n\t};\n};\n"
  },
  {
    "path": "client/src/Hooks/useInviteForm.ts",
    "content": "import { zodResolver } from \"@hookform/resolvers/zod\";\nimport { inviteSchema, type InviteFormData } from \"@/Validation/invite\";\n\nexport const useInviteForm = () => {\n\tconst defaults: InviteFormData = {\n\t\temail: \"\",\n\t\trole: [\"user\"],\n\t};\n\n\treturn {\n\t\tresolver: zodResolver(inviteSchema),\n\t\tdefaults,\n\t};\n};\n"
  },
  {
    "path": "client/src/Hooks/useIsAdmin.ts",
    "content": "import type { RootState } from \"@/Types/state\";\nimport { useSelector } from \"react-redux\";\n\nconst useIsAdmin = (): boolean => {\n\tconst { user } = useSelector((state: RootState) => state.auth);\n\tconst isAdmin =\n\t\t(user?.role?.includes(\"admin\") ?? false) ||\n\t\t(user?.role?.includes(\"superadmin\") ?? false);\n\treturn isAdmin;\n};\n\nconst useIsSuperAdmin = (): boolean => {\n\tconst { user } = useSelector((state: RootState) => state.auth);\n\tconst isSuperAdmin = user?.role?.includes(\"superadmin\") ?? false;\n\treturn isSuperAdmin;\n};\n\nexport { useIsAdmin, useIsSuperAdmin };\n"
  },
  {
    "path": "client/src/Hooks/useLoginForm.ts",
    "content": "import { useMemo } from \"react\";\nimport { loginSchema, type LoginFormData } from \"@/Validation/login\";\n\nexport const useLoginForm = () => {\n\treturn useMemo(() => {\n\t\tconst defaults: LoginFormData = {\n\t\t\temail: \"\",\n\t\t\tpassword: \"\",\n\t\t};\n\n\t\treturn { schema: loginSchema, defaults };\n\t}, []);\n};\n"
  },
  {
    "path": "client/src/Hooks/useMaintenanceWindowForm.ts",
    "content": "import { useMemo } from \"react\";\nimport dayjs from \"dayjs\";\nimport {\n\tmaintenanceWindowSchema,\n\trepeatOptions,\n\ttype MaintenanceWindowFormData,\n} from \"@/Validation/maintenanceWindow\";\nimport type { MaintenanceWindow } from \"@/Types/MaintenanceWindow\";\n\ninterface UseMaintenanceWindowFormOptions {\n\tdata?: MaintenanceWindow | null;\n}\n\nconst getRepeatId = (repeatMs: number): string => {\n\tconst option = repeatOptions.find((opt) => opt.value === repeatMs);\n\treturn option?.id ?? \"none\";\n};\n\nexport const useMaintenanceWindowForm = ({\n\tdata = null,\n}: UseMaintenanceWindowFormOptions = {}) => {\n\treturn useMemo(() => {\n\t\tlet defaults: MaintenanceWindowFormData;\n\n\t\tif (data) {\n\t\t\tconst startDate = dayjs(data.start);\n\n\t\t\tdefaults = {\n\t\t\t\tname: data.name,\n\t\t\t\trepeat: getRepeatId(data.repeat),\n\t\t\t\tstartDate: startDate.format(\"YYYY-MM-DD\"),\n\t\t\t\tstartTime: startDate.format(\"HH:mm\"),\n\t\t\t\tduration: data.duration ?? 0,\n\t\t\t\tdurationUnit: data.durationUnit ?? \"minutes\",\n\t\t\t\tmonitors: [data.monitorId],\n\t\t\t};\n\t\t} else {\n\t\t\tconst now = dayjs();\n\t\t\tdefaults = {\n\t\t\t\tname: \"\",\n\t\t\t\trepeat: \"none\",\n\t\t\t\tstartDate: now.format(\"YYYY-MM-DD\"),\n\t\t\t\tstartTime: now.format(\"HH:mm\"),\n\t\t\t\tduration: 0,\n\t\t\t\tdurationUnit: \"minutes\",\n\t\t\t\tmonitors: [],\n\t\t\t};\n\t\t}\n\n\t\treturn { schema: maintenanceWindowSchema, defaults };\n\t}, [data]);\n};\n"
  },
  {
    "path": "client/src/Hooks/useMonitorForm.ts",
    "content": "import { useMemo } from \"react\";\nimport { monitorSchema, type MonitorFormData } from \"@/Validation/monitor\";\nimport type { Monitor, MonitorType } from \"@/Types/Monitor\";\n\ninterface UseMonitorFormOptions {\n\tdata?: Monitor | null;\n\tdefaultType?: MonitorType;\n}\n\nconst getBaseDefaults = (data?: Monitor | null) => ({\n\tname: data?.name || \"\",\n\tdescription: data?.description || \"\",\n\tinterval: data?.interval || 60000,\n\tnotifications: data?.notifications || [],\n\tstatusWindowSize: data?.statusWindowSize || 5,\n\tstatusWindowThreshold: data?.statusWindowThreshold || 60,\n\tgeoCheckEnabled: data?.geoCheckEnabled ?? false,\n\tgeoCheckLocations: data?.geoCheckLocations || [],\n\tgeoCheckInterval: data?.geoCheckInterval || 300000,\n});\n\nexport const useMonitorForm = ({\n\tdata = null,\n\tdefaultType = \"http\",\n}: UseMonitorFormOptions = {}) => {\n\treturn useMemo(() => {\n\t\tconst type = data?.type || defaultType;\n\t\tconst base = getBaseDefaults(data);\n\n\t\tlet defaults: MonitorFormData;\n\n\t\tswitch (type) {\n\t\t\tcase \"http\":\n\t\t\t\tdefaults = {\n\t\t\t\t\t...base,\n\t\t\t\t\ttype: \"http\",\n\t\t\t\t\turl: data?.url || \"\",\n\t\t\t\t\tignoreTlsErrors: data?.ignoreTlsErrors || false,\n\t\t\t\t\tuseAdvancedMatching: data?.useAdvancedMatching || false,\n\t\t\t\t\tmatchMethod: data?.matchMethod || \"\",\n\t\t\t\t\texpectedValue: data?.expectedValue || \"\",\n\t\t\t\t\tjsonPath: data?.jsonPath || \"\",\n\t\t\t\t};\n\t\t\t\tbreak;\n\t\t\tcase \"ping\":\n\t\t\t\tdefaults = {\n\t\t\t\t\t...base,\n\t\t\t\t\ttype: \"ping\",\n\t\t\t\t\turl: data?.url || \"\",\n\t\t\t\t};\n\t\t\t\tbreak;\n\t\t\tcase \"port\":\n\t\t\t\tdefaults = {\n\t\t\t\t\t...base,\n\t\t\t\t\ttype: \"port\",\n\t\t\t\t\turl: data?.url || \"\",\n\t\t\t\t\tport: data?.port || 80,\n\t\t\t\t};\n\t\t\t\tbreak;\n\t\t\tcase \"docker\":\n\t\t\t\tdefaults = {\n\t\t\t\t\t...base,\n\t\t\t\t\ttype: \"docker\",\n\t\t\t\t\turl: data?.url || \"\",\n\t\t\t\t};\n\t\t\t\tbreak;\n\t\t\tcase \"game\":\n\t\t\t\tdefaults = {\n\t\t\t\t\t...base,\n\t\t\t\t\ttype: \"game\",\n\t\t\t\t\turl: data?.url || \"\",\n\t\t\t\t\tport: data?.port || 27015,\n\t\t\t\t\tgameId: data?.gameId || \"\",\n\t\t\t\t};\n\t\t\t\tbreak;\n\t\t\tcase \"grpc\":\n\t\t\t\tdefaults = {\n\t\t\t\t\t...base,\n\t\t\t\t\ttype: \"grpc\",\n\t\t\t\t\turl: data?.url || \"\",\n\t\t\t\t\tport: data?.port || 50051,\n\t\t\t\t\tgrpcServiceName: data?.grpcServiceName || \"\",\n\t\t\t\t\tignoreTlsErrors: data?.ignoreTlsErrors || false,\n\t\t\t\t};\n\t\t\t\tbreak;\n\t\t\tcase \"pagespeed\":\n\t\t\t\tdefaults = {\n\t\t\t\t\t...base,\n\t\t\t\t\ttype: \"pagespeed\",\n\t\t\t\t\turl: data?.url || \"\",\n\t\t\t\t};\n\t\t\t\tbreak;\n\t\t\tcase \"hardware\":\n\t\t\t\tdefaults = {\n\t\t\t\t\t...base,\n\t\t\t\t\ttype: \"hardware\",\n\t\t\t\t\turl: data?.url || \"\",\n\t\t\t\t\tsecret: data?.secret || \"\",\n\t\t\t\t\tcpuAlertThreshold: data?.cpuAlertThreshold ?? 100,\n\t\t\t\t\tmemoryAlertThreshold: data?.memoryAlertThreshold ?? 100,\n\t\t\t\t\tdiskAlertThreshold: data?.diskAlertThreshold ?? 100,\n\t\t\t\t\ttempAlertThreshold: data?.tempAlertThreshold ?? 100,\n\t\t\t\t\tselectedDisks: data?.selectedDisks || [],\n\t\t\t\t};\n\t\t\t\tbreak;\n\t\t\tcase \"websocket\":\n\t\t\t\tdefaults = {\n\t\t\t\t\t...base,\n\t\t\t\t\ttype: \"websocket\",\n\t\t\t\t\turl: data?.url || \"\",\n\t\t\t\t\tignoreTlsErrors: data?.ignoreTlsErrors || false,\n\t\t\t\t};\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tdefaults = {\n\t\t\t\t\t...base,\n\t\t\t\t\ttype: \"http\",\n\t\t\t\t\turl: \"\",\n\t\t\t\t\tignoreTlsErrors: false,\n\t\t\t\t\tuseAdvancedMatching: false,\n\t\t\t\t\tmatchMethod: \"\",\n\t\t\t\t\texpectedValue: \"\",\n\t\t\t\t\tjsonPath: \"\",\n\t\t\t\t};\n\t\t}\n\n\t\treturn { schema: monitorSchema, defaults };\n\t}, [data, defaultType]);\n};\n"
  },
  {
    "path": "client/src/Hooks/useNotificationForm.ts",
    "content": "import { useMemo } from \"react\";\nimport { notificationSchema } from \"@/Validation/notifications\";\nimport type { Notification } from \"@/Types/Notification\";\n\ninterface UseNotificationFormOptions {\n\tdata?: Notification | null;\n}\n\nexport const useNotificationForm = ({ data = null }: UseNotificationFormOptions = {}) => {\n\treturn useMemo(() => {\n\t\tconst defaults =\n\t\t\tdata?.type === \"matrix\"\n\t\t\t\t? {\n\t\t\t\t\t\ttype: \"matrix\" as const,\n\t\t\t\t\t\tnotificationName: data.notificationName || \"\",\n\t\t\t\t\t\thomeserverUrl: data.homeserverUrl || \"\",\n\t\t\t\t\t\troomId: data.roomId || \"\",\n\t\t\t\t\t\taccessToken: data.accessToken || \"\",\n\t\t\t\t\t}\n\t\t\t\t: {\n\t\t\t\t\t\ttype: (data?.type || \"email\") as Exclude<Notification[\"type\"], \"matrix\">,\n\t\t\t\t\t\tnotificationName: data?.notificationName || \"\",\n\t\t\t\t\t\taddress: data?.address || \"\",\n\t\t\t\t\t};\n\n\t\treturn { schema: notificationSchema, defaults };\n\t}, [data]);\n};\n"
  },
  {
    "path": "client/src/Hooks/usePasswordForm.ts",
    "content": "import { zodResolver } from \"@hookform/resolvers/zod\";\nimport { passwordSchema, type PasswordFormData } from \"@/Validation/password\";\n\nexport const usePasswordForm = () => {\n\treturn {\n\t\tresolver: zodResolver(passwordSchema),\n\t\tdefaults: {\n\t\t\tcurrentPassword: \"\",\n\t\t\tnewPassword: \"\",\n\t\t\tconfirm: \"\",\n\t\t} as PasswordFormData,\n\t};\n};\n"
  },
  {
    "path": "client/src/Hooks/useProfileForm.ts",
    "content": "import { zodResolver } from \"@hookform/resolvers/zod\";\nimport { profileSchema, type ProfileFormData } from \"@/Validation/profile\";\n\nexport const useProfileForm = () => {\n\treturn {\n\t\tresolver: zodResolver(profileSchema),\n\t\tdefaults: {\n\t\t\tfirstName: \"\",\n\t\t\tlastName: \"\",\n\t\t\tprofileImage: null,\n\t\t\tdeleteProfileImage: false,\n\t\t} as ProfileFormData,\n\t};\n};\n"
  },
  {
    "path": "client/src/Hooks/useRecoveryForm.ts",
    "content": "import { recoverySchema } from \"@/Validation/recovery\";\n\nexport const useRecoveryForm = () => {\n\tconst defaults = {\n\t\temail: \"\",\n\t};\n\n\treturn {\n\t\tschema: recoverySchema,\n\t\tdefaults,\n\t};\n};\n"
  },
  {
    "path": "client/src/Hooks/useRegisterForm.ts",
    "content": "import { registerSchema, type RegisterFormData } from \"@/Validation/register\";\n\nexport const useRegisterForm = () => {\n\tconst defaults: RegisterFormData = {\n\t\tfirstName: \"\",\n\t\tlastName: \"\",\n\t\temail: \"\",\n\t\tpassword: \"\",\n\t\tconfirm: \"\",\n\t};\n\n\treturn {\n\t\tschema: registerSchema,\n\t\tdefaults,\n\t};\n};\n"
  },
  {
    "path": "client/src/Hooks/useSetNewPasswordForm.ts",
    "content": "import {\n\tsetNewPasswordSchema,\n\ttype SetNewPasswordFormData,\n} from \"@/Validation/setNewPassword\";\n\nexport const useSetNewPasswordForm = () => {\n\tconst defaults: SetNewPasswordFormData = {\n\t\tpassword: \"\",\n\t\tconfirm: \"\",\n\t};\n\n\treturn {\n\t\tschema: setNewPasswordSchema,\n\t\tdefaults,\n\t};\n};\n"
  },
  {
    "path": "client/src/Hooks/useSettingsForm.ts",
    "content": "import { useMemo } from \"react\";\nimport { settingsSchema } from \"@/Validation/settings\";\nimport type { Settings } from \"@/Types/Settings\";\nimport type { SettingsFormInput } from \"@/Validation/settings\";\n\ninterface UseSettingsFormOptions {\n\tdata?: Settings | null;\n}\nexport const useSettingsForm = ({ data = null }: UseSettingsFormOptions = {}) => {\n\treturn useMemo(() => {\n\t\tconst defaults: SettingsFormInput = {\n\t\t\tsystemEmailIgnoreTLS: data?.systemEmailIgnoreTLS ?? false,\n\t\t\tsystemEmailRequireTLS: data?.systemEmailRequireTLS ?? false,\n\t\t\tsystemEmailRejectUnauthorized: data?.systemEmailRejectUnauthorized ?? true,\n\t\t\tsystemEmailSecure: data?.systemEmailSecure ?? false,\n\t\t\tsystemEmailPool: data?.systemEmailPool ?? false,\n\t\t\tshowURL: data?.showURL ?? false,\n\t\t\tsystemEmailHost: data?.systemEmailHost || \"\",\n\t\t\tsystemEmailUser: data?.systemEmailUser || \"\",\n\t\t\tsystemEmailAddress: data?.systemEmailAddress || \"\",\n\t\t\tsystemEmailConnectionHost: data?.systemEmailConnectionHost || \"localhost\",\n\t\t\tsystemEmailTLSServername: data?.systemEmailTLSServername || \"\",\n\t\t\tsystemEmailPort: data?.systemEmailPort,\n\t\t\tglobalThresholds: {\n\t\t\t\tcpu:\n\t\t\t\t\tdata?.globalThresholds?.cpu && data.globalThresholds.cpu >= 1\n\t\t\t\t\t\t? data.globalThresholds.cpu\n\t\t\t\t\t\t: 80,\n\t\t\t\tmemory:\n\t\t\t\t\tdata?.globalThresholds?.memory && data.globalThresholds.memory >= 1\n\t\t\t\t\t\t? data.globalThresholds.memory\n\t\t\t\t\t\t: 80,\n\t\t\t\tdisk:\n\t\t\t\t\tdata?.globalThresholds?.disk && data.globalThresholds.disk >= 1\n\t\t\t\t\t\t? data.globalThresholds.disk\n\t\t\t\t\t\t: 80,\n\t\t\t\ttemperature:\n\t\t\t\t\tdata?.globalThresholds?.temperature && data.globalThresholds.temperature >= 1\n\t\t\t\t\t\t? data.globalThresholds.temperature\n\t\t\t\t\t\t: 80,\n\t\t\t},\n\t\t\tcheckTTL: data?.checkTTL ?? 30,\n\t\t\tpagespeedApiKey: \"\",\n\t\t\tsystemEmailPassword: \"\",\n\t\t};\n\n\t\treturn { schema: settingsSchema, defaults };\n\t}, [data]);\n};\n"
  },
  {
    "path": "client/src/Hooks/useSidebar.ts",
    "content": "import type { RootState } from \"@/Types/state\";\nimport { useSelector } from \"react-redux\";\n\n// CSS variable names for sidebar widths\nconst SIDEBAR_WIDTH_VAR = 250;\nconst SIDEBAR_COLLAPSED_WIDTH_VAR = 64;\n\n// Transition timing for sidebar width changes\nconst SIDEBAR_TRANSITION = \"width 650ms cubic-bezier(0.36, -0.01, 0, 0.77)\";\n\nexport const useSidebar = () => {\n\tconst collapsed = useSelector(\n\t\t(state: RootState) => state.ui.sidebar?.collapsed ?? false\n\t);\n\n\treturn {\n\t\tcollapsed,\n\t\tcollapsedWidth: SIDEBAR_COLLAPSED_WIDTH_VAR,\n\t\texpandedWidth: SIDEBAR_WIDTH_VAR,\n\t\twidth: collapsed ? SIDEBAR_COLLAPSED_WIDTH_VAR : SIDEBAR_WIDTH_VAR,\n\t\ttransition: SIDEBAR_TRANSITION,\n\t};\n};\n\nexport default useSidebar;\n"
  },
  {
    "path": "client/src/Hooks/useStatusPageForm.ts",
    "content": "import { useMemo } from \"react\";\nimport { statusPageSchema, type StatusPageFormData } from \"@/Validation/statusPage\";\nimport type { StatusPage } from \"@/Types/StatusPage\";\nimport type { Monitor } from \"@/Types/Monitor\";\n\ninterface UseStatusPageFormOptions {\n\tdata?: StatusPage | null;\n\tmonitors?: Monitor[] | null;\n}\n\nconst generateDefaultUrl = () => Math.floor(Math.random() * 1000000).toString();\n\nconst transformLogo = (logo: StatusPage[\"logo\"]): StatusPageFormData[\"logo\"] => {\n\tif (!logo || !logo.data) return null;\n\treturn {\n\t\tdata: `data:${logo.contentType};base64,${logo.data}`,\n\t\tcontentType: logo.contentType,\n\t};\n};\n\nexport const useStatusPageForm = ({\n\tdata = null,\n\tmonitors = null,\n}: UseStatusPageFormOptions = {}) => {\n\treturn useMemo(() => {\n\t\tconst defaults: StatusPageFormData = {\n\t\t\tcompanyName: data?.companyName || \"\",\n\t\t\turl: data?.url || generateDefaultUrl(),\n\t\t\ttimezone: data?.timezone || Intl.DateTimeFormat().resolvedOptions().timeZone,\n\t\t\ttype: data?.type || [\"uptime\"],\n\t\t\tcolor: data?.color || \"#4169E1\",\n\t\t\tmonitors: data?.monitors || [],\n\t\t\tisPublished: data?.isPublished ?? false,\n\t\t\tshowCharts: data?.showCharts ?? true,\n\t\t\tshowUptimePercentage: data?.showUptimePercentage ?? true,\n\t\t\tshowAdminLoginLink: data?.showAdminLoginLink ?? false,\n\t\t\tshowInfrastructure: data?.showInfrastructure ?? false,\n\t\t\tcustomCSS: data?.customCSS || \"\",\n\t\t\tlogo: transformLogo(data?.logo),\n\t\t};\n\n\t\treturn { schema: statusPageSchema, defaults };\n\t}, [data, monitors]);\n};\n"
  },
  {
    "path": "client/src/Pages/Account/EditUser/index.tsx",
    "content": "import { Trash2 } from \"lucide-react\";\nimport { TextField, Button, Autocomplete } from \"@/Components/inputs\";\nimport Stack from \"@mui/material/Stack\";\nimport Typography from \"@mui/material/Typography\";\nimport IconButton from \"@mui/material/IconButton\";\nimport Divider from \"@mui/material/Divider\";\nimport FormHelperText from \"@mui/material/FormHelperText\";\nimport { useForm, Controller } from \"react-hook-form\";\nimport { ConfigBox, BasePage } from \"@/Components/design-elements\";\n\nimport { UserRoles } from \"@/Types/User\";\nimport { useTranslation } from \"react-i18next\";\nimport type { UserRole, User } from \"@/Types/User\";\nimport { useParams, useNavigate } from \"react-router-dom\";\nimport { useTheme } from \"@mui/material\";\nimport { useEditUserForm } from \"@/Hooks/useEditUserForm\";\nimport { useGet, usePatch, useDelete } from \"@/Hooks/UseApi\";\nimport type { EditUserFormData } from \"@/Validation/editUser\";\nimport { useEffect, useState } from \"react\";\nimport { DialogInput } from \"@/Components/inputs/Dialog\";\nimport { useSelector } from \"react-redux\";\nimport type { RootState } from \"@/Types/state\";\nimport { LAYOUT } from \"@/Utils/Theme/constants\";\nimport { useIsAdmin, useIsSuperAdmin } from \"@/Hooks/useIsAdmin\";\n\ninterface RoleOption {\n\tid: UserRole;\n\tname: string;\n}\n\nconst EditUserPage = () => {\n\tconst theme = useTheme();\n\tconst { t } = useTranslation();\n\tconst { userId } = useParams<{ userId: string }>();\n\tconst { resolver, defaults } = useEditUserForm();\n\tconst { patch, loading: isSaving } = usePatch();\n\tconst { deleteFn, loading: isDeleting } = useDelete();\n\tconst navigate = useNavigate();\n\tconst [showDeleteDialog, setShowDeleteDialog] = useState(false);\n\tconst currentUser = useSelector((state: RootState) => state.auth.user);\n\tconst isSuperAdmin = useIsSuperAdmin();\n\tconst isAdmin = useIsAdmin();\n\n\tconst { data: user, isLoading } = useGet<User>(`/auth/users/${userId}`);\n\n\tconst { control, handleSubmit, reset, watch, setValue } = useForm<EditUserFormData>({\n\t\tresolver,\n\t\tdefaultValues: defaults,\n\t});\n\n\tuseEffect(() => {\n\t\tif (user) {\n\t\t\treset({\n\t\t\t\tfirstName: user.firstName || \"\",\n\t\t\t\tlastName: user.lastName || \"\",\n\t\t\t\trole: user.role || [],\n\t\t\t});\n\t\t}\n\t}, [user, reset]);\n\n\tconst editableRoles = UserRoles.filter((role) => role !== \"superadmin\");\n\tconst roleOptions: RoleOption[] = editableRoles.map((role) => ({\n\t\tid: role,\n\t\tname: t(`common.auth.roles.${role}`),\n\t}));\n\n\tconst watchedRoles = watch(\"role\");\n\tconst selectedRoles = roleOptions.filter((r) => watchedRoles?.includes(r.id));\n\tconst handleRemoveRole = (roleToRemove: UserRole) => {\n\t\tconst newRoles = watchedRoles.filter((role) => role !== roleToRemove);\n\t\tsetValue(\"role\", newRoles, { shouldValidate: true });\n\t};\n\n\tconst canDeleteUser =\n\t\tisAdmin &&\n\t\tuserId !== currentUser?.id &&\n\t\t!user?.role?.includes(\"demo\") &&\n\t\t(isSuperAdmin || user?.role?.every((r) => r !== \"admin\" && r !== \"superadmin\"));\n\n\tconst handleDeleteUser = async () => {\n\t\tconst result = await deleteFn(`/auth/users/${userId}`);\n\t\tsetShowDeleteDialog(false);\n\t\tif (result) {\n\t\t\tnavigate(\"/account\", { state: { tab: \"team\" } });\n\t\t}\n\t};\n\n\tconst onSubmit = async (data: EditUserFormData) => {\n\t\tawait patch(`/auth/users/${userId}`, data);\n\t};\n\n\treturn (\n\t\t<BasePage loading={isLoading}>\n\t\t\t<form onSubmit={handleSubmit(onSubmit)}>\n\t\t\t\t<Stack gap={theme.spacing(8)}>\n\t\t\t\t\t<ConfigBox\n\t\t\t\t\t\ttitle={t(\"pages.account.form.name.title\")}\n\t\t\t\t\t\tsubtitle={t(\"pages.account.form.name.description\")}\n\t\t\t\t\t\trightContent={\n\t\t\t\t\t\t\t<Stack gap={theme.spacing(8)}>\n\t\t\t\t\t\t\t\t<Controller\n\t\t\t\t\t\t\t\t\tname=\"firstName\"\n\t\t\t\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\t\t\t\trender={({ field, fieldState }) => (\n\t\t\t\t\t\t\t\t\t\t<TextField\n\t\t\t\t\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\t\t\t\t\tfieldLabel={t(\"common.form.name.option.firstName.label\")}\n\t\t\t\t\t\t\t\t\t\t\tplaceholder={t(\"common.form.name.option.firstName.placeholder\")}\n\t\t\t\t\t\t\t\t\t\t\terror={!!fieldState.error}\n\t\t\t\t\t\t\t\t\t\t\thelperText={fieldState.error?.message}\n\t\t\t\t\t\t\t\t\t\t\tautoComplete=\"given-name\"\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t<Controller\n\t\t\t\t\t\t\t\t\tname=\"lastName\"\n\t\t\t\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\t\t\t\trender={({ field, fieldState }) => (\n\t\t\t\t\t\t\t\t\t\t<TextField\n\t\t\t\t\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\t\t\t\t\tfieldLabel={t(\"common.form.name.option.lastName.label\")}\n\t\t\t\t\t\t\t\t\t\t\tplaceholder={t(\"common.form.name.option.lastName.placeholder\")}\n\t\t\t\t\t\t\t\t\t\t\terror={!!fieldState.error}\n\t\t\t\t\t\t\t\t\t\t\thelperText={fieldState.error?.message}\n\t\t\t\t\t\t\t\t\t\t\tautoComplete=\"family-name\"\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t<TextField\n\t\t\t\t\t\t\t\t\tfieldLabel={t(\"common.form.email.option.email.label\")}\n\t\t\t\t\t\t\t\t\tplaceholder={t(\"common.form.email.option.email.placeholder\")}\n\t\t\t\t\t\t\t\t\tvalue={user?.email || \"\"}\n\t\t\t\t\t\t\t\t\tdisabled\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t</Stack>\n\t\t\t\t\t\t}\n\t\t\t\t\t/>\n\t\t\t\t\t<ConfigBox\n\t\t\t\t\t\ttitle={t(\"pages.editUser.form.roles.title\")}\n\t\t\t\t\t\tsubtitle={t(\"pages.editUser.form.roles.description\")}\n\t\t\t\t\t\trightContent={\n\t\t\t\t\t\t\t<Stack spacing={theme.spacing(4)}>\n\t\t\t\t\t\t\t\t<Controller\n\t\t\t\t\t\t\t\t\tname=\"role\"\n\t\t\t\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\t\t\t\trender={({ field, fieldState }) => (\n\t\t\t\t\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t\t\t\t\t<Autocomplete\n\t\t\t\t\t\t\t\t\t\t\t\tfieldLabel={t(\"common.form.role.option.role.label\")}\n\t\t\t\t\t\t\t\t\t\t\t\tmultiple\n\t\t\t\t\t\t\t\t\t\t\t\toptions={roleOptions}\n\t\t\t\t\t\t\t\t\t\t\t\tvalue={selectedRoles}\n\t\t\t\t\t\t\t\t\t\t\t\tgetOptionLabel={(option) => option.name}\n\t\t\t\t\t\t\t\t\t\t\t\tonChange={(_: unknown, newValue: RoleOption[]) => {\n\t\t\t\t\t\t\t\t\t\t\t\t\tfield.onChange(newValue.map((r) => r.id));\n\t\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\t\tisOptionEqualToValue={(option, value) => option.id === value.id}\n\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t\t{fieldState.error && (\n\t\t\t\t\t\t\t\t\t\t\t\t<FormHelperText error>{fieldState.error.message}</FormHelperText>\n\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t</>\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t{selectedRoles.length > 0 && (\n\t\t\t\t\t\t\t\t\t<Stack\n\t\t\t\t\t\t\t\t\t\tflex={1}\n\t\t\t\t\t\t\t\t\t\twidth=\"100%\"\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t{selectedRoles.map((role, index) => (\n\t\t\t\t\t\t\t\t\t\t\t<Stack\n\t\t\t\t\t\t\t\t\t\t\t\tdirection=\"row\"\n\t\t\t\t\t\t\t\t\t\t\t\talignItems=\"center\"\n\t\t\t\t\t\t\t\t\t\t\t\tkey={role.id}\n\t\t\t\t\t\t\t\t\t\t\t\twidth=\"100%\"\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t<Typography flexGrow={1}>{role.name}</Typography>\n\t\t\t\t\t\t\t\t\t\t\t\t<IconButton\n\t\t\t\t\t\t\t\t\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t\t\t\t\t\t\t\t\tonClick={() => handleRemoveRole(role.id)}\n\t\t\t\t\t\t\t\t\t\t\t\t\taria-label=\"Remove role\"\n\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<Trash2 size={16} />\n\t\t\t\t\t\t\t\t\t\t\t\t</IconButton>\n\t\t\t\t\t\t\t\t\t\t\t\t{index < selectedRoles.length - 1 && <Divider />}\n\t\t\t\t\t\t\t\t\t\t\t</Stack>\n\t\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t\t</Stack>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t</Stack>\n\t\t\t\t\t\t}\n\t\t\t\t\t/>\n\t\t\t\t\t<Stack\n\t\t\t\t\t\tgap={LAYOUT.XS}\n\t\t\t\t\t\tdirection=\"row\"\n\t\t\t\t\t\tjustifyContent={\"flex-end\"}\n\t\t\t\t\t\twidth=\"100%\"\n\t\t\t\t\t>\n\t\t\t\t\t\t{canDeleteUser && (\n\t\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\t\tvariant=\"contained\"\n\t\t\t\t\t\t\t\tcolor=\"error\"\n\t\t\t\t\t\t\t\tonClick={() => setShowDeleteDialog(true)}\n\t\t\t\t\t\t\t\tsx={{ minWidth: 100 }}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{t(\"common.buttons.removeUser\")}\n\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t)}\n\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\ttype=\"submit\"\n\t\t\t\t\t\t\tvariant=\"contained\"\n\t\t\t\t\t\t\tcolor=\"primary\"\n\t\t\t\t\t\t\tloading={isSaving}\n\t\t\t\t\t\t\tsx={{ minWidth: 100 }}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{t(\"common.buttons.save\")}\n\t\t\t\t\t\t</Button>\n\t\t\t\t\t</Stack>\n\t\t\t\t</Stack>\n\t\t\t</form>\n\t\t\t<DialogInput\n\t\t\t\topen={showDeleteDialog}\n\t\t\t\ttitle={t(\"pages.editUser.dialog.removeUser.title\")}\n\t\t\t\tcontent={t(\"pages.editUser.dialog.removeUser.content\", {\n\t\t\t\t\tname: `${user?.firstName} ${user?.lastName}`,\n\t\t\t\t})}\n\t\t\t\tonCancel={() => setShowDeleteDialog(false)}\n\t\t\t\tonConfirm={handleDeleteUser}\n\t\t\t\tconfirmText={t(\"common.buttons.removeUser\")}\n\t\t\t\tloading={isDeleting}\n\t\t\t/>\n\t\t</BasePage>\n\t);\n};\n\nexport default EditUserPage;\n"
  },
  {
    "path": "client/src/Pages/Account/TabPassword.tsx",
    "content": "import { Stack } from \"@mui/material\";\nimport { ConfigBox } from \"@/Components/design-elements\";\nimport { TextField, Button } from \"@/Components/inputs\";\n\nimport { useTranslation } from \"react-i18next\";\nimport { useTheme } from \"@mui/material\";\nimport { useForm, Controller } from \"react-hook-form\";\nimport { usePasswordForm } from \"@/Hooks/usePasswordForm\";\nimport { usePatch } from \"@/Hooks/UseApi\";\nimport type { PasswordFormData } from \"@/Validation/password\";\n\nexport const TabPassword = () => {\n\tconst { t } = useTranslation();\n\tconst theme = useTheme();\n\tconst { resolver, defaults } = usePasswordForm();\n\tconst { patch, loading } = usePatch<FormData, void>();\n\n\tconst { control, handleSubmit, reset } = useForm<PasswordFormData>({\n\t\tresolver,\n\t\tdefaultValues: defaults,\n\t});\n\n\tconst onSubmit = async (data: PasswordFormData) => {\n\t\tconst fd = new FormData();\n\t\tfd.append(\"password\", data.currentPassword);\n\t\tfd.append(\"newPassword\", data.newPassword);\n\n\t\tconst result = await patch(\"/auth/user\", fd);\n\t\tif (result?.success) {\n\t\t\treset();\n\t\t}\n\t};\n\n\treturn (\n\t\t<Stack\n\t\t\tgap={theme.spacing(8)}\n\t\t\tcomponent=\"form\"\n\t\t\tonSubmit={handleSubmit(onSubmit)}\n\t\t>\n\t\t\t<ConfigBox\n\t\t\t\ttitle={t(\"pages.account.form.currentPassword.title\")}\n\t\t\t\tsubtitle={t(\"pages.account.form.currentPassword.description\")}\n\t\t\t\trightContent={\n\t\t\t\t\t<Controller\n\t\t\t\t\t\tname=\"currentPassword\"\n\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\trender={({ field, fieldState }) => (\n\t\t\t\t\t\t\t<TextField\n\t\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\t\ttype=\"password\"\n\t\t\t\t\t\t\t\tfieldLabel={t(\"pages.account.form.currentPassword.option.label\")}\n\t\t\t\t\t\t\t\tplaceholder={t(\"pages.account.form.currentPassword.option.placeholder\")}\n\t\t\t\t\t\t\t\tautoComplete=\"current-password\"\n\t\t\t\t\t\t\t\terror={!!fieldState.error}\n\t\t\t\t\t\t\t\thelperText={fieldState.error?.message ?? \"\"}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t)}\n\t\t\t\t\t/>\n\t\t\t\t}\n\t\t\t/>\n\t\t\t<ConfigBox\n\t\t\t\ttitle={t(\"pages.account.form.newPassword.title\")}\n\t\t\t\tsubtitle={t(\"pages.account.form.newPassword.description\")}\n\t\t\t\trightContent={\n\t\t\t\t\t<Stack gap={theme.spacing(8)}>\n\t\t\t\t\t\t<Controller\n\t\t\t\t\t\t\tname=\"newPassword\"\n\t\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\t\trender={({ field, fieldState }) => (\n\t\t\t\t\t\t\t\t<TextField\n\t\t\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\t\t\ttype=\"password\"\n\t\t\t\t\t\t\t\t\tfieldLabel={t(\n\t\t\t\t\t\t\t\t\t\t\"pages.account.form.newPassword.option.newPassword.label\"\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\tplaceholder={t(\n\t\t\t\t\t\t\t\t\t\t\"pages.account.form.newPassword.option.newPassword.placeholder\"\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\tautoComplete=\"new-password\"\n\t\t\t\t\t\t\t\t\terror={!!fieldState.error}\n\t\t\t\t\t\t\t\t\thelperText={fieldState.error?.message ?? \"\"}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<Controller\n\t\t\t\t\t\t\tname=\"confirm\"\n\t\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\t\trender={({ field, fieldState }) => (\n\t\t\t\t\t\t\t\t<TextField\n\t\t\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\t\t\ttype=\"password\"\n\t\t\t\t\t\t\t\t\tfieldLabel={t(\"pages.account.form.newPassword.option.confirm.label\")}\n\t\t\t\t\t\t\t\t\tplaceholder={t(\n\t\t\t\t\t\t\t\t\t\t\"pages.account.form.newPassword.option.confirm.placeholder\"\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\tautoComplete=\"new-password\"\n\t\t\t\t\t\t\t\t\terror={!!fieldState.error}\n\t\t\t\t\t\t\t\t\thelperText={fieldState.error?.message ?? \"\"}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</Stack>\n\t\t\t\t}\n\t\t\t/>\n\t\t\t<Button\n\t\t\t\ttype=\"submit\"\n\t\t\t\tvariant=\"contained\"\n\t\t\t\tcolor=\"primary\"\n\t\t\t\tloading={loading}\n\t\t\t\tsx={{ alignSelf: \"flex-end\", minWidth: 100 }}\n\t\t\t>\n\t\t\t\t{t(\"common.buttons.save\")}\n\t\t\t</Button>\n\t\t</Stack>\n\t);\n};\n"
  },
  {
    "path": "client/src/Pages/Account/TabProfile.tsx",
    "content": "import { Stack } from \"@mui/material\";\nimport { ConfigBox } from \"@/Components/design-elements\";\nimport { TextField, Button } from \"@/Components/inputs\";\nimport { ImageUpload } from \"@/Components/inputs\";\n\nimport { useTheme } from \"@mui/material\";\nimport { useTranslation } from \"react-i18next\";\nimport { useForm, Controller } from \"react-hook-form\";\nimport { useSelector, useDispatch } from \"react-redux\";\nimport { useProfileForm } from \"@/Hooks/useProfileForm\";\nimport { usePatch } from \"@/Hooks/UseApi\";\nimport { setUser } from \"@/Features/Auth/authSlice\";\nimport type { ProfileFormData } from \"@/Validation/profile\";\nimport type { RootState } from \"@/Types/state\";\nimport type { User } from \"@/Types/User\";\n\nexport const TabProfile = () => {\n\tconst theme = useTheme();\n\tconst { t } = useTranslation();\n\tconst dispatch = useDispatch();\n\tconst user = useSelector((state: RootState) => state.auth?.user);\n\tconst { resolver, defaults } = useProfileForm();\n\tconst { patch, loading: patchLoading } = usePatch<FormData, User>();\n\n\tconst { control, handleSubmit, setValue, watch } = useForm<ProfileFormData>({\n\t\tresolver,\n\t\tdefaultValues: {\n\t\t\tfirstName: user?.firstName ?? defaults.firstName,\n\t\t\tlastName: user?.lastName ?? defaults.lastName,\n\t\t\tprofileImage: defaults.profileImage,\n\t\t\tdeleteProfileImage: defaults.deleteProfileImage,\n\t\t},\n\t});\n\n\tconst currentImage = watch(\"profileImage\");\n\tconst deleteImage = watch(\"deleteProfileImage\");\n\n\tconst getCurrentImageSrc = () => {\n\t\tif (deleteImage) return undefined;\n\t\tif (currentImage) return URL.createObjectURL(currentImage);\n\t\tif (user?.avatarImage) return `data:image/png;base64,${user.avatarImage}`;\n\t\treturn undefined;\n\t};\n\n\tconst handleImageChange = (\n\t\tfileObj: { src: string; name: string; file: File } | undefined\n\t) => {\n\t\tif (fileObj) {\n\t\t\tsetValue(\"profileImage\", fileObj.file);\n\t\t\tsetValue(\"deleteProfileImage\", false);\n\t\t} else {\n\t\t\tsetValue(\"profileImage\", null);\n\t\t\tsetValue(\"deleteProfileImage\", true);\n\t\t}\n\t};\n\n\tconst onSubmit = async (data: ProfileFormData) => {\n\t\tconst fd = new FormData();\n\t\tfd.append(\"firstName\", data.firstName);\n\t\tfd.append(\"lastName\", data.lastName);\n\n\t\tif (data.profileImage) {\n\t\t\tfd.append(\"profileImage\", data.profileImage);\n\t\t}\n\n\t\tif (data.deleteProfileImage) {\n\t\t\tfd.append(\"deleteProfileImage\", \"true\");\n\t\t}\n\n\t\tconst result = await patch(\"/auth/user\", fd);\n\t\tif (result?.success && result.data) {\n\t\t\tdispatch(setUser(result.data));\n\t\t}\n\t};\n\n\treturn (\n\t\t<Stack\n\t\t\tgap={theme.spacing(8)}\n\t\t\tcomponent=\"form\"\n\t\t\tonSubmit={handleSubmit(onSubmit)}\n\t\t>\n\t\t\t<ConfigBox\n\t\t\t\ttitle={t(\"pages.account.form.name.title\")}\n\t\t\t\tsubtitle={t(\"pages.account.form.name.description\")}\n\t\t\t\trightContent={\n\t\t\t\t\t<Stack gap={theme.spacing(8)}>\n\t\t\t\t\t\t<Controller\n\t\t\t\t\t\t\tname=\"firstName\"\n\t\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\t\trender={({ field, fieldState }) => (\n\t\t\t\t\t\t\t\t<TextField\n\t\t\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\t\t\tfieldLabel={t(\"common.form.name.option.firstName.label\")}\n\t\t\t\t\t\t\t\t\tplaceholder={t(\"common.form.name.option.firstName.placeholder\")}\n\t\t\t\t\t\t\t\t\tautoComplete=\"given-name\"\n\t\t\t\t\t\t\t\t\terror={!!fieldState.error}\n\t\t\t\t\t\t\t\t\thelperText={fieldState.error?.message ?? \"\"}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<Controller\n\t\t\t\t\t\t\tname=\"lastName\"\n\t\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\t\trender={({ field, fieldState }) => (\n\t\t\t\t\t\t\t\t<TextField\n\t\t\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\t\t\tfieldLabel={t(\"common.form.name.option.lastName.label\")}\n\t\t\t\t\t\t\t\t\tplaceholder={t(\"common.form.name.option.lastName.placeholder\")}\n\t\t\t\t\t\t\t\t\tautoComplete=\"family-name\"\n\t\t\t\t\t\t\t\t\terror={!!fieldState.error}\n\t\t\t\t\t\t\t\t\thelperText={fieldState.error?.message ?? \"\"}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</Stack>\n\t\t\t\t}\n\t\t\t/>\n\t\t\t<ConfigBox\n\t\t\t\ttitle={t(\"pages.account.form.photo.title\")}\n\t\t\t\tsubtitle={t(\"pages.account.form.photo.description\")}\n\t\t\t\trightContent={\n\t\t\t\t\t<ImageUpload\n\t\t\t\t\t\tsrc={getCurrentImageSrc()}\n\t\t\t\t\t\tonChange={handleImageChange}\n\t\t\t\t\t/>\n\t\t\t\t}\n\t\t\t/>\n\t\t\t<Button\n\t\t\t\ttype=\"submit\"\n\t\t\t\tvariant=\"contained\"\n\t\t\t\tcolor=\"primary\"\n\t\t\t\tloading={patchLoading}\n\t\t\t\tsx={{ alignSelf: \"flex-end\", minWidth: 100 }}\n\t\t\t>\n\t\t\t\t{t(\"common.buttons.save\")}\n\t\t\t</Button>\n\t\t</Stack>\n\t);\n};\n"
  },
  {
    "path": "client/src/Pages/Account/TabTeam.tsx",
    "content": "import { Stack } from \"@mui/material\";\nimport { useTheme } from \"@mui/material\";\nimport { useState, useMemo } from \"react\";\nimport { HeaderTeamControls } from \"./components/HeaderTeamControls\";\nimport { TeamTable } from \"./components/TeamTable\";\nimport { InviteTeamMemberDialog } from \"./components/InviteTeamMemberDialog\";\nimport { AddTeamMemberDialog } from \"./components/AddTeamMemberDialog\";\nimport { useGet } from \"@/Hooks/UseApi\";\nimport type { User, UserRole } from \"@/Types/User\";\n\nexport const TabTeam = () => {\n\tconst theme = useTheme();\n\tconst [filter, setFilter] = useState<UserRole | \"\">(\"\");\n\tconst [inviteDialogOpen, setInviteDialogOpen] = useState(false);\n\tconst [addMemberDialogOpen, setAddMemberDialogOpen] = useState(false);\n\n\tconst { data: users, refetch } = useGet<User[]>(\"/auth/users\");\n\n\tconst filteredUsers = useMemo(() => {\n\t\tif (!users) return [];\n\t\tif (!filter) return users;\n\n\t\treturn users.filter((u) => u.role.includes(filter));\n\t}, [users, filter]);\n\n\tconst handleOpenInviteDialog = () => setInviteDialogOpen(true);\n\tconst handleCloseInviteDialog = () => setInviteDialogOpen(false);\n\n\tconst handleOpenAddMemberDialog = () => setAddMemberDialogOpen(true);\n\tconst handleCloseAddMemberDialog = () => setAddMemberDialogOpen(false);\n\n\tconst handleRefetch = () => {\n\t\trefetch();\n\t};\n\n\treturn (\n\t\t<Stack gap={theme.spacing(8)}>\n\t\t\t<HeaderTeamControls\n\t\t\t\tfilter={filter}\n\t\t\t\tonFilterChange={setFilter}\n\t\t\t\tonInviteClick={handleOpenInviteDialog}\n\t\t\t\tonAddMemberClick={handleOpenAddMemberDialog}\n\t\t\t/>\n\t\t\t<TeamTable users={filteredUsers} />\n\t\t\t<InviteTeamMemberDialog\n\t\t\t\topen={inviteDialogOpen}\n\t\t\t\tonClose={handleCloseInviteDialog}\n\t\t\t/>\n\t\t\t<AddTeamMemberDialog\n\t\t\t\topen={addMemberDialogOpen}\n\t\t\t\tonClose={handleCloseAddMemberDialog}\n\t\t\t\tonSuccess={handleRefetch}\n\t\t\t/>\n\t\t</Stack>\n\t);\n};\n"
  },
  {
    "path": "client/src/Pages/Account/components/AddTeamMemberDialog.tsx",
    "content": "import { Stack } from \"@mui/material\";\nimport MenuItem from \"@mui/material/MenuItem\";\nimport { useTheme } from \"@mui/material\";\nimport { useTranslation } from \"react-i18next\";\nimport { useForm, Controller } from \"react-hook-form\";\nimport { zodResolver } from \"@hookform/resolvers/zod/dist/zod.js\";\nimport { Dialog, TextField, Select } from \"@/Components/inputs\";\nimport { useAddTeamMemberForm } from \"@/Hooks/useAddTeamMemberForm\";\nimport type { AddTeamMemberFormData } from \"@/Validation/addTeamMember\";\nimport type { UserRole, User } from \"@/Types/User\";\nimport { usePost } from \"@/Hooks/UseApi\";\n\ninterface AddTeamMemberDialogProps {\n\topen: boolean;\n\tonClose: () => void;\n\tonSuccess?: () => void;\n}\n\ninterface RegisterPayload {\n\tfirstName: string;\n\tlastName: string;\n\temail: string;\n\tpassword: string;\n\trole: string[];\n}\n\nexport const AddTeamMemberDialog = ({\n\topen,\n\tonClose,\n\tonSuccess,\n}: AddTeamMemberDialogProps) => {\n\tconst theme = useTheme();\n\tconst { t } = useTranslation();\n\tconst { schema, defaults } = useAddTeamMemberForm();\n\tconst { post, loading } = usePost<RegisterPayload, User>();\n\n\tconst { control, handleSubmit, reset, setError } = useForm<AddTeamMemberFormData>({\n\t\tresolver: zodResolver(schema),\n\t\tdefaultValues: defaults,\n\t\tvalues: defaults,\n\t});\n\n\tconst roleOptions: { value: UserRole; label: string }[] = [\n\t\t{ value: \"admin\", label: t(\"common.auth.roles.admin\") },\n\t\t{ value: \"user\", label: t(\"common.auth.roles.user\") },\n\t];\n\n\tconst handleClose = () => {\n\t\treset();\n\t\tonClose();\n\t};\n\n\tconst onSubmit = async (data: AddTeamMemberFormData) => {\n\t\tif (loading) return;\n\n\t\tconst { confirm, ...userData } = data;\n\t\tconst payload: RegisterPayload = userData;\n\n\t\tconst result = await post(\"/auth/users\", payload);\n\n\t\tif (result?.success) {\n\t\t\treset();\n\t\t\tonClose();\n\t\t\tonSuccess?.();\n\t\t} else if (result?.msg) {\n\t\t\tif (result.msg.toLowerCase().includes(\"email\")) {\n\t\t\t\tsetError(\"email\", { message: result.msg });\n\t\t\t}\n\t\t}\n\t};\n\n\treturn (\n\t\t<Dialog\n\t\t\topen={open}\n\t\t\ttitle={t(\"pages.account.team.addMember.title\")}\n\t\t\tcontent={t(\"pages.account.team.addMember.description\")}\n\t\t\tonCancel={handleClose}\n\t\t\tonConfirm={handleSubmit(onSubmit)}\n\t\t\tconfirmText={t(\"common.buttons.addMember\")}\n\t\t\tloading={loading}\n\t\t\tmaxWidth=\"sm\"\n\t\t\tfullWidth\n\t\t>\n\t\t\t<Stack\n\t\t\t\tgap={theme.spacing(4)}\n\t\t\t\tmt={theme.spacing(4)}\n\t\t\t>\n\t\t\t\t<Controller\n\t\t\t\t\tname=\"firstName\"\n\t\t\t\t\tcontrol={control}\n\t\t\t\t\trender={({ field, fieldState }) => (\n\t\t\t\t\t\t<TextField\n\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\tfieldLabel={t(\"common.form.name.option.firstName.label\")}\n\t\t\t\t\t\t\tplaceholder={t(\"common.form.name.option.firstName.placeholder\")}\n\t\t\t\t\t\t\terror={!!fieldState.error}\n\t\t\t\t\t\t\thelperText={fieldState.error?.message ?? \"\"}\n\t\t\t\t\t\t\tfullWidth\n\t\t\t\t\t\t/>\n\t\t\t\t\t)}\n\t\t\t\t/>\n\t\t\t\t<Controller\n\t\t\t\t\tname=\"lastName\"\n\t\t\t\t\tcontrol={control}\n\t\t\t\t\trender={({ field, fieldState }) => (\n\t\t\t\t\t\t<TextField\n\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\tfieldLabel={t(\"common.form.name.option.lastName.label\")}\n\t\t\t\t\t\t\tplaceholder={t(\"common.form.name.option.lastName.placeholder\")}\n\t\t\t\t\t\t\terror={!!fieldState.error}\n\t\t\t\t\t\t\thelperText={fieldState.error?.message ?? \"\"}\n\t\t\t\t\t\t\tfullWidth\n\t\t\t\t\t\t/>\n\t\t\t\t\t)}\n\t\t\t\t/>\n\t\t\t\t<Controller\n\t\t\t\t\tname=\"email\"\n\t\t\t\t\tcontrol={control}\n\t\t\t\t\trender={({ field, fieldState }) => (\n\t\t\t\t\t\t<TextField\n\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\tfieldLabel={t(\"common.form.email.option.email.label\")}\n\t\t\t\t\t\t\tplaceholder={t(\"common.form.email.option.email.placeholder\")}\n\t\t\t\t\t\t\ttype=\"email\"\n\t\t\t\t\t\t\terror={!!fieldState.error}\n\t\t\t\t\t\t\thelperText={fieldState.error?.message ?? \"\"}\n\t\t\t\t\t\t\tfullWidth\n\t\t\t\t\t\t/>\n\t\t\t\t\t)}\n\t\t\t\t/>\n\t\t\t\t<Controller\n\t\t\t\t\tname=\"role\"\n\t\t\t\t\tcontrol={control}\n\t\t\t\t\trender={({ field }) => (\n\t\t\t\t\t\t<Select\n\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\tvalue={field.value[0] ?? \"user\"}\n\t\t\t\t\t\t\tonChange={(e) => field.onChange([e.target.value])}\n\t\t\t\t\t\t\tfieldLabel={t(\"common.form.role.option.role.label\")}\n\t\t\t\t\t\t\tfullWidth\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{roleOptions.map((option) => (\n\t\t\t\t\t\t\t\t<MenuItem\n\t\t\t\t\t\t\t\t\tkey={option.value}\n\t\t\t\t\t\t\t\t\tvalue={option.value}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t{option.label}\n\t\t\t\t\t\t\t\t</MenuItem>\n\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t</Select>\n\t\t\t\t\t)}\n\t\t\t\t/>\n\t\t\t\t<Controller\n\t\t\t\t\tname=\"password\"\n\t\t\t\t\tcontrol={control}\n\t\t\t\t\trender={({ field, fieldState }) => (\n\t\t\t\t\t\t<TextField\n\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\tfieldLabel={t(\"pages.auth.common.form.option.password.label\")}\n\t\t\t\t\t\t\tplaceholder={t(\"pages.auth.common.form.option.password.placeholder\")}\n\t\t\t\t\t\t\ttype=\"password\"\n\t\t\t\t\t\t\terror={!!fieldState.error}\n\t\t\t\t\t\t\thelperText={fieldState.error?.message ?? \"\"}\n\t\t\t\t\t\t\tfullWidth\n\t\t\t\t\t\t/>\n\t\t\t\t\t)}\n\t\t\t\t/>\n\t\t\t\t<Controller\n\t\t\t\t\tname=\"confirm\"\n\t\t\t\t\tcontrol={control}\n\t\t\t\t\trender={({ field, fieldState }) => (\n\t\t\t\t\t\t<TextField\n\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\tfieldLabel={t(\"pages.auth.common.form.option.confirmPassword.label\")}\n\t\t\t\t\t\t\tplaceholder={t(\"pages.auth.common.form.option.password.placeholder\")}\n\t\t\t\t\t\t\ttype=\"password\"\n\t\t\t\t\t\t\terror={!!fieldState.error}\n\t\t\t\t\t\t\thelperText={fieldState.error?.message ?? \"\"}\n\t\t\t\t\t\t\tfullWidth\n\t\t\t\t\t\t/>\n\t\t\t\t\t)}\n\t\t\t\t/>\n\t\t\t</Stack>\n\t\t</Dialog>\n\t);\n};\n"
  },
  {
    "path": "client/src/Pages/Account/components/HeaderTeamControls.tsx",
    "content": "import Stack from \"@mui/material/Stack\";\nimport MenuItem from \"@mui/material/MenuItem\";\nimport { Button, Select } from \"@/Components/inputs\";\nimport { Icon } from \"@/Components/design-elements\";\nimport { UserPlus, Mail } from \"lucide-react\";\n\nimport { UserRoles } from \"@/Types/User\";\nimport { useTheme } from \"@mui/material/styles\";\nimport type { UserRole } from \"@/Types/User\";\nimport { useTranslation } from \"react-i18next\";\nimport { useIsAdmin, useIsSuperAdmin } from \"@/Hooks/useIsAdmin\";\n\ninterface HeaderTeamControlsProps {\n\tfilter: UserRole | \"\";\n\tonFilterChange: (value: UserRole | \"\") => void;\n\tonInviteClick?: () => void;\n\tonAddMemberClick?: () => void;\n}\n\nexport const HeaderTeamControls = ({\n\tfilter,\n\tonFilterChange,\n\tonInviteClick,\n\tonAddMemberClick,\n}: HeaderTeamControlsProps) => {\n\tconst theme = useTheme();\n\tconst { t } = useTranslation();\n\tconst isAdmin = useIsAdmin();\n\tconst isSuperAdmin = useIsSuperAdmin();\n\n\tconst handleFilterChange = (event: { target: { value: unknown } }) => {\n\t\tonFilterChange(event.target.value as UserRole | \"\");\n\t};\n\n\treturn (\n\t\t<Stack\n\t\t\tdirection=\"row\"\n\t\t\talignItems=\"center\"\n\t\t\tjustifyContent=\"flex-end\"\n\t\t\tgap={theme.spacing(4)}\n\t\t>\n\t\t\t<Select\n\t\t\t\tvalue={filter}\n\t\t\t\tonChange={handleFilterChange}\n\t\t\t\tplaceholder={t(\"pages.account.team.filter.placeholder\")}\n\t\t\t\tsx={{ minWidth: 150 }}\n\t\t\t>\n\t\t\t\t<MenuItem value=\"\">{t(\"pages.account.team.filter.all\")}</MenuItem>\n\t\t\t\t{UserRoles.map((role) => (\n\t\t\t\t\t<MenuItem\n\t\t\t\t\t\tkey={role}\n\t\t\t\t\t\tvalue={role}\n\t\t\t\t\t>\n\t\t\t\t\t\t{t(`common.auth.roles.${role}`)}\n\t\t\t\t\t</MenuItem>\n\t\t\t\t))}\n\t\t\t</Select>\n\t\t\t{isAdmin && (\n\t\t\t\t<Button\n\t\t\t\t\tvariant=\"contained\"\n\t\t\t\t\tcolor=\"primary\"\n\t\t\t\t\tstartIcon={<Icon icon={Mail} />}\n\t\t\t\t\tonClick={onInviteClick}\n\t\t\t\t>\n\t\t\t\t\t{t(\"common.buttons.inviteMember\")}\n\t\t\t\t</Button>\n\t\t\t)}\n\t\t\t{isSuperAdmin && (\n\t\t\t\t<Button\n\t\t\t\t\tvariant=\"contained\"\n\t\t\t\t\tcolor=\"primary\"\n\t\t\t\t\tstartIcon={<Icon icon={UserPlus} />}\n\t\t\t\t\tonClick={onAddMemberClick}\n\t\t\t\t>\n\t\t\t\t\t{t(\"common.buttons.addMember\")}\n\t\t\t\t</Button>\n\t\t\t)}\n\t\t</Stack>\n\t);\n};\n"
  },
  {
    "path": "client/src/Pages/Account/components/InviteTeamMemberDialog.tsx",
    "content": "import { Stack } from \"@mui/material\";\nimport MenuItem from \"@mui/material/MenuItem\";\nimport { useTheme, FormHelperText, Typography } from \"@mui/material\";\nimport { useState } from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { useForm, Controller } from \"react-hook-form\";\nimport { Dialog, TextField, Select, Button } from \"@/Components/inputs\";\nimport type { UserRole } from \"@/Types/User\";\nimport { useInviteForm } from \"@/Hooks/useInviteForm\";\nimport type { InviteFormData } from \"@/Validation/invite\";\nimport { usePost } from \"@/Hooks/UseApi\";\n\nconst CLIENT_HOST = import.meta.env.VITE_APP_CLIENT_HOST;\n\ninterface InviteResponse {\n\ttoken: string;\n}\n\ninterface InviteTeamMemberDialogProps {\n\topen: boolean;\n\tonClose: () => void;\n}\n\nexport const InviteTeamMemberDialog = ({\n\topen,\n\tonClose,\n}: InviteTeamMemberDialogProps) => {\n\tconst theme = useTheme();\n\tconst { t } = useTranslation();\n\tconst { resolver, defaults } = useInviteForm();\n\n\tconst { control, handleSubmit, reset } = useForm<InviteFormData>({\n\t\tresolver,\n\t\tdefaultValues: defaults,\n\t\tvalues: defaults,\n\t});\n\n\tconst { post: generateToken, loading: generateLoading } = usePost<\n\t\tInviteFormData,\n\t\tInviteResponse\n\t>();\n\tconst { post: sendInvite, loading: sendLoading } = usePost<\n\t\tInviteFormData,\n\t\tInviteResponse\n\t>();\n\tconst [inviteLink, setInviteLink] = useState<string | null>(null);\n\n\tconst roleOptions: { value: UserRole; label: string }[] = [\n\t\t{ value: \"admin\", label: t(\"common.auth.roles.admin\") },\n\t\t{ value: \"user\", label: t(\"common.auth.roles.user\") },\n\t];\n\n\tconst handleGenerateToken = async (data: InviteFormData) => {\n\t\tconst result = await generateToken(\"/invite\", data);\n\t\tif (result?.data?.token) {\n\t\t\tconst token = result.data.token;\n\t\t\tconst link = CLIENT_HOST ? `${CLIENT_HOST}/register/${token}` : token;\n\t\t\tsetInviteLink(link);\n\t\t}\n\t};\n\n\tconst handleSendInvite = async (data: InviteFormData) => {\n\t\tconst result = await sendInvite(\"/invite/send\", data);\n\t\tif (result?.success) {\n\t\t\thandleClose();\n\t\t}\n\t};\n\n\tconst handleClose = () => {\n\t\treset();\n\t\tsetInviteLink(null);\n\t\tonClose();\n\t};\n\n\treturn (\n\t\t<Dialog\n\t\t\topen={open}\n\t\t\ttitle={t(\"pages.account.team.invite.title\")}\n\t\t\tcontent={t(\"pages.account.team.invite.description\")}\n\t\t\tonCancel={handleClose}\n\t\t\tonConfirm={handleSubmit(handleSendInvite)}\n\t\t\tconfirmText={t(\"common.buttons.sendInvite\")}\n\t\t\tloading={sendLoading || generateLoading}\n\t\t\tmaxWidth=\"sm\"\n\t\t\tfullWidth\n\t\t\tadditionalButtons={\n\t\t\t\t<Button\n\t\t\t\t\tvariant=\"contained\"\n\t\t\t\t\tcolor=\"primary\"\n\t\t\t\t\tonClick={handleSubmit(handleGenerateToken)}\n\t\t\t\t\tloading={generateLoading || sendLoading}\n\t\t\t\t>\n\t\t\t\t\t{t(\"common.buttons.generateToken\")}\n\t\t\t\t</Button>\n\t\t\t}\n\t\t>\n\t\t\t<Stack\n\t\t\t\tgap={theme.spacing(4)}\n\t\t\t\tmt={theme.spacing(4)}\n\t\t\t>\n\t\t\t\t<Controller\n\t\t\t\t\tname=\"email\"\n\t\t\t\t\tcontrol={control}\n\t\t\t\t\trender={({ field, fieldState }) => (\n\t\t\t\t\t\t<TextField\n\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\tfieldLabel={t(\"common.form.email.option.email.label\")}\n\t\t\t\t\t\t\tplaceholder={t(\"common.form.email.option.email.placeholder\")}\n\t\t\t\t\t\t\ttype=\"email\"\n\t\t\t\t\t\t\tfullWidth\n\t\t\t\t\t\t\terror={!!fieldState.error}\n\t\t\t\t\t\t\thelperText={fieldState.error?.message ?? \"\"}\n\t\t\t\t\t\t/>\n\t\t\t\t\t)}\n\t\t\t\t/>\n\t\t\t\t<Controller\n\t\t\t\t\tname=\"role\"\n\t\t\t\t\tcontrol={control}\n\t\t\t\t\trender={({ field: { value, onChange, ...field }, fieldState }) => (\n\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t<Select\n\t\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\t\tvalue={Array.isArray(value) ? (value[0] ?? \"\") : \"\"}\n\t\t\t\t\t\t\t\tonChange={(e) => onChange([e.target.value as UserRole])}\n\t\t\t\t\t\t\t\tfieldLabel={t(\"common.form.role.option.role.label\")}\n\t\t\t\t\t\t\t\tfullWidth\n\t\t\t\t\t\t\t\terror={!!fieldState.error}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{roleOptions.map((option) => (\n\t\t\t\t\t\t\t\t\t<MenuItem\n\t\t\t\t\t\t\t\t\t\tkey={option.value}\n\t\t\t\t\t\t\t\t\t\tvalue={option.value}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t{option.label}\n\t\t\t\t\t\t\t\t\t</MenuItem>\n\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t</Select>\n\t\t\t\t\t\t\t{fieldState.error && (\n\t\t\t\t\t\t\t\t<FormHelperText error>{fieldState.error.message}</FormHelperText>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</>\n\t\t\t\t\t)}\n\t\t\t\t/>\n\t\t\t\t{inviteLink && (\n\t\t\t\t\t<>\n\t\t\t\t\t\t<Typography variant=\"body2\">\n\t\t\t\t\t\t\t{t(\"pages.account.team.invite.linkLabel\")}\n\t\t\t\t\t\t</Typography>\n\t\t\t\t\t\t<TextField\n\t\t\t\t\t\t\tvalue={inviteLink}\n\t\t\t\t\t\t\tfullWidth\n\t\t\t\t\t\t\tslotProps={{\n\t\t\t\t\t\t\t\tinput: {\n\t\t\t\t\t\t\t\t\treadOnly: true,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</>\n\t\t\t\t)}\n\t\t\t</Stack>\n\t\t</Dialog>\n\t);\n};\n"
  },
  {
    "path": "client/src/Pages/Account/components/TeamTable.tsx",
    "content": "import Typography from \"@mui/material/Typography\";\nimport { useNavigate } from \"react-router-dom\";\nimport { useTranslation } from \"react-i18next\";\nimport { Table } from \"@/Components/design-elements\";\nimport type { Header } from \"@/Components/design-elements/Table\";\nimport { useIsAdmin } from \"@/Hooks/useIsAdmin\";\nimport type { User } from \"@/Types/User\";\n\ninterface TeamTableProps {\n\tusers: User[];\n}\n\nexport const TeamTable = ({ users }: TeamTableProps) => {\n\tconst { t } = useTranslation();\n\tconst navigate = useNavigate();\n\tconst isAdmin = useIsAdmin();\n\n\tconst headers: Header<User>[] = [\n\t\t{\n\t\t\tid: \"name\",\n\t\t\tcontent: t(\"common.table.headers.name\"),\n\t\t\trender: (row) => <Typography>{`${row.firstName} ${row.lastName}`}</Typography>,\n\t\t},\n\t\t{\n\t\t\tid: \"email\",\n\t\t\tcontent: t(\"pages.account.team.table.headers.email\"),\n\t\t\trender: (row) => <Typography>{row.email}</Typography>,\n\t\t},\n\t\t{\n\t\t\tid: \"role\",\n\t\t\tcontent: t(\"pages.account.team.table.headers.role\"),\n\t\t\trender: (row) => (\n\t\t\t\t<Typography>\n\t\t\t\t\t{row.role.map((r) => t(`common.auth.roles.${r}`)).join(\", \")}\n\t\t\t\t</Typography>\n\t\t\t),\n\t\t},\n\t\t{\n\t\t\tid: \"created\",\n\t\t\tcontent: t(\"pages.account.team.table.headers.created\"),\n\t\t\trender: (row) => (\n\t\t\t\t<Typography>{new Date(row.createdAt).toLocaleDateString()}</Typography>\n\t\t\t),\n\t\t},\n\t];\n\n\tconst handleRowClick = (row: User) => {\n\t\tif (isAdmin) {\n\t\t\tnavigate(`/account/team/${row.id}`);\n\t\t}\n\t};\n\n\treturn (\n\t\t<Table\n\t\t\theaders={headers}\n\t\t\tdata={users}\n\t\t\tonRowClick={isAdmin ? handleRowClick : undefined}\n\t\t/>\n\t);\n};\n"
  },
  {
    "path": "client/src/Pages/Account/index.tsx",
    "content": "import { BasePage, Tabs, Tab } from \"@/Components/design-elements\";\nimport { useState, useEffect } from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { TabProfile } from \"./TabProfile\";\nimport { TabPassword } from \"./TabPassword\";\nimport { TabTeam } from \"./TabTeam\";\n\ninterface AccountProps {\n\topen?: \"profile\" | \"password\" | \"team\";\n}\n\nconst TAB_MAP = {\n\tprofile: 0,\n\tpassword: 1,\n\tteam: 2,\n} as const;\n\nconst Account = ({ open = \"profile\" }: AccountProps) => {\n\tconst { t } = useTranslation();\n\tconst [activeTab, setActiveTab] = useState<number>(TAB_MAP[open]);\n\n\t// Sync activeTab when open prop changes (e.g., navigating from sidebar)\n\tuseEffect(() => {\n\t\tsetActiveTab(TAB_MAP[open]);\n\t}, [open]);\n\n\treturn (\n\t\t<BasePage>\n\t\t\t<Tabs\n\t\t\t\tvalue={activeTab}\n\t\t\t\tonChange={(_, newValue: number) => setActiveTab(newValue)}\n\t\t\t>\n\t\t\t\t<Tab label={t(\"pages.account.tabs.profile\")} />\n\t\t\t\t<Tab label={t(\"pages.account.tabs.password\")} />\n\t\t\t\t<Tab label={t(\"pages.account.tabs.team\")} />\n\t\t\t</Tabs>\n\t\t\t{activeTab === 0 && <TabProfile />}\n\t\t\t{activeTab === 1 && <TabPassword />}\n\t\t\t{activeTab === 2 && <TabTeam />}\n\t\t</BasePage>\n\t);\n};\n\nexport default Account;\n"
  },
  {
    "path": "client/src/Pages/Auth/Login/index.tsx",
    "content": "import { BaseAuthPage, TextLink } from \"@/Components/design-elements\";\nimport { Button, TextField } from \"@/Components/inputs\";\n\nimport { useTranslation } from \"react-i18next\";\nimport { useForm, Controller } from \"react-hook-form\";\nimport { zodResolver } from \"@hookform/resolvers/zod/dist/zod.js\";\nimport { useLoginForm } from \"@/Hooks/useLoginForm\";\nimport type { LoginFormData } from \"@/Validation/login\";\nimport { useDispatch } from \"react-redux\";\nimport { useNavigate } from \"react-router-dom\";\nimport { setAuthState } from \"@/Features/Auth/authSlice\";\nimport { usePost } from \"@/Hooks/UseApi\";\n\nconst LoginPage = () => {\n\tconst { t } = useTranslation();\n\tconst dispatch = useDispatch();\n\tconst navigate = useNavigate();\n\tconst { post, loading } = usePost();\n\n\tconst { schema, defaults } = useLoginForm();\n\n\tconst { control, handleSubmit } = useForm<LoginFormData>({\n\t\tresolver: zodResolver(schema),\n\t\tdefaultValues: defaults,\n\t});\n\n\tconst onSubmit = async (data: LoginFormData) => {\n\t\tif (loading) return;\n\n\t\tconst result = await post(\"/auth/login\", data);\n\n\t\tif (result?.success) {\n\t\t\tdispatch(setAuthState(result));\n\t\t\tnavigate(\"/uptime\");\n\t\t}\n\t};\n\n\treturn (\n\t\t<BaseAuthPage\n\t\t\tcomponent=\"form\"\n\t\t\tonSubmit={handleSubmit(onSubmit)}\n\t\t\ttitle={t(\"pages.auth.login.title\")}\n\t\t\tsubtitle={t(\"pages.auth.login.subtitle\")}\n\t\t>\n\t\t\t<Controller\n\t\t\t\tname=\"email\"\n\t\t\t\tcontrol={control}\n\t\t\t\trender={({ field, fieldState }) => (\n\t\t\t\t\t<TextField\n\t\t\t\t\t\t{...field}\n\t\t\t\t\t\tfieldLabel={t(\"pages.auth.common.form.option.email.label\")}\n\t\t\t\t\t\tplaceholder={t(\"pages.auth.common.form.option.email.placeholder\")}\n\t\t\t\t\t\terror={!!fieldState.error}\n\t\t\t\t\t\thelperText={fieldState.error ? t(fieldState.error.message ?? \"\") : \"\"}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\t\t\t/>\n\t\t\t<Controller\n\t\t\t\tname=\"password\"\n\t\t\t\tcontrol={control}\n\t\t\t\trender={({ field, fieldState }) => (\n\t\t\t\t\t<TextField\n\t\t\t\t\t\t{...field}\n\t\t\t\t\t\ttype=\"password\"\n\t\t\t\t\t\tfieldLabel={t(\"pages.auth.common.form.option.password.label\")}\n\t\t\t\t\t\tplaceholder={t(\"pages.auth.common.form.option.password.placeholder\")}\n\t\t\t\t\t\terror={!!fieldState.error}\n\t\t\t\t\t\thelperText={fieldState.error ? t(fieldState.error.message ?? \"\") : \"\"}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\t\t\t/>\n\t\t\t<Button\n\t\t\t\tvariant=\"contained\"\n\t\t\t\ttype=\"submit\"\n\t\t\t\tloading={loading}\n\t\t\t>\n\t\t\t\t{t(\"pages.auth.login.submit\")}\n\t\t\t</Button>\n\t\t\t<TextLink\n\t\t\t\talignSelf={\"center\"}\n\t\t\t\ttext={t(\"pages.auth.login.links.forgotPassword.text\")}\n\t\t\t\tlinkText={t(\"pages.auth.login.links.forgotPassword.linkText\")}\n\t\t\t\thref=\"/forgot-password\"\n\t\t\t/>\n\t\t\t<TextLink\n\t\t\t\talignSelf={\"center\"}\n\t\t\t\ttext={t(\"pages.auth.login.links.register.text\")}\n\t\t\t\tlinkText={t(\"pages.auth.login.links.register.linkText\")}\n\t\t\t\thref=\"/register\"\n\t\t\t/>\n\t\t</BaseAuthPage>\n\t);\n};\n\nexport default LoginPage;\n"
  },
  {
    "path": "client/src/Pages/Auth/Recovery/index.tsx",
    "content": "import { Button, TextField } from \"@/Components/inputs\";\nimport { BaseAuthPage, TextLink } from \"@/Components/design-elements\";\n\nimport { useForm, Controller } from \"react-hook-form\";\nimport { zodResolver } from \"@hookform/resolvers/zod/dist/zod.js\";\nimport { useRecoveryForm } from \"@/Hooks/useRecoveryForm\";\nimport type { RecoveryFormData } from \"@/Validation/recovery\";\nimport { usePost } from \"@/Hooks/UseApi\";\nimport { useTranslation } from \"react-i18next\";\n\nconst ForgotPasswordPage = () => {\n\tconst { t } = useTranslation();\n\tconst { post, loading } = usePost();\n\n\tconst { schema, defaults } = useRecoveryForm();\n\n\tconst { control, handleSubmit } = useForm<RecoveryFormData>({\n\t\tresolver: zodResolver(schema),\n\t\tdefaultValues: defaults,\n\t});\n\n\tconst onSubmit = async (data: RecoveryFormData) => {\n\t\tif (loading) return;\n\n\t\tconst result = await post(\"/auth/recovery/request\", data);\n\n\t\tif (result?.success) {\n\t\t\t// Navigate to Check email page\n\t\t}\n\t};\n\n\treturn (\n\t\t<BaseAuthPage\n\t\t\tcomponent=\"form\"\n\t\t\tonSubmit={handleSubmit(onSubmit)}\n\t\t\ttitle={t(\"pages.auth.forgotPassword.title\")}\n\t\t\tsubtitle={t(\"pages.auth.forgotPassword.subtitle\")}\n\t\t>\n\t\t\t<Controller\n\t\t\t\tname=\"email\"\n\t\t\t\tcontrol={control}\n\t\t\t\trender={({ field, fieldState }) => (\n\t\t\t\t\t<TextField\n\t\t\t\t\t\t{...field}\n\t\t\t\t\t\tfieldLabel={t(\"pages.auth.common.form.option.email.label\")}\n\t\t\t\t\t\tplaceholder={t(\"pages.auth.common.form.option.email.placeholder\")}\n\t\t\t\t\t\terror={!!fieldState.error}\n\t\t\t\t\t\thelperText={fieldState.error ? t(fieldState.error.message ?? \"\") : \"\"}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\t\t\t/>\n\t\t\t<Button\n\t\t\t\tvariant=\"contained\"\n\t\t\t\ttype=\"submit\"\n\t\t\t\tloading={loading}\n\t\t\t>\n\t\t\t\t{t(\"pages.auth.forgotPassword.submit\")}\n\t\t\t</Button>\n\t\t\t<TextLink\n\t\t\t\talignSelf={\"center\"}\n\t\t\t\ttext={t(\"pages.auth.forgotPassword.links.login.text\")}\n\t\t\t\tlinkText={t(\"pages.auth.forgotPassword.links.login.linkText\")}\n\t\t\t\thref=\"/login\"\n\t\t\t/>\n\t\t</BaseAuthPage>\n\t);\n};\n\nexport default ForgotPasswordPage;\n"
  },
  {
    "path": "client/src/Pages/Auth/Register/index.tsx",
    "content": "import { BaseAuthPage } from \"@/Components/design-elements\";\nimport { Button, TextField } from \"@/Components/inputs\";\nimport { useForm, Controller } from \"react-hook-form\";\nimport { zodResolver } from \"@hookform/resolvers/zod/dist/zod.js\";\nimport { useRegisterForm } from \"@/Hooks/useRegisterForm\";\nimport type { RegisterFormData } from \"@/Validation/register\";\nimport { useTranslation } from \"react-i18next\";\nimport { usePost, useGet } from \"@/Hooks/UseApi\";\nimport { setAuthState } from \"@/Features/Auth/authSlice\";\nimport { useDispatch } from \"react-redux\";\nimport { useNavigate, useParams } from \"react-router-dom\";\nimport type { AuthResponse } from \"@/Types/User\";\nimport { useEffect, useRef } from \"react\";\n\ninterface RegisterPayload {\n\tuser: Omit<RegisterFormData, \"confirm\">;\n\ttoken?: string;\n}\n\ninterface InviteVerifyResponse {\n\temail: string;\n}\n\nconst RegisterPage = () => {\n\tconst { t } = useTranslation();\n\tconst { schema, defaults } = useRegisterForm();\n\tconst { post, loading } = usePost<RegisterPayload, AuthResponse>();\n\tconst dispatch = useDispatch();\n\tconst navigate = useNavigate();\n\tconst { token } = useParams<{ token?: string }>();\n\n\tconst { post: verifyToken } = usePost<{ token: string }, InviteVerifyResponse>();\n\tconst hasVerified = useRef(false);\n\n\tconst { data: superAdminExists, isLoading: isCheckingAdmin } = useGet<boolean>(\n\t\ttoken ? null : \"/auth/users/superadmin\"\n\t);\n\n\tconst { control, handleSubmit, setError, reset } = useForm<RegisterFormData>({\n\t\tresolver: zodResolver(schema),\n\t\tdefaultValues: defaults,\n\t});\n\n\tuseEffect(() => {\n\t\tif (superAdminExists === true) {\n\t\t\tnavigate(\"/login\", { replace: true });\n\t\t}\n\t}, [superAdminExists, navigate]);\n\n\tuseEffect(() => {\n\t\tif (!token || hasVerified.current) return;\n\t\thasVerified.current = true;\n\n\t\tverifyToken(\"/invite/verify\", { token }).then((result) => {\n\t\t\tif (result?.success && result?.data) {\n\t\t\t\treset({\n\t\t\t\t\t...defaults,\n\t\t\t\t\temail: result.data.email ?? \"\",\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tnavigate(\"/register\", { replace: true });\n\t\t\t}\n\t\t});\n\t}, [token]);\n\n\tif (isCheckingAdmin) return null;\n\n\tconst onSubmit = async (data: RegisterFormData) => {\n\t\tif (loading) return;\n\n\t\tconst { confirm, ...userData } = data;\n\t\tconst payload: RegisterPayload = { user: userData };\n\t\tif (token) {\n\t\t\tpayload.token = token;\n\t\t}\n\t\tconst result = await post(\"/auth/register\", payload);\n\n\t\tif (result?.success) {\n\t\t\tdispatch(setAuthState(result));\n\t\t\tnavigate(\"/uptime\");\n\t\t} else if (result?.msg) {\n\t\t\tif (result.msg.toLowerCase().includes(\"email\")) {\n\t\t\t\tsetError(\"email\", { message: result.msg });\n\t\t\t}\n\t\t}\n\t};\n\n\treturn (\n\t\t<BaseAuthPage\n\t\t\tcomponent=\"form\"\n\t\t\tonSubmit={handleSubmit(onSubmit)}\n\t\t\ttitle={t(\"pages.auth.register.title\")}\n\t\t\tsubtitle={t(\"pages.auth.register.subtitle\")}\n\t\t>\n\t\t\t<Controller\n\t\t\t\tname=\"firstName\"\n\t\t\t\tcontrol={control}\n\t\t\t\trender={({ field, fieldState }) => (\n\t\t\t\t\t<TextField\n\t\t\t\t\t\t{...field}\n\t\t\t\t\t\tfieldLabel={t(\"common.form.name.option.firstName.label\")}\n\t\t\t\t\t\tplaceholder={t(\"common.form.name.option.firstName.placeholder\")}\n\t\t\t\t\t\terror={!!fieldState.error}\n\t\t\t\t\t\thelperText={fieldState.error?.message ?? \"\"}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\t\t\t/>\n\t\t\t<Controller\n\t\t\t\tname=\"lastName\"\n\t\t\t\tcontrol={control}\n\t\t\t\trender={({ field, fieldState }) => (\n\t\t\t\t\t<TextField\n\t\t\t\t\t\t{...field}\n\t\t\t\t\t\tfieldLabel={t(\"common.form.name.option.lastName.label\")}\n\t\t\t\t\t\tplaceholder={t(\"common.form.name.option.lastName.placeholder\")}\n\t\t\t\t\t\terror={!!fieldState.error}\n\t\t\t\t\t\thelperText={fieldState.error?.message ?? \"\"}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\t\t\t/>\n\t\t\t<Controller\n\t\t\t\tname=\"email\"\n\t\t\t\tcontrol={control}\n\t\t\t\trender={({ field, fieldState }) => (\n\t\t\t\t\t<TextField\n\t\t\t\t\t\t{...field}\n\t\t\t\t\t\tdisabled={!!token}\n\t\t\t\t\t\tfieldLabel={t(\"common.form.email.option.email.label\")}\n\t\t\t\t\t\tplaceholder={t(\"common.form.email.option.email.placeholder\")}\n\t\t\t\t\t\terror={!!fieldState.error}\n\t\t\t\t\t\thelperText={fieldState.error?.message ?? \"\"}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\t\t\t/>\n\t\t\t<Controller\n\t\t\t\tname=\"password\"\n\t\t\t\tcontrol={control}\n\t\t\t\trender={({ field, fieldState }) => (\n\t\t\t\t\t<TextField\n\t\t\t\t\t\t{...field}\n\t\t\t\t\t\ttype=\"password\"\n\t\t\t\t\t\tfieldLabel={t(\"pages.auth.common.form.option.password.label\")}\n\t\t\t\t\t\tplaceholder={t(\"pages.auth.common.form.option.password.placeholder\")}\n\t\t\t\t\t\terror={!!fieldState.error}\n\t\t\t\t\t\thelperText={fieldState.error?.message ?? \"\"}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\t\t\t/>\n\t\t\t<Controller\n\t\t\t\tname=\"confirm\"\n\t\t\t\tcontrol={control}\n\t\t\t\trender={({ field, fieldState }) => (\n\t\t\t\t\t<TextField\n\t\t\t\t\t\t{...field}\n\t\t\t\t\t\ttype=\"password\"\n\t\t\t\t\t\tfieldLabel={t(\"pages.auth.common.form.option.confirmPassword.label\")}\n\t\t\t\t\t\tplaceholder={t(\"pages.auth.common.form.option.password.placeholder\")}\n\t\t\t\t\t\terror={!!fieldState.error}\n\t\t\t\t\t\thelperText={fieldState.error?.message ?? \"\"}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\t\t\t/>\n\t\t\t<Button\n\t\t\t\tvariant=\"contained\"\n\t\t\t\ttype=\"submit\"\n\t\t\t\tloading={loading}\n\t\t\t>\n\t\t\t\t{t(\"pages.auth.register.submit\")}\n\t\t\t</Button>\n\t\t</BaseAuthPage>\n\t);\n};\n\nexport default RegisterPage;\n"
  },
  {
    "path": "client/src/Pages/Auth/SetNewPassword/index.tsx",
    "content": "import { BaseAuthPage, BulletPointCheck, TextLink } from \"@/Components/design-elements\";\nimport { Button, TextField } from \"@/Components/inputs\";\nimport Stack from \"@mui/material/Stack\";\nimport { useTheme } from \"@mui/material/styles\";\nimport { useTranslation } from \"react-i18next\";\nimport { useForm, Controller } from \"react-hook-form\";\nimport { zodResolver } from \"@hookform/resolvers/zod/dist/zod.js\";\nimport { useSetNewPasswordForm } from \"@/Hooks/useSetNewPasswordForm\";\nimport type { SetNewPasswordFormData } from \"@/Validation/setNewPassword\";\nimport { specialCharPattern } from \"@/Validation/patterns\";\nimport { useParams, useNavigate } from \"react-router-dom\";\nimport { usePost } from \"@/Hooks/UseApi\";\nimport { useDispatch } from \"react-redux\";\nimport { setAuthState } from \"@/Features/Auth/authSlice\";\n\nconst SetNewPasswordPage = () => {\n\tconst theme = useTheme();\n\tconst { t } = useTranslation();\n\tconst { token } = useParams<{ token: string }>();\n\tconst navigate = useNavigate();\n\tconst dispatch = useDispatch();\n\tconst { post, loading } = usePost();\n\n\tconst { schema, defaults } = useSetNewPasswordForm();\n\n\tconst { control, handleSubmit, watch } = useForm<SetNewPasswordFormData>({\n\t\tresolver: zodResolver(schema),\n\t\tdefaultValues: defaults,\n\t});\n\n\tconst password = watch(\"password\");\n\tconst confirm = watch(\"confirm\");\n\n\tconst getVariant = (condition: boolean): \"success\" | \"info\" => {\n\t\treturn condition ? \"success\" : \"info\";\n\t};\n\n\tconst hasLength = password.length >= 8;\n\tconst hasSpecial = specialCharPattern.test(password);\n\tconst hasNumber = /\\d/.test(password);\n\tconst hasUppercase = /[A-Z]/.test(password);\n\tconst hasLowercase = /[a-z]/.test(password);\n\tconst passwordsMatch = password.length > 0 && password === confirm;\n\n\tconst onSubmit = async (data: SetNewPasswordFormData) => {\n\t\tif (loading) return;\n\n\t\tconst result = await post(\"/auth/recovery/reset\", {\n\t\t\tpassword: data.password,\n\t\t\trecoveryToken: token,\n\t\t});\n\n\t\tif (result?.success) {\n\t\t\tdispatch(setAuthState(result));\n\t\t\tnavigate(\"/uptime\");\n\t\t}\n\t};\n\n\treturn (\n\t\t<BaseAuthPage\n\t\t\tcomponent=\"form\"\n\t\t\tonSubmit={handleSubmit(onSubmit)}\n\t\t\ttitle={t(\"pages.auth.setNewPassword.title\")}\n\t\t\tsubtitle={t(\"pages.auth.setNewPassword.subtitle\")}\n\t\t>\n\t\t\t<Controller\n\t\t\t\tname=\"password\"\n\t\t\t\tcontrol={control}\n\t\t\t\trender={({ field, fieldState }) => (\n\t\t\t\t\t<TextField\n\t\t\t\t\t\t{...field}\n\t\t\t\t\t\ttype=\"password\"\n\t\t\t\t\t\tfieldLabel={t(\"pages.auth.common.form.option.password.label\")}\n\t\t\t\t\t\tplaceholder={t(\"pages.auth.common.form.option.password.placeholder\")}\n\t\t\t\t\t\terror={!!fieldState.error}\n\t\t\t\t\t\thelperText={fieldState.error?.message ?? \"\"}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\t\t\t/>\n\t\t\t<Controller\n\t\t\t\tname=\"confirm\"\n\t\t\t\tcontrol={control}\n\t\t\t\trender={({ field, fieldState }) => (\n\t\t\t\t\t<TextField\n\t\t\t\t\t\t{...field}\n\t\t\t\t\t\ttype=\"password\"\n\t\t\t\t\t\tfieldLabel={t(\"pages.auth.common.form.option.confirmPassword.label\")}\n\t\t\t\t\t\tplaceholder={t(\"pages.auth.common.form.option.password.placeholder\")}\n\t\t\t\t\t\terror={!!fieldState.error}\n\t\t\t\t\t\thelperText={fieldState.error?.message ?? \"\"}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\t\t\t/>\n\t\t\t<Stack gap={theme.spacing(4)}>\n\t\t\t\t<BulletPointCheck\n\t\t\t\t\ttext={t(\"pages.auth.common.passwordRules.length\")}\n\t\t\t\t\tvariant={getVariant(hasLength)}\n\t\t\t\t/>\n\t\t\t\t<BulletPointCheck\n\t\t\t\t\ttext={t(\"pages.auth.common.passwordRules.special\")}\n\t\t\t\t\tvariant={getVariant(hasSpecial)}\n\t\t\t\t/>\n\t\t\t\t<BulletPointCheck\n\t\t\t\t\ttext={t(\"pages.auth.common.passwordRules.number\")}\n\t\t\t\t\tvariant={getVariant(hasNumber)}\n\t\t\t\t/>\n\t\t\t\t<BulletPointCheck\n\t\t\t\t\ttext={t(\"pages.auth.common.passwordRules.uppercase\")}\n\t\t\t\t\tvariant={getVariant(hasUppercase)}\n\t\t\t\t/>\n\t\t\t\t<BulletPointCheck\n\t\t\t\t\ttext={t(\"pages.auth.common.passwordRules.lowercase\")}\n\t\t\t\t\tvariant={getVariant(hasLowercase)}\n\t\t\t\t/>\n\t\t\t\t<BulletPointCheck\n\t\t\t\t\ttext={t(\"pages.auth.common.passwordRules.match\")}\n\t\t\t\t\tvariant={getVariant(passwordsMatch)}\n\t\t\t\t/>\n\t\t\t</Stack>\n\t\t\t<Button\n\t\t\t\tvariant=\"contained\"\n\t\t\t\ttype=\"submit\"\n\t\t\t\tfullWidth\n\t\t\t\tloading={loading}\n\t\t\t>\n\t\t\t\t{t(\"common.buttons.resetPassword\")}\n\t\t\t</Button>\n\t\t\t<TextLink\n\t\t\t\talignSelf=\"center\"\n\t\t\t\ttext={t(\"pages.auth.forgotPassword.links.login.text\")}\n\t\t\t\tlinkText={t(\"pages.auth.forgotPassword.links.login.linkText\")}\n\t\t\t\thref=\"/login\"\n\t\t\t/>\n\t\t</BaseAuthPage>\n\t);\n};\n\nexport default SetNewPasswordPage;\n"
  },
  {
    "path": "client/src/Pages/Auth/components/HeaderAuthControls.tsx",
    "content": "import Stack, { type StackProps } from \"@mui/material/Stack\";\nimport Typography from \"@mui/material/Typography\";\nimport Logo from \"@/assets/icons/checkmate-icon.svg?react\";\nimport { LanguageSelector, SwitchTheme } from \"@/Components/inputs\";\n\nimport { useTheme } from \"@mui/material/styles\";\nimport { useTranslation } from \"react-i18next\";\n\ninterface HeaderAuthControlsProps extends StackProps {\n\thideLogo?: boolean;\n}\n\nexport const HeaderAuthControls = ({\n\thideLogo = false,\n\t...stackProps\n}: HeaderAuthControlsProps) => {\n\t// Hooks\n\tconst theme = useTheme();\n\tconst { t } = useTranslation();\n\n\treturn (\n\t\t<Stack\n\t\t\twidth={\"100%\"}\n\t\t\tdirection=\"row\"\n\t\t\talignItems=\"center\"\n\t\t\tjustifyContent=\"space-between\"\n\t\t\tpx={theme.spacing(12)}\n\t\t\tgap={theme.spacing(4)}\n\t\t\t{...stackProps}\n\t\t>\n\t\t\t<Stack\n\t\t\t\tdirection=\"row\"\n\t\t\t\talignItems=\"center\"\n\t\t\t\tgap={theme.spacing(4)}\n\t\t\t>\n\t\t\t\t{!hideLogo && (\n\t\t\t\t\t<>\n\t\t\t\t\t\t<Logo style={{ borderRadius: theme.shape.borderRadius }} />\n\t\t\t\t\t\t<Typography sx={{ userSelect: \"none\" }}>{t(\"common.appName\")}</Typography>\n\t\t\t\t\t</>\n\t\t\t\t)}\n\t\t\t</Stack>\n\t\t\t<Stack\n\t\t\t\tdirection=\"row\"\n\t\t\t\tspacing={theme.spacing(2)}\n\t\t\t\talignItems=\"center\"\n\t\t\t>\n\t\t\t\t<LanguageSelector />\n\t\t\t\t<SwitchTheme />\n\t\t\t</Stack>\n\t\t</Stack>\n\t);\n};\n"
  },
  {
    "path": "client/src/Pages/Checks/Components/ChecksTable.tsx",
    "content": "import { Table, Pagination, ValueLabel, StatusLabel } from \"@/Components/design-elements\";\nimport Box from \"@mui/material/Box\";\nimport type { Header } from \"@/Components/design-elements/Table\";\nimport type { Monitor } from \"@/Types/Monitor\";\n\nimport { useTranslation } from \"react-i18next\";\nimport { formatDateWithTz } from \"@/Utils/TimeUtils\";\nimport type { Check } from \"@/Types/Check\";\nimport type { RootState } from \"@/Types/state\";\nimport { useSelector } from \"react-redux\";\n\nexport const ChecksTable = ({\n\tmonitors,\n\tchecks,\n\tchecksCount,\n\tpage,\n\tsetPage,\n\trowsPerPage,\n\tsetRowsPerPage,\n}: {\n\tmonitors: Monitor[] | null;\n\tchecks: Check[];\n\tchecksCount: number;\n\tpage: number;\n\tsetPage: (page: number) => void;\n\trowsPerPage: number;\n\tsetRowsPerPage: (rowsPerPage: number) => void;\n}) => {\n\tconst { t } = useTranslation();\n\tconst uiTimezone = useSelector((state: RootState) => state.ui.timezone);\n\n\tconst getHeaders = (t: Function, uiTimezone: string) => {\n\t\tconst headers: Header<Check>[] = [\n\t\t\t{\n\t\t\t\tid: \"monitorName\",\n\t\t\t\tcontent: t(\"common.table.headers.monitor\"),\n\t\t\t\trender: (row) => {\n\t\t\t\t\treturn (\n\t\t\t\t\t\tmonitors?.find((monitor) => monitor.id === row.metadata.monitorId)?.name ||\n\t\t\t\t\t\t\"N/A\"\n\t\t\t\t\t);\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"status\",\n\t\t\t\tcontent: \"Status\",\n\t\t\t\trender: (row) => {\n\t\t\t\t\treturn <StatusLabel status={row.status === true ? \"up\" : \"down\"} />;\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"date\",\n\t\t\t\tcontent: t(\"common.table.headers.dateTime\"),\n\t\t\t\trender: (row) => {\n\t\t\t\t\treturn formatDateWithTz(\n\t\t\t\t\t\trow.createdAt,\n\t\t\t\t\t\t\"ddd, MMMM D, YYYY, HH:mm A\",\n\t\t\t\t\t\tuiTimezone\n\t\t\t\t\t);\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"statusCode\",\n\t\t\t\tcontent: t(\"pages.checks.table.headers.statusCode\"),\n\t\t\t\trender: (row) => {\n\t\t\t\t\tconst code = row.statusCode;\n\t\t\t\t\tif (!code) return \"N/A\";\n\t\t\t\t\tconst value = code < 300 ? \"positive\" : code < 400 ? \"neutral\" : \"negative\";\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<ValueLabel\n\t\t\t\t\t\t\tvalue={value}\n\t\t\t\t\t\t\ttext={String(code)}\n\t\t\t\t\t\t/>\n\t\t\t\t\t);\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"message\",\n\t\t\t\tcontent: t(\"common.table.headers.message\"),\n\t\t\t\trender: (row) => {\n\t\t\t\t\treturn row.message || \"N/A\";\n\t\t\t\t},\n\t\t\t},\n\t\t];\n\t\treturn headers;\n\t};\n\n\tconst headers = getHeaders(t, uiTimezone);\n\n\tconst handlePageChange = (\n\t\t_e: React.MouseEvent<HTMLButtonElement> | null,\n\t\tnewPage: number\n\t) => {\n\t\tsetPage(newPage);\n\t};\n\n\tconst handleRowsPerPageChange = (\n\t\te: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>\n\t) => {\n\t\tconst value = Number(e.target.value);\n\t\tsetPage(0);\n\t\tsetRowsPerPage(value);\n\t};\n\n\treturn (\n\t\t<Box>\n\t\t\t<Table\n\t\t\t\theaders={headers}\n\t\t\t\tdata={checks}\n\t\t\t\temptyViewText={t(\"pages.checks.table.empty\")}\n\t\t\t/>\n\t\t\t<Pagination\n\t\t\t\tcomponent=\"div\"\n\t\t\t\tcount={checksCount}\n\t\t\t\tpage={page}\n\t\t\t\trowsPerPage={rowsPerPage}\n\t\t\t\tonPageChange={handlePageChange}\n\t\t\t\tonRowsPerPageChange={handleRowsPerPageChange}\n\t\t\t/>\n\t\t</Box>\n\t);\n};\n"
  },
  {
    "path": "client/src/Pages/Checks/index.tsx",
    "content": "import Stack from \"@mui/material/Stack\";\nimport {\n\tBasePage,\n\tTotalChecksBox,\n\tUpChecksBox,\n\tDownChecksBox,\n} from \"@/Components/design-elements\";\nimport { HeaderTimeRange } from \"@/Components/common\";\nimport { Select } from \"@/Components/inputs\";\nimport { ChecksTable } from \"./Components/ChecksTable\";\n\nimport { MenuItem } from \"@mui/material\";\nimport { useTranslation } from \"react-i18next\";\nimport { useState, useMemo } from \"react\";\nimport { useParams } from \"react-router-dom\";\nimport { useGet } from \"@/Hooks/UseApi\";\nimport type { Monitor } from \"@/Types/Monitor\";\nimport type { ChecksSummary, ChecksResponse } from \"@/Types/Check\";\n\nconst Checks = () => {\n\tconst { t } = useTranslation();\n\tconst { monitorId } = useParams<{ monitorId?: string }>();\n\n\tconst [selectedMonitor, setSelectedMonitor] = useState<string>(monitorId || \"0\");\n\tconst [dateRange, setDateRange] = useState<string>(\"recent\");\n\tconst [statusFilter, setStatusFilter] = useState<string>(\"down\");\n\tconst [page, setPage] = useState<number>(0);\n\tconst [rowsPerPage, setRowsPerPage] = useState<number>(10);\n\n\tconst monitorsUrl = \"/monitors/team\";\n\tconst summaryUrl = `/checks/team/summary?dateRange=${dateRange}`;\n\n\tconst { data: monitorsResponse, isLoading: isLoadingMonitors } =\n\t\tuseGet<Monitor[]>(monitorsUrl);\n\n\tconst { data: summaryResponse, isLoading: isLoadingSummary } =\n\t\tuseGet<ChecksSummary>(summaryUrl);\n\n\tconst selectedMonitorType = monitorsResponse?.find(\n\t\t(m) => m.id === selectedMonitor\n\t)?.type;\n\n\tconst teamChecksUrl = useMemo(() => {\n\t\tif (selectedMonitor !== \"0\") return null;\n\t\tconst params = new URLSearchParams();\n\t\tparams.append(\"sortOrder\", \"desc\");\n\t\tif (dateRange) params.append(\"dateRange\", dateRange);\n\t\tif (statusFilter) params.append(\"filter\", statusFilter);\n\t\tparams.append(\"page\", String(page));\n\t\tparams.append(\"rowsPerPage\", String(rowsPerPage));\n\t\treturn `/checks/team?${params.toString()}`;\n\t}, [selectedMonitor, dateRange, statusFilter, page, rowsPerPage]);\n\n\tconst monitorChecksUrl = useMemo(() => {\n\t\tif (selectedMonitor === \"0\" || !selectedMonitorType) return null;\n\t\tconst params = new URLSearchParams();\n\t\tparams.append(\"type\", selectedMonitorType);\n\t\tparams.append(\"sortOrder\", \"desc\");\n\t\tif (statusFilter) params.append(\"filter\", statusFilter);\n\t\tif (dateRange) params.append(\"dateRange\", dateRange);\n\t\tparams.append(\"page\", String(page));\n\t\tparams.append(\"rowsPerPage\", String(rowsPerPage));\n\t\treturn `/checks/${selectedMonitor}?${params.toString()}`;\n\t}, [selectedMonitor, selectedMonitorType, dateRange, statusFilter, page, rowsPerPage]);\n\n\tconst {\n\t\tdata: teamChecksData,\n\t\tisLoading: isLoadingTeamChecks,\n\t\tisValidating: isValidatingTeamChecks,\n\t} = useGet<ChecksResponse>(\n\t\tteamChecksUrl,\n\t\t{},\n\t\t{ keepPreviousData: true, refreshInterval: 30000 }\n\t);\n\tconst {\n\t\tdata: monitorChecksData,\n\t\tisLoading: isLoadingMonitorChecks,\n\t\tisValidating: isValidatingMonitorChecks,\n\t} = useGet<ChecksResponse>(\n\t\tmonitorChecksUrl,\n\t\t{},\n\t\t{ keepPreviousData: true, refreshInterval: 30000 }\n\t);\n\n\tconst checks =\n\t\tselectedMonitor === \"0\"\n\t\t\t? (teamChecksData?.checks ?? [])\n\t\t\t: (monitorChecksData?.checks ?? []);\n\tconst checksCount =\n\t\tselectedMonitor === \"0\"\n\t\t\t? (teamChecksData?.checksCount ?? 0)\n\t\t\t: (monitorChecksData?.checksCount ?? 0);\n\n\tconst isLoadingChecks =\n\t\tisLoadingTeamChecks ||\n\t\tisLoadingMonitorChecks ||\n\t\tisValidatingTeamChecks ||\n\t\tisValidatingMonitorChecks;\n\n\tconst isLoading = isLoadingMonitors || isLoadingSummary || isLoadingChecks;\n\tconst totalChecks = summaryResponse?.totalChecks || 0;\n\tconst downChecks = summaryResponse?.downChecks || 0;\n\tconst upChecks = totalChecks - (summaryResponse?.downChecks || 0);\n\n\treturn (\n\t\t<BasePage>\n\t\t\t<Stack\n\t\t\t\tdirection={{ xs: \"column\", md: \"row\" }}\n\t\t\t\tgap={4}\n\t\t\t>\n\t\t\t\t<TotalChecksBox n={totalChecks} />\n\t\t\t\t<UpChecksBox n={upChecks} />\n\t\t\t\t<DownChecksBox n={downChecks || 0} />\n\t\t\t</Stack>\n\n\t\t\t<Stack\n\t\t\t\tdirection={{ xs: \"column\", md: \"row\" }}\n\t\t\t\tjustifyContent=\"space-between\"\n\t\t\t\talignItems={{ xs: \"stretch\", md: \"center\" }}\n\t\t\t\tgap={2}\n\t\t\t>\n\t\t\t\t<Stack\n\t\t\t\t\tgap={2}\n\t\t\t\t\tdirection={{ xs: \"column\", md: \"row\" }}\n\t\t\t\t>\n\t\t\t\t\t<Select\n\t\t\t\t\t\tfullWidth\n\t\t\t\t\t\tvalue={selectedMonitor}\n\t\t\t\t\t\tonChange={(e: any) => {\n\t\t\t\t\t\t\tsetSelectedMonitor(e.target.value);\n\t\t\t\t\t\t\tsetPage(0);\n\t\t\t\t\t\t}}\n\t\t\t\t\t>\n\t\t\t\t\t\t<MenuItem value=\"0\">{t(\"pages.checks.selects.monitor.all\")}</MenuItem>\n\t\t\t\t\t\t{monitorsResponse?.map((monitor) => (\n\t\t\t\t\t\t\t<MenuItem\n\t\t\t\t\t\t\t\tkey={monitor.id}\n\t\t\t\t\t\t\t\tvalue={monitor.id}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{monitor.name}\n\t\t\t\t\t\t\t</MenuItem>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</Select>\n\t\t\t\t\t<Select\n\t\t\t\t\t\tvalue={statusFilter}\n\t\t\t\t\t\tonChange={(e: any) => {\n\t\t\t\t\t\t\tsetStatusFilter(e.target.value);\n\t\t\t\t\t\t\tsetPage(0);\n\t\t\t\t\t\t}}\n\t\t\t\t\t>\n\t\t\t\t\t\t<MenuItem value=\"all\">{t(\"pages.checks.selects.status.all\")}</MenuItem>\n\t\t\t\t\t\t<MenuItem value=\"up\">{t(\"pages.checks.selects.status.up\")}</MenuItem>\n\t\t\t\t\t\t<MenuItem value=\"down\">{t(\"pages.checks.selects.status.down\")}</MenuItem>\n\t\t\t\t\t</Select>\n\t\t\t\t</Stack>\n\t\t\t\t<HeaderTimeRange\n\t\t\t\t\tisLoading={isLoading || isLoadingChecks}\n\t\t\t\t\tdateRange={dateRange}\n\t\t\t\t\tsetDateRange={setDateRange}\n\t\t\t\t/>\n\t\t\t</Stack>\n\n\t\t\t<ChecksTable\n\t\t\t\tmonitors={monitorsResponse ?? null}\n\t\t\t\tchecks={checks}\n\t\t\t\tchecksCount={checksCount}\n\t\t\t\tpage={page}\n\t\t\t\tsetPage={setPage}\n\t\t\t\trowsPerPage={rowsPerPage}\n\t\t\t\tsetRowsPerPage={setRowsPerPage}\n\t\t\t/>\n\t\t</BasePage>\n\t);\n};\n\nexport default Checks;\n"
  },
  {
    "path": "client/src/Pages/CreateMonitor/index.tsx",
    "content": "import { useMemo, useState } from \"react\";\nimport { useEffect } from \"react\";\nimport { logger } from \"@/Utils/logger\";\nimport { useParams, useLocation, useNavigate } from \"react-router\";\nimport { useForm, Controller } from \"react-hook-form\";\nimport { zodResolver } from \"@hookform/resolvers/zod\";\nimport { useTheme } from \"@mui/material\";\nimport Stack from \"@mui/material/Stack\";\nimport RadioGroup from \"@mui/material/RadioGroup\";\nimport FormControl from \"@mui/material/FormControl\";\nimport { Trans, useTranslation } from \"react-i18next\";\nimport MenuItem from \"@mui/material/MenuItem\";\nimport Typography from \"@mui/material/Typography\";\nimport Link from \"@mui/material/Link\";\nimport Divider from \"@mui/material/Divider\";\nimport IconButton from \"@mui/material/IconButton\";\nimport { Trash2 } from \"lucide-react\";\nimport { HeaderDeleteControls } from \"@/Components/monitors\";\nimport { GeoContinents } from \"@/Types/GeoCheck\";\n\nimport { BasePage, ConfigBox } from \"@/Components/design-elements\";\nimport {\n\tRadioWithDescription,\n\tButton,\n\tTextField,\n\tSelect,\n\tAutocomplete,\n\tSwitchComponent as Switch,\n\tSliderWithLabel,\n\tDialog,\n} from \"@/Components/inputs\";\nimport { SPACING, LAYOUT } from \"@/Utils/Theme/constants\";\nimport { useGet, usePost, usePatch, useDelete } from \"@/Hooks/UseApi\";\nimport { useMonitorForm } from \"@/Hooks/useMonitorForm\";\nimport {\n\ttype Monitor,\n\ttype MonitorType,\n\ttype GamesMap,\n\tsupportsGeoCheck,\n} from \"@/Types/Monitor\";\nimport type { Notification } from \"@/Types/Notification\";\nimport type { MonitorFormData } from \"@/Validation/monitor\";\n\ninterface GeneralSettingsConfig {\n\turlLabel: string;\n\turlPlaceholder: string;\n\tnamePlaceholder: string;\n\tshowUrl: boolean;\n\tshowPort: boolean;\n\tshowGameSelect: boolean;\n\tshowSecret: boolean;\n\tshowGrpcServiceName: boolean;\n\tshowIgnoreTls: boolean;\n}\n\nconst getGeneralSettingsConfig = (\n\ttype: MonitorType,\n\tt: (key: string) => string\n): GeneralSettingsConfig => {\n\tconst configs: Record<string, GeneralSettingsConfig> = {\n\t\thttp: {\n\t\t\turlLabel: t(\"pages.createMonitor.form.general.option.url.label\"),\n\t\t\turlPlaceholder: t(\"pages.createMonitor.form.general.option.url.placeholder\"),\n\t\t\tnamePlaceholder: t(\"pages.createMonitor.form.general.option.name.placeholder\"),\n\t\t\tshowUrl: true,\n\t\t\tshowPort: false,\n\t\t\tshowGameSelect: false,\n\t\t\tshowSecret: false,\n\t\t\tshowGrpcServiceName: false,\n\t\t\tshowIgnoreTls: false,\n\t\t},\n\t\tping: {\n\t\t\turlLabel: t(\"pages.createMonitor.form.general.option.host.label\"),\n\t\t\turlPlaceholder: t(\"pages.createMonitor.form.general.option.host.placeholder\"),\n\t\t\tnamePlaceholder: t(\"pages.createMonitor.form.general.option.name.placeholder\"),\n\t\t\tshowUrl: true,\n\t\t\tshowPort: false,\n\t\t\tshowGameSelect: false,\n\t\t\tshowSecret: false,\n\t\t\tshowGrpcServiceName: false,\n\t\t\tshowIgnoreTls: false,\n\t\t},\n\t\tdocker: {\n\t\t\turlLabel: t(\"pages.createMonitor.form.general.option.container.label\"),\n\t\t\turlPlaceholder: t(\"pages.createMonitor.form.general.option.container.placeholder\"),\n\t\t\tnamePlaceholder: t(\"pages.createMonitor.form.general.option.name.placeholder\"),\n\t\t\tshowUrl: true,\n\t\t\tshowPort: false,\n\t\t\tshowGameSelect: false,\n\t\t\tshowSecret: false,\n\t\t\tshowGrpcServiceName: false,\n\t\t\tshowIgnoreTls: false,\n\t\t},\n\t\tport: {\n\t\t\turlLabel: t(\"pages.createMonitor.form.general.option.url.label\"),\n\t\t\turlPlaceholder: t(\"pages.createMonitor.form.general.option.url.placeholder\"),\n\t\t\tnamePlaceholder: t(\"pages.createMonitor.form.general.option.name.placeholder\"),\n\t\t\tshowUrl: true,\n\t\t\tshowPort: true,\n\t\t\tshowGameSelect: false,\n\t\t\tshowSecret: false,\n\t\t\tshowGrpcServiceName: false,\n\t\t\tshowIgnoreTls: false,\n\t\t},\n\t\tgame: {\n\t\t\turlLabel: t(\"pages.createMonitor.form.general.option.url.label\"),\n\t\t\turlPlaceholder: t(\"pages.createMonitor.form.general.option.url.placeholder\"),\n\t\t\tnamePlaceholder: t(\"pages.createMonitor.form.general.option.name.placeholder\"),\n\t\t\tshowUrl: true,\n\t\t\tshowPort: true,\n\t\t\tshowGameSelect: true,\n\t\t\tshowSecret: false,\n\t\t\tshowGrpcServiceName: false,\n\t\t\tshowIgnoreTls: false,\n\t\t},\n\t\tgrpc: {\n\t\t\turlLabel: t(\"pages.createMonitor.form.general.option.host.label\"),\n\t\t\turlPlaceholder: t(\"pages.createMonitor.form.general.option.host.placeholder\"),\n\t\t\tnamePlaceholder: t(\"pages.createMonitor.form.general.option.name.placeholder\"),\n\t\t\tshowUrl: true,\n\t\t\tshowPort: true,\n\t\t\tshowGameSelect: false,\n\t\t\tshowSecret: false,\n\t\t\tshowGrpcServiceName: true,\n\t\t\tshowIgnoreTls: true,\n\t\t},\n\t\tpagespeed: {\n\t\t\turlLabel: t(\"pages.createMonitor.form.general.option.url.label\"),\n\t\t\turlPlaceholder: t(\"pages.createMonitor.form.general.option.url.placeholder\"),\n\t\t\tnamePlaceholder: t(\"pages.createMonitor.form.general.option.name.placeholder\"),\n\t\t\tshowUrl: true,\n\t\t\tshowPort: false,\n\t\t\tshowGameSelect: false,\n\t\t\tshowSecret: false,\n\t\t\tshowGrpcServiceName: false,\n\t\t\tshowIgnoreTls: false,\n\t\t},\n\t\thardware: {\n\t\t\turlLabel: t(\"pages.createMonitor.form.general.option.url.label\"),\n\t\t\turlPlaceholder: t(\"pages.createMonitor.form.general.option.url.placeholder\"),\n\t\t\tnamePlaceholder: t(\"pages.createMonitor.form.general.option.name.placeholder\"),\n\t\t\tshowUrl: true,\n\t\t\tshowPort: false,\n\t\t\tshowGameSelect: false,\n\t\t\tshowSecret: true,\n\t\t\tshowGrpcServiceName: false,\n\t\t\tshowIgnoreTls: false,\n\t\t},\n\t\twebsocket: {\n\t\t\turlLabel: t(\"pages.createMonitor.form.general.option.wsUrl.label\"),\n\t\t\turlPlaceholder: t(\"pages.createMonitor.form.general.option.wsUrl.placeholder\"),\n\t\t\tnamePlaceholder: t(\"pages.createMonitor.form.general.option.name.placeholder\"),\n\t\t\tshowUrl: true,\n\t\t\tshowPort: false,\n\t\t\tshowGameSelect: false,\n\t\t\tshowSecret: false,\n\t\t\tshowGrpcServiceName: false,\n\t\t\tshowIgnoreTls: true,\n\t\t},\n\t};\n\treturn configs[type] || configs.http;\n};\n\nconst CreateMonitorPage = () => {\n\tconst theme = useTheme();\n\tconst { t } = useTranslation();\n\tconst { monitorId } = useParams();\n\tconst location = useLocation();\n\tconst navigate = useNavigate();\n\tconst isEditMode = Boolean(monitorId);\n\n\t// Extract page type from URL path (e.g., /pagespeed/create -> pagespeed)\n\tconst pageType = useMemo(() => {\n\t\tconst pathSegments = location.pathname.split(\"/\").filter(Boolean);\n\t\tconst firstSegment = pathSegments[0];\n\t\tif (firstSegment === \"pagespeed\") return \"pagespeed\";\n\t\tif (firstSegment === \"infrastructure\") return \"hardware\";\n\t\treturn \"uptime\";\n\t}, [location.pathname]);\n\n\tconst showTypeSelector = pageType === \"uptime\" && !isEditMode;\n\tconst defaultType: MonitorType =\n\t\tpageType === \"pagespeed\"\n\t\t\t? \"pagespeed\"\n\t\t\t: pageType === \"hardware\"\n\t\t\t\t? \"hardware\"\n\t\t\t\t: \"http\";\n\n\tconst { data: existingMonitor, refetch: refetchMonitor } = useGet<Monitor>(\n\t\tisEditMode ? `/monitors/${monitorId}` : null\n\t);\n\n\tconst { data: notifications } = useGet<Notification[]>(\"/notifications/team\");\n\tconst { data: games } = useGet<GamesMap>(\"/monitors/games\");\n\n\tconst { schema, defaults } = useMonitorForm({\n\t\tdata: existingMonitor ?? null,\n\t\tdefaultType,\n\t});\n\n\tconst form = useForm<MonitorFormData>({\n\t\tresolver: zodResolver(schema),\n\t\tdefaultValues: defaults,\n\t});\n\tconst { control, watch, handleSubmit, clearErrors } = form;\n\n\tuseEffect(() => {\n\t\tform.reset(defaults);\n\t}, [defaults, form]);\n\n\tconst watchedType = watch(\"type\") as MonitorType;\n\n\tconst watchedUseAdvancedMatching = watch(\"useAdvancedMatching\") as boolean;\n\tconst watchGeoCheckEnabled = watch(\"geoCheckEnabled\") as boolean;\n\n\tuseEffect(() => {\n\t\tclearErrors();\n\t}, [watchedType, clearErrors]);\n\n\tconst generalSettingsConfig = useMemo(\n\t\t() => getGeneralSettingsConfig(watchedType, t),\n\t\t[watchedType, t]\n\t);\n\n\tconst { post, loading: isCreating } = usePost<MonitorFormData, Monitor>();\n\tconst { patch, loading: isUpdating } = usePatch<MonitorFormData, Monitor>();\n\tconst isSubmitting = isCreating || isUpdating;\n\t// Delete functionality\n\tconst [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false);\n\tconst { deleteFn, loading: isDeleting } = useDelete();\n\n\tconst handleDeleteClick = () => {\n\t\tsetIsDeleteDialogOpen(true);\n\t};\n\n\tconst handleDeleteConfirm = async () => {\n\t\tif (!monitorId) return;\n\t\tawait deleteFn(`/monitors/${monitorId}`);\n\t\tsetIsDeleteDialogOpen(false);\n\t\t// Navigate based on page type\n\t\tif (pageType === \"pagespeed\") {\n\t\t\tnavigate(\"/pagespeed\");\n\t\t} else if (pageType === \"hardware\") {\n\t\t\tnavigate(\"/infrastructure\");\n\t\t} else {\n\t\t\tnavigate(\"/uptime\");\n\t\t}\n\t};\n\n\tconst handleDeleteCancel = () => {\n\t\tsetIsDeleteDialogOpen(false);\n\t};\n\n\tconst onSubmit = async (data: MonitorFormData) => {\n\t\tlet result;\n\t\tif (isEditMode && monitorId) {\n\t\t\tresult = await patch(`/monitors/${monitorId}`, data);\n\t\t} else {\n\t\t\tresult = await post(\"/monitors\", data);\n\t\t}\n\n\t\tif (result?.success) {\n\t\t\tif (pageType === \"pagespeed\") {\n\t\t\t\tnavigate(\"/pagespeed\");\n\t\t\t} else if (pageType === \"hardware\") {\n\t\t\t\tnavigate(\"/infrastructure\");\n\t\t\t} else {\n\t\t\t\tnavigate(\"/uptime\");\n\t\t\t}\n\t\t}\n\t};\n\n\tconst onError = (errors: unknown) => {\n\t\tlogger.debug(\"Monitor creation validation errors\", errors);\n\t};\n\n\treturn (\n\t\t<BasePage\n\t\t\tcomponent=\"form\"\n\t\t\tonSubmit={handleSubmit(onSubmit, onError)}\n\t\t>\n\t\t\t<HeaderDeleteControls\n\t\t\t\tmonitor={existingMonitor}\n\t\t\t\tisAdmin={true}\n\t\t\t\trefetch={refetchMonitor}\n\t\t\t\tonDelete={handleDeleteClick}\n\t\t\t/>\n\t\t\t{/* Monitor Type Selection - only shown for uptime monitors */}\n\t\t\t{showTypeSelector && (\n\t\t\t\t<ConfigBox\n\t\t\t\t\ttitle={t(\"pages.createMonitor.form.type.title\")}\n\t\t\t\t\tsubtitle={t(\"pages.createMonitor.form.type.description\")}\n\t\t\t\t\trightContent={\n\t\t\t\t\t\t<Controller\n\t\t\t\t\t\t\tname=\"type\"\n\t\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\t\trender={({ field, fieldState }) => (\n\t\t\t\t\t\t\t\t<FormControl error={!!fieldState.error}>\n\t\t\t\t\t\t\t\t\t<RadioGroup\n\t\t\t\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\t\t\t\tsx={{ gap: theme.spacing(LAYOUT.MD) }}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<RadioWithDescription\n\t\t\t\t\t\t\t\t\t\t\tvalue=\"http\"\n\t\t\t\t\t\t\t\t\t\t\tlabel={t(\"pages.common.monitors.monitorTypes.optionHttp\")}\n\t\t\t\t\t\t\t\t\t\t\tdescription={t(\n\t\t\t\t\t\t\t\t\t\t\t\t\"pages.createMonitor.form.type.optionHttpDescription\"\n\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t<RadioWithDescription\n\t\t\t\t\t\t\t\t\t\t\tvalue=\"ping\"\n\t\t\t\t\t\t\t\t\t\t\tlabel={t(\"pages.common.monitors.monitorTypes.optionPing\")}\n\t\t\t\t\t\t\t\t\t\t\tdescription={t(\n\t\t\t\t\t\t\t\t\t\t\t\t\"pages.createMonitor.form.type.optionPingDescription\"\n\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t<RadioWithDescription\n\t\t\t\t\t\t\t\t\t\t\tvalue=\"docker\"\n\t\t\t\t\t\t\t\t\t\t\tlabel={t(\"pages.common.monitors.monitorTypes.optionDocker\")}\n\t\t\t\t\t\t\t\t\t\t\tdescription={t(\n\t\t\t\t\t\t\t\t\t\t\t\t\"pages.createMonitor.form.type.optionDockerDescription\"\n\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t<RadioWithDescription\n\t\t\t\t\t\t\t\t\t\t\tvalue=\"port\"\n\t\t\t\t\t\t\t\t\t\t\tlabel={t(\"pages.common.monitors.monitorTypes.optionPort\")}\n\t\t\t\t\t\t\t\t\t\t\tdescription={t(\n\t\t\t\t\t\t\t\t\t\t\t\t\"pages.createMonitor.form.type.optionPortDescription\"\n\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t<RadioWithDescription\n\t\t\t\t\t\t\t\t\t\t\tvalue=\"game\"\n\t\t\t\t\t\t\t\t\t\t\tlabel={t(\"pages.common.monitors.monitorTypes.optionGame\")}\n\t\t\t\t\t\t\t\t\t\t\tdescription={t(\n\t\t\t\t\t\t\t\t\t\t\t\t\"pages.createMonitor.form.type.optionGameDescription\"\n\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t<RadioWithDescription\n\t\t\t\t\t\t\t\t\t\t\tvalue=\"grpc\"\n\t\t\t\t\t\t\t\t\t\t\tlabel={t(\"pages.common.monitors.monitorTypes.optionGrpc\")}\n\t\t\t\t\t\t\t\t\t\t\tdescription={t(\n\t\t\t\t\t\t\t\t\t\t\t\t\"pages.createMonitor.form.type.optionGrpcDescription\"\n\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t<RadioWithDescription\n\t\t\t\t\t\t\t\t\t\t\tvalue=\"websocket\"\n\t\t\t\t\t\t\t\t\t\t\tlabel={t(\"pages.common.monitors.monitorTypes.optionWebSocket\")}\n\t\t\t\t\t\t\t\t\t\t\tdescription={t(\n\t\t\t\t\t\t\t\t\t\t\t\t\"pages.createMonitor.form.type.optionWebSocketDescription\"\n\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t</RadioGroup>\n\t\t\t\t\t\t\t\t</FormControl>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t/>\n\t\t\t\t\t}\n\t\t\t\t/>\n\t\t\t)}\n\n\t\t\t<ConfigBox\n\t\t\t\ttitle={t(\"pages.createMonitor.form.general.title\")}\n\t\t\t\tsubtitle={t(`pages.createMonitor.form.general.description.${watchedType}`)}\n\t\t\t\trightContent={\n\t\t\t\t\t<Stack spacing={theme.spacing(LAYOUT.MD)}>\n\t\t\t\t\t\t{/* URL/Host/Container field - not shown for hardware */}\n\t\t\t\t\t\t{generalSettingsConfig.showUrl && (\n\t\t\t\t\t\t\t<Controller\n\t\t\t\t\t\t\t\tname=\"url\"\n\t\t\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\t\t\trender={({ field, fieldState }) => (\n\t\t\t\t\t\t\t\t\t<TextField\n\t\t\t\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\t\t\t\ttype=\"text\"\n\t\t\t\t\t\t\t\t\t\tfieldLabel={generalSettingsConfig.urlLabel}\n\t\t\t\t\t\t\t\t\t\tplaceholder={generalSettingsConfig.urlPlaceholder}\n\t\t\t\t\t\t\t\t\t\tfullWidth\n\t\t\t\t\t\t\t\t\t\tdisabled={isEditMode}\n\t\t\t\t\t\t\t\t\t\terror={!!fieldState.error}\n\t\t\t\t\t\t\t\t\t\thelperText={fieldState.error?.message ?? \"\"}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t)}\n\n\t\t\t\t\t\t{/* Port field - only for port and game types */}\n\t\t\t\t\t\t{generalSettingsConfig.showPort && (\n\t\t\t\t\t\t\t<Controller\n\t\t\t\t\t\t\t\tname=\"port\"\n\t\t\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\t\t\trender={({ field, fieldState }) => (\n\t\t\t\t\t\t\t\t\t<TextField\n\t\t\t\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\t\t\t\tvalue={field.value === 0 ? \"\" : field.value}\n\t\t\t\t\t\t\t\t\t\tonChange={(e) => {\n\t\t\t\t\t\t\t\t\t\t\tconst val = e.target.value;\n\t\t\t\t\t\t\t\t\t\t\tfield.onChange(val === \"\" ? 0 : Number(val));\n\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\ttype=\"number\"\n\t\t\t\t\t\t\t\t\t\tfieldLabel={t(\"pages.createMonitor.form.general.option.port.label\")}\n\t\t\t\t\t\t\t\t\t\tplaceholder={t(\n\t\t\t\t\t\t\t\t\t\t\t\"pages.createMonitor.form.general.option.port.placeholder\"\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\tfullWidth\n\t\t\t\t\t\t\t\t\t\terror={!!fieldState.error}\n\t\t\t\t\t\t\t\t\t\thelperText={fieldState.error?.message ?? \"\"}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t)}\n\n\t\t\t\t\t\t{/* Game select - only for game type */}\n\t\t\t\t\t\t{generalSettingsConfig.showGameSelect && (\n\t\t\t\t\t\t\t<Controller\n\t\t\t\t\t\t\t\tname=\"gameId\"\n\t\t\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\t\t\trender={({ field, fieldState }) => (\n\t\t\t\t\t\t\t\t\t<Select\n\t\t\t\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\t\t\t\tvalue={field.value ?? \"\"}\n\t\t\t\t\t\t\t\t\t\tfieldLabel={t(\"pages.createMonitor.form.general.option.game.label\")}\n\t\t\t\t\t\t\t\t\t\terror={!!fieldState.error}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<MenuItem value=\"\">\n\t\t\t\t\t\t\t\t\t\t\t{t(\"pages.createMonitor.form.general.option.game.placeholder\")}{\" \"}\n\t\t\t\t\t\t\t\t\t\t</MenuItem>\n\t\t\t\t\t\t\t\t\t\t{games &&\n\t\t\t\t\t\t\t\t\t\t\tObject.entries(games).map(([key, game]) => (\n\t\t\t\t\t\t\t\t\t\t\t\t<MenuItem\n\t\t\t\t\t\t\t\t\t\t\t\t\tkey={key}\n\t\t\t\t\t\t\t\t\t\t\t\t\tvalue={key}\n\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t{game.name}\n\t\t\t\t\t\t\t\t\t\t\t\t</MenuItem>\n\t\t\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t\t</Select>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t)}\n\n\t\t\t\t\t\t{/* gRPC Service Name field - only for grpc type */}\n\t\t\t\t\t\t{generalSettingsConfig.showGrpcServiceName && (\n\t\t\t\t\t\t\t<Controller\n\t\t\t\t\t\t\t\tname=\"grpcServiceName\"\n\t\t\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\t\t\trender={({ field, fieldState }) => (\n\t\t\t\t\t\t\t\t\t<TextField\n\t\t\t\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\t\t\t\tvalue={field.value ?? \"\"}\n\t\t\t\t\t\t\t\t\t\ttype=\"text\"\n\t\t\t\t\t\t\t\t\t\tfieldLabel={t(\n\t\t\t\t\t\t\t\t\t\t\t\"pages.createMonitor.form.general.option.grpcServiceName.label\"\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\tplaceholder={t(\n\t\t\t\t\t\t\t\t\t\t\t\"pages.createMonitor.form.general.option.grpcServiceName.placeholder\"\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\tfullWidth\n\t\t\t\t\t\t\t\t\t\terror={!!fieldState.error}\n\t\t\t\t\t\t\t\t\t\thelperText={fieldState.error?.message ?? \"\"}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t)}\n\n\t\t\t\t\t\t{/* Secret field - only for hardware type */}\n\t\t\t\t\t\t{generalSettingsConfig.showSecret && (\n\t\t\t\t\t\t\t<Controller\n\t\t\t\t\t\t\t\tname=\"secret\"\n\t\t\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\t\t\trender={({ field, fieldState }) => (\n\t\t\t\t\t\t\t\t\t<TextField\n\t\t\t\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\t\t\t\tvalue={field.value ?? \"\"}\n\t\t\t\t\t\t\t\t\t\ttype=\"text\"\n\t\t\t\t\t\t\t\t\t\tfieldLabel={t(\"pages.createMonitor.form.general.option.secret.label\")}\n\t\t\t\t\t\t\t\t\t\tplaceholder={t(\n\t\t\t\t\t\t\t\t\t\t\t\"pages.createMonitor.form.general.option.secret.placeholder\"\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\tfullWidth\n\t\t\t\t\t\t\t\t\t\terror={!!fieldState.error}\n\t\t\t\t\t\t\t\t\t\thelperText={fieldState.error?.message ?? \"\"}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t)}\n\n\t\t\t\t\t\t<Controller\n\t\t\t\t\t\t\tname=\"name\"\n\t\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\t\trender={({ field, fieldState }) => (\n\t\t\t\t\t\t\t\t<TextField\n\t\t\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\t\t\ttype=\"text\"\n\t\t\t\t\t\t\t\t\tfieldLabel={t(\"pages.createMonitor.form.general.option.name.label\")}\n\t\t\t\t\t\t\t\t\tplaceholder={generalSettingsConfig.namePlaceholder}\n\t\t\t\t\t\t\t\t\tfullWidth\n\t\t\t\t\t\t\t\t\terror={!!fieldState.error}\n\t\t\t\t\t\t\t\t\thelperText={fieldState.error?.message ?? \"\"}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</Stack>\n\t\t\t\t}\n\t\t\t/>\n\n\t\t\t<ConfigBox\n\t\t\t\ttitle={t(\"pages.createMonitor.form.frequency.title\")}\n\t\t\t\tsubtitle={t(\"pages.createMonitor.form.frequency.description\")}\n\t\t\t\trightContent={\n\t\t\t\t\t<Controller\n\t\t\t\t\t\tname=\"interval\"\n\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\trender={({ field, fieldState }) => (\n\t\t\t\t\t\t\t<Select\n\t\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\t\tvalue={field.value ?? 60000}\n\t\t\t\t\t\t\t\tfieldLabel={t(\n\t\t\t\t\t\t\t\t\t\"pages.createMonitor.form.frequency.option.frequency.label\"\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\terror={!!fieldState.error}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<MenuItem value={15000}>\n\t\t\t\t\t\t\t\t\t{t(\n\t\t\t\t\t\t\t\t\t\t\"pages.createMonitor.form.frequency.option.frequency.value.fifteenSeconds\"\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t</MenuItem>\n\t\t\t\t\t\t\t\t<MenuItem value={30000}>\n\t\t\t\t\t\t\t\t\t{t(\n\t\t\t\t\t\t\t\t\t\t\"pages.createMonitor.form.frequency.option.frequency.value.thirtySeconds\"\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t</MenuItem>\n\t\t\t\t\t\t\t\t<MenuItem value={60000}>\n\t\t\t\t\t\t\t\t\t{t(\n\t\t\t\t\t\t\t\t\t\t\"pages.createMonitor.form.frequency.option.frequency.value.oneMinute\"\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t</MenuItem>\n\t\t\t\t\t\t\t\t<MenuItem value={120000}>\n\t\t\t\t\t\t\t\t\t{t(\n\t\t\t\t\t\t\t\t\t\t\"pages.createMonitor.form.frequency.option.frequency.value.twoMinutes\"\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t</MenuItem>\n\t\t\t\t\t\t\t\t<MenuItem value={180000}>\n\t\t\t\t\t\t\t\t\t{t(\n\t\t\t\t\t\t\t\t\t\t\"pages.createMonitor.form.frequency.option.frequency.value.threeMinutes\"\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t</MenuItem>\n\t\t\t\t\t\t\t\t<MenuItem value={240000}>\n\t\t\t\t\t\t\t\t\t{t(\n\t\t\t\t\t\t\t\t\t\t\"pages.createMonitor.form.frequency.option.frequency.value.fourMinutes\"\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t</MenuItem>\n\t\t\t\t\t\t\t\t<MenuItem value={300000}>\n\t\t\t\t\t\t\t\t\t{t(\n\t\t\t\t\t\t\t\t\t\t\"pages.createMonitor.form.frequency.option.frequency.value.fiveMinutes\"\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t</MenuItem>\n\t\t\t\t\t\t\t\t<MenuItem value={600000}>\n\t\t\t\t\t\t\t\t\t{t(\n\t\t\t\t\t\t\t\t\t\t\"pages.createMonitor.form.frequency.option.frequency.value.tenMinutes\"\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t</MenuItem>\n\t\t\t\t\t\t\t\t<MenuItem value={900000}>\n\t\t\t\t\t\t\t\t\t{t(\n\t\t\t\t\t\t\t\t\t\t\"pages.createMonitor.form.frequency.option.frequency.value.fifteenMinutes\"\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t</MenuItem>\n\t\t\t\t\t\t\t\t<MenuItem value={1800000}>\n\t\t\t\t\t\t\t\t\t{t(\n\t\t\t\t\t\t\t\t\t\t\"pages.createMonitor.form.frequency.option.frequency.value.thirtyMinutes\"\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t</MenuItem>\n\t\t\t\t\t\t\t</Select>\n\t\t\t\t\t\t)}\n\t\t\t\t\t/>\n\t\t\t\t}\n\t\t\t/>\n\n\t\t\t{/* Alert Thresholds - only for hardware type */}\n\t\t\t{generalSettingsConfig.showSecret && (\n\t\t\t\t<ConfigBox\n\t\t\t\t\ttitle={t(\"pages.createMonitor.form.thresholds.title\")}\n\t\t\t\t\tsubtitle={t(\"pages.createMonitor.form.thresholds.description\")}\n\t\t\t\t\trightContent={\n\t\t\t\t\t\t<Stack spacing={theme.spacing(LAYOUT.MD)}>\n\t\t\t\t\t\t\t<Controller\n\t\t\t\t\t\t\t\tname=\"cpuAlertThreshold\"\n\t\t\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\t\t\trender={({ field }) => (\n\t\t\t\t\t\t\t\t\t<SliderWithLabel\n\t\t\t\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\t\t\t\tsliderMaxWidth={{ xs: \"100%\", md: \"50%\" }}\n\t\t\t\t\t\t\t\t\t\tfieldLabel={t(\n\t\t\t\t\t\t\t\t\t\t\t\"pages.createMonitor.form.thresholds.option.cpuThreshold.label\"\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\tmin={0}\n\t\t\t\t\t\t\t\t\t\tmax={100}\n\t\t\t\t\t\t\t\t\t\tstep={1}\n\t\t\t\t\t\t\t\t\t\tvalueLabelDisplay=\"auto\"\n\t\t\t\t\t\t\t\t\t\tvalueLabelFormat={(value) => `${value}%`}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t<Controller\n\t\t\t\t\t\t\t\tname=\"memoryAlertThreshold\"\n\t\t\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\t\t\trender={({ field }) => (\n\t\t\t\t\t\t\t\t\t<SliderWithLabel\n\t\t\t\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\t\t\t\tsliderMaxWidth={{ xs: \"100%\", md: \"50%\" }}\n\t\t\t\t\t\t\t\t\t\tfieldLabel={t(\n\t\t\t\t\t\t\t\t\t\t\t\"pages.createMonitor.form.thresholds.option.memoryThreshold.label\"\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\tmin={0}\n\t\t\t\t\t\t\t\t\t\tmax={100}\n\t\t\t\t\t\t\t\t\t\tstep={1}\n\t\t\t\t\t\t\t\t\t\tvalueLabelDisplay=\"auto\"\n\t\t\t\t\t\t\t\t\t\tvalueLabelFormat={(value) => `${value}%`}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t<Controller\n\t\t\t\t\t\t\t\tname=\"diskAlertThreshold\"\n\t\t\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\t\t\trender={({ field }) => (\n\t\t\t\t\t\t\t\t\t<SliderWithLabel\n\t\t\t\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\t\t\t\tsliderMaxWidth={{ xs: \"100%\", md: \"50%\" }}\n\t\t\t\t\t\t\t\t\t\tfieldLabel={t(\n\t\t\t\t\t\t\t\t\t\t\t\"pages.createMonitor.form.thresholds.option.diskThreshold.label\"\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\tmin={0}\n\t\t\t\t\t\t\t\t\t\tmax={100}\n\t\t\t\t\t\t\t\t\t\tstep={1}\n\t\t\t\t\t\t\t\t\t\tvalueLabelDisplay=\"auto\"\n\t\t\t\t\t\t\t\t\t\tvalueLabelFormat={(value) => `${value}%`}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t<Controller\n\t\t\t\t\t\t\t\tname=\"tempAlertThreshold\"\n\t\t\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\t\t\trender={({ field }) => (\n\t\t\t\t\t\t\t\t\t<SliderWithLabel\n\t\t\t\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\t\t\t\tsliderMaxWidth={{ xs: \"100%\", md: \"50%\" }}\n\t\t\t\t\t\t\t\t\t\tfieldLabel={t(\n\t\t\t\t\t\t\t\t\t\t\t\"pages.createMonitor.form.thresholds.option.tempThreshold.label\"\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\tmin={0}\n\t\t\t\t\t\t\t\t\t\tmax={100}\n\t\t\t\t\t\t\t\t\t\tstep={1}\n\t\t\t\t\t\t\t\t\t\tvalueLabelDisplay=\"auto\"\n\t\t\t\t\t\t\t\t\t\tvalueLabelFormat={(value) => `${value}°C`}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</Stack>\n\t\t\t\t\t}\n\t\t\t\t/>\n\t\t\t)}\n\n\t\t\t<ConfigBox\n\t\t\t\ttitle={t(\"pages.createMonitor.form.incidents.title\")}\n\t\t\t\tsubtitle={t(\"pages.createMonitor.form.incidents.description\")}\n\t\t\t\trightContent={\n\t\t\t\t\t<Stack spacing={theme.spacing(LAYOUT.MD)}>\n\t\t\t\t\t\t<Controller\n\t\t\t\t\t\t\tname=\"statusWindowSize\"\n\t\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\t\trender={({ field }) => (\n\t\t\t\t\t\t\t\t<SliderWithLabel\n\t\t\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\t\t\tsliderMaxWidth={{ xs: \"100%\", md: \"50%\" }}\n\t\t\t\t\t\t\t\t\tfieldLabel={t(\"pages.createMonitor.form.incidents.option.checks.label\")}\n\t\t\t\t\t\t\t\t\tmin={1}\n\t\t\t\t\t\t\t\t\tmax={25}\n\t\t\t\t\t\t\t\t\tvalueLabelDisplay=\"auto\"\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<Controller\n\t\t\t\t\t\t\tname=\"statusWindowThreshold\"\n\t\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\t\trender={({ field }) => (\n\t\t\t\t\t\t\t\t<SliderWithLabel\n\t\t\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\t\t\tsliderMaxWidth={{ xs: \"100%\", md: \"50%\" }}\n\t\t\t\t\t\t\t\t\tfieldLabel={t(\n\t\t\t\t\t\t\t\t\t\t\"pages.createMonitor.form.incidents.option.percentage.label\"\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\tmin={1}\n\t\t\t\t\t\t\t\t\tmax={100}\n\t\t\t\t\t\t\t\t\tvalueLabelDisplay=\"auto\"\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</Stack>\n\t\t\t\t}\n\t\t\t/>\n\n\t\t\t<ConfigBox\n\t\t\t\ttitle={t(\"pages.createMonitor.form.notifications.title\")}\n\t\t\t\tsubtitle={t(\"pages.createMonitor.form.notifications.description\")}\n\t\t\t\trightContent={\n\t\t\t\t\t<Controller\n\t\t\t\t\t\tname=\"notifications\"\n\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\trender={({ field }) => {\n\t\t\t\t\t\t\t// Map notifications to have 'name' property for Autocomplete\n\t\t\t\t\t\t\tconst notificationOptions = (notifications ?? []).map((n) => ({\n\t\t\t\t\t\t\t\t...n,\n\t\t\t\t\t\t\t\tname: n.notificationName,\n\t\t\t\t\t\t\t}));\n\t\t\t\t\t\t\tconst selectedNotifications = notificationOptions.filter((n) =>\n\t\t\t\t\t\t\t\t(field.value ?? []).includes(n.id)\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t<Stack spacing={theme.spacing(LAYOUT.MD)}>\n\t\t\t\t\t\t\t\t\t<Autocomplete\n\t\t\t\t\t\t\t\t\t\tmultiple\n\t\t\t\t\t\t\t\t\t\toptions={notificationOptions}\n\t\t\t\t\t\t\t\t\t\tvalue={selectedNotifications}\n\t\t\t\t\t\t\t\t\t\tgetOptionLabel={(option) => option.name}\n\t\t\t\t\t\t\t\t\t\tonChange={(_: unknown, newValue: typeof notificationOptions) => {\n\t\t\t\t\t\t\t\t\t\t\tfield.onChange(newValue.map((n) => n.id));\n\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\tisOptionEqualToValue={(option, value) => option.id === value.id}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t{selectedNotifications.length > 0 && (\n\t\t\t\t\t\t\t\t\t\t<Stack\n\t\t\t\t\t\t\t\t\t\t\tflex={1}\n\t\t\t\t\t\t\t\t\t\t\twidth=\"100%\"\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t{selectedNotifications.map((notification, index) => (\n\t\t\t\t\t\t\t\t\t\t\t\t<Stack\n\t\t\t\t\t\t\t\t\t\t\t\t\tdirection=\"row\"\n\t\t\t\t\t\t\t\t\t\t\t\t\talignItems=\"center\"\n\t\t\t\t\t\t\t\t\t\t\t\t\tkey={notification.id}\n\t\t\t\t\t\t\t\t\t\t\t\t\twidth=\"100%\"\n\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<Typography flexGrow={1}>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{notification.notificationName}\n\t\t\t\t\t\t\t\t\t\t\t\t\t</Typography>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<IconButton\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tfield.onChange(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t(field.value ?? []).filter(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t(id: string) => id !== notification.id\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\taria-label=\"Remove notification\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<Trash2 size={16} />\n\t\t\t\t\t\t\t\t\t\t\t\t\t</IconButton>\n\t\t\t\t\t\t\t\t\t\t\t\t\t{index < selectedNotifications.length - 1 && <Divider />}\n\t\t\t\t\t\t\t\t\t\t\t\t</Stack>\n\t\t\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t\t\t</Stack>\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t</Stack>\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}}\n\t\t\t\t\t/>\n\t\t\t\t}\n\t\t\t/>\n\n\t\t\t{(watchedType === \"http\" ||\n\t\t\t\twatchedType === \"grpc\" ||\n\t\t\t\twatchedType === \"websocket\") && (\n\t\t\t\t<ConfigBox\n\t\t\t\t\ttitle={t(\"pages.createMonitor.form.ignoreTls.title\")}\n\t\t\t\t\tsubtitle={t(\"pages.createMonitor.form.ignoreTls.description\")}\n\t\t\t\t\trightContent={\n\t\t\t\t\t\t<Controller\n\t\t\t\t\t\t\tname=\"ignoreTlsErrors\"\n\t\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\t\trender={({ field }) => (\n\t\t\t\t\t\t\t\t<Stack\n\t\t\t\t\t\t\t\t\tdirection=\"row\"\n\t\t\t\t\t\t\t\t\talignItems=\"center\"\n\t\t\t\t\t\t\t\t\tspacing={theme.spacing(SPACING.LG)}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<Switch\n\t\t\t\t\t\t\t\t\t\tchecked={field.value ?? false}\n\t\t\t\t\t\t\t\t\t\tonChange={(e) => field.onChange(e.target.checked)}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t<Typography>\n\t\t\t\t\t\t\t\t\t\t{t(\"pages.createMonitor.form.ignoreTls.option.tls.label\")}\n\t\t\t\t\t\t\t\t\t</Typography>\n\t\t\t\t\t\t\t\t</Stack>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t/>\n\t\t\t\t\t}\n\t\t\t\t/>\n\t\t\t)}\n\n\t\t\t{watchedType === \"http\" && (\n\t\t\t\t<ConfigBox\n\t\t\t\t\ttitle={t(\"pages.createMonitor.form.advanced.title\")}\n\t\t\t\t\tsubtitle={t(\"pages.createMonitor.form.advanced.description\")}\n\t\t\t\t\trightContent={\n\t\t\t\t\t\t<Stack spacing={theme.spacing(LAYOUT.MD)}>\n\t\t\t\t\t\t\t<Controller\n\t\t\t\t\t\t\t\tname=\"useAdvancedMatching\"\n\t\t\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\t\t\trender={({ field }) => (\n\t\t\t\t\t\t\t\t\t<Stack\n\t\t\t\t\t\t\t\t\t\tdirection=\"row\"\n\t\t\t\t\t\t\t\t\t\talignItems=\"center\"\n\t\t\t\t\t\t\t\t\t\tspacing={theme.spacing(SPACING.LG)}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<Switch\n\t\t\t\t\t\t\t\t\t\t\tchecked={field.value ?? false}\n\t\t\t\t\t\t\t\t\t\t\tonChange={(e) => field.onChange(e.target.checked)}\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t<Typography>\n\t\t\t\t\t\t\t\t\t\t\t{t(\n\t\t\t\t\t\t\t\t\t\t\t\t\"pages.createMonitor.form.advanced.option.advancedMatching.label\"\n\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t</Typography>\n\t\t\t\t\t\t\t\t\t</Stack>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t{watchedUseAdvancedMatching && (\n\t\t\t\t\t\t\t\t<Stack spacing={theme.spacing(LAYOUT.MD)}>\n\t\t\t\t\t\t\t\t\t<Controller\n\t\t\t\t\t\t\t\t\t\tname=\"matchMethod\"\n\t\t\t\t\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\t\t\t\t\trender={({ field }) => (\n\t\t\t\t\t\t\t\t\t\t\t<Select\n\t\t\t\t\t\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\t\t\t\t\t\tvalue={field.value ?? \"equal\"}\n\t\t\t\t\t\t\t\t\t\t\t\tfieldLabel={t(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"pages.createMonitor.form.advanced.option.matchMethod.label\"\n\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t<MenuItem value=\"equal\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t{t(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"pages.createMonitor.form.advanced.option.matchMethod.equal\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t</MenuItem>\n\t\t\t\t\t\t\t\t\t\t\t\t<MenuItem value=\"include\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t{t(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"pages.createMonitor.form.advanced.option.matchMethod.include\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t</MenuItem>\n\t\t\t\t\t\t\t\t\t\t\t\t<MenuItem value=\"regex\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t{t(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"pages.createMonitor.form.advanced.option.matchMethod.regex\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t</MenuItem>\n\t\t\t\t\t\t\t\t\t\t\t</Select>\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t<Controller\n\t\t\t\t\t\t\t\t\t\tname=\"expectedValue\"\n\t\t\t\t\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\t\t\t\t\trender={({ field, fieldState }) => (\n\t\t\t\t\t\t\t\t\t\t\t<TextField\n\t\t\t\t\t\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\t\t\t\t\t\tvalue={field.value ?? \"\"}\n\t\t\t\t\t\t\t\t\t\t\t\tfieldLabel={t(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"pages.createMonitor.form.advanced.option.expectedValue.label\"\n\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\tfullWidth\n\t\t\t\t\t\t\t\t\t\t\t\terror={!!fieldState.error}\n\t\t\t\t\t\t\t\t\t\t\t\thelperText={fieldState.error?.message ?? \"\"}\n\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t<Controller\n\t\t\t\t\t\t\t\t\t\tname=\"jsonPath\"\n\t\t\t\t\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\t\t\t\t\trender={({ field, fieldState }) => (\n\t\t\t\t\t\t\t\t\t\t\t<TextField\n\t\t\t\t\t\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\t\t\t\t\t\tvalue={field.value ?? \"\"}\n\t\t\t\t\t\t\t\t\t\t\t\tfieldLabel={t(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"pages.createMonitor.form.advanced.option.jsonPath.label\"\n\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\tfullWidth\n\t\t\t\t\t\t\t\t\t\t\t\terror={!!fieldState.error}\n\t\t\t\t\t\t\t\t\t\t\t\thelperText={fieldState.error?.message ?? \"\"}\n\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t<Typography\n\t\t\t\t\t\t\t\t\t\tcomponent=\"span\"\n\t\t\t\t\t\t\t\t\t\tcolor=\"text.secondary\"\n\t\t\t\t\t\t\t\t\t\tsx={{ opacity: 0.8 }}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<Trans\n\t\t\t\t\t\t\t\t\t\t\ti18nKey=\"pages.createMonitor.form.advanced.option.jsonPath.description\"\n\t\t\t\t\t\t\t\t\t\t\tcomponents={{\n\t\t\t\t\t\t\t\t\t\t\t\tjmesLink: (\n\t\t\t\t\t\t\t\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\t\t\t\t\t\t\t\thref=\"https://jmespath.org/\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\trel=\"noopener noreferrer\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t</Typography>\n\t\t\t\t\t\t\t\t</Stack>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</Stack>\n\t\t\t\t\t}\n\t\t\t\t/>\n\t\t\t)}\n\n\t\t\t{supportsGeoCheck(watchedType) && (\n\t\t\t\t<ConfigBox\n\t\t\t\t\ttitle={t(\"pages.createMonitor.form.geoChecks.title\")}\n\t\t\t\t\tsubtitle={t(\"pages.createMonitor.form.geoChecks.description\")}\n\t\t\t\t\trightContent={\n\t\t\t\t\t\t<Stack spacing={theme.spacing(LAYOUT.MD)}>\n\t\t\t\t\t\t\t<Controller\n\t\t\t\t\t\t\t\tname=\"geoCheckEnabled\"\n\t\t\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\t\t\trender={({ field }) => (\n\t\t\t\t\t\t\t\t\t<Stack\n\t\t\t\t\t\t\t\t\t\tdirection=\"row\"\n\t\t\t\t\t\t\t\t\t\talignItems=\"center\"\n\t\t\t\t\t\t\t\t\t\tspacing={theme.spacing(SPACING.LG)}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<Switch\n\t\t\t\t\t\t\t\t\t\t\tchecked={field.value ?? false}\n\t\t\t\t\t\t\t\t\t\t\tonChange={(e) => field.onChange(e.target.checked)}\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t<Typography>\n\t\t\t\t\t\t\t\t\t\t\t{t(\"pages.createMonitor.form.geoChecks.option.enabled.label\")}\n\t\t\t\t\t\t\t\t\t\t</Typography>\n\t\t\t\t\t\t\t\t\t</Stack>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t{watchGeoCheckEnabled && (\n\t\t\t\t\t\t\t\t<Stack spacing={theme.spacing(LAYOUT.MD)}>\n\t\t\t\t\t\t\t\t\t<Controller\n\t\t\t\t\t\t\t\t\t\tname=\"geoCheckLocations\"\n\t\t\t\t\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\t\t\t\t\trender={({ field }) => {\n\t\t\t\t\t\t\t\t\t\t\t// Map continents to have 'name' property for Autocomplete\n\t\t\t\t\t\t\t\t\t\t\tconst locationOptions = GeoContinents.map((continent) => ({\n\t\t\t\t\t\t\t\t\t\t\t\tid: continent,\n\t\t\t\t\t\t\t\t\t\t\t\tname: t(\n\t\t\t\t\t\t\t\t\t\t\t\t\t`pages.createMonitor.form.geoChecks.option.locations.options.${continent}`\n\t\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t\t}));\n\t\t\t\t\t\t\t\t\t\t\tconst selectedLocations = locationOptions.filter((loc) =>\n\t\t\t\t\t\t\t\t\t\t\t\t(field.value ?? []).includes(loc.id)\n\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t\t\t\t<Stack spacing={theme.spacing(LAYOUT.MD)}>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<Autocomplete\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tmultiple\n\t\t\t\t\t\t\t\t\t\t\t\t\t\toptions={locationOptions}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tvalue={selectedLocations}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tgetOptionLabel={(option) => option.name}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tonChange={(_: unknown, newValue: typeof locationOptions) => {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tfield.onChange(newValue.map((loc) => loc.id));\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tisOptionEqualToValue={(option, value) =>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\toption.id === value.id\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tfieldLabel={t(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"pages.createMonitor.form.geoChecks.option.locations.label\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t\t\t\t{selectedLocations.length > 0 && (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<Stack\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tflex={1}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\twidth=\"100%\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{selectedLocations.map((location, index) => (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<Stack\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdirection=\"row\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\talignItems=\"center\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tkey={location.id}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\twidth=\"100%\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<Typography flexGrow={1}>{location.name}</Typography>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<IconButton\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tfield.onChange(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t(field.value ?? []).filter(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t(id: string) => id !== location.id\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\taria-label=\"Remove location\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<Trash2 size={16} />\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</IconButton>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{index < selectedLocations.length - 1 && <Divider />}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</Stack>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</Stack>\n\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t</Stack>\n\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t<Controller\n\t\t\t\t\t\t\t\t\t\tname=\"geoCheckInterval\"\n\t\t\t\t\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\t\t\t\t\trender={({ field }) => (\n\t\t\t\t\t\t\t\t\t\t\t<Select\n\t\t\t\t\t\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\t\t\t\t\t\tvalue={field.value ?? 300000}\n\t\t\t\t\t\t\t\t\t\t\t\tfieldLabel={t(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"pages.createMonitor.form.geoChecks.option.interval.label\"\n\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t<MenuItem value={300000}>\n\t\t\t\t\t\t\t\t\t\t\t\t\t{t(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"pages.createMonitor.form.geoChecks.option.interval.value.fiveMinutes\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t</MenuItem>\n\t\t\t\t\t\t\t\t\t\t\t\t<MenuItem value={600000}>\n\t\t\t\t\t\t\t\t\t\t\t\t\t{t(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"pages.createMonitor.form.geoChecks.option.interval.value.tenMinutes\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t</MenuItem>\n\t\t\t\t\t\t\t\t\t\t\t\t<MenuItem value={900000}>\n\t\t\t\t\t\t\t\t\t\t\t\t\t{t(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"pages.createMonitor.form.geoChecks.option.interval.value.fifteenMinutes\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t</MenuItem>\n\t\t\t\t\t\t\t\t\t\t\t\t<MenuItem value={1800000}>\n\t\t\t\t\t\t\t\t\t\t\t\t\t{t(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"pages.createMonitor.form.geoChecks.option.interval.value.thirtyMinutes\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t</MenuItem>\n\t\t\t\t\t\t\t\t\t\t\t</Select>\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t</Stack>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</Stack>\n\t\t\t\t\t}\n\t\t\t\t/>\n\t\t\t)}\n\n\t\t\t<Stack\n\t\t\t\tdirection=\"row\"\n\t\t\t\tjustifyContent=\"flex-end\"\n\t\t\t>\n\t\t\t\t<Button\n\t\t\t\t\tloading={isSubmitting}\n\t\t\t\t\ttype=\"submit\"\n\t\t\t\t\tvariant=\"contained\"\n\t\t\t\t\tcolor=\"primary\"\n\t\t\t\t>\n\t\t\t\t\t{t(\"common.buttons.save\")}\n\t\t\t\t</Button>\n\t\t\t</Stack>\n\t\t\t<Dialog\n\t\t\t\topen={isDeleteDialogOpen}\n\t\t\t\ttitle={t(\"common.dialogs.delete.title\")}\n\t\t\t\tcontent={t(\"common.dialogs.delete.description\")}\n\t\t\t\tonConfirm={handleDeleteConfirm}\n\t\t\t\tonCancel={handleDeleteCancel}\n\t\t\t\tloading={isDeleting}\n\t\t\t/>\n\t\t</BasePage>\n\t);\n};\n\nexport default CreateMonitorPage;\n"
  },
  {
    "path": "client/src/Pages/Incidents/Components/CardDetails.tsx",
    "content": "import Stack from \"@mui/material/Stack\";\nimport Grid from \"@mui/material/Grid\";\nimport Divider from \"@mui/material/Divider\";\nimport Typography from \"@mui/material/Typography\";\nimport { BaseBox, ValueLabel } from \"@/Components/design-elements\";\nimport { LAYOUT } from \"@/Utils/Theme/constants\";\n\nimport { useTranslation } from \"react-i18next\";\nimport type { Incident } from \"@/Types/Incident\";\nimport type { Monitor } from \"@/Types/Monitor\";\nimport { useTheme } from \"@mui/material\";\nimport { useSelector } from \"react-redux\";\nimport type { RootState } from \"@/Types/state\";\nimport { formatDateWithTz } from \"@/Utils/TimeUtils\";\nimport { getIncidentsDuration } from \"@/Pages/Incidents/utils\";\n\ninterface CardDetailsProps {\n\tincident: Incident | null;\n\tmonitor: Monitor | null;\n\tsx?: object;\n}\n\nexport const CardDetails = ({ incident, monitor, sx }: CardDetailsProps) => {\n\tconst { t } = useTranslation();\n\tconst theme = useTheme();\n\tconst uiTimezone = useSelector((state: RootState) => state.ui.timezone);\n\n\tif (!incident) {\n\t\treturn null;\n\t}\n\treturn (\n\t\t<Stack\n\t\t\tgap={theme.spacing(LAYOUT.MD)}\n\t\t\tsx={sx}\n\t\t>\n\t\t\t<Typography textTransform={\"uppercase\"}>\n\t\t\t\t{t(\"pages.incidents.dialog.details.title\")}\n\t\t\t</Typography>\n\t\t\t<BaseBox padding={LAYOUT.MD}>\n\t\t\t\t<Stack gap={theme.spacing(LAYOUT.MD)}>\n\t\t\t\t\t<Typography textTransform={\"uppercase\"}>\n\t\t\t\t\t\t{t(\"pages.incidents.dialog.details.overview\")}\n\t\t\t\t\t</Typography>\n\t\t\t\t\t<Divider />\n\n\t\t\t\t\t<Grid\n\t\t\t\t\t\tcontainer\n\t\t\t\t\t\tspacing={theme.spacing(LAYOUT.MD)}\n\t\t\t\t\t\talignItems=\"center\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<Grid size={2}>{t(\"pages.incidents.dialog.details.status\")}</Grid>\n\t\t\t\t\t\t<Grid size={10}>\n\t\t\t\t\t\t\t<ValueLabel\n\t\t\t\t\t\t\t\tvalue={incident.status ? \"negative\" : \"positive\"}\n\t\t\t\t\t\t\t\ttext={\n\t\t\t\t\t\t\t\t\tincident.status\n\t\t\t\t\t\t\t\t\t\t? t(\"common.labels.active\")\n\t\t\t\t\t\t\t\t\t\t: t(\"common.labels.resolved\")\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</Grid>\n\t\t\t\t\t\t{monitor && (\n\t\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t\t<Grid size={2}>{t(\"pages.incidents.dialog.details.monitor\")}</Grid>\n\t\t\t\t\t\t\t\t<Grid size={10}>\n\t\t\t\t\t\t\t\t\t<Typography>{monitor.name ?? \"N/A\"}</Typography>\n\t\t\t\t\t\t\t\t</Grid>\n\t\t\t\t\t\t\t\t<Grid size={2}>\n\t\t\t\t\t\t\t\t\t<Typography>{t(\"pages.incidents.dialog.details.url\")}</Typography>\n\t\t\t\t\t\t\t\t</Grid>\n\t\t\t\t\t\t\t\t<Grid size={10}>\n\t\t\t\t\t\t\t\t\t<Typography>{monitor.url ?? \"N/A\"}</Typography>\n\t\t\t\t\t\t\t\t</Grid>\n\t\t\t\t\t\t\t</>\n\t\t\t\t\t\t)}\n\t\t\t\t\t</Grid>\n\t\t\t\t</Stack>\n\t\t\t</BaseBox>\n\t\t\t<BaseBox padding={LAYOUT.MD}>\n\t\t\t\t<Stack gap={theme.spacing(LAYOUT.MD)}>\n\t\t\t\t\t<Typography textTransform={\"uppercase\"}>\n\t\t\t\t\t\t{t(\"pages.incidents.dialog.details.analysis\")}\n\t\t\t\t\t</Typography>\n\t\t\t\t\t<Divider />\n\t\t\t\t\t<Grid\n\t\t\t\t\t\tcontainer\n\t\t\t\t\t\tspacing={theme.spacing(LAYOUT.MD)}\n\t\t\t\t\t>\n\t\t\t\t\t\t<Grid size={6}>\n\t\t\t\t\t\t\t<Typography>{t(\"pages.incidents.dialog.details.timeline\")}</Typography>\n\t\t\t\t\t\t</Grid>\n\t\t\t\t\t\t<Grid size={6}>\n\t\t\t\t\t\t\t<Typography>{t(\"pages.incidents.dialog.details.detailsLabel\")}</Typography>\n\t\t\t\t\t\t</Grid>\n\t\t\t\t\t\t<Grid size={6}>\n\t\t\t\t\t\t\t<Divider></Divider>\n\t\t\t\t\t\t</Grid>\n\t\t\t\t\t\t<Grid size={6}>\n\t\t\t\t\t\t\t<Divider></Divider>\n\t\t\t\t\t\t</Grid>\n\t\t\t\t\t\t<Grid size={2}>\n\t\t\t\t\t\t\t<Typography>{t(\"pages.incidents.dialog.details.startedAt\")}</Typography>\n\t\t\t\t\t\t</Grid>\n\t\t\t\t\t\t<Grid size={4}>\n\t\t\t\t\t\t\t<Typography>\n\t\t\t\t\t\t\t\t{formatDateWithTz(incident.startTime, \"D MMM YYYY, h:mm A\", uiTimezone)}\n\t\t\t\t\t\t\t</Typography>\n\t\t\t\t\t\t</Grid>\n\t\t\t\t\t\t<Grid size={2}>\n\t\t\t\t\t\t\t<Typography>{t(\"pages.incidents.dialog.details.statusCode\")}</Typography>\n\t\t\t\t\t\t</Grid>\n\t\t\t\t\t\t<Grid size={4}>\n\t\t\t\t\t\t\t<Typography>{incident.statusCode ?? \"N/A\"}</Typography>\n\t\t\t\t\t\t</Grid>\n\t\t\t\t\t\t<Grid size={2}>\n\t\t\t\t\t\t\t<Typography>{t(\"pages.incidents.dialog.details.downtime\")}</Typography>\n\t\t\t\t\t\t</Grid>\n\t\t\t\t\t\t<Grid size={4}>\n\t\t\t\t\t\t\t<Typography>{getIncidentsDuration(incident)}</Typography>\n\t\t\t\t\t\t</Grid>\n\t\t\t\t\t\t<Grid size={2}>\n\t\t\t\t\t\t\t<Typography>{t(\"pages.incidents.dialog.details.message\")}</Typography>\n\t\t\t\t\t\t</Grid>\n\t\t\t\t\t\t<Grid size={4}>\n\t\t\t\t\t\t\t<Typography>{incident.message ?? \"N/A\"}</Typography>\n\t\t\t\t\t\t</Grid>\n\t\t\t\t\t</Grid>\n\t\t\t\t</Stack>\n\t\t\t</BaseBox>\n\t\t\t{!incident.status && (\n\t\t\t\t<BaseBox padding={LAYOUT.MD}>\n\t\t\t\t\t<Stack gap={theme.spacing(LAYOUT.XS)}>\n\t\t\t\t\t\t<Typography textTransform={\"uppercase\"}>\n\t\t\t\t\t\t\t{t(\"pages.incidents.dialog.details.resolutionDetails\")}\n\t\t\t\t\t\t</Typography>\n\t\t\t\t\t\t<Divider />\n\t\t\t\t\t\t<Grid\n\t\t\t\t\t\t\tcontainer\n\t\t\t\t\t\t\tspacing={theme.spacing(LAYOUT.MD)}\n\t\t\t\t\t\t\talignItems=\"center\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<Grid size={2}>\n\t\t\t\t\t\t\t\t<Typography>{t(\"pages.incidents.dialog.details.resolvedAt\")}</Typography>\n\t\t\t\t\t\t\t</Grid>\n\t\t\t\t\t\t\t<Grid size={10}>\n\t\t\t\t\t\t\t\t<Typography>\n\t\t\t\t\t\t\t\t\t{incident.endTime\n\t\t\t\t\t\t\t\t\t\t? formatDateWithTz(incident.endTime, \"D MMM YYYY, h:mm A\", uiTimezone)\n\t\t\t\t\t\t\t\t\t\t: \"N/A\"}\n\t\t\t\t\t\t\t\t</Typography>\n\t\t\t\t\t\t\t</Grid>\n\t\t\t\t\t\t\t<Grid size={2}>\n\t\t\t\t\t\t\t\t<Typography>\n\t\t\t\t\t\t\t\t\t{t(\"pages.incidents.dialog.details.resolutionType\")}\n\t\t\t\t\t\t\t\t</Typography>\n\t\t\t\t\t\t\t</Grid>\n\t\t\t\t\t\t\t<Grid size={10}>\n\t\t\t\t\t\t\t\t<Typography>\n\t\t\t\t\t\t\t\t\t{incident.resolutionType\n\t\t\t\t\t\t\t\t\t\t? t(\n\t\t\t\t\t\t\t\t\t\t\t\t`pages.incidents.dialog.details.resolutionTypes.${incident.resolutionType}`\n\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t: \"N/A\"}\n\t\t\t\t\t\t\t\t</Typography>\n\t\t\t\t\t\t\t</Grid>\n\t\t\t\t\t\t\t{incident.resolvedBy && (\n\t\t\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t\t\t<Grid size={2}>\n\t\t\t\t\t\t\t\t\t\t<Typography>\n\t\t\t\t\t\t\t\t\t\t\t{t(\"pages.incidents.dialog.details.resolvedBy\")}\n\t\t\t\t\t\t\t\t\t\t</Typography>\n\t\t\t\t\t\t\t\t\t</Grid>\n\t\t\t\t\t\t\t\t\t<Grid size={10}>\n\t\t\t\t\t\t\t\t\t\t<Typography>\n\t\t\t\t\t\t\t\t\t\t\t{incident.resolvedByEmail ?? incident.resolvedBy}\n\t\t\t\t\t\t\t\t\t\t</Typography>\n\t\t\t\t\t\t\t\t\t</Grid>\n\t\t\t\t\t\t\t\t</>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t{incident.comment && (\n\t\t\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t\t\t<Grid size={2}>\n\t\t\t\t\t\t\t\t\t\t<Typography>{t(\"pages.incidents.dialog.details.comment\")}</Typography>\n\t\t\t\t\t\t\t\t\t</Grid>\n\t\t\t\t\t\t\t\t\t<Grid size={10}>\n\t\t\t\t\t\t\t\t\t\t<Typography>{incident.comment}</Typography>\n\t\t\t\t\t\t\t\t\t</Grid>\n\t\t\t\t\t\t\t\t</>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</Grid>\n\t\t\t\t\t</Stack>\n\t\t\t\t</BaseBox>\n\t\t\t)}\n\t\t</Stack>\n\t);\n};\n"
  },
  {
    "path": "client/src/Pages/Incidents/Components/CardSummary.tsx",
    "content": "import Stack from \"@mui/material/Stack\";\nimport Typography from \"@mui/material/Typography\";\nimport Divider from \"@mui/material/Divider\";\nimport Grid from \"@mui/material/Grid\";\nimport { BaseBox, ValueLabel } from \"@/Components/design-elements\";\nimport { CircleCheck, TriangleAlert, Bell, Wrench, Globe } from \"lucide-react\";\nimport Box from \"@mui/material/Box\";\n\nimport { useTranslation } from \"react-i18next\";\nimport { useTheme } from \"@mui/material\";\nimport type { IncidentSummary, IncidentSummaryItem } from \"@/Types/Incident\";\nimport { getIncidentsDuration } from \"@/Pages/Incidents/utils\";\n\ninterface SummaryItemProps {\n\ticon: React.ReactNode;\n\tlabel: string;\n\tvalue: string | number;\n}\n\nconst SummaryItem = ({ icon, label, value }: SummaryItemProps) => {\n\tconst theme = useTheme();\n\treturn (\n\t\t<Stack\n\t\t\tdirection=\"row\"\n\t\t\talignItems=\"center\"\n\t\t\tjustifyContent=\"space-between\"\n\t\t\tgap={theme.spacing(2)}\n\t\t>\n\t\t\t<Stack\n\t\t\t\tdirection=\"row\"\n\t\t\t\talignItems=\"center\"\n\t\t\t\tgap={theme.spacing(2)}\n\t\t\t>\n\t\t\t\t{icon}\n\t\t\t\t<Typography variant=\"body2\">{label}</Typography>\n\t\t\t</Stack>\n\t\t\t<Typography\n\t\t\t\tvariant=\"body2\"\n\t\t\t\tfontWeight={600}\n\t\t\t>\n\t\t\t\t{value}\n\t\t\t</Typography>\n\t\t</Stack>\n\t);\n};\n\ninterface SummaryCardProps {\n\ttitle: string;\n\tsx?: React.CSSProperties;\n}\n\nexport const SummaryCard = ({\n\ttitle,\n\tsx,\n\tchildren,\n}: React.PropsWithChildren<SummaryCardProps>) => {\n\tconst theme = useTheme();\n\treturn (\n\t\t<BaseBox\n\t\t\tsx={{ ...sx }}\n\t\t\tpadding={8}\n\t\t\tflex={1}\n\t\t>\n\t\t\t<Stack\n\t\t\t\tgap={theme.spacing(4)}\n\t\t\t\theight=\"100%\"\n\t\t\t>\n\t\t\t\t<Typography\n\t\t\t\t\tcomponent=\"h2\"\n\t\t\t\t\tsx={{\n\t\t\t\t\t\ttextTransform: \"uppercase\",\n\t\t\t\t\t\tfontWeight: 500,\n\t\t\t\t\t\tfontSize: 13,\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t{title}\n\t\t\t\t</Typography>\n\t\t\t\t<Divider />\n\t\t\t\t{children}\n\t\t\t</Stack>\n\t\t</BaseBox>\n\t);\n};\n\ninterface SummaryCardActiveIncidentsProps {\n\tsummary?: IncidentSummary | null;\n}\n\nexport const SummaryCardActiveIncidents = ({\n\tsummary,\n}: SummaryCardActiveIncidentsProps) => {\n\tconst { t } = useTranslation();\n\tconst theme = useTheme();\n\n\tif (!summary) return null;\n\n\tconst activeCount = summary.totalActive;\n\tconst hasActive = activeCount > 0;\n\tconst color = hasActive ? theme.palette.error.main : theme.palette.success.main;\n\tconst icon = hasActive ? (\n\t\t<TriangleAlert color={color} />\n\t) : (\n\t\t<CircleCheck color={color} />\n\t);\n\tconst msg = t(\"pages.incidents.summaryCard.activeIncidents.active\", {\n\t\tcount: activeCount,\n\t});\n\n\treturn (\n\t\t<SummaryCard\n\t\t\ttitle={t(\"pages.incidents.summaryCard.activeIncidents.title\")}\n\t\t\tsx={{ height: \"100%\" }}\n\t\t>\n\t\t\t<Stack\n\t\t\t\tflex={1}\n\t\t\t\talignItems=\"center\"\n\t\t\t\tjustifyContent=\"center\"\n\t\t\t\tgap={theme.spacing(4)}\n\t\t\t>\n\t\t\t\t{icon}\n\t\t\t\t<Typography>{msg}</Typography>\n\t\t\t</Stack>\n\t\t</SummaryCard>\n\t);\n};\n\nconst SummaryIncidentItem = ({ incident }: { incident: IncidentSummaryItem }) => {\n\tconst theme = useTheme();\n\tconst { t } = useTranslation();\n\tconst duration = getIncidentsDuration(incident);\n\treturn (\n\t\t<Grid\n\t\t\tcontainer\n\t\t\talignItems=\"center\"\n\t\t\tspacing={2}\n\t\t\tsx={{\n\t\t\t\twidth: \"100%\",\n\t\t\t\tpy: theme.spacing(0.5),\n\t\t\t}}\n\t\t>\n\t\t\t<Grid\n\t\t\t\tsize={{ xs: 12, lg: 5 }}\n\t\t\t\tsx={{\n\t\t\t\t\tdisplay: \"flex\",\n\t\t\t\t\talignItems: \"center\",\n\t\t\t\t\tjustifyContent: \"flex-start\",\n\t\t\t\t\tgap: theme.spacing(2),\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t<Globe />\n\t\t\t\t<Typography\n\t\t\t\t\tvariant=\"body1\"\n\t\t\t\t\tfontWeight={500}\n\t\t\t\t\tnoWrap\n\t\t\t\t>\n\t\t\t\t\t{incident.monitorName ?? t(\"common.labels.na\")}\n\t\t\t\t</Typography>\n\t\t\t</Grid>\n\n\t\t\t<Grid\n\t\t\t\tsize={{ xs: 12, md: 6, lg: 3 }}\n\t\t\t\tsx={{\n\t\t\t\t\tdisplay: \"flex\",\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t<ValueLabel\n\t\t\t\t\tvalue={incident.status ? \"negative\" : \"positive\"}\n\t\t\t\t\ttext={incident.status ? t(\"common.labels.active\") : t(\"common.labels.resolved\")}\n\t\t\t\t/>\n\t\t\t</Grid>\n\n\t\t\t<Grid\n\t\t\t\tsize={{ xs: 12, md: 6, lg: 4 }}\n\t\t\t\tsx={{\n\t\t\t\t\ttextAlign: { xs: \"left\", md: \"right\" },\n\t\t\t\t\tfontWeight: 500,\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t<Typography variant=\"body1\">{duration}</Typography>\n\t\t\t</Grid>\n\t\t</Grid>\n\t);\n};\n\ninterface SummaryCardLatestIncidentsProps {\n\tsummary?: IncidentSummary | null;\n}\n\nexport const SummaryCardLatestIncidents = ({\n\tsummary,\n}: SummaryCardLatestIncidentsProps) => {\n\tconst { t } = useTranslation();\n\tconst theme = useTheme();\n\n\tconst latestIncidents = summary?.latestIncidents ?? [];\n\n\treturn (\n\t\t<SummaryCard title={t(\"pages.incidents.summaryCard.latestIncidents.title\")}>\n\t\t\t<Stack gap={theme.spacing(4)}>\n\t\t\t\t{latestIncidents.slice(0, 3).map((incident, index) => (\n\t\t\t\t\t<Box key={incident.id}>\n\t\t\t\t\t\t<SummaryIncidentItem incident={incident} />\n\t\t\t\t\t\t{index < latestIncidents.length - 1 && (\n\t\t\t\t\t\t\t<Divider sx={{ mt: theme.spacing(2) }} />\n\t\t\t\t\t\t)}\n\t\t\t\t\t</Box>\n\t\t\t\t))}\n\t\t\t</Stack>\n\t\t</SummaryCard>\n\t);\n};\n\ninterface SummaryCardStatsProps {\n\tsummary?: IncidentSummary | null;\n}\n\nexport const SummaryCardStats = ({ summary }: SummaryCardStatsProps) => {\n\tconst { t } = useTranslation();\n\tif (!summary) return null;\n\tconst mostAffected =\n\t\t!summary.total || summary.total === 0\n\t\t\t? t(\"common.labels.na\")\n\t\t\t: summary.topMonitor?.monitorName || t(\"common.labels.na\");\n\treturn (\n\t\t<SummaryCard title={t(\"pages.incidents.summaryCard.incidentStats.title\")}>\n\t\t\t<SummaryItem\n\t\t\t\ticon={<Bell size={18} />}\n\t\t\t\tlabel={t(\"pages.incidents.summaryCard.incidentStats.totalIncidents\")}\n\t\t\t\tvalue={summary?.total || 0}\n\t\t\t/>\n\t\t\t<SummaryItem\n\t\t\t\ticon={<TriangleAlert size={18} />}\n\t\t\t\tlabel={t(\"pages.incidents.summaryCard.incidentStats.mostAffectedMonitor\")}\n\t\t\t\tvalue={mostAffected}\n\t\t\t/>\n\t\t\t<SummaryItem\n\t\t\t\ticon={<Wrench size={18} />}\n\t\t\t\tlabel={t(\"pages.incidents.summaryCard.incidentStats.avgResolutionTime\")}\n\t\t\t\tvalue={\n\t\t\t\t\tsummary.total > 0\n\t\t\t\t\t\t? `${summary.avgResolutionTimeHours || 0} hours`\n\t\t\t\t\t\t: t(\"common.labels.na\")\n\t\t\t\t}\n\t\t\t/>\n\t\t</SummaryCard>\n\t);\n};\n"
  },
  {
    "path": "client/src/Pages/Incidents/Components/ControlsIncidentFilter.tsx",
    "content": "import Stack from \"@mui/material/Stack\";\nimport { Select, Button } from \"@/Components/inputs\";\nimport MenuItem from \"@mui/material/MenuItem\";\nimport useMediaQuery from \"@mui/material/useMediaQuery\";\nimport { Typography, useTheme } from \"@mui/material\";\nimport { useTranslation } from \"react-i18next\";\nimport type { Monitor } from \"@/Types/Monitor\";\n\nconst resolutionTypes = [\"all\", \"manual\", \"automatic\"];\n\ninterface ControlsIncidentFilterProps {\n\tmonitors?: Monitor[];\n\tselectedMonitor: string;\n\tsetSelectedMonitor: React.Dispatch<React.SetStateAction<string>>;\n\tselectedResolutionType: string;\n\tsetSelectedResolutionType: React.Dispatch<React.SetStateAction<string>>;\n\tonClearFilters: () => void;\n}\n\nexport const ControlsIncidentFilter = ({\n\tmonitors,\n\tselectedMonitor,\n\tsetSelectedMonitor,\n\tselectedResolutionType,\n\tsetSelectedResolutionType,\n\tonClearFilters,\n}: ControlsIncidentFilterProps) => {\n\tconst { t } = useTranslation();\n\tconst theme = useTheme();\n\tconst isSmall = useMediaQuery(theme.breakpoints.down(\"md\"));\n\tconst isFilterActive =\n\t\tselectedMonitor !== \"0\" ||\n\t\t(selectedResolutionType !== \"\" && selectedResolutionType !== \"all\");\n\n\treturn (\n\t\t<Stack\n\t\t\tdirection={isSmall ? \"column\" : \"row\"}\n\t\t\tgap={theme.spacing(2)}\n\t\t>\n\t\t\t<Select\n\t\t\t\tplaceholder={t(\"pages.incidents.filters.monitor\")}\n\t\t\t\tvalue={selectedMonitor}\n\t\t\t\tonChange={(e) => setSelectedMonitor(e.target.value)}\n\t\t\t>\n\t\t\t\t<MenuItem value=\"0\">\n\t\t\t\t\t<Typography>{t(\"pages.incidents.filters.allMonitors\")}</Typography>\n\t\t\t\t</MenuItem>\n\t\t\t\t{monitors?.map((monitor) => (\n\t\t\t\t\t<MenuItem\n\t\t\t\t\t\tkey={monitor.id}\n\t\t\t\t\t\tvalue={monitor.id}\n\t\t\t\t\t>\n\t\t\t\t\t\t<Typography>{monitor.name}</Typography>\n\t\t\t\t\t</MenuItem>\n\t\t\t\t))}\n\t\t\t</Select>\n\t\t\t<Select\n\t\t\t\tplaceholder={t(\"pages.incidents.filters.resolutionType\")}\n\t\t\t\tvalue={selectedResolutionType}\n\t\t\t\tonChange={(e) => setSelectedResolutionType(e.target.value)}\n\t\t\t>\n\t\t\t\t{resolutionTypes.map((type) => (\n\t\t\t\t\t<MenuItem\n\t\t\t\t\t\tkey={type}\n\t\t\t\t\t\tvalue={type}\n\t\t\t\t\t>\n\t\t\t\t\t\t<Typography textTransform=\"capitalize\">\n\t\t\t\t\t\t\t{t(`pages.incidents.filters.resolutionTypes.${type}`)}\n\t\t\t\t\t\t</Typography>\n\t\t\t\t\t</MenuItem>\n\t\t\t\t))}\n\t\t\t</Select>\n\t\t\t{isFilterActive && (\n\t\t\t\t<Button\n\t\t\t\t\tvariant=\"contained\"\n\t\t\t\t\tonClick={onClearFilters}\n\t\t\t\t>\n\t\t\t\t\t{t(\"pages.incidents.filters.clearFilters\")}\n\t\t\t\t</Button>\n\t\t\t)}\n\t\t</Stack>\n\t);\n};\n"
  },
  {
    "path": "client/src/Pages/Incidents/Components/DialogIncidentDetails.tsx",
    "content": "import { Dialog } from \"@/Components/inputs\";\nimport { CardDetails } from \"@/Pages/Incidents/Components/CardDetails\";\n\nimport { useTranslation } from \"react-i18next\";\nimport type { Incident } from \"@/Types/Incident\";\nimport type { Monitor } from \"@/Types/Monitor\";\n\ninterface DialogIncidentDetailsProps {\n\topen: boolean;\n\tincident: Incident | null;\n\tmonitor: Monitor | null;\n\tonClose: () => void;\n\tonResolve: () => void;\n}\n\nexport const DialogIncidentDetails = ({\n\topen,\n\tincident,\n\tmonitor,\n\tonClose,\n\tonResolve,\n}: DialogIncidentDetailsProps) => {\n\tconst { t } = useTranslation();\n\n\tconst isActive = incident?.status === true;\n\n\treturn (\n\t\t<Dialog\n\t\t\topen={open}\n\t\t\tonCancel={onClose}\n\t\t\tonConfirm={isActive ? onResolve : undefined}\n\t\t\tcancelText={t(\"common.buttons.close\")}\n\t\t\tconfirmText={isActive ? t(\"pages.incidents.dialog.details.resolve\") : undefined}\n\t\t\tmaxWidth=\"sm\"\n\t\t\tfullWidth\n\t\t>\n\t\t\t<CardDetails\n\t\t\t\tincident={incident}\n\t\t\t\tmonitor={monitor}\n\t\t\t/>\n\t\t</Dialog>\n\t);\n};\n"
  },
  {
    "path": "client/src/Pages/Incidents/Components/DialogResolution.tsx",
    "content": "import { useState, useEffect } from \"react\";\nimport Box from \"@mui/material/Box\";\nimport { Dialog, TextField } from \"@/Components/inputs\";\nimport { usePut } from \"@/Hooks/UseApi\";\nimport { useTranslation } from \"react-i18next\";\nimport { useTheme } from \"@mui/material\";\n\ninterface DialogResolutionProps {\n\topen: boolean;\n\tincidentId: string | null;\n\tonClose: () => void;\n\tonResolved?: () => void;\n}\n\nexport const DialogResolution = ({\n\topen,\n\tincidentId,\n\tonClose,\n\tonResolved,\n}: DialogResolutionProps) => {\n\tconst { t } = useTranslation();\n\tconst theme = useTheme();\n\tconst [comment, setComment] = useState(\"\");\n\tconst { put: resolveIncident, loading: isResolving } = usePut();\n\n\tuseEffect(() => {\n\t\tif (open) {\n\t\t\tsetComment(\"\");\n\t\t}\n\t}, [open]);\n\n\tconst handleCancel = () => {\n\t\tonClose();\n\t};\n\n\tconst handleConfirm = async () => {\n\t\tif (!incidentId) return;\n\t\tconst body = comment.trim() ? { comment: comment.trim() } : {};\n\t\tconst result = await resolveIncident(`/incidents/${incidentId}/resolve`, body);\n\t\tif (result) {\n\t\t\tonClose();\n\t\t\tonResolved?.();\n\t\t}\n\t};\n\n\treturn (\n\t\t<Dialog\n\t\t\topen={open}\n\t\t\ttitle={t(\"pages.incidents.dialog.resolveIncident.title\")}\n\t\t\tonCancel={handleCancel}\n\t\t\tonConfirm={handleConfirm}\n\t\t\tconfirmColor=\"error\"\n\t\t\tcancelColor=\"primary\"\n\t\t\tloading={isResolving}\n\t\t\tmaxWidth=\"sm\"\n\t\t\tfullWidth\n\t\t>\n\t\t\t<Box sx={{ mt: theme.spacing(4) }}>\n\t\t\t\t<TextField\n\t\t\t\t\tfieldLabel={t(\"pages.incidents.dialog.resolveIncident.option.comment.label\")}\n\t\t\t\t\tplaceholder={t(\n\t\t\t\t\t\t\"pages.incidents.dialog.resolveIncident.option.comment.placeholder\"\n\t\t\t\t\t)}\n\t\t\t\t\tvalue={comment}\n\t\t\t\t\tonChange={(e) => setComment(e.target.value)}\n\t\t\t\t\tfullWidth\n\t\t\t\t/>\n\t\t\t</Box>\n\t\t</Dialog>\n\t);\n};\n"
  },
  {
    "path": "client/src/Pages/Incidents/Components/IncidentTable.tsx",
    "content": "import { Table } from \"@/Components/design-elements\";\nimport { Pagination } from \"@/Components/design-elements/Table\";\nimport type { Header } from \"@/Components/design-elements/Table\";\nimport { ValueLabel } from \"@/Components/design-elements\";\nimport type { ValueType } from \"@/Components/design-elements/StatusLabel\";\nimport { ActionsMenu } from \"@/Components/actions-menu\";\nimport type { Incident } from \"@/Types/Incident\";\nimport type { Monitor } from \"@/Types/Monitor\";\nimport type { ActionMenuItem } from \"@/Components/actions-menu\";\nimport { useTranslation } from \"react-i18next\";\nimport { useNavigate } from \"react-router-dom\";\nimport { formatDateWithTz } from \"@/Utils/TimeUtils\";\nimport { useSelector } from \"react-redux\";\nimport type { RootState } from \"@/Types/state\";\nimport Typography from \"@mui/material/Typography\";\nimport { useTheme } from \"@mui/material/styles\";\nimport Box from \"@mui/material/Box\";\nimport { getMonitorPath } from \"@/Utils/MonitorUtils\";\n\ninterface IncidentsTableProps {\n\ttitle?: string;\n\tincidents?: Incident[];\n\tmonitors?: Monitor[];\n\tincidentsCount: number;\n\tpage: number;\n\tsetPage: (page: number) => void;\n\trowsPerPage: number;\n\tsetRowsPerPage: (rowsPerPage: number) => void;\n\tonOpenDetails?: (incidentId: string) => void;\n\tonResolve?: (incidentId: string) => void;\n}\n\nexport const IncidentsTable = ({\n\tincidents,\n\tmonitors,\n\tincidentsCount,\n\tpage,\n\tsetPage,\n\trowsPerPage,\n\tsetRowsPerPage,\n\tonOpenDetails,\n\tonResolve,\n}: IncidentsTableProps) => {\n\tconst { t } = useTranslation();\n\tconst theme = useTheme();\n\tconst navigate = useNavigate();\n\tconst uiTimezone = useSelector((state: RootState) => state.ui.timezone);\n\n\tconst getActions = (incident: Incident): ActionMenuItem[] => {\n\t\tconst monitor = monitors?.find((m) => m.id === incident.monitorId);\n\t\tconst isActive = incident.status === true;\n\n\t\tconst actions: ActionMenuItem[] = [\n\t\t\t{\n\t\t\t\tid: \"details\",\n\t\t\t\tlabel: t(\"pages.incidents.table.actions.details\"),\n\t\t\t\taction: () => onOpenDetails?.(incident.id),\n\t\t\t\tcloseMenu: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"goToMonitor\",\n\t\t\t\tlabel: t(\"pages.incidents.table.actions.goToMonitor\"),\n\t\t\t\taction: () => {\n\t\t\t\t\tif (monitor) {\n\t\t\t\t\t\tconst path = getMonitorPath(monitor.type);\n\t\t\t\t\t\tif (path && monitor.id) {\n\t\t\t\t\t\t\tnavigate(`/${path}/${monitor.id}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tcloseMenu: true,\n\t\t\t},\n\t\t];\n\n\t\tif (isActive) {\n\t\t\tactions.push({\n\t\t\t\tid: \"resolve\",\n\t\t\t\tlabel: t(\"pages.incidents.table.actions.resolveManually\"),\n\t\t\t\taction: () => onResolve?.(incident.id),\n\t\t\t\tcloseMenu: true,\n\t\t\t});\n\t\t}\n\n\t\treturn actions;\n\t};\n\n\tconst getHeaders = (): Header<Incident>[] => {\n\t\treturn [\n\t\t\t{\n\t\t\t\tid: \"monitorName\",\n\t\t\t\tcontent: t(\"common.table.headers.monitor\"),\n\t\t\t\trender: (row) => {\n\t\t\t\t\tconst monitor = monitors?.find((m) => m.id === row.monitorId);\n\t\t\t\t\treturn monitor?.name || \"N/A\";\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"status\",\n\t\t\t\tcontent: t(\"common.table.headers.status\"),\n\t\t\t\trender: (row) => {\n\t\t\t\t\tconst isActive = row.status === true;\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<ValueLabel\n\t\t\t\t\t\t\tvalue={isActive ? \"negative\" : \"positive\"}\n\t\t\t\t\t\t\ttext={\n\t\t\t\t\t\t\t\tisActive\n\t\t\t\t\t\t\t\t\t? t(\"pages.incidents.table.status.active\")\n\t\t\t\t\t\t\t\t\t: t(\"pages.incidents.table.status.resolved\")\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t/>\n\t\t\t\t\t);\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"startTime\",\n\t\t\t\tcontent: t(\"pages.incidents.table.headers.startTime\"),\n\t\t\t\trender: (row) => {\n\t\t\t\t\treturn formatDateWithTz(row.createdAt, \"YYYY-MM-DD HH:mm:ss A\", uiTimezone);\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"endTime\",\n\t\t\t\tcontent: t(\"pages.incidents.table.headers.endTime\"),\n\t\t\t\trender: (row) => {\n\t\t\t\t\tif (row.endTime) {\n\t\t\t\t\t\treturn formatDateWithTz(row.endTime, \"YYYY-MM-DD HH:mm:ss A\", uiTimezone);\n\t\t\t\t\t}\n\t\t\t\t\treturn \"-\";\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"resolutionType\",\n\t\t\t\tcontent: t(\"pages.incidents.table.headers.resolutionType\"),\n\t\t\t\trender: (row) => {\n\t\t\t\t\tif (row.resolutionType) {\n\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t<Typography\n\t\t\t\t\t\t\t\tvariant=\"body2\"\n\t\t\t\t\t\t\t\tsx={{\n\t\t\t\t\t\t\t\t\ttextTransform: \"capitalize\",\n\t\t\t\t\t\t\t\t\tcolor:\n\t\t\t\t\t\t\t\t\t\trow.resolutionType === \"manual\"\n\t\t\t\t\t\t\t\t\t\t\t? theme.palette.warning.main\n\t\t\t\t\t\t\t\t\t\t\t: theme.palette.success.main,\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{row.resolutionType}\n\t\t\t\t\t\t\t</Typography>\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\treturn \"-\";\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"statusCode\",\n\t\t\t\tcontent: t(\"pages.incidents.table.headers.statusCode\"),\n\t\t\t\trender: (row) => {\n\t\t\t\t\tconst code = row.statusCode;\n\t\t\t\t\tif (!code) return \"N/A\";\n\t\t\t\t\tlet value: ValueType = \"neutral\";\n\t\t\t\t\tif (code < 300) value = \"positive\";\n\t\t\t\t\telse if (code >= 400) value = \"negative\";\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<ValueLabel\n\t\t\t\t\t\t\tvalue={value}\n\t\t\t\t\t\t\ttext={String(code)}\n\t\t\t\t\t\t/>\n\t\t\t\t\t);\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"message\",\n\t\t\t\tcontent: t(\"common.table.headers.message\"),\n\t\t\t\trender: (row) => row.message || \"-\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"actions\",\n\t\t\t\tcontent: t(\"common.table.headers.actions\"),\n\t\t\t\trender: (row) => <ActionsMenu items={getActions(row)} />,\n\t\t\t},\n\t\t];\n\t};\n\n\tconst handlePageChange = (\n\t\t_e: React.MouseEvent<HTMLButtonElement> | null,\n\t\tnewPage: number\n\t) => {\n\t\tsetPage(newPage);\n\t};\n\n\tconst handleRowsPerPageChange = (\n\t\te: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>\n\t) => {\n\t\tconst value = Number(e.target.value);\n\t\tsetPage(0);\n\t\tsetRowsPerPage(value);\n\t};\n\n\tif (!incidents || !monitors) {\n\t\treturn null;\n\t}\n\n\treturn (\n\t\t<Box>\n\t\t\t<Table\n\t\t\t\theaders={getHeaders()}\n\t\t\t\tdata={incidents}\n\t\t\t\tonRowClick={(row) => onOpenDetails?.(row.id)}\n\t\t\t\temptyViewText={t(\"common.table.empty\")}\n\t\t\t/>\n\t\t\t<Pagination\n\t\t\t\tcomponent=\"div\"\n\t\t\t\tcount={incidentsCount}\n\t\t\t\tpage={page}\n\t\t\t\trowsPerPage={rowsPerPage}\n\t\t\t\tonPageChange={handlePageChange}\n\t\t\t\tonRowsPerPageChange={handleRowsPerPageChange}\n\t\t\t\titemsOnPage={incidents.length}\n\t\t\t/>\n\t\t</Box>\n\t);\n};\n"
  },
  {
    "path": "client/src/Pages/Incidents/index.tsx",
    "content": "import { BasePage } from \"@/Components/design-elements\";\nimport Stack from \"@mui/material/Stack\";\nimport Typography from \"@mui/material/Typography\";\nimport Divider from \"@mui/material/Divider\";\nimport { useTranslation } from \"react-i18next\";\nimport {\n\tSummaryCardActiveIncidents,\n\tSummaryCardLatestIncidents,\n\tSummaryCardStats,\n} from \"@/Pages/Incidents/Components/CardSummary\";\nimport { IncidentsTable } from \"@/Pages/Incidents/Components/IncidentTable\";\nimport { DialogResolution } from \"@/Pages/Incidents/Components/DialogResolution\";\nimport { DialogIncidentDetails } from \"@/Pages/Incidents/Components/DialogIncidentDetails\";\nimport { HeaderTimeRange } from \"@/Components/common\";\nimport { ControlsIncidentFilter } from \"@/Pages/Incidents/Components/ControlsIncidentFilter\";\n\nimport { useGet } from \"@/Hooks/UseApi\";\nimport { useState, useEffect, useMemo } from \"react\";\nimport { useParams } from \"react-router-dom\";\nimport type { Incident, IncidentsResponse, IncidentSummary } from \"@/Types/Incident\";\nimport type { Monitor } from \"@/Types/Monitor\";\nimport { useTheme } from \"@mui/material\";\n\nconst IncidentsPage = () => {\n\tconst { t } = useTranslation();\n\tconst theme = useTheme();\n\tconst { monitorId } = useParams();\n\n\t// Filter state\n\tconst [selectedMonitor, setSelectedMonitor] = useState(monitorId || \"0\");\n\tconst [filter, setFilter] = useState(\"all\");\n\tconst [dateRange, setDateRange] = useState(\"recent\");\n\tconst [page, setPage] = useState(0);\n\tconst [rowsPerPage, setRowsPerPage] = useState(10);\n\tconst [activeIncidentsPage, setActiveIncidentsPage] = useState(0);\n\tconst [activeIncidentsRowsPerPage, setActiveIncidentsRowsPerPage] = useState(5);\n\n\t// Resolve dialog state\n\tconst [isResolveDialogOpen, setIsResolveDialogOpen] = useState(false);\n\tconst [resolveIncidentId, setResolveIncidentId] = useState<string | null>(null);\n\n\t// Details dialog state\n\tconst [isDetailsDialogOpen, setIsDetailsDialogOpen] = useState(false);\n\tconst [selectedIncident, setSelectedIncident] = useState<Incident | null>(null);\n\tconst [selectedIncidentMonitor, setSelectedIncidentMonitor] = useState<Monitor | null>(\n\t\tnull\n\t);\n\n\t// Build incidents URL with query params\n\tconst incidentsUrl = useMemo(() => {\n\t\tconst params = new URLSearchParams();\n\t\tif (selectedMonitor !== \"0\") params.append(\"monitorId\", selectedMonitor);\n\t\t// Always show only resolved incidents (active ones are in the separate table above)\n\t\tparams.append(\"status\", \"false\");\n\t\tif (filter === \"manual\" || filter === \"automatic\")\n\t\t\tparams.append(\"resolutionType\", filter);\n\t\tparams.append(\"sortOrder\", \"desc\");\n\t\tif (dateRange !== \"all\") params.append(\"dateRange\", dateRange);\n\t\tparams.append(\"page\", String(page));\n\t\tparams.append(\"rowsPerPage\", String(rowsPerPage));\n\t\treturn `/incidents/team?${params.toString()}`;\n\t}, [selectedMonitor, filter, dateRange, page, rowsPerPage]);\n\n\t// Fetch incidents\n\tconst {\n\t\tdata: incidentsData,\n\t\tisLoading: isLoadingIncidents,\n\t\trefetch: refetchIncidents,\n\t} = useGet<IncidentsResponse>(\n\t\tincidentsUrl,\n\t\t{},\n\t\t{ keepPreviousData: true, refreshInterval: 10000 }\n\t);\n\n\t// Fetch monitors for lookup\n\tconst { data: monitorsData } = useGet<Monitor[]>(\"/monitors/team\");\n\n\t// Build active incidents URL (always fetch all active, no date filter)\n\tconst activeIncidentsUrl = useMemo(() => {\n\t\tconst params = new URLSearchParams();\n\t\tif (selectedMonitor !== \"0\") params.append(\"monitorId\", selectedMonitor);\n\t\tparams.append(\"status\", \"true\");\n\t\tparams.append(\"sortOrder\", \"desc\");\n\t\tparams.append(\"page\", String(activeIncidentsPage));\n\t\tparams.append(\"rowsPerPage\", String(activeIncidentsRowsPerPage));\n\t\treturn `/incidents/team?${params.toString()}`;\n\t}, [selectedMonitor, activeIncidentsPage, activeIncidentsRowsPerPage]);\n\n\t// Fetch active incidents\n\tconst { data: activeIncidentsData, refetch: refetchActiveIncidents } =\n\t\tuseGet<IncidentsResponse>(\n\t\t\tactiveIncidentsUrl,\n\t\t\t{},\n\t\t\t{ keepPreviousData: true, refreshInterval: 10000 }\n\t\t);\n\n\t// Fetch incident summary\n\tconst { data: summaryData, refetch: refetchSummary } = useGet<IncidentSummary>(\n\t\t\"/incidents/team/summary\"\n\t);\n\n\t// Reset page when filters change\n\tuseEffect(() => {\n\t\tsetPage(0);\n\t}, [selectedMonitor, filter, dateRange]);\n\n\t// Derived state\n\tconst incidents = incidentsData?.incidents ?? [];\n\tconst incidentsCount = incidentsData?.count ?? 0;\n\tconst activeIncidents = activeIncidentsData?.incidents ?? [];\n\tconst activeIncidentsCount = activeIncidentsData?.count ?? 0;\n\n\tconst handleClearFilters = () => {\n\t\tsetSelectedMonitor(\"0\");\n\t\tsetFilter(\"all\");\n\t};\n\n\tconst handleOpenDetails = (incidentId: string) => {\n\t\tconst incident =\n\t\t\tincidents.find((i) => i.id === incidentId) ??\n\t\t\tactiveIncidents.find((i) => i.id === incidentId) ??\n\t\t\tnull;\n\t\tconst monitor = monitorsData?.find((m) => m.id === incident?.monitorId) ?? null;\n\t\tsetIsDetailsDialogOpen(true);\n\t\tsetSelectedIncident(incident);\n\t\tsetSelectedIncidentMonitor(monitor);\n\t};\n\n\tconst handleDetailsClose = () => {\n\t\tsetIsDetailsDialogOpen(false);\n\t};\n\n\tconst handleDetailsResolve = () => {\n\t\tif (selectedIncident) {\n\t\t\thandleDetailsClose();\n\t\t\thandleResolve(selectedIncident.id);\n\t\t}\n\t};\n\n\tconst handleResolve = (incidentId: string) => {\n\t\tsetResolveIncidentId(incidentId);\n\t\tsetIsResolveDialogOpen(true);\n\t};\n\n\tconst handleResolveClose = () => {\n\t\tsetIsResolveDialogOpen(false);\n\t\tsetResolveIncidentId(null);\n\t};\n\n\tconst handleResolved = () => {\n\t\trefetchIncidents();\n\t\trefetchActiveIncidents();\n\t\trefetchSummary();\n\t};\n\n\treturn (\n\t\t<BasePage>\n\t\t\t<Stack\n\t\t\t\tdirection={{ xs: \"column\", md: \"row\" }}\n\t\t\t\tgap={theme.spacing(8)}\n\t\t\t>\n\t\t\t\t<SummaryCardActiveIncidents summary={summaryData} />\n\t\t\t\t<SummaryCardLatestIncidents summary={summaryData} />\n\t\t\t\t<SummaryCardStats summary={summaryData} />\n\t\t\t</Stack>\n\t\t\t<ControlsIncidentFilter\n\t\t\t\tmonitors={monitorsData ?? undefined}\n\t\t\t\tselectedMonitor={selectedMonitor}\n\t\t\t\tsetSelectedMonitor={setSelectedMonitor}\n\t\t\t\tselectedResolutionType={filter}\n\t\t\t\tsetSelectedResolutionType={setFilter}\n\t\t\t\tonClearFilters={handleClearFilters}\n\t\t\t/>\n\t\t\t{activeIncidentsCount > 0 ? (\n\t\t\t\t<>\n\t\t\t\t\t<Typography\n\t\t\t\t\t\tvariant=\"h6\"\n\t\t\t\t\t\tsx={{ mb: theme.spacing(4), textTransform: \"uppercase\" }}\n\t\t\t\t\t>\n\t\t\t\t\t\t{t(\"pages.incidents.table.activeIncidents\")}\n\t\t\t\t\t</Typography>\n\n\t\t\t\t\t<IncidentsTable\n\t\t\t\t\t\tincidents={activeIncidents}\n\t\t\t\t\t\tmonitors={monitorsData ?? undefined}\n\t\t\t\t\t\tincidentsCount={activeIncidentsCount}\n\t\t\t\t\t\tpage={activeIncidentsPage}\n\t\t\t\t\t\tsetPage={setActiveIncidentsPage}\n\t\t\t\t\t\trowsPerPage={activeIncidentsRowsPerPage}\n\t\t\t\t\t\tsetRowsPerPage={setActiveIncidentsRowsPerPage}\n\t\t\t\t\t\tonOpenDetails={handleOpenDetails}\n\t\t\t\t\t\tonResolve={handleResolve}\n\t\t\t\t\t/>\n\t\t\t\t\t<Divider />\n\t\t\t\t</>\n\t\t\t) : (\n\t\t\t\t<Typography\n\t\t\t\t\tvariant=\"body1\"\n\t\t\t\t\tsx={{ mb: theme.spacing(4), color: theme.palette.success.main }}\n\t\t\t\t>\n\t\t\t\t\t{t(\"pages.incidents.summaryCard.activeIncidents.active_zero\")}\n\t\t\t\t</Typography>\n\t\t\t)}\n\n\t\t\t<Typography\n\t\t\t\tvariant=\"h6\"\n\t\t\t\tsx={{ mb: theme.spacing(4), textTransform: \"uppercase\" }}\n\t\t\t>\n\t\t\t\t{t(\"pages.incidents.table.resolvedIncidents\")}\n\t\t\t</Typography>\n\n\t\t\t<HeaderTimeRange\n\t\t\t\tdateRange={dateRange}\n\t\t\t\tsetDateRange={setDateRange}\n\t\t\t\tisLoading={isLoadingIncidents}\n\t\t\t/>\n\t\t\t<IncidentsTable\n\t\t\t\tincidents={incidents}\n\t\t\t\tmonitors={monitorsData ?? undefined}\n\t\t\t\tincidentsCount={incidentsCount}\n\t\t\t\tpage={page}\n\t\t\t\tsetPage={setPage}\n\t\t\t\trowsPerPage={rowsPerPage}\n\t\t\t\tsetRowsPerPage={setRowsPerPage}\n\t\t\t\tonOpenDetails={handleOpenDetails}\n\t\t\t\tonResolve={handleResolve}\n\t\t\t/>\n\t\t\t<DialogResolution\n\t\t\t\topen={isResolveDialogOpen}\n\t\t\t\tincidentId={resolveIncidentId}\n\t\t\t\tonClose={handleResolveClose}\n\t\t\t\tonResolved={handleResolved}\n\t\t\t/>\n\t\t\t<DialogIncidentDetails\n\t\t\t\topen={isDetailsDialogOpen}\n\t\t\t\tincident={selectedIncident}\n\t\t\t\tmonitor={selectedIncidentMonitor}\n\t\t\t\tonClose={handleDetailsClose}\n\t\t\t\tonResolve={handleDetailsResolve}\n\t\t\t/>\n\t\t</BasePage>\n\t);\n};\n\nexport default IncidentsPage;\n"
  },
  {
    "path": "client/src/Pages/Incidents/utils.ts",
    "content": "import type { Incident, IncidentSummaryItem } from \"@/Types/Incident\";\nimport prettyMilliseconds from \"pretty-ms\";\n\ntype IncidentLike = Pick<Incident, \"startTime\" | \"endTime\" | \"status\">;\n\nexport const getIncidentsDuration = (incident: IncidentLike | IncidentSummaryItem) => {\n\tif (!incident?.startTime) {\n\t\treturn \"-\";\n\t}\n\tconst startTime = new Date(incident?.startTime);\n\tconst endTime = incident.status\n\t\t? new Date()\n\t\t: incident?.endTime\n\t\t\t? new Date(incident.endTime)\n\t\t\t: null;\n\n\tif (!endTime) {\n\t\treturn \"-\";\n\t}\n\n\tconst durationMs = endTime.getTime() - startTime.getTime();\n\n\tif (durationMs < 0) {\n\t\treturn \"-\";\n\t}\n\n\treturn prettyMilliseconds(durationMs, {\n\t\tsecondsDecimalDigits: 0,\n\t\tmillisecondsDecimalDigits: 0,\n\t});\n};\n"
  },
  {
    "path": "client/src/Pages/Infrastructure/Details/Components/Charts.tsx",
    "content": "import Grid from \"@mui/material/Grid\";\nimport { HistogramInfrastructure } from \"@/Components/monitors\";\n\nimport { useTranslation } from \"react-i18next\";\nimport type { HardwareCheckStats } from \"@/Types/Monitor\";\nimport { useMemo } from \"react\";\nimport { useTheme } from \"@mui/material/styles\";\nimport useMediaQuery from \"@mui/material/useMediaQuery\";\nconst formatPercent = (value: number) => `${(value * 100).toFixed(0)}%`;\nconst formatTemp = (value: number) => `${value.toFixed(0)}°C`;\n\nconst getChartConfigs = (theme: any, checks: HardwareCheckStats[], t: any) => {\n\treturn [\n\t\t{\n\t\t\ttitle: t(\"pages.infrastructure.charts.labels.memory\"),\n\t\t\ttype: \"memory\",\n\t\t\tdataKeys: [\"avgMemoryUsage\"],\n\t\t\tstrokeColor: theme.palette.primary.main,\n\t\t\tgradientStartColor: theme.palette.primary.main,\n\t\t\tyDomain: [0, 1],\n\t\t\tyAxisFormatter: formatPercent,\n\t\t\tidx: null,\n\t\t},\n\t\t{\n\t\t\ttitle: t(\"pages.infrastructure.charts.labels.cpu\"),\n\t\t\ttype: \"cpu\",\n\t\t\tdataKeys: [\"avgCpuUsage\"],\n\t\t\tstrokeColor: theme.palette.success.main,\n\t\t\tgradientStartColor: theme.palette.success.main,\n\t\t\tyDomain: [0, 1],\n\t\t\tyAxisFormatter: formatPercent,\n\t\t\tidx: null,\n\t\t},\n\t\t{\n\t\t\ttitle: t(\"pages.infrastructure.charts.labels.temp\"),\n\t\t\ttype: \"temp\",\n\t\t\tdataKeys: [\"avg_temp\"],\n\t\t\tstrokeColor: theme.palette.error.main,\n\t\t\tgradientStartColor: theme.palette.error.main,\n\t\t\tyDomain: [0, 150],\n\t\t\tyAxisFormatter: formatTemp,\n\t\t\tidx: null,\n\t\t},\n\t\t...(checks[0]?.disks?.map((_, idx) => ({\n\t\t\ttitle: t(\"pages.infrastructure.charts.labels.disk\", { idx }),\n\t\t\ttype: \"disk\",\n\t\t\tdataKeys: [`disks[${idx}].usagePercent`],\n\t\t\tstrokeColor: theme.palette.warning.main,\n\t\t\tgradientStartColor: theme.palette.warning.main,\n\t\t\tyDomain: [0, 1],\n\t\t\tyAxisFormatter: formatPercent,\n\t\t\tidx,\n\t\t})) || []),\n\t];\n};\n\nexport const InfraDetailsCharts = ({\n\tchecks,\n\tdateRange,\n}: {\n\tchecks: HardwareCheckStats[];\n\tdateRange: string;\n}) => {\n\tconst theme = useTheme();\n\tconst isSmall = useMediaQuery(theme.breakpoints.down(\"md\"));\n\tconst { t } = useTranslation();\n\tconst chartConfigs = useMemo(\n\t\t() => getChartConfigs(theme, checks, t),\n\t\t[theme, checks, t]\n\t);\n\n\treturn (\n\t\t<Grid\n\t\t\tcontainer\n\t\t\tspacing={theme.spacing(8)}\n\t\t>\n\t\t\t{chartConfigs.map((config) => {\n\t\t\t\treturn (\n\t\t\t\t\t<Grid\n\t\t\t\t\t\tsize={isSmall ? 12 : 6}\n\t\t\t\t\t\tkey={`${config.type}-${config.idx ?? \"\"}`}\n\t\t\t\t\t>\n\t\t\t\t\t\t<HistogramInfrastructure\n\t\t\t\t\t\t\tdateRange={dateRange}\n\t\t\t\t\t\t\ttitle={config.title}\n\t\t\t\t\t\t\ttype={config.type}\n\t\t\t\t\t\t\tidx={config.idx}\n\t\t\t\t\t\t\tkey={`${config.type}-${config.idx ?? \"\"}`}\n\t\t\t\t\t\t\tchecks={checks}\n\t\t\t\t\t\t\txKey=\"bucketDate\"\n\t\t\t\t\t\t\tyDomain={config.yDomain}\n\t\t\t\t\t\t\tdataKeys={config.dataKeys}\n\t\t\t\t\t\t\tgradient={true}\n\t\t\t\t\t\t\tgradientStartColor={config.gradientStartColor}\n\t\t\t\t\t\t\tgradientEndColor=\"#ffffff\"\n\t\t\t\t\t\t\tstrokeColor={config.strokeColor}\n\t\t\t\t\t\t\tyAxisFormatter={config.yAxisFormatter}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</Grid>\n\t\t\t\t);\n\t\t\t})}\n\t\t</Grid>\n\t);\n};\n"
  },
  {
    "path": "client/src/Pages/Infrastructure/Details/Components/ChartsNetwork.tsx",
    "content": "import Grid from \"@mui/material/Grid\";\nimport { HistogramInfrastructure } from \"@/Components/monitors\";\n\nimport { useTranslation } from \"react-i18next\";\nimport type { HardwareCheckStats } from \"@/Types/Monitor\";\nimport { useMemo } from \"react\";\nimport { useTheme } from \"@mui/material/styles\";\nimport useMediaQuery from \"@mui/material/useMediaQuery\";\n\nconst formatBytesToMB = (value: number) => `${(value / (1024 * 1024)).toFixed(2)} MB`;\n\ninterface ChartConfig {\n\ttitle: string;\n\ttype: string;\n\tdataKeys: string[];\n\tstrokeColor: string;\n\tgradientStartColor: string;\n\tidx: number | null;\n\tinterfaceName?: string;\n}\n\nconst getChartConfigs = (\n\ttheme: any,\n\tchecks: HardwareCheckStats[],\n\tt: any\n): ChartConfig[] => {\n\tconst configs: ChartConfig[] = [];\n\n\t// Find the first check that has network data to get interface names\n\tconst checkWithNet = checks.find((c) => c.net && c.net.length > 0);\n\tconst netInterfaces = checkWithNet?.net || [];\n\n\tnetInterfaces.forEach((iface, idx) => {\n\t\tconfigs.push(\n\t\t\t{\n\t\t\t\ttitle: t(\"pages.infrastructure.charts.labels.netBytesSent\", {\n\t\t\t\t\tname: iface.name,\n\t\t\t\t}),\n\t\t\t\ttype: \"netBytesSent\",\n\t\t\t\tdataKeys: [`net[${idx}].bytesSentPerSecond`],\n\t\t\t\tstrokeColor: theme.palette.primary.main,\n\t\t\t\tgradientStartColor: theme.palette.primary.main,\n\t\t\t\tidx,\n\t\t\t\tinterfaceName: iface.name,\n\t\t\t},\n\t\t\t{\n\t\t\t\ttitle: t(\"pages.infrastructure.charts.labels.netBytesRecv\", {\n\t\t\t\t\tname: iface.name,\n\t\t\t\t}),\n\t\t\t\ttype: \"netBytesRecv\",\n\t\t\t\tdataKeys: [`net[${idx}].deltaBytesRecv`],\n\t\t\t\tstrokeColor: theme.palette.success.main,\n\t\t\t\tgradientStartColor: theme.palette.success.main,\n\t\t\t\tidx,\n\t\t\t\tinterfaceName: iface.name,\n\t\t\t}\n\t\t);\n\t});\n\n\treturn configs;\n};\n\nexport const InfraNetworkCharts = ({\n\tchecks,\n\tdateRange,\n}: {\n\tchecks: HardwareCheckStats[];\n\tdateRange: string;\n}) => {\n\tconst theme = useTheme();\n\tconst isSmall = useMediaQuery(theme.breakpoints.down(\"md\"));\n\tconst { t } = useTranslation();\n\tconst chartConfigs = useMemo(\n\t\t() => getChartConfigs(theme, checks, t),\n\t\t[theme, checks, t]\n\t);\n\n\treturn (\n\t\t<Grid\n\t\t\tcontainer\n\t\t\tspacing={theme.spacing(8)}\n\t\t>\n\t\t\t{chartConfigs.map((config) => {\n\t\t\t\treturn (\n\t\t\t\t\t<Grid\n\t\t\t\t\t\tsize={isSmall ? 12 : 6}\n\t\t\t\t\t\tkey={`${config.type}-${config.interfaceName ?? config.idx ?? \"\"}`}\n\t\t\t\t\t>\n\t\t\t\t\t\t<HistogramInfrastructure\n\t\t\t\t\t\t\tdateRange={dateRange}\n\t\t\t\t\t\t\ttitle={config.title}\n\t\t\t\t\t\t\ttype={config.type}\n\t\t\t\t\t\t\tidx={config.idx}\n\t\t\t\t\t\t\tchecks={checks}\n\t\t\t\t\t\t\txKey=\"bucketDate\"\n\t\t\t\t\t\t\tdataKeys={config.dataKeys}\n\t\t\t\t\t\t\tgradient={true}\n\t\t\t\t\t\t\tgradientStartColor={config.gradientStartColor}\n\t\t\t\t\t\t\tgradientEndColor=\"#ffffff\"\n\t\t\t\t\t\t\tstrokeColor={config.strokeColor}\n\t\t\t\t\t\t\tyAxisFormatter={formatBytesToMB}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</Grid>\n\t\t\t\t);\n\t\t\t})}\n\t\t</Grid>\n\t);\n};\n"
  },
  {
    "path": "client/src/Pages/Infrastructure/Details/Components/Gauges.tsx",
    "content": "import Stack from \"@mui/material/Stack\";\nimport { DetailGauge } from \"@/Components/design-elements\";\n\nimport prettyBytes from \"pretty-bytes\";\nimport { useTranslation } from \"react-i18next\";\nimport { getFrequency } from \"@/Utils/InfraUtils\";\nimport { useTheme } from \"@mui/material\";\nimport useMediaQuery from \"@mui/material/useMediaQuery\";\nimport type { CheckSnapshot } from \"@/Types/Check\";\n\nexport const InfraDetailsGauges = ({\n\tsnapshot,\n}: {\n\tsnapshot: CheckSnapshot | undefined;\n}) => {\n\tconst { t } = useTranslation();\n\tconst theme = useTheme();\n\tconst isSmall = useMediaQuery(theme.breakpoints.down(\"md\"));\n\n\tif (!snapshot) {\n\t\treturn null;\n\t}\n\n\treturn (\n\t\t<Stack\n\t\t\tdirection={isSmall ? \"column\" : \"row\"}\n\t\t\tspacing={theme.spacing(8)}\n\t\t\talignItems={\"center\"}\n\t\t>\n\t\t\t<DetailGauge\n\t\t\t\ttitle={t(\"pages.infrastructure.gauges.memory.title\")}\n\t\t\t\tprogress={(snapshot?.memory?.usage_percent || 0) * 100}\n\t\t\t\tupperLabel={t(\"pages.infrastructure.gauges.memory.upperLabel\")}\n\t\t\t\tupperValue={prettyBytes(snapshot?.memory?.used_bytes || 0)}\n\t\t\t\tlowerLabel={t(\"pages.infrastructure.gauges.memory.lowerLabel\")}\n\t\t\t\tlowerValue={prettyBytes(snapshot?.memory?.total_bytes || 0)}\n\t\t\t/>\n\t\t\t<DetailGauge\n\t\t\t\ttitle={t(\"pages.infrastructure.gauges.cpu.title\")}\n\t\t\t\tprogress={(snapshot?.cpu?.usage_percent || 0) * 100}\n\t\t\t\tupperLabel={t(\"pages.infrastructure.gauges.cpu.upperLabel\")}\n\t\t\t\tupperValue={getFrequency(snapshot?.cpu?.current_frequency || 0)}\n\t\t\t\tlowerLabel={t(\"pages.infrastructure.gauges.cpu.lowerLabel\")}\n\t\t\t\tlowerValue={getFrequency(snapshot?.cpu?.frequency || 0)}\n\t\t\t/>\n\t\t\t{snapshot?.disk?.map((disk, idx) => {\n\t\t\t\treturn (\n\t\t\t\t\t<DetailGauge\n\t\t\t\t\t\tkey={disk?.device || 0 + idx}\n\t\t\t\t\t\t// title={`Disk ${idx} usage`}\n\t\t\t\t\t\ttitle={t(\"pages.infrastructure.gauges.disk.title\", { idx })}\n\t\t\t\t\t\tprogress={(disk.usage_percent || 0) * 100}\n\t\t\t\t\t\tupperLabel={t(\"pages.infrastructure.gauges.disk.upperLabel\")}\n\t\t\t\t\t\tupperValue={prettyBytes(disk?.used_bytes || 0)}\n\t\t\t\t\t\tlowerLabel={t(\"pages.infrastructure.gauges.disk.lowerLabel\")}\n\t\t\t\t\t\tlowerValue={prettyBytes(disk?.total_bytes || 0)}\n\t\t\t\t\t/>\n\t\t\t\t);\n\t\t\t})}\n\t\t</Stack>\n\t);\n};\n"
  },
  {
    "path": "client/src/Pages/Infrastructure/Details/Components/StatusBoxes.tsx",
    "content": "import Stack from \"@mui/material/Stack\";\nimport { StatBox } from \"@/Components/design-elements\";\n\nimport prettyBytes from \"pretty-bytes\";\nimport { useTheme } from \"@mui/material\";\nimport { useTranslation } from \"react-i18next\";\nimport type { Monitor } from \"@/Types/Monitor\";\nimport { getAvgTemp, getCores, getFrequency, getOsAndPlatform } from \"@/Utils/InfraUtils\";\n\nexport const StatusBoxes = ({ monitor }: { monitor: Monitor }) => {\n\tconst { t } = useTranslation();\n\tconst theme = useTheme();\n\n\tconst latestCheck = monitor?.recentChecks?.[0];\n\t// Get data from latest check\n\tconst physicalCores = getCores(latestCheck?.cpu?.physical_core);\n\tconst logicalCores = getCores(latestCheck?.cpu?.logical_core);\n\tconst cpuFrequency = getFrequency(latestCheck?.cpu?.frequency);\n\tconst cpuTemps = latestCheck?.cpu?.temperature ?? [];\n\tconst cpuTemperature = getAvgTemp(cpuTemps);\n\tconst memoryTotalBytes = latestCheck?.memory?.total_bytes ?? 0;\n\tconst diskTotalBytes =\n\t\tlatestCheck?.disk?.reduce((acc, disk) => acc + (disk.total_bytes || 0), 0) || 0;\n\tconst os = getOsAndPlatform(latestCheck?.host);\n\n\tconst platform = latestCheck?.host?.platform ?? undefined;\n\tconst osPlatform =\n\t\ttypeof os === \"undefined\" && typeof platform === \"undefined\"\n\t\t\t? undefined\n\t\t\t: `${os} ${platform}`;\n\n\treturn (\n\t\t<Stack\n\t\t\tdirection=\"row\"\n\t\t\tgap={theme.spacing(8)}\n\t\t\tflexWrap={\"wrap\"}\n\t\t>\n\t\t\t<StatBox\n\t\t\t\ttitle={t(\"pages.infrastructure.statBoxes.cpuPhysical\")}\n\t\t\t\tsubtitle={physicalCores.toString()}\n\t\t\t/>\n\t\t\t<StatBox\n\t\t\t\ttitle={t(\"pages.infrastructure.statBoxes.cpuLogical\")}\n\t\t\t\tsubtitle={logicalCores.toString()}\n\t\t\t/>\n\t\t\t<StatBox\n\t\t\t\ttitle={t(\"pages.infrastructure.statBoxes.cpuFrequency\")}\n\t\t\t\tsubtitle={cpuFrequency}\n\t\t\t/>\n\t\t\t<StatBox\n\t\t\t\ttitle={t(\"pages.infrastructure.statBoxes.avgCpuTemperature\")}\n\t\t\t\tsubtitle={cpuTemperature}\n\t\t\t/>\n\t\t\t<StatBox\n\t\t\t\ttitle={t(\"pages.infrastructure.statBoxes.memory\")}\n\t\t\t\tsubtitle={prettyBytes(memoryTotalBytes)}\n\t\t\t/>\n\t\t\t<StatBox\n\t\t\t\ttitle={t(\"pages.infrastructure.statBoxes.disk\")}\n\t\t\t\tsubtitle={prettyBytes(diskTotalBytes)}\n\t\t\t/>\n\t\t\t<StatBox\n\t\t\t\ttitle={t(\"pages.infrastructure.statBoxes.os\")}\n\t\t\t\tsubtitle={osPlatform || \"N/A\"}\n\t\t\t/>\n\t\t</Stack>\n\t);\n};\n"
  },
  {
    "path": "client/src/Pages/Infrastructure/Details/Components/TabNetwork.tsx",
    "content": "import Stack from \"@mui/material/Stack\";\nimport { InfraNetworkCharts } from \"./ChartsNetwork\";\n\nimport { useTheme } from \"@mui/material\";\nimport type { HardwareStats } from \"@/Types/Monitor\";\n\nexport const TabNetwork = ({\n\tstats,\n\tdateRange,\n}: {\n\tstats: HardwareStats | undefined;\n\tdateRange: string;\n}) => {\n\tconst theme = useTheme();\n\n\tif (!stats) {\n\t\treturn null;\n\t}\n\n\tconst checks = stats?.checks || [];\n\treturn (\n\t\t<Stack gap={theme.spacing(8)}>\n\t\t\t<InfraNetworkCharts\n\t\t\t\tchecks={checks}\n\t\t\t\tdateRange={dateRange}\n\t\t\t/>\n\t\t</Stack>\n\t);\n};\n"
  },
  {
    "path": "client/src/Pages/Infrastructure/Details/Components/TabOverview.tsx",
    "content": "import Stack from \"@mui/material/Stack\";\nimport { InfraDetailsGauges } from \"@/Pages/Infrastructure/Details/Components/Gauges\";\nimport { StatusBoxes } from \"@/Pages/Infrastructure/Details/Components/StatusBoxes\";\nimport { InfraDetailsCharts } from \"@/Pages/Infrastructure/Details/Components/Charts\";\n\nimport { useTheme } from \"@mui/material\";\nimport type { HardwareStats, Monitor } from \"@/Types/Monitor\";\n\nexport const TabOverview = ({\n\tmonitor,\n\tstats,\n\tdateRange,\n}: {\n\tmonitor: Monitor | undefined;\n\tstats: HardwareStats | undefined;\n\tdateRange: string;\n}) => {\n\tconst theme = useTheme();\n\tif (!monitor) {\n\t\treturn null;\n\t}\n\n\tconst checks = stats?.checks || [];\n\treturn (\n\t\t<Stack gap={theme.spacing(8)}>\n\t\t\t<StatusBoxes monitor={monitor} />\n\t\t\t<InfraDetailsGauges snapshot={monitor.recentChecks?.[0]} />\n\t\t\t<InfraDetailsCharts\n\t\t\t\tchecks={checks}\n\t\t\t\tdateRange={dateRange}\n\t\t\t/>\n\t\t</Stack>\n\t);\n};\n"
  },
  {
    "path": "client/src/Pages/Infrastructure/Details/index.tsx",
    "content": "import { BasePage, Tab, Tabs } from \"@/Components/design-elements\";\nimport { HeaderTimeRange } from \"@/Components/common\";\nimport { MonitorStatBoxes, HeaderMonitorControls } from \"@/Components/monitors\";\nimport { TabNetwork } from \"@/Pages/Infrastructure/Details/Components/TabNetwork\";\nimport { TabOverview } from \"@/Pages/Infrastructure/Details/Components/TabOverview\";\n\nimport { useMemo, useState } from \"react\";\nimport { useParams } from \"react-router-dom\";\nimport { useGet } from \"@/Hooks/UseApi\";\nimport type { HardwareDetailsResponse } from \"@/Types/Monitor\";\nimport { useIsAdmin } from \"@/Hooks/useIsAdmin\";\nimport { useTranslation } from \"react-i18next\";\n\nconst InfrastructureDetails = () => {\n\tconst { t } = useTranslation();\n\tconst isAdmin = useIsAdmin();\n\n\tconst { monitorId } = useParams<{ monitorId: string }>();\n\n\tconst [dateRange, setDateRange] = useState<string>(\"recent\");\n\tconst [selectedTab, setSelectedTab] = useState<number>(0);\n\n\tconst monitorDetailsUrl = useMemo(() => {\n\t\tif (!monitorId) {\n\t\t\treturn null;\n\t\t}\n\t\tconst params = new URLSearchParams();\n\t\tparams.append(\"dateRange\", dateRange);\n\t\treturn `/monitors/hardware/details/${monitorId}?${params.toString()}`;\n\t}, [monitorId, dateRange]);\n\n\tconst {\n\t\tdata: monitorDetailsData,\n\t\tisLoading: monitorIsLoading,\n\t\trefetch: refetchMonitor,\n\t} = useGet<HardwareDetailsResponse>(\n\t\tmonitorDetailsUrl,\n\t\t{},\n\t\t{ refreshInterval: 10000, keepPreviousData: true }\n\t);\n\n\tconst monitor = monitorDetailsData?.monitor;\n\tconst monitorStats = monitorDetailsData?.monitorStats ?? null;\n\tconst stats = monitorDetailsData?.stats;\n\n\treturn (\n\t\t<BasePage>\n\t\t\t<HeaderMonitorControls\n\t\t\t\tpath=\"infrastructure\"\n\t\t\t\tmonitor={monitor}\n\t\t\t\tisAdmin={isAdmin}\n\t\t\t\trefetch={refetchMonitor}\n\t\t\t/>\n\t\t\t<MonitorStatBoxes\n\t\t\t\tmonitor={monitor}\n\t\t\t\tmonitorStats={monitorStats}\n\t\t\t/>\n\t\t\t<HeaderTimeRange\n\t\t\t\tisLoading={monitorIsLoading}\n\t\t\t\thasDateRange={true}\n\t\t\t\tdateRange={dateRange}\n\t\t\t\tsetDateRange={setDateRange}\n\t\t\t/>\n\t\t\t<Tabs\n\t\t\t\tvalue={selectedTab}\n\t\t\t\tonChange={(_e, value) => {\n\t\t\t\t\tsetSelectedTab(value);\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t<Tab label={t(\"pages.infrastructure.tabs.labels.overview\")} />\n\t\t\t\t<Tab label={t(\"pages.infrastructure.tabs.labels.network\")} />\n\t\t\t</Tabs>\n\t\t\t{selectedTab === 0 && (\n\t\t\t\t<TabOverview\n\t\t\t\t\tmonitor={monitor}\n\t\t\t\t\tstats={stats}\n\t\t\t\t\tdateRange={dateRange}\n\t\t\t\t/>\n\t\t\t)}\n\t\t\t{selectedTab === 1 && (\n\t\t\t\t<TabNetwork\n\t\t\t\t\tstats={stats}\n\t\t\t\t\tdateRange={dateRange}\n\t\t\t\t/>\n\t\t\t)}\n\t\t</BasePage>\n\t);\n};\n\nexport default InfrastructureDetails;\n"
  },
  {
    "path": "client/src/Pages/Infrastructure/Monitors/Components/MonitorsTable.tsx",
    "content": "import Box from \"@mui/material/Box\";\nimport Typography from \"@mui/material/Typography\";\nimport { Table, Pagination, StatusLabel, Gauge } from \"@/Components/design-elements\";\nimport type { Header } from \"@/Components/design-elements/Table\";\nimport { ActionsMenu, type ActionMenuItem } from \"@/Components/actions-menu\";\nimport { ArrowUp, ArrowDown } from \"lucide-react\";\n\nimport { useTranslation } from \"react-i18next\";\nimport useMediaQuery from \"@mui/material/useMediaQuery\";\nimport { useTheme } from \"@mui/material/styles\";\nimport { useNavigate } from \"react-router-dom\";\nimport { usePost } from \"@/Hooks/UseApi\";\n\nimport type { Monitor } from \"@/Types/Monitor\";\n\nexport const InfraMonitorsTable = ({\n\tmonitors,\n\trefetch,\n\tsetSelectedMonitor,\n\tsortField,\n\tsetSortField,\n\tsortOrder,\n\tsetSortOrder,\n\tcount,\n\tpage,\n\tsetPage,\n\trowsPerPage,\n\tsetRowsPerPage,\n}: {\n\tmonitors: Monitor[];\n\trefetch: Function;\n\tsetSelectedMonitor: Function;\n\tsortField: string;\n\tsetSortField: (field: string) => void;\n\tsortOrder: \"asc\" | \"desc\";\n\tsetSortOrder: (order: \"asc\" | \"desc\") => void;\n\tcount: number;\n\tpage: number;\n\tsetPage: (page: number) => void;\n\trowsPerPage: number;\n\tsetRowsPerPage: (rowsPerPage: number) => void;\n}) => {\n\tconst { t } = useTranslation();\n\tconst theme = useTheme();\n\tconst isSmall = useMediaQuery(theme.breakpoints.down(\"md\"));\n\tconst navigate = useNavigate();\n\tconst {\n\t\tpost,\n\t\t// loading: isPatching,\n\t\t// error: postError,\n\t} = usePost<any, Monitor>();\n\n\tconst handlePageChange = (\n\t\t_e: React.MouseEvent<HTMLButtonElement> | null,\n\t\tnewPage: number\n\t) => {\n\t\tsetPage(newPage);\n\t};\n\n\tconst handleRowsPerPageChange = (\n\t\te: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>\n\t) => {\n\t\tconst value = Number(e.target.value);\n\t\tsetPage(0);\n\t\tsetRowsPerPage(value);\n\t};\n\n\tconst handleSort = (e: any, field: string) => {\n\t\te.preventDefault();\n\t\te.stopPropagation();\n\t\tif (sortField === field) {\n\t\t\tconst newOrder = sortOrder === \"asc\" ? \"desc\" : \"asc\";\n\t\t\tsetSortOrder(newOrder);\n\t\t} else {\n\t\t\tsetSortField(field);\n\t\t\tsetSortOrder(\"asc\");\n\t\t}\n\t\trefetch();\n\t};\n\n\tconst getActions = (monitor: Monitor): ActionMenuItem[] => {\n\t\treturn [\n\t\t\t{\n\t\t\t\tid: 1,\n\t\t\t\tlabel: t(\"pages.common.monitors.actions.openSite\"),\n\t\t\t\taction: () => {\n\t\t\t\t\twindow.open(monitor.url, \"_blank\", \"noreferrer\");\n\t\t\t\t},\n\t\t\t\tcloseMenu: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 2,\n\t\t\t\tlabel: t(\"pages.common.monitors.actions.details\"),\n\t\t\t\taction: () => {\n\t\t\t\t\tnavigate(`${monitor.id}`);\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 3,\n\t\t\t\tlabel: t(\"pages.common.monitors.actions.incidents\"),\n\t\t\t\taction: () => {\n\t\t\t\t\tnavigate(`/incidents?monitorId=${monitor.id}`);\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 4,\n\t\t\t\tlabel: t(\"pages.common.monitors.actions.configure\"),\n\t\t\t\taction: () => {\n\t\t\t\t\tnavigate(`/infrastructure/configure/${monitor.id}`);\n\t\t\t\t},\n\t\t\t},\n\t\t\t// {\n\t\t\t//   id: 5,\n\t\t\t//   label: \"Clone\",\n\t\t\t//   action: () => {\n\n\t\t\t//   },\n\t\t\t// },\n\t\t\t{\n\t\t\t\tid: 6,\n\t\t\t\tlabel:\n\t\t\t\t\tmonitor.isActive === false\n\t\t\t\t\t\t? t(\"common.buttons.resume\")\n\t\t\t\t\t\t: t(\"common.buttons.pause\"),\n\t\t\t\taction: async () => {\n\t\t\t\t\tawait post(`/monitors/pause/${monitor.id}`, {});\n\t\t\t\t\trefetch();\n\t\t\t\t},\n\t\t\t\tcloseMenu: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 7,\n\t\t\t\tlabel: (\n\t\t\t\t\t<Typography color={theme.palette.error.main}>\n\t\t\t\t\t\t{t(\"common.buttons.delete\")}\n\t\t\t\t\t</Typography>\n\t\t\t\t),\n\t\t\t\taction: () => {\n\t\t\t\t\tsetSelectedMonitor(monitor);\n\t\t\t\t},\n\t\t\t\tcloseMenu: true,\n\t\t\t},\n\t\t];\n\t};\n\n\tconst getHeaders = () => {\n\t\tconst renderSortIcon = (isActive: boolean) => (\n\t\t\t<Box\n\t\t\t\twidth={16}\n\t\t\t\tdisplay=\"inline-flex\"\n\t\t\t\tjustifyContent=\"center\"\n\t\t\t>\n\t\t\t\t{isActive ? (\n\t\t\t\t\tsortOrder === \"asc\" ? (\n\t\t\t\t\t\t<ArrowUp size={16} />\n\t\t\t\t\t) : (\n\t\t\t\t\t\t<ArrowDown size={16} />\n\t\t\t\t\t)\n\t\t\t\t) : null}\n\t\t\t</Box>\n\t\t);\n\t\tconst headers: Header<Monitor>[] = [\n\t\t\t{\n\t\t\t\tid: \"name\",\n\t\t\t\tcontent: (\n\t\t\t\t\t<Typography\n\t\t\t\t\t\tcomponent=\"div\"\n\t\t\t\t\t\tdisplay=\"inline-flex\"\n\t\t\t\t\t\talignItems=\"center\"\n\t\t\t\t\t\tgap={theme.spacing(4)}\n\t\t\t\t\t\tonClick={(e) => handleSort(e, \"name\")}\n\t\t\t\t\t\tsx={{ cursor: \"pointer\" }}\n\t\t\t\t\t>\n\t\t\t\t\t\t{t(\"common.table.headers.name\")}\n\t\t\t\t\t\t{renderSortIcon(sortField === \"name\")}\n\t\t\t\t\t</Typography>\n\t\t\t\t),\n\t\t\t\trender: (row) => {\n\t\t\t\t\treturn row.name;\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"status\",\n\t\t\t\tcontent: (\n\t\t\t\t\t<Typography\n\t\t\t\t\t\tcomponent=\"div\"\n\t\t\t\t\t\tdisplay=\"inline-flex\"\n\t\t\t\t\t\talignItems=\"center\"\n\t\t\t\t\t\tgap={theme.spacing(4)}\n\t\t\t\t\t\tonClick={(e) => handleSort(e, \"status\")}\n\t\t\t\t\t\tsx={{ cursor: \"pointer\" }}\n\t\t\t\t\t>\n\t\t\t\t\t\t{t(\"common.table.headers.status\")}\n\t\t\t\t\t\t{renderSortIcon(sortField === \"status\")}\n\t\t\t\t\t</Typography>\n\t\t\t\t),\n\t\t\t\trender: (row) => {\n\t\t\t\t\treturn <StatusLabel status={row.status} />;\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"cpu\",\n\t\t\t\tcontent: t(\"pages.infrastructure.table.headers.cpu\"),\n\t\t\t\trender: (row) => {\n\t\t\t\t\tconst check = row.recentChecks?.[0];\n\t\t\t\t\tconst cpuUsage = (check?.cpu?.usage_percent || 0) * 100;\n\t\t\t\t\treturn <Gauge progress={cpuUsage} />;\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"memory\",\n\t\t\t\tcontent: t(\"pages.infrastructure.table.headers.memory\"),\n\t\t\t\trender: (row) => {\n\t\t\t\t\tconst check = row.recentChecks?.[0];\n\t\t\t\t\tconst memoryUsage = (check?.memory?.usage_percent || 0) * 100;\n\t\t\t\t\treturn <Gauge progress={memoryUsage} />;\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"disk\",\n\t\t\t\tcontent: t(\"pages.infrastructure.table.headers.disk\"),\n\t\t\t\trender: (row) => {\n\t\t\t\t\tconst check = row.recentChecks?.[0];\n\n\t\t\t\t\tconst totalDiskUsage = check?.disk?.reduce(\n\t\t\t\t\t\t(acc, disk) => acc + (disk?.usage_percent || 0),\n\t\t\t\t\t\t0\n\t\t\t\t\t);\n\t\t\t\t\tconst diskCount = check?.disk?.length || 1;\n\t\t\t\t\tconst diskUsage = ((totalDiskUsage || 0) / diskCount) * 100;\n\t\t\t\t\treturn <Gauge progress={diskUsage} />;\n\t\t\t\t},\n\t\t\t},\n\n\t\t\t{\n\t\t\t\tid: \"actions\",\n\t\t\t\tcontent: t(\"common.table.headers.actions\"),\n\t\t\t\trender: (row) => {\n\t\t\t\t\treturn <ActionsMenu items={getActions(row)} />;\n\t\t\t\t},\n\t\t\t},\n\t\t];\n\t\treturn headers;\n\t};\n\n\tlet headers = getHeaders();\n\n\tif (isSmall) {\n\t\theaders = headers.filter((h) => h.id !== \"histogram\");\n\t}\n\treturn (\n\t\t<Box>\n\t\t\t<Table\n\t\t\t\theaders={headers}\n\t\t\t\tdata={monitors}\n\t\t\t\tonRowClick={(row) => {\n\t\t\t\t\tnavigate(`/infrastructure/${row.id}`);\n\t\t\t\t}}\n\t\t\t/>\n\t\t\t<Pagination\n\t\t\t\tcomponent=\"div\"\n\t\t\t\tcount={count}\n\t\t\t\tpage={page}\n\t\t\t\trowsPerPage={rowsPerPage}\n\t\t\t\tonPageChange={handlePageChange}\n\t\t\t\tonRowsPerPageChange={handleRowsPerPageChange}\n\t\t\t\titemsOnPage={monitors.length}\n\t\t\t/>\n\t\t</Box>\n\t);\n};\n"
  },
  {
    "path": "client/src/Pages/Infrastructure/Monitors/index.tsx",
    "content": "import Stack from \"@mui/material/Stack\";\nimport useMediaQuery from \"@mui/material/useMediaQuery\";\nimport { MonitorBasePageWithStates } from \"@/Components/design-elements\";\nimport { HeaderCreate } from \"@/Components/common\";\nimport { ControlsFilter, HeaderMonitorsSummary } from \"@/Components/monitors\";\nimport { TextField, Dialog } from \"@/Components/inputs\";\n\nimport { useGet, useDelete } from \"@/Hooks/UseApi\";\nimport { useIsAdmin } from \"@/Hooks/useIsAdmin\";\nimport type { Monitor, MonitorsWithChecksResponse } from \"@/Types/Monitor\";\nimport { useTheme } from \"@mui/material\";\nimport { useState, useCallback, useMemo } from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { useSelector, useDispatch } from \"react-redux\";\nimport { setRowsPerPage } from \"@/Features/UI/uiSlice.js\";\nimport type { RootState } from \"@/Types/state\";\nimport { InfraMonitorsTable } from \"./Components/MonitorsTable\";\nimport useDebounce from \"@/Hooks/useDebounce\";\n\nconst InfrastructureMonitors = () => {\n\tconst { t } = useTranslation();\n\tconst theme = useTheme();\n\tconst isSmall = useMediaQuery(theme.breakpoints.down(\"md\"));\n\tconst isAdmin = useIsAdmin();\n\tconst dispatch = useDispatch();\n\n\t// Redux state\n\tconst rowsPerPage = useSelector(\n\t\t(state: RootState) => state.ui?.infrastructure?.rowsPerPage ?? 5\n\t);\n\n\t// Local state\n\tconst [selectedStatus, setSelectedStatus] = useState<string>(\"\");\n\tconst [selectedState, setSelectedState] = useState<string>(\"\");\n\tconst [search, setSearch] = useState<string>(\"\");\n\tconst [page, setPage] = useState<number>(0);\n\tconst [sortField, setSortField] = useState<string>(\"\");\n\tconst [sortOrder, setSortOrder] = useState<\"asc\" | \"desc\">(\"asc\");\n\tconst [selectedMonitor, setSelectedMonitor] = useState<Monitor | null>(null);\n\tconst isDialogOpen = Boolean(selectedMonitor);\n\n\tconst debouncedSearch = useDebounce<string>(search, 300);\n\n\tconst handleClearFilters = useCallback(() => {\n\t\tsetSelectedStatus(\"\");\n\t\tsetSelectedState(\"\");\n\t\tsetSearch(\"\");\n\t}, []);\n\n\t// Convert filter selections to API filter values\n\tconst toFilterStatus = useMemo(() => {\n\t\tif (selectedStatus === \"up\") return \"true\";\n\t\tif (selectedStatus === \"down\") return \"false\";\n\t\treturn undefined;\n\t}, [selectedStatus]);\n\n\tconst toFilterActive = useMemo(() => {\n\t\tif (selectedState === \"active\") return \"true\";\n\t\tif (selectedState === \"paused\") return \"false\";\n\t\treturn undefined;\n\t}, [selectedState]);\n\n\t// Determine field and filter for the API request\n\t// Priority: status > isActive > search\n\tconst filterLookup = new Map<string | undefined, string>([\n\t\t[toFilterStatus, \"status\"],\n\t\t[toFilterActive, \"isActive\"],\n\t]);\n\tconst activeFilter = [...filterLookup].find(([key]) => key !== undefined);\n\tconst field = activeFilter?.[1] || (debouncedSearch ? \"name\" : sortField || undefined);\n\tconst filter = activeFilter?.[0] || debouncedSearch || undefined;\n\n\t// Build URL for monitors with checks\n\tconst monitorsWithChecksUrl = useMemo(() => {\n\t\tconst params = new URLSearchParams();\n\t\tparams.append(\"type\", \"hardware\");\n\t\tparams.append(\"limit\", \"1\");\n\t\tif (page !== undefined) params.append(\"page\", String(page));\n\t\tif (rowsPerPage) params.append(\"rowsPerPage\", String(rowsPerPage));\n\t\tif (filter) params.append(\"filter\", filter);\n\t\tif (field) params.append(\"field\", field);\n\t\tif (sortOrder) params.append(\"order\", sortOrder);\n\t\treturn `/monitors/team/with-checks?${params.toString()}`;\n\t}, [page, rowsPerPage, filter, field, sortOrder]);\n\n\tconst {\n\t\tdata: monitorsWithChecksData,\n\t\tisLoading: monitorsWithChecksLoading,\n\t\terror: monitorsWithChecksError,\n\t\trefetch,\n\t} = useGet<MonitorsWithChecksResponse>(\n\t\tmonitorsWithChecksUrl,\n\t\t{},\n\t\t{ refreshInterval: 5000, keepPreviousData: true }\n\t);\n\n\tconst { summary, count } = monitorsWithChecksData ?? { summary: null, count: 0 };\n\tconst isLoading = monitorsWithChecksLoading;\n\n\t// Check if any filters are active\n\tconst hasActiveFilters = Boolean(selectedStatus || selectedState || search);\n\n\t// Show empty state only when there are truly no monitors (not just filtered out)\n\tconst effectiveTotalCount =\n\t\thasActiveFilters && (summary?.totalMonitors ?? 0) === 0\n\t\t\t? 1\n\t\t\t: (summary?.totalMonitors ?? 0);\n\n\t// Delete hook\n\tconst { deleteFn, loading: isDeleting } = useDelete();\n\n\tconst handleConfirm = async () => {\n\t\tif (!selectedMonitor) return;\n\t\tawait deleteFn(`/monitors/${selectedMonitor.id}`);\n\t\tsetSelectedMonitor(null);\n\t\trefetch();\n\t};\n\n\tconst handleCancel = () => {\n\t\tsetSelectedMonitor(null);\n\t};\n\n\treturn (\n\t\t<MonitorBasePageWithStates\n\t\t\tloading={isLoading}\n\t\t\terror={monitorsWithChecksError}\n\t\t\ttotalCount={effectiveTotalCount}\n\t\t\tpage=\"infrastructure\"\n\t\t\tactionLink=\"/infrastructure/create\"\n\t\t>\n\t\t\t<HeaderCreate\n\t\t\t\tpath=\"/infrastructure/create\"\n\t\t\t\tisLoading={isLoading}\n\t\t\t\tisAdmin={isAdmin}\n\t\t\t/>\n\t\t\t<HeaderMonitorsSummary\n\t\t\t\tsummary={summary}\n\t\t\t\tshowBreached={true}\n\t\t\t/>\n\t\t\t<Stack\n\t\t\t\tdirection={isSmall ? \"column\" : \"row\"}\n\t\t\t\tjustifyContent={isSmall ? \"flex-start\" : \"space-between\"}\n\t\t\t\tgap={theme.spacing(4)}\n\t\t\t>\n\t\t\t\t<ControlsFilter\n\t\t\t\t\tshowTypes={false}\n\t\t\t\t\tselectedStatus={selectedStatus}\n\t\t\t\t\tsetSelectedStatus={setSelectedStatus}\n\t\t\t\t\tselectedState={selectedState}\n\t\t\t\t\tsetSelectedState={setSelectedState}\n\t\t\t\t\tonClearFilters={handleClearFilters}\n\t\t\t\t/>\n\t\t\t\t<TextField\n\t\t\t\t\tplaceholder={t(\"pages.uptime.filters.search.placeholder\")}\n\t\t\t\t\tvalue={search}\n\t\t\t\t\tonChange={(event) => {\n\t\t\t\t\t\tsetSearch(event.target.value);\n\t\t\t\t\t}}\n\t\t\t\t/>\n\t\t\t</Stack>\n\t\t\t<InfraMonitorsTable\n\t\t\t\tmonitors={monitorsWithChecksData?.monitors || []}\n\t\t\t\trefetch={refetch}\n\t\t\t\tsetSelectedMonitor={setSelectedMonitor}\n\t\t\t\tsortField={sortField}\n\t\t\t\tsetSortField={setSortField}\n\t\t\t\tsortOrder={sortOrder}\n\t\t\t\tsetSortOrder={setSortOrder}\n\t\t\t\tcount={count || 0}\n\t\t\t\tpage={page}\n\t\t\t\tsetPage={setPage}\n\t\t\t\trowsPerPage={rowsPerPage}\n\t\t\t\tsetRowsPerPage={(value: number) => {\n\t\t\t\t\tdispatch(\n\t\t\t\t\t\tsetRowsPerPage({\n\t\t\t\t\t\t\tvalue,\n\t\t\t\t\t\t\ttable: \"infrastructure\",\n\t\t\t\t\t\t})\n\t\t\t\t\t);\n\t\t\t\t\tsetPage(0);\n\t\t\t\t}}\n\t\t\t/>\n\t\t\t<Dialog\n\t\t\t\topen={isDialogOpen}\n\t\t\t\ttitle={t(\"common.dialogs.delete.title\")}\n\t\t\t\tcontent={t(\"common.dialogs.delete.description\")}\n\t\t\t\tonConfirm={handleConfirm}\n\t\t\t\tonCancel={handleCancel}\n\t\t\t\tloading={isDeleting}\n\t\t\t/>\n\t\t</MonitorBasePageWithStates>\n\t);\n};\n\nexport default InfrastructureMonitors;\n"
  },
  {
    "path": "client/src/Pages/Logs/TabDiagnostics.tsx",
    "content": "import Stack from \"@mui/material/Stack\";\nimport { Stats } from \"@/Pages/Logs/components/Stats\";\nimport { StatGauges } from \"@/Pages/Logs/components/StatGauges\";\n\nimport { useTheme } from \"@mui/material\";\nimport { useGet } from \"@/Hooks/UseApi\";\nimport type { Diagnostics } from \"@/Types/Diagnostics\";\n\nexport const TabDiagnostics = () => {\n\tconst theme = useTheme();\n\tconst {\n\t\tdata: diagnostics,\n\t\tisLoading: _isLoading,\n\t\terror: _error,\n\t\trefetch: _refetch,\n\t} = useGet<Diagnostics>(\"/diagnostic/system\", {}, { refreshInterval: 5000 });\n\n\treturn (\n\t\t<Stack gap={theme.spacing(8)}>\n\t\t\t<Stats diagnostics={diagnostics} />\n\t\t\t<StatGauges diagnostics={diagnostics} />\n\t\t</Stack>\n\t);\n};\n"
  },
  {
    "path": "client/src/Pages/Logs/TabLogs.tsx",
    "content": "import Stack from \"@mui/material/Stack\";\nimport MenuItem from \"@mui/material/MenuItem\";\nimport Typography from \"@mui/material/Typography\";\nimport { useSelector } from \"react-redux\";\nimport { Select } from \"@/Components/inputs\";\nimport { TableLogs } from \"@/Pages/Logs/components/TableLogs\";\n\nimport { useTheme } from \"@mui/material\";\nimport { useGet } from \"@/Hooks/UseApi\";\nimport { useState } from \"react\";\nimport type { Log, LogLevelOption } from \"@/Types/Log\";\nimport { LOG_LEVEL_OPTIONS } from \"@/Types/Log\";\nimport { t } from \"i18next\";\nimport type { RootState } from \"@/Types/state\";\n\nexport const TabLogs = () => {\n\tconst theme = useTheme();\n\tconst { data: logs } = useGet<Log[]>(\"/logs\");\n\tconst [selectedLogLevel, setSelectedLogLevel] = useState<LogLevelOption>(\"all\");\n\tconst [page, setPage] = useState(0);\n\tconst rowsPerPage = useSelector(\n\t\t(state: RootState) => state?.ui?.logs?.rowsPerPage ?? 15\n\t);\n\n\tconst filteredLogs = logs\n\t\t?.filter((log) => {\n\t\t\tif (selectedLogLevel === \"all\") return true;\n\t\t\treturn log.level === selectedLogLevel;\n\t\t})\n\t\t.reverse()\n\t\t.map((log, idx) => ({ ...log, id: idx }));\n\n\tconst paginatedLogs =\n\t\tfilteredLogs?.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage) ?? [];\n\n\treturn (\n\t\t<Stack gap={theme.spacing(8)}>\n\t\t\t<Select\n\t\t\t\tsx={{ maxWidth: 200 }}\n\t\t\t\tfieldLabel={t(\"pages.logs.logLevelSelect.label\")}\n\t\t\t\tvalue={selectedLogLevel}\n\t\t\t\tonChange={(e) => setSelectedLogLevel(e.target.value)}\n\t\t\t>\n\t\t\t\t{LOG_LEVEL_OPTIONS.map((level) => {\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<MenuItem\n\t\t\t\t\t\t\tkey={level}\n\t\t\t\t\t\t\tvalue={level}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<Typography textTransform={\"capitalize\"}>{level}</Typography>\n\t\t\t\t\t\t</MenuItem>\n\t\t\t\t\t);\n\t\t\t\t})}\n\t\t\t</Select>\n\t\t\t<TableLogs\n\t\t\t\tlogs={paginatedLogs}\n\t\t\t\tlogCount={filteredLogs?.length ?? 0}\n\t\t\t\tpage={page}\n\t\t\t\tsetPage={setPage}\n\t\t\t/>\n\t\t</Stack>\n\t);\n};\n"
  },
  {
    "path": "client/src/Pages/Logs/TabQueue.tsx",
    "content": "import Stack from \"@mui/material/Stack\";\nimport Typography from \"@mui/material/Typography\";\nimport { TableJobs, TableFailedJobs } from \"./components/TableJobs\";\n\nimport { useTheme } from \"@mui/material\";\nimport { useTranslation } from \"react-i18next\";\nimport { useGet, usePost } from \"@/Hooks/UseApi\";\nimport type { QueueData } from \"@/Types/Queue\";\nimport { Metrics } from \"@/Pages/Logs/components/Metrics\";\nimport { Button } from \"@/Components/inputs\";\n\nexport const TabQueue = () => {\n\tconst theme = useTheme();\n\tconst { t } = useTranslation();\n\tconst {\n\t\tdata: queueData,\n\t\t// isLoading,\n\t\t// error,\n\t\trefetch,\n\t} = useGet<QueueData>(\"/queue/all-metrics\", {}, { refreshInterval: 5000 });\n\n\tconst { post, loading: isFlushing } = usePost();\n\n\tconst jobs = queueData?.jobs ?? [];\n\tconst metrics = queueData?.metrics ?? null;\n\n\tconst handleFlushQueue = async () => {\n\t\tawait post(\"/queue/flush\", {});\n\t\trefetch();\n\t};\n\n\treturn (\n\t\t<Stack gap={theme.spacing(8)}>\n\t\t\t<Metrics metrics={metrics} />\n\t\t\t<Typography\n\t\t\t\tvariant=\"h6\"\n\t\t\t\tsx={{ textTransform: \"uppercase\" }}\n\t\t\t>\n\t\t\t\t{t(\"pages.logs.jobQueue\")}\n\t\t\t</Typography>\n\t\t\t<TableJobs jobs={jobs} />\n\t\t\t<Typography\n\t\t\t\tvariant=\"h6\"\n\t\t\t\tsx={{ textTransform: \"uppercase\" }}\n\t\t\t>\n\t\t\t\t{t(\"pages.logs.failedJobs\")}\n\t\t\t</Typography>\n\t\t\t<TableFailedJobs metrics={metrics} />\n\t\t\t<Stack alignItems={\"flex-end\"}>\n\t\t\t\t<Button\n\t\t\t\t\tvariant=\"contained\"\n\t\t\t\t\tonClick={handleFlushQueue}\n\t\t\t\t\tloading={isFlushing}\n\t\t\t\t>\n\t\t\t\t\t{t(\"common.buttons.flushQueue\")}\n\t\t\t\t</Button>\n\t\t\t</Stack>\n\t\t</Stack>\n\t);\n};\n"
  },
  {
    "path": "client/src/Pages/Logs/components/Metrics.tsx",
    "content": "import Stack from \"@mui/material/Stack\";\nimport { StatBox } from \"@/Components/design-elements\";\n\nimport { useTheme } from \"@mui/material\";\nimport { useTranslation } from \"react-i18next\";\nimport type { QueueMetrics } from \"@/Types/Queue\";\n\ninterface MetricsProps {\n\tmetrics: QueueMetrics | null;\n}\n\nexport const Metrics = ({ metrics }: MetricsProps) => {\n\tconst { t } = useTranslation();\n\tconst theme = useTheme();\n\n\tif (!metrics) {\n\t\treturn null;\n\t}\n\n\treturn (\n\t\t<Stack\n\t\t\tdirection={{ xs: \"column\", md: \"row\" }}\n\t\t\tgap={theme.spacing(8)}\n\t\t>\n\t\t\t<StatBox\n\t\t\t\ttitle={t(\"pages.logs.metrics.jobs\")}\n\t\t\t\tsubtitle={String(metrics.jobs)}\n\t\t\t/>\n\t\t\t<StatBox\n\t\t\t\tpalette={metrics.activeJobs > 0 ? \"success\" : undefined}\n\t\t\t\ttitle={t(\"pages.logs.metrics.activeJobs\")}\n\t\t\t\tsubtitle={String(metrics.activeJobs)}\n\t\t\t/>\n\t\t\t<StatBox\n\t\t\t\tpalette={metrics.failingJobs > 0 ? \"error\" : undefined}\n\t\t\t\ttitle={t(\"pages.logs.metrics.failingJobs\")}\n\t\t\t\tsubtitle={String(metrics.failingJobs)}\n\t\t\t/>\n\t\t\t<StatBox\n\t\t\t\ttitle={t(\"pages.logs.metrics.totalRuns\")}\n\t\t\t\tsubtitle={String(metrics.totalRuns)}\n\t\t\t/>\n\t\t\t<StatBox\n\t\t\t\tpalette={metrics.totalFailures > 0 ? \"error\" : undefined}\n\t\t\t\ttitle={t(\"pages.logs.metrics.totalFailures\")}\n\t\t\t\tsubtitle={String(metrics.totalFailures)}\n\t\t\t/>\n\t\t</Stack>\n\t);\n};\n"
  },
  {
    "path": "client/src/Pages/Logs/components/StatGauges.tsx",
    "content": "import Stack from \"@mui/material/Stack\";\nimport { DetailGauge } from \"@/Components/design-elements\";\n\nimport { getPercentage, formatPercentageFromWhole } from \"@/Utils/FormatUtils\";\nimport prettyBytes from \"pretty-bytes\";\nimport { useTranslation } from \"react-i18next\";\nimport { useTheme } from \"@mui/material\";\nimport type { Diagnostics } from \"@/Types/Diagnostics\";\n\ninterface StatGaugesProps {\n\tdiagnostics: Diagnostics | null;\n}\n\nexport const StatGauges = ({ diagnostics }: StatGaugesProps) => {\n\tconst theme = useTheme();\n\tconst { t } = useTranslation();\n\tif (!diagnostics) {\n\t\treturn null;\n\t}\n\n\tconst heapTotalSize = getPercentage(\n\t\tdiagnostics?.v8HeapStats?.totalHeapSizeBytes,\n\t\tdiagnostics?.v8HeapStats?.heapSizeLimitBytes\n\t);\n\n\tconst heapUsedSize = getPercentage(\n\t\tdiagnostics?.v8HeapStats?.usedHeapSizeBytes,\n\t\tdiagnostics?.v8HeapStats?.heapSizeLimitBytes\n\t);\n\n\tconst actualHeapUsed = getPercentage(\n\t\tdiagnostics?.v8HeapStats?.usedHeapSizeBytes,\n\t\tdiagnostics?.v8HeapStats?.totalHeapSizeBytes\n\t);\n\n\treturn (\n\t\t<Stack\n\t\t\tdirection={{ xs: \"column\", md: \"row\" }}\n\t\t\tgap={theme.spacing(8)}\n\t\t>\n\t\t\t<DetailGauge\n\t\t\t\ttitle={t(\"pages.logs.diagnostics.gauges.heapAllocation\")}\n\t\t\t\tprogress={heapTotalSize}\n\t\t\t\tupperValue={formatPercentageFromWhole(heapTotalSize)}\n\t\t\t\tlowerLabel={t(\"pages.logs.diagnostics.gauges.total\")}\n\t\t\t\tlowerValue={prettyBytes(diagnostics.v8HeapStats?.heapSizeLimitBytes ?? 0)}\n\t\t\t/>\n\t\t\t<DetailGauge\n\t\t\t\ttitle={t(\"pages.logs.diagnostics.gauges.heapUsage\")}\n\t\t\t\tprogress={heapUsedSize}\n\t\t\t\tupperLabel={t(\"pages.logs.diagnostics.gauges.availableMemoryPercentage\")}\n\t\t\t\tupperValue={formatPercentageFromWhole(heapUsedSize)}\n\t\t\t\tlowerLabel={t(\"pages.logs.diagnostics.gauges.used\")}\n\t\t\t\tlowerValue={prettyBytes(diagnostics.v8HeapStats?.usedHeapSizeBytes ?? 0)}\n\t\t\t/>\n\t\t\t<DetailGauge\n\t\t\t\ttitle={t(\"pages.logs.diagnostics.gauges.heapUtilization\")}\n\t\t\t\tprogress={actualHeapUsed}\n\t\t\t\tupperLabel={t(\"pages.logs.diagnostics.gauges.allocatedPercentage\")}\n\t\t\t\tupperValue={formatPercentageFromWhole(actualHeapUsed)}\n\t\t\t\tlowerLabel={t(\"pages.logs.diagnostics.gauges.total\")}\n\t\t\t\tlowerValue={prettyBytes(diagnostics.v8HeapStats?.usedHeapSizeBytes ?? 0)}\n\t\t\t/>\n\t\t\t<DetailGauge\n\t\t\t\ttitle={t(\"pages.logs.diagnostics.gauges.instantCpuUsage\")}\n\t\t\t\tprogress={diagnostics.cpuUsage?.usagePercentage ?? 0}\n\t\t\t\tupperLabel={t(\"pages.logs.diagnostics.gauges.usedSPercentage\")}\n\t\t\t\tupperValue={formatPercentageFromWhole(diagnostics.cpuUsage?.usagePercentage ?? 0)}\n\t\t\t/>\n\t\t</Stack>\n\t);\n};\n"
  },
  {
    "path": "client/src/Pages/Logs/components/Stats.tsx",
    "content": "import Stack from \"@mui/material/Stack\";\nimport { StatBox } from \"@/Components/design-elements\";\n\nimport prettyBytes from \"pretty-bytes\";\nimport prettyMilliseconds from \"pretty-ms\";\nimport { useTheme } from \"@mui/material\";\nimport { useTranslation } from \"react-i18next\";\nimport type { Diagnostics } from \"@/Types/Diagnostics\";\n\ninterface StatsProps {\n\tdiagnostics: Diagnostics | null;\n}\n\nexport const Stats = ({ diagnostics }: StatsProps) => {\n\tconst { t } = useTranslation();\n\tconst theme = useTheme();\n\n\tif (!diagnostics) {\n\t\treturn null;\n\t}\n\n\treturn (\n\t\t<Stack\n\t\t\tdirection={{ xs: \"column\", md: \"row\" }}\n\t\t\tgap={theme.spacing(8)}\n\t\t>\n\t\t\t<StatBox\n\t\t\t\ttitle={t(\"pages.logs.diagnostics.stats.eventLoopDelay\")}\n\t\t\t\tsubtitle={prettyMilliseconds(diagnostics.eventLoopDelayMs ?? 0, {\n\t\t\t\t\tmillisecondsDecimalDigits: 2,\n\t\t\t\t})}\n\t\t\t/>\n\t\t\t<StatBox\n\t\t\t\ttitle={t(\"pages.logs.diagnostics.stats.uptime\")}\n\t\t\t\tsubtitle={prettyMilliseconds(diagnostics.uptimeMs ?? 0, { hideSeconds: true })}\n\t\t\t/>\n\t\t\t<StatBox\n\t\t\t\ttitle={t(\"pages.logs.diagnostics.stats.usedHeapSize\")}\n\t\t\t\tsubtitle={prettyBytes(diagnostics.v8HeapStats?.usedHeapSizeBytes ?? 0)}\n\t\t\t/>\n\t\t\t<StatBox\n\t\t\t\ttitle={t(\"pages.logs.diagnostics.stats.totalHeapSize\")}\n\t\t\t\tsubtitle={prettyBytes(diagnostics.v8HeapStats?.totalHeapSizeBytes ?? 0)}\n\t\t\t/>\n\t\t\t<StatBox\n\t\t\t\ttitle={t(\"pages.logs.diagnostics.stats.osMemoryLimit\")}\n\t\t\t\tsubtitle={prettyBytes(diagnostics.osStats?.totalMemoryBytes ?? 0)}\n\t\t\t/>\n\t\t</Stack>\n\t);\n};\n"
  },
  {
    "path": "client/src/Pages/Logs/components/TableJobs.tsx",
    "content": "import { Table } from \"@/Components/design-elements\";\nimport { Typography, useTheme } from \"@mui/material\";\nimport prettyMilliseconds from \"pretty-ms\";\nimport { formatTimestamp } from \"@/Utils/TimeUtils\";\n\nimport { useTranslation } from \"react-i18next\";\nimport type { QueueJobFailure, QueueJobSummary, QueueMetrics } from \"@/Types/Queue\";\nimport type { Header } from \"@/Components/design-elements\";\n\ntype QueueJobWithId = QueueJobSummary & { id: string | number };\n\ninterface TableJobsProps {\n\tjobs: QueueJobSummary[];\n}\n\nexport const TableJobs = ({ jobs }: TableJobsProps) => {\n\tconst { t } = useTranslation();\n\tconst theme = useTheme();\n\n\tconst jobsWithId: QueueJobWithId[] = jobs.map((job) => ({\n\t\t...job,\n\t\tid: job.monitorId,\n\t}));\n\n\tconst headers: Header<QueueJobWithId>[] = [\n\t\t{\n\t\t\tid: \"id\",\n\t\t\tcontent: t(\"common.table.headers.monitorId\"),\n\t\t\trender: (row) => <Typography fontFamily={\"monospace\"}>{row.monitorId}</Typography>,\n\t\t},\n\t\t{\n\t\t\tid: \"url\",\n\t\t\tcontent: t(\"common.table.headers.url\"),\n\t\t\trender: (row) => <Typography>{row.monitorUrl}</Typography>,\n\t\t},\n\t\t{\n\t\t\tid: \"interval\",\n\t\t\tcontent: t(\"common.table.headers.interval\"),\n\t\t\trender: (row) => (\n\t\t\t\t<Typography>{prettyMilliseconds(row.monitorInterval ?? 0)}</Typography>\n\t\t\t),\n\t\t},\n\t\t{\n\t\t\tid: \"type\",\n\t\t\tcontent: t(\"common.table.headers.type\"),\n\t\t\trender: (row) => <Typography>{row.monitorType}</Typography>,\n\t\t},\n\t\t{\n\t\t\tid: \"active\",\n\t\t\tcontent: t(\"common.table.headers.active\"),\n\t\t\trender: (row) => <Typography>{row.active.toString()}</Typography>,\n\t\t},\n\t\t{\n\t\t\tid: \"runCount\",\n\t\t\tcontent: t(\"pages.logs.table.headers.runCount\"),\n\t\t\trender: (row) => <Typography>{row.runCount}</Typography>,\n\t\t},\n\t\t{\n\t\t\tid: \"failCount\",\n\t\t\tcontent: t(\"pages.logs.table.headers.failCount\"),\n\t\t\trender: (row) => <Typography>{row.failCount}</Typography>,\n\t\t},\n\t\t{\n\t\t\tid: \"lastRun\",\n\t\t\tcontent: t(\"pages.logs.table.headers.lastRunAt\"),\n\t\t\trender: (row) => <Typography>{formatTimestamp(row.lastRunAt)}</Typography>,\n\t\t},\n\t\t{\n\t\t\tid: \"lockedAt\",\n\t\t\tcontent: t(\"pages.logs.table.headers.lockedAt\"),\n\t\t\trender: (row) => <Typography>{formatTimestamp(row.lockedAt)}</Typography>,\n\t\t},\n\n\t\t{\n\t\t\tid: \"lastFinish\",\n\t\t\tcontent: t(\"pages.logs.table.headers.lastFinishedAt\"),\n\t\t\trender: (row) => <Typography>{formatTimestamp(row.lastFinishedAt)}</Typography>,\n\t\t},\n\t\t{\n\t\t\tid: \"lastRunTook\",\n\t\t\tcontent: t(\"pages.logs.table.headers.lastRunTook\"),\n\t\t\trender: (row) => {\n\t\t\t\tconst value = row.lastRunTook ? prettyMilliseconds(row.lastRunTook) : \"-\";\n\t\t\t\treturn <Typography>{value}</Typography>;\n\t\t\t},\n\t\t},\n\t];\n\n\treturn (\n\t\t<Table\n\t\t\theaders={headers}\n\t\t\tdata={jobsWithId}\n\t\t\tgetRowSx={(row) => ({\n\t\t\t\t...(row.lockedAt && {\n\t\t\t\t\t\"& td\": { backgroundColor: theme.palette.success.light },\n\t\t\t\t}),\n\t\t\t})}\n\t\t/>\n\t);\n};\n\ntype QueueJobFailureWithId = QueueJobFailure & { id: string | number };\n\ninterface TableFailedJobsProps {\n\tmetrics: QueueMetrics | null;\n}\nexport const TableFailedJobs = ({ metrics }: TableFailedJobsProps) => {\n\tconst { t } = useTranslation();\n\tif (!metrics) {\n\t\treturn null;\n\t}\n\n\tconst jobFailuresWithId: QueueJobFailureWithId[] = metrics.jobsWithFailures.map(\n\t\t(job) => ({\n\t\t\t...job,\n\t\t\tid: job.monitorId,\n\t\t})\n\t);\n\n\tconst headers: Header<QueueJobFailureWithId>[] = [\n\t\t{\n\t\t\tid: \"monitorId\",\n\t\t\tcontent: t(\"common.table.headers.monitorId\"),\n\t\t\trender: (row) => {\n\t\t\t\treturn <Typography fontFamily={\"monospace\"}>{row.monitorId}</Typography>;\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: \"monitorUrl\",\n\t\t\tcontent: t(\"common.table.headers.url\"),\n\t\t\trender: (row) => {\n\t\t\t\treturn <Typography>{row.monitorUrl}</Typography>;\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: \"failCount\",\n\t\t\tcontent: t(\"pages.logs.table.headers.failCount\"),\n\t\t\trender: (row) => {\n\t\t\t\treturn <Typography>{row.failCount}</Typography>;\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: \"failedAt\",\n\t\t\tcontent: t(\"pages.logs.table.headers.lastFailedAt\"),\n\t\t\trender: (row) => {\n\t\t\t\treturn <Typography>{formatTimestamp(row.failedAt)}</Typography>;\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: \"failReason\",\n\t\t\tcontent: t(\"pages.logs.table.headers.failReason\"),\n\t\t\trender: (row) => {\n\t\t\t\treturn <Typography>{row.failReason}</Typography>;\n\t\t\t},\n\t\t},\n\t];\n\n\treturn (\n\t\t<Table\n\t\t\theaders={headers}\n\t\t\tdata={jobFailuresWithId}\n\t\t/>\n\t);\n};\n"
  },
  {
    "path": "client/src/Pages/Logs/components/TableLogs.tsx",
    "content": "import Box from \"@mui/material/Box\";\nimport Typography from \"@mui/material/Typography\";\nimport { Table } from \"@/Components/design-elements\";\nimport { Pagination } from \"@/Components/design-elements/Table\";\nimport { useTheme } from \"@mui/material\";\nimport type { Header } from \"@/Components/design-elements/Table\";\nimport type { Log, LogLevel } from \"@/Types/Log\";\nimport { useTranslation } from \"react-i18next\";\nimport { useSelector, useDispatch } from \"react-redux\";\nimport type { RootState } from \"@/Types/state\";\nimport { setRowsPerPage } from \"@/Features/UI/uiSlice\";\nimport { formatTimestamp } from \"@/Utils/TimeUtils\";\n\ntype LogWithId = Log & { id: number };\n\ninterface TableLogsProps {\n\tlogs: LogWithId[];\n\tlogCount: number;\n\tpage: number;\n\tsetPage: (page: number) => void;\n}\n\nconst LevelBadge = ({ level }: { level: LogLevel }) => {\n\tconst theme = useTheme();\n\n\tconst levelColors: Record<LogLevel, string> = {\n\t\tinfo: theme.palette.success.main,\n\t\twarn: theme.palette.warning.main,\n\t\terror: theme.palette.error.main,\n\t\tdebug: theme.palette.info.main,\n\t};\n\n\tconst color = levelColors[level] || theme.palette.text.primary;\n\n\treturn (\n\t\t<Typography\n\t\t\tfontWeight={600}\n\t\t\tcolor={color}\n\t\t\ttextTransform={\"uppercase\"}\n\t\t>\n\t\t\t{level}\n\t\t</Typography>\n\t);\n};\n\nexport const TableLogs = ({ logs, logCount, page, setPage }: TableLogsProps) => {\n\tconst { t } = useTranslation();\n\tconst dispatch = useDispatch();\n\tconst rowsPerPage = useSelector(\n\t\t(state: RootState) => state?.ui?.logs?.rowsPerPage ?? 15\n\t);\n\n\tconst headers: Header<Log & { id: number }>[] = [\n\t\t{\n\t\t\tid: \"timestamp\",\n\t\t\tcontent: t(\"pages.logs.table.headers.timestamp\"),\n\t\t\trender: (row) => (\n\t\t\t\t<Typography sx={{ fontFamily: \"monospace\" }}>\n\t\t\t\t\t{formatTimestamp(row.timestamp)}\n\t\t\t\t</Typography>\n\t\t\t),\n\t\t},\n\t\t{\n\t\t\tid: \"level\",\n\t\t\tcontent: t(\"pages.logs.table.headers.level\"),\n\t\t\trender: (row) => <LevelBadge level={row.level} />,\n\t\t},\n\t\t{\n\t\t\tid: \"service\",\n\t\t\tcontent: t(\"pages.logs.table.headers.service\"),\n\t\t\trender: (row) => <Typography>{row.service || \"-\"}</Typography>,\n\t\t},\n\t\t{\n\t\t\tid: \"method\",\n\t\t\tcontent: t(\"pages.logs.table.headers.method\"),\n\t\t\trender: (row) => (\n\t\t\t\t<Typography fontFamily={\"monospace\"}>{row.method || \"-\"}</Typography>\n\t\t\t),\n\t\t},\n\t\t{\n\t\t\tid: \"message\",\n\t\t\tcontent: t(\"common.table.headers.message\"),\n\t\t\trender: (row) => (\n\t\t\t\t<Typography\n\t\t\t\t\tmaxWidth={400}\n\t\t\t\t\toverflow={\"hidden\"}\n\t\t\t\t\ttextOverflow={\"ellipsis\"}\n\t\t\t\t\twhiteSpace={\"nowrap\"}\n\t\t\t\t>\n\t\t\t\t\t{row.message || \"-\"}\n\t\t\t\t</Typography>\n\t\t\t),\n\t\t},\n\t];\n\n\tconst handlePageChange = (\n\t\t_e: React.MouseEvent<HTMLButtonElement> | null,\n\t\tnewPage: number\n\t) => {\n\t\tsetPage(newPage);\n\t};\n\n\tconst handleRowsPerPageChange = (\n\t\te: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>\n\t) => {\n\t\tdispatch(setRowsPerPage({ value: Number(e.target.value), table: \"logs\" }));\n\t\tsetPage(0);\n\t};\n\n\treturn (\n\t\t<Box>\n\t\t\t<Table\n\t\t\t\theaders={headers}\n\t\t\t\tdata={logs}\n\t\t\t\temptyViewText={t(\"pages.logs.noLogs\")}\n\t\t\t/>\n\t\t\t<Pagination\n\t\t\t\titemsOnPage={logs.length}\n\t\t\t\tcomponent=\"div\"\n\t\t\t\tcount={logCount}\n\t\t\t\tpage={page}\n\t\t\t\trowsPerPage={rowsPerPage}\n\t\t\t\tonPageChange={handlePageChange}\n\t\t\t\tonRowsPerPageChange={handleRowsPerPageChange}\n\t\t\t/>\n\t\t</Box>\n\t);\n};\n"
  },
  {
    "path": "client/src/Pages/Logs/index.tsx",
    "content": "import { BasePage, Tabs, Tab } from \"@/Components/design-elements\";\nimport { TabLogs } from \"@/Pages/Logs/TabLogs\";\nimport { TabQueue } from \"@/Pages/Logs/TabQueue\";\nimport { TabDiagnostics } from \"@/Pages/Logs/TabDiagnostics\";\n\nimport { useState } from \"react\";\nimport { useTranslation } from \"react-i18next\";\n\nconst LogsPage = () => {\n\tconst { t } = useTranslation();\n\tconst [activeTab, setActiveTab] = useState<number>(1);\n\treturn (\n\t\t<BasePage>\n\t\t\t<Tabs\n\t\t\t\tvalue={activeTab}\n\t\t\t\tonChange={(_, newValue: number) => setActiveTab(newValue)}\n\t\t\t>\n\t\t\t\t<Tab label={t(\"pages.logs.tabs.logs\")} />\n\t\t\t\t<Tab label={t(\"pages.logs.tabs.queue\")} />\n\t\t\t\t<Tab label={t(\"pages.logs.tabs.diagnostics\")} />\n\t\t\t</Tabs>\n\t\t\t{activeTab === 0 && <TabLogs />}\n\t\t\t{activeTab === 1 && <TabQueue />}\n\t\t\t{activeTab === 2 && <TabDiagnostics />}\n\t\t</BasePage>\n\t);\n};\n\nexport default LogsPage;\n"
  },
  {
    "path": "client/src/Pages/Maintenance/MaintenanceWindowTable.tsx",
    "content": "import Typography from \"@mui/material/Typography\";\nimport { Table, ValueLabel } from \"@/Components/design-elements\";\nimport { Pagination } from \"@/Components/design-elements/Table\";\nimport { ActionsMenu } from \"@/Components/actions-menu\";\nimport { DialogInput } from \"@/Components/inputs/Dialog\";\n\nimport prettyMilliseconds from \"pretty-ms\";\nimport { useTheme } from \"@mui/material\";\nimport type { Header } from \"@/Components/design-elements/Table\";\nimport type { ActionMenuItem } from \"@/Components/actions-menu\";\nimport type { MaintenanceWindow } from \"@/Types/MaintenanceWindow\";\nimport { useTranslation } from \"react-i18next\";\nimport { useNavigate } from \"react-router-dom\";\nimport { useSelector, useDispatch } from \"react-redux\";\nimport type { RootState } from \"@/Types/state\";\nimport Box from \"@mui/material/Box\";\nimport { setRowsPerPage } from \"@/Features/UI/uiSlice\";\nimport dayjs from \"dayjs\";\nimport { useState } from \"react\";\nimport { useDelete, usePatch } from \"@/Hooks/UseApi\";\n\ninterface MaintenanceWindowTableProps {\n\tmaintenanceWindows: MaintenanceWindow[];\n\tmaintenanceWindowCount: number;\n\tpage: number;\n\tsetPage: (page: number) => void;\n\trefetch: () => void;\n}\n\nconst getTimeToNextWindow = (\n\tstartTime: string,\n\tendTime: string,\n\trepeat: number\n): string => {\n\tconst now = dayjs();\n\tlet start = dayjs(startTime);\n\tlet end = dayjs(endTime);\n\n\t// For repeating windows, advance to next occurrence\n\tif (repeat > 0) {\n\t\twhile (end.isBefore(now)) {\n\t\t\tstart = start.add(repeat, \"milliseconds\");\n\t\t\tend = end.add(repeat, \"milliseconds\");\n\t\t}\n\t}\n\n\t// Currently in maintenance window\n\tif (now.isAfter(start) && now.isBefore(end)) {\n\t\treturn \"In maintenance window\";\n\t}\n\n\t// Window is in the future\n\tif (start.isAfter(now)) {\n\t\treturn prettyMilliseconds(start.diff(now), { unitCount: 2, hideSeconds: true });\n\t}\n\n\treturn \"N/A\";\n};\n\nexport const MaintenanceWindowTable = ({\n\tmaintenanceWindows,\n\tmaintenanceWindowCount,\n\tpage,\n\tsetPage,\n\trefetch,\n}: MaintenanceWindowTableProps) => {\n\tconst theme = useTheme();\n\tconst { t } = useTranslation();\n\tconst navigate = useNavigate();\n\tconst dispatch = useDispatch();\n\tconst rowsPerPage = useSelector(\n\t\t(state: RootState) => state?.ui?.maintenance?.rowsPerPage ?? 5\n\t);\n\n\tconst [deleteDialogOpen, setDeleteDialogOpen] = useState(false);\n\tconst [selectedWindow, setSelectedWindow] = useState<MaintenanceWindow | null>(null);\n\n\tconst { deleteFn, loading: deleteLoading } = useDelete();\n\tconst { patch } = usePatch();\n\n\tconst handleDelete = async () => {\n\t\tif (!selectedWindow) return;\n\t\tconst result = await deleteFn(`/maintenance-window/${selectedWindow.id}`);\n\t\tif (result) {\n\t\t\trefetch();\n\t\t\tsetDeleteDialogOpen(false);\n\t\t\tsetSelectedWindow(null);\n\t\t}\n\t};\n\n\tconst handlePause = async (maintenanceWindow: MaintenanceWindow) => {\n\t\tconst result = await patch(`/maintenance-window/${maintenanceWindow.id}`, {\n\t\t\tactive: !maintenanceWindow.active,\n\t\t});\n\t\tif (result) {\n\t\t\trefetch();\n\t\t}\n\t};\n\n\tconst getActions = (maintenanceWindow: MaintenanceWindow): ActionMenuItem[] => [\n\t\t{\n\t\t\tid: \"edit\",\n\t\t\tlabel: t(\"pages.common.monitors.actions.configure\"),\n\t\t\taction: () => navigate(`/maintenance/create/${maintenanceWindow.id}`),\n\t\t\tcloseMenu: true,\n\t\t},\n\t\t{\n\t\t\tid: \"pause\",\n\t\t\tlabel: maintenanceWindow.active\n\t\t\t\t? t(\"pages.common.monitors.actions.pause\")\n\t\t\t\t: t(\"pages.common.monitors.actions.resume\"),\n\t\t\taction: () => handlePause(maintenanceWindow),\n\t\t\tcloseMenu: true,\n\t\t},\n\t\t{\n\t\t\tid: \"remove\",\n\t\t\tlabel: (\n\t\t\t\t<Typography color={theme.palette.error.main}>\n\t\t\t\t\t{t(\"pages.common.monitors.actions.delete\")}\n\t\t\t\t</Typography>\n\t\t\t),\n\t\t\taction: () => {\n\t\t\t\tsetSelectedWindow(maintenanceWindow);\n\t\t\t\tsetDeleteDialogOpen(true);\n\t\t\t},\n\t\t\tcloseMenu: true,\n\t\t},\n\t];\n\n\tconst getHeaders = (): Header<MaintenanceWindow>[] => [\n\t\t{\n\t\t\tid: \"name\",\n\t\t\tcontent: t(\"common.table.headers.name\"),\n\t\t\trender: (row) => row.name,\n\t\t},\n\t\t{\n\t\t\tid: \"status\",\n\t\t\tcontent: t(\"common.table.headers.status\"),\n\t\t\trender: (row) => (\n\t\t\t\t<ValueLabel\n\t\t\t\t\tvalue={row.active ? \"positive\" : \"neutral\"}\n\t\t\t\t\ttext={row.active ? t(\"common.labels.active\") : t(\"common.labels.paused\")}\n\t\t\t\t/>\n\t\t\t),\n\t\t},\n\t\t{\n\t\t\tid: \"nextWindow\",\n\t\t\tcontent: t(\"pages.maintenanceWindow.table.headers.nextWindow\"),\n\t\t\trender: (row) => getTimeToNextWindow(row.start, row.end, row.repeat),\n\t\t},\n\t\t{\n\t\t\tid: \"repeat\",\n\t\t\tcontent: t(\"pages.maintenanceWindow.table.headers.repeat\"),\n\t\t\trender: (row) =>\n\t\t\t\trow.repeat === 0\n\t\t\t\t\t? t(\"common.labels.na\")\n\t\t\t\t\t: prettyMilliseconds(row.repeat, { verbose: true }),\n\t\t},\n\t\t{\n\t\t\tid: \"actions\",\n\t\t\tcontent: t(\"common.table.headers.actions\"),\n\t\t\trender: (row) => <ActionsMenu items={getActions(row)} />,\n\t\t},\n\t];\n\n\tconst handlePageChange = (\n\t\t_e: React.MouseEvent<HTMLButtonElement> | null,\n\t\tnewPage: number\n\t) => {\n\t\tsetPage(newPage);\n\t};\n\n\tconst handleRowsPerPageChange = (\n\t\te: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>\n\t) => {\n\t\tdispatch(setRowsPerPage({ value: Number(e.target.value), table: \"maintenance\" }));\n\t\tsetPage(0);\n\t};\n\n\treturn (\n\t\t<Box>\n\t\t\t<Table\n\t\t\t\theaders={getHeaders()}\n\t\t\t\tdata={maintenanceWindows}\n\t\t\t\tonRowClick={(row) => navigate(`/maintenance/create/${row.id}`)}\n\t\t\t\temptyViewText={t(\"common.table.empty\")}\n\t\t\t/>\n\t\t\t<Pagination\n\t\t\t\titemsOnPage={maintenanceWindows.length}\n\t\t\t\tcomponent=\"div\"\n\t\t\t\tcount={maintenanceWindowCount}\n\t\t\t\tpage={page}\n\t\t\t\trowsPerPage={rowsPerPage}\n\t\t\t\tonPageChange={handlePageChange}\n\t\t\t\tonRowsPerPageChange={handleRowsPerPageChange}\n\t\t\t/>\n\t\t\t<DialogInput\n\t\t\t\topen={deleteDialogOpen}\n\t\t\t\ttitle={t(\"common.dialogs.delete.title\")}\n\t\t\t\tcontent={t(\"common.dialogs.delete.description\")}\n\t\t\t\tonCancel={() => {\n\t\t\t\t\tsetDeleteDialogOpen(false);\n\t\t\t\t\tsetSelectedWindow(null);\n\t\t\t\t}}\n\t\t\t\tonConfirm={handleDelete}\n\t\t\t\tloading={deleteLoading}\n\t\t\t/>\n\t\t</Box>\n\t);\n};\n"
  },
  {
    "path": "client/src/Pages/Maintenance/create/index.tsx",
    "content": "import Stack from \"@mui/material/Stack\";\nimport MenuItem from \"@mui/material/MenuItem\";\nimport { logger } from \"@/Utils/logger\";\nimport Typography from \"@mui/material/Typography\";\nimport IconButton from \"@mui/material/IconButton\";\nimport { SPACING, LAYOUT } from \"@/Utils/Theme/constants\";\nimport { BasePage, ConfigBox } from \"@/Components/design-elements\";\nimport {\n\tTextField,\n\tSelect,\n\tDatePicker,\n\tTimePicker,\n\tButton,\n\tAutocomplete,\n} from \"@/Components/inputs\";\n\nimport { useTheme } from \"@mui/material\";\nimport { useTranslation } from \"react-i18next\";\nimport dayjs from \"dayjs\";\nimport type { MaintenanceWindow } from \"@/Types/MaintenanceWindow\";\nimport type { MaintenanceWindowFormData } from \"@/Validation/maintenanceWindow\";\nimport { repeatOptions, durationUnitOptions } from \"@/Validation/maintenanceWindow\";\nimport { useMaintenanceWindowForm } from \"@/Hooks/useMaintenanceWindowForm\";\nimport { useGet, usePost, usePatch } from \"@/Hooks/UseApi\";\nimport { useParams, useNavigate } from \"react-router-dom\";\nimport type { Monitor } from \"@/Types/Monitor\";\nimport { useForm, Controller } from \"react-hook-form\";\nimport { useEffect } from \"react\";\nimport { zodResolver } from \"@hookform/resolvers/zod/dist/zod.js\";\nimport { Trash2 } from \"lucide-react\";\n\nconst CreateMaintenanceWindowPage = () => {\n\tconst theme = useTheme();\n\tconst { t } = useTranslation();\n\tconst navigate = useNavigate();\n\tconst { maintenanceWindowId } = useParams<{ maintenanceWindowId: string }>();\n\tconst isEditMode = Boolean(maintenanceWindowId);\n\n\tconst { data: existingMaintenanceWindow } = useGet<MaintenanceWindow>(\n\t\tisEditMode ? `/maintenance-window/${maintenanceWindowId}` : null,\n\t\t{},\n\t\t{ keepPreviousData: false }\n\t);\n\n\tconst { data: monitors } = useGet<Monitor[]>(\"/monitors/team\");\n\n\tconst { post, loading: isPosting } = usePost();\n\tconst { patch, loading: isPatching } = usePatch();\n\n\tconst { schema, defaults } = useMaintenanceWindowForm({\n\t\tdata: existingMaintenanceWindow,\n\t});\n\n\tconst form = useForm<MaintenanceWindowFormData>({\n\t\tresolver: zodResolver(schema),\n\t\tdefaultValues: defaults,\n\t});\n\n\tconst { control, handleSubmit, trigger } = form;\n\tuseEffect(() => {\n\t\tif (existingMaintenanceWindow) {\n\t\t\tform.reset(defaults);\n\t\t}\n\t}, [existingMaintenanceWindow, defaults, form]);\n\n\tconst buildPayload = (data: MaintenanceWindowFormData) => {\n\t\tconst startDateTime = dayjs(data.startDate)\n\t\t\t.set(\"hour\", parseInt(data.startTime.split(\":\")[0], 10))\n\t\t\t.set(\"minute\", parseInt(data.startTime.split(\":\")[1], 10));\n\n\t\tconst durationUnit = durationUnitOptions.find((o) => o.id === data.durationUnit);\n\t\tconst durationInMs = data.duration * (durationUnit?.multiplier ?? 1000);\n\t\tconst endDateTime = startDateTime.add(durationInMs, \"milliseconds\");\n\n\t\tconst repeatOption = repeatOptions.find((o) => o.id === data.repeat);\n\t\tconst repeat = repeatOption?.value ?? 0;\n\n\t\tconst payload: Record<string, unknown> = {\n\t\t\tname: data.name,\n\t\t\tduration: data.duration,\n\t\t\tdurationUnit: data.durationUnit,\n\t\t\tmonitors: data.monitors,\n\t\t\tstart: startDateTime.toISOString(),\n\t\t\tend: endDateTime.toISOString(),\n\t\t\trepeat,\n\t\t};\n\n\t\tif (repeat === 0) {\n\t\t\tpayload.expiry = endDateTime.toISOString();\n\t\t}\n\n\t\treturn payload;\n\t};\n\n\tconst onSubmit = async (data: MaintenanceWindowFormData) => {\n\t\tconst payload = buildPayload(data);\n\n\t\tlet result;\n\t\tif (isEditMode && maintenanceWindowId) {\n\t\t\tresult = await patch(`/maintenance-window/${maintenanceWindowId}`, payload);\n\t\t} else {\n\t\t\tresult = await post(\"/maintenance-window\", payload);\n\t\t}\n\n\t\tif (result?.success) {\n\t\t\tnavigate(\"/maintenance\");\n\t\t}\n\t};\n\n\tconst isLoading = isPosting || isPatching;\n\n\tconst onError = (errors: any) => {\n\t\tlogger.error(\"Maintenance form submission failed\", undefined, { errors });\n\t};\n\n\treturn (\n\t\t<BasePage\n\t\t\tcomponent={\"form\"}\n\t\t\tonSubmit={handleSubmit(onSubmit, onError)}\n\t\t>\n\t\t\t<ConfigBox\n\t\t\t\ttitle={t(\"pages.maintenanceWindow.form.general.title\")}\n\t\t\t\tsubtitle={t(\"pages.maintenanceWindow.form.general.description\")}\n\t\t\t\trightContent={\n\t\t\t\t\t<Stack spacing={theme.spacing(LAYOUT.MD)}>\n\t\t\t\t\t\t<Controller\n\t\t\t\t\t\t\tname=\"name\"\n\t\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\t\tdefaultValue={defaults.name}\n\t\t\t\t\t\t\trender={({ field, fieldState }) => (\n\t\t\t\t\t\t\t\t<TextField\n\t\t\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\t\t\ttype=\"text\"\n\t\t\t\t\t\t\t\t\tfieldLabel={t(\"pages.maintenanceWindow.form.general.option.name.label\")}\n\t\t\t\t\t\t\t\t\tplaceholder={t(\n\t\t\t\t\t\t\t\t\t\t\"pages.maintenanceWindow.form.general.option.name.placeholder\"\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\tfullWidth\n\t\t\t\t\t\t\t\t\terror={!!fieldState.error}\n\t\t\t\t\t\t\t\t\thelperText={fieldState.error?.message ?? \"\"}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<Controller\n\t\t\t\t\t\t\tname=\"repeat\"\n\t\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\t\tdefaultValue={defaults.repeat}\n\t\t\t\t\t\t\trender={({ field, fieldState }) => (\n\t\t\t\t\t\t\t\t<Select\n\t\t\t\t\t\t\t\t\tvalue={field.value}\n\t\t\t\t\t\t\t\t\tfieldLabel={t(\n\t\t\t\t\t\t\t\t\t\t\"pages.maintenanceWindow.form.general.option.repeat.label\"\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\terror={!!fieldState.error}\n\t\t\t\t\t\t\t\t\tonChange={field.onChange}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t{repeatOptions.map((option) => (\n\t\t\t\t\t\t\t\t\t\t<MenuItem\n\t\t\t\t\t\t\t\t\t\t\tkey={option.id}\n\t\t\t\t\t\t\t\t\t\t\tvalue={option.id}\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t<Typography>{option.name}</Typography>\n\t\t\t\t\t\t\t\t\t\t</MenuItem>\n\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t</Select>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</Stack>\n\t\t\t\t}\n\t\t\t/>\n\t\t\t<ConfigBox\n\t\t\t\ttitle={t(\"pages.maintenanceWindow.form.startDate.title\")}\n\t\t\t\tsubtitle={t(\"pages.maintenanceWindow.form.startDate.description\")}\n\t\t\t\trightContent={\n\t\t\t\t\t<Stack spacing={theme.spacing(LAYOUT.MD)}>\n\t\t\t\t\t\t<Controller\n\t\t\t\t\t\t\tname=\"startDate\"\n\t\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\t\tdefaultValue={defaults.startDate}\n\t\t\t\t\t\t\trender={({ field, fieldState }) => (\n\t\t\t\t\t\t\t\t<DatePicker\n\t\t\t\t\t\t\t\t\tfieldLabel={t(\n\t\t\t\t\t\t\t\t\t\t\"pages.maintenanceWindow.form.startDate.option.startDate.label\"\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\tvalue={field.value ? dayjs(field.value, \"YYYY-MM-DD\") : null}\n\t\t\t\t\t\t\t\t\tonChange={(date) => {\n\t\t\t\t\t\t\t\t\t\tfield.onChange(date ? date.format(\"YYYY-MM-DD\") : \"\");\n\t\t\t\t\t\t\t\t\t\ttrigger(\"startDate\");\n\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\terror={!!fieldState.error}\n\t\t\t\t\t\t\t\t\thelperText={fieldState.error?.message}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</Stack>\n\t\t\t\t}\n\t\t\t/>\n\t\t\t<ConfigBox\n\t\t\t\ttitle={t(\"pages.maintenanceWindow.form.startTime.title\")}\n\t\t\t\tsubtitle={t(\"pages.maintenanceWindow.form.startTime.description\")}\n\t\t\t\trightContent={\n\t\t\t\t\t<Stack spacing={theme.spacing(LAYOUT.MD)}>\n\t\t\t\t\t\t<Controller\n\t\t\t\t\t\t\tname=\"startTime\"\n\t\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\t\tdefaultValue={defaults.startTime}\n\t\t\t\t\t\t\trender={({ field }) => (\n\t\t\t\t\t\t\t\t<TimePicker\n\t\t\t\t\t\t\t\t\tfieldLabel={t(\n\t\t\t\t\t\t\t\t\t\t\"pages.maintenanceWindow.form.startTime.option.startTime.label\"\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\tvalue={field.value ? dayjs(field.value, \"HH:mm\") : null}\n\t\t\t\t\t\t\t\t\tonChange={(time) => {\n\t\t\t\t\t\t\t\t\t\tfield.onChange(time ? time.format(\"HH:mm\") : \"\");\n\t\t\t\t\t\t\t\t\t\ttrigger(\"startDate\");\n\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<Stack\n\t\t\t\t\t\t\tdirection=\"row\"\n\t\t\t\t\t\t\talignItems=\"flex-start\"\n\t\t\t\t\t\t\tspacing={theme.spacing(LAYOUT.MD)}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<Controller\n\t\t\t\t\t\t\t\tname=\"duration\"\n\t\t\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\t\t\tdefaultValue={defaults.duration}\n\t\t\t\t\t\t\t\trender={({ field, fieldState }) => (\n\t\t\t\t\t\t\t\t\t<TextField\n\t\t\t\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\t\t\t\ttype=\"number\"\n\t\t\t\t\t\t\t\t\t\tfieldLabel={t(\n\t\t\t\t\t\t\t\t\t\t\t\"pages.maintenanceWindow.form.startTime.option.duration.label\"\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\tvalue={field.value === 0 ? \"\" : field.value}\n\t\t\t\t\t\t\t\t\t\tonChange={(e) => {\n\t\t\t\t\t\t\t\t\t\t\tconst val = e.target.value;\n\t\t\t\t\t\t\t\t\t\t\tfield.onChange(val === \"\" ? 0 : Number(val));\n\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\terror={!!fieldState.error}\n\t\t\t\t\t\t\t\t\t\thelperText={fieldState.error?.message ?? \"\"}\n\t\t\t\t\t\t\t\t\t\tsx={{ width: 120 }}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t<Controller\n\t\t\t\t\t\t\t\tname=\"durationUnit\"\n\t\t\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\t\t\tdefaultValue={defaults.durationUnit}\n\t\t\t\t\t\t\t\trender={({ field }) => (\n\t\t\t\t\t\t\t\t\t<Select\n\t\t\t\t\t\t\t\t\t\tfieldLabel=\" \"\n\t\t\t\t\t\t\t\t\t\tvalue={field.value}\n\t\t\t\t\t\t\t\t\t\tonChange={field.onChange}\n\t\t\t\t\t\t\t\t\t\tsx={{ minWidth: 120 }}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t{durationUnitOptions.map((option) => (\n\t\t\t\t\t\t\t\t\t\t\t<MenuItem\n\t\t\t\t\t\t\t\t\t\t\t\tkey={option.id}\n\t\t\t\t\t\t\t\t\t\t\t\tvalue={option.id}\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t<Typography>{option.name}</Typography>\n\t\t\t\t\t\t\t\t\t\t\t</MenuItem>\n\t\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t\t</Select>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</Stack>\n\t\t\t\t\t</Stack>\n\t\t\t\t}\n\t\t\t/>\n\t\t\t<ConfigBox\n\t\t\t\ttitle={t(\"pages.maintenanceWindow.form.startTime.monitors.title\")}\n\t\t\t\tsubtitle={t(\"pages.maintenanceWindow.form.startTime.monitors.description\")}\n\t\t\t\trightContent={\n\t\t\t\t\t<Controller\n\t\t\t\t\t\tname=\"monitors\"\n\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\tdefaultValue={defaults.monitors}\n\t\t\t\t\t\trender={({ field, fieldState }) => {\n\t\t\t\t\t\t\tconst monitorsList = monitors ?? [];\n\t\t\t\t\t\t\tconst selectedMonitors = field.value\n\t\t\t\t\t\t\t\t.map((id: string) => monitorsList.find((m) => m.id === id))\n\t\t\t\t\t\t\t\t.filter((m): m is Monitor => m !== undefined);\n\n\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t<Stack spacing={theme.spacing(LAYOUT.MD)}>\n\t\t\t\t\t\t\t\t\t<Autocomplete\n\t\t\t\t\t\t\t\t\t\tmultiple\n\t\t\t\t\t\t\t\t\t\toptions={monitorsList}\n\t\t\t\t\t\t\t\t\t\tgetOptionLabel={(option: Monitor) => option.name}\n\t\t\t\t\t\t\t\t\t\tvalue={selectedMonitors}\n\t\t\t\t\t\t\t\t\t\tonChange={(_, newValue) => {\n\t\t\t\t\t\t\t\t\t\t\tfield.onChange(newValue.map((m: Monitor) => m.id));\n\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\tfieldLabel={t(\n\t\t\t\t\t\t\t\t\t\t\t\"pages.maintenanceWindow.form.startTime.monitors.option.addMonitors.label\"\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\trenderInput={(params) => (\n\t\t\t\t\t\t\t\t\t\t\t<TextField\n\t\t\t\t\t\t\t\t\t\t\t\t{...params}\n\t\t\t\t\t\t\t\t\t\t\t\tplaceholder={\n\t\t\t\t\t\t\t\t\t\t\t\t\tselectedMonitors.length === 0\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t? t(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"pages.maintenanceWindow.form.startTime.monitors.option.addMonitors.label\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t: \"\"\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\terror={!!fieldState.error}\n\t\t\t\t\t\t\t\t\t\t\t\thelperText={fieldState.error?.message}\n\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t{selectedMonitors.length > 0 && (\n\t\t\t\t\t\t\t\t\t\t<Stack>\n\t\t\t\t\t\t\t\t\t\t\t{selectedMonitors.map((monitor) => (\n\t\t\t\t\t\t\t\t\t\t\t\t<Stack\n\t\t\t\t\t\t\t\t\t\t\t\t\tkey={monitor.id}\n\t\t\t\t\t\t\t\t\t\t\t\t\tdirection=\"row\"\n\t\t\t\t\t\t\t\t\t\t\t\t\talignItems=\"center\"\n\t\t\t\t\t\t\t\t\t\t\t\t\tpadding={theme.spacing(LAYOUT.XS)}\n\t\t\t\t\t\t\t\t\t\t\t\t\tmarginTop={theme.spacing(SPACING.LG)}\n\t\t\t\t\t\t\t\t\t\t\t\t\tborderRadius={1}\n\t\t\t\t\t\t\t\t\t\t\t\t\tsx={{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tborder: `1px solid ${theme.palette.divider}`,\n\t\t\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<Typography flexGrow={1}>{monitor.name}</Typography>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<IconButton\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tfield.onChange(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tfield.value.filter((id: string) => id !== monitor.id)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\taria-label=\"Remove monitor\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<Trash2 size={16} />\n\t\t\t\t\t\t\t\t\t\t\t\t\t</IconButton>\n\t\t\t\t\t\t\t\t\t\t\t\t</Stack>\n\t\t\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t\t\t</Stack>\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t</Stack>\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}}\n\t\t\t\t\t/>\n\t\t\t\t}\n\t\t\t/>\n\t\t\t<Stack\n\t\t\t\tdirection=\"row\"\n\t\t\t\tjustifyContent=\"flex-end\"\n\t\t\t\tspacing={theme.spacing(SPACING.LG)}\n\t\t\t>\n\t\t\t\t<Button\n\t\t\t\t\tloading={isLoading}\n\t\t\t\t\ttype=\"submit\"\n\t\t\t\t\tvariant=\"contained\"\n\t\t\t\t\tcolor=\"primary\"\n\t\t\t\t>\n\t\t\t\t\t{t(\"common.buttons.save\")}\n\t\t\t\t</Button>\n\t\t\t</Stack>\n\t\t</BasePage>\n\t);\n};\n\nexport default CreateMaintenanceWindowPage;\n"
  },
  {
    "path": "client/src/Pages/Maintenance/index.tsx",
    "content": "import { BasePageWithStates } from \"@/Components/design-elements\";\nimport { HeaderCreate } from \"@/Components/common\";\nimport { useTranslation } from \"react-i18next\";\nimport { useGet } from \"@/Hooks/UseApi\";\nimport { MaintenanceWindowTable } from \"./MaintenanceWindowTable\";\nimport { useState } from \"react\";\nimport { useSelector } from \"react-redux\";\nimport type { RootState } from \"@/Types/state\";\nimport type { MaintenanceWindow } from \"@/Types/MaintenanceWindow\";\nimport { useIsAdmin } from \"@/Hooks/useIsAdmin\";\n\ninterface MaintenanceWindowsResponse {\n\tmaintenanceWindows: MaintenanceWindow[];\n\tmaintenanceWindowCount: number;\n}\n\nconst MaintenanceWindowPage = () => {\n\tconst { t } = useTranslation();\n\tconst isAdmin = useIsAdmin();\n\tconst [page, setPage] = useState(0);\n\tconst rowsPerPage = useSelector(\n\t\t(state: RootState) => state?.ui?.maintenance?.rowsPerPage ?? 5\n\t);\n\n\tconst { data, isLoading, isValidating, error, refetch } =\n\t\tuseGet<MaintenanceWindowsResponse>(\n\t\t\t`/maintenance-window/team?page=${page}&rowsPerPage=${rowsPerPage}`\n\t\t);\n\n\tconst maintenanceWindows = data?.maintenanceWindows ?? [];\n\tconst maintenanceWindowCount = data?.maintenanceWindowCount ?? 0;\n\n\treturn (\n\t\t<BasePageWithStates\n\t\t\tpage={t(\"pages.maintenanceWindow.fallback.title\")}\n\t\t\ttotalCount={maintenanceWindowCount}\n\t\t\tbullets={\n\t\t\t\tt(\"pages.maintenanceWindow.fallback.checks\", { returnObjects: true }) as string[]\n\t\t\t}\n\t\t\tloading={isLoading}\n\t\t\terror={!!error}\n\t\t\tactionButtonText={t(\"pages.maintenanceWindow.fallback.actionButton\")}\n\t\t\tactionLink=\"/maintenance/create\"\n\t\t>\n\t\t\t<HeaderCreate\n\t\t\t\tpath=\"/maintenance/create\"\n\t\t\t\tisLoading={isLoading || isValidating}\n\t\t\t\tisAdmin={isAdmin}\n\t\t\t/>\n\t\t\t<MaintenanceWindowTable\n\t\t\t\tmaintenanceWindows={maintenanceWindows}\n\t\t\t\tmaintenanceWindowCount={maintenanceWindowCount}\n\t\t\t\tpage={page}\n\t\t\t\tsetPage={setPage}\n\t\t\t\trefetch={refetch}\n\t\t\t/>\n\t\t</BasePageWithStates>\n\t);\n};\n\nexport default MaintenanceWindowPage;\n"
  },
  {
    "path": "client/src/Pages/NotFound/index.tsx",
    "content": "import NotFoundSvg from \"@/assets/Images/sushi_404.svg\";\nimport { Button } from \"@/Components/inputs\";\nimport Box from \"@mui/material/Box\";\nimport Stack from \"@mui/material/Stack\";\nimport Typography from \"@mui/material/Typography\";\n\nimport { useNavigate } from \"react-router-dom\";\nimport { useTheme } from \"@mui/material\";\nimport { useTranslation } from \"react-i18next\";\n\ninterface NotFoundProps {\n\ttitle?: string;\n\tdesc?: string;\n}\n\nconst NotFoundPage = ({ title, desc }: NotFoundProps) => {\n\tconst navigate = useNavigate();\n\tconst theme = useTheme();\n\tconst { t } = useTranslation();\n\n\tif (!title || title === \"\") {\n\t\ttitle = t(\"pages.notFound.title\");\n\t}\n\n\tif (!desc || desc === \"\") {\n\t\tdesc = t(\"pages.notFound.subtitle\");\n\t}\n\n\treturn (\n\t\t<Stack\n\t\t\theight=\"100vh\"\n\t\t\tjustifyContent=\"center\"\n\t\t>\n\t\t\t<Stack\n\t\t\t\tgap={theme.spacing(2)}\n\t\t\t\talignItems=\"center\"\n\t\t\t>\n\t\t\t\t<Box\n\t\t\t\t\tcomponent=\"img\"\n\t\t\t\t\tsrc={NotFoundSvg}\n\t\t\t\t\talt=\"404\"\n\t\t\t\t\tmaxHeight={\"25rem\"}\n\t\t\t\t/>\n\t\t\t\t<Typography\n\t\t\t\t\tcomponent=\"h1\"\n\t\t\t\t\tvariant=\"h1\"\n\t\t\t\t>\n\t\t\t\t\t{title}\n\t\t\t\t</Typography>\n\t\t\t\t<Typography variant=\"body1\">{desc}</Typography>\n\t\t\t\t<Button\n\t\t\t\t\tvariant=\"contained\"\n\t\t\t\t\tcolor=\"primary\"\n\t\t\t\t\tsx={{ mt: theme.spacing(10) }}\n\t\t\t\t\tonClick={() => navigate(\"/\")}\n\t\t\t\t>\n\t\t\t\t\t{t(\"common.buttons.notFound\")}\n\t\t\t\t</Button>\n\t\t\t</Stack>\n\t\t</Stack>\n\t);\n};\n\nexport default NotFoundPage;\n"
  },
  {
    "path": "client/src/Pages/Notifications/components/NotificationsTable.tsx",
    "content": "import { ActionsMenu, type ActionMenuItem } from \"@/Components/actions-menu\";\nimport Typography from \"@mui/material/Typography\";\nimport type { Header } from \"@/Components/design-elements/Table\";\nimport { Table } from \"@/Components/design-elements\";\n\nimport type { Notification } from \"@/Types/Notification\";\nimport { useNavigate } from \"react-router\";\nimport { useTranslation } from \"react-i18next\";\nimport { useTheme } from \"@mui/material\";\n\ninterface NotificationsTableProps {\n\tnotifications: Notification[];\n\tsetSelectedChannel: Function;\n}\n\nexport const NotificationsTable = ({\n\tnotifications,\n\tsetSelectedChannel,\n}: NotificationsTableProps) => {\n\tconst navigate = useNavigate();\n\tconst { t } = useTranslation();\n\tconst theme = useTheme();\n\n\tconst getActions = (channel: Notification): ActionMenuItem[] => {\n\t\treturn [\n\t\t\t{\n\t\t\t\tid: 1,\n\t\t\t\tlabel: t(\"pages.common.monitors.actions.configure\"),\n\t\t\t\taction: () => {\n\t\t\t\t\tnavigate(`/notifications/configure/${channel.id}`);\n\t\t\t\t},\n\t\t\t\tcloseMenu: true,\n\t\t\t},\n\n\t\t\t{\n\t\t\t\tid: 7,\n\t\t\t\tlabel: (\n\t\t\t\t\t<Typography color={theme.palette.error.main}>\n\t\t\t\t\t\t{t(\"pages.common.monitors.actions.delete\")}\n\t\t\t\t\t</Typography>\n\t\t\t\t),\n\t\t\t\taction: async () => {\n\t\t\t\t\tsetSelectedChannel(channel);\n\t\t\t\t},\n\t\t\t\tcloseMenu: true,\n\t\t\t},\n\t\t];\n\t};\n\n\tconst getHeaders = () => {\n\t\tconst headers: Header<Notification>[] = [\n\t\t\t{\n\t\t\t\tid: \"name\",\n\t\t\t\tcontent: t(\"common.table.headers.name\"),\n\t\t\t\trender: (row) => {\n\t\t\t\t\treturn <Typography>{row?.notificationName}</Typography>;\n\t\t\t\t},\n\t\t\t},\n\n\t\t\t{\n\t\t\t\tid: \"type\",\n\t\t\t\tcontent: t(\"common.table.headers.type\"),\n\t\t\t\trender: (row) => {\n\t\t\t\t\treturn <Typography textTransform={\"capitalize\"}>{row?.type}</Typography>;\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"destination\",\n\t\t\t\tcontent: t(\"pages.notifications.table.headers.destination\"),\n\t\t\t\trender: (row) => {\n\t\t\t\t\treturn <Typography>{row?.address}</Typography>;\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"actions\",\n\t\t\t\tcontent: t(\"common.table.headers.actions\"),\n\t\t\t\trender: (row) => {\n\t\t\t\t\treturn <ActionsMenu items={getActions(row)} />;\n\t\t\t\t},\n\t\t\t},\n\t\t];\n\t\treturn headers;\n\t};\n\n\tconst headers = getHeaders();\n\n\treturn (\n\t\t<Table\n\t\t\theaders={headers}\n\t\t\tdata={notifications}\n\t\t\tonRowClick={(row) => {\n\t\t\t\tnavigate(`/notifications/configure/${row.id}`);\n\t\t\t}}\n\t\t/>\n\t);\n};\n"
  },
  {
    "path": "client/src/Pages/Notifications/create/index.tsx",
    "content": "import { BasePage, ConfigBox } from \"@/Components/design-elements\";\nimport { TextField, Select, Button } from \"@/Components/inputs\";\nimport MenuItem from \"@mui/material/MenuItem\";\nimport Typography from \"@mui/material/Typography\";\nimport Stack from \"@mui/material/Stack\";\nimport { useTheme } from \"@mui/material/styles\";\n\nimport { useEffect, useMemo } from \"react\";\nimport { useParams } from \"react-router-dom\";\nimport { useNavigate } from \"react-router-dom\";\nimport { Controller, useForm } from \"react-hook-form\";\nimport { zodResolver } from \"@hookform/resolvers/zod\";\nimport { useGet, usePost, usePatch } from \"@/Hooks/UseApi\";\nimport { useNotificationForm } from \"@/Hooks/useNotificationForm\";\nimport type { NotificationFormData } from \"@/Validation/notifications\";\nimport type { Notification } from \"@/Types/Notification\";\nimport { useTranslation } from \"react-i18next\";\nimport { NotificationChannels } from \"@/Types/Notification\";\n\nconst NotificationsCreatePage = () => {\n\tconst { t } = useTranslation();\n\tconst theme = useTheme();\n\tconst navigate = useNavigate();\n\tconst { notificationId } = useParams<{ notificationId: string }>();\n\tconst isEditMode = Boolean(notificationId);\n\n\tconst { data: existingNotification } = useGet<Notification>(\n\t\tisEditMode ? `/notifications/${notificationId}` : null\n\t);\n\n\tconst { post, loading: isSubmitting } = usePost<NotificationFormData, Notification>();\n\tconst { patch, loading: isPatching } = usePatch<NotificationFormData, Notification>();\n\tconst { post: testPost, loading: isTesting } = usePost<NotificationFormData, void>();\n\n\tconst { schema, defaults } = useNotificationForm({ data: existingNotification });\n\n\tconst form = useForm<NotificationFormData>({\n\t\tresolver: zodResolver(schema),\n\t\tdefaultValues: defaults,\n\t});\n\n\tconst { control, watch, reset, handleSubmit, clearErrors, trigger, getValues } = form;\n\n\tuseEffect(() => {\n\t\treset(defaults);\n\t}, [defaults, reset]);\n\n\tconst watchedType = watch(\"type\");\n\n\tuseEffect(() => {\n\t\tclearErrors();\n\t}, [watchedType, clearErrors]);\n\n\tconst addressConfig = useMemo(() => {\n\t\tif (watchedType === \"pager_duty\") {\n\t\t\treturn {\n\t\t\t\ttitle: t(\"pages.notifications.form.pagerDuty.title\"),\n\t\t\t\tdescription: t(\"pages.notifications.form.pagerDuty.description\"),\n\t\t\t\tfieldLabel: t(\"pages.notifications.form.pagerDuty.optionIntegrationKey\"),\n\t\t\t\tplaceholder: t(\"pages.notifications.form.pagerDuty.placeholder\"),\n\t\t\t};\n\t\t}\n\t\tif (watchedType === \"email\") {\n\t\t\treturn {\n\t\t\t\ttitle: t(\"pages.notifications.form.address.title\"),\n\t\t\t\tdescription: t(\"pages.notifications.form.address.description\"),\n\t\t\t\tfieldLabel: t(\"pages.notifications.form.address.optionAddress\"),\n\t\t\t\tplaceholder: t(\"pages.notifications.form.address.placeholderEmail\"),\n\t\t\t};\n\t\t}\n\t\treturn {\n\t\t\ttitle: t(\"pages.notifications.form.address.title\"),\n\t\t\tdescription: t(\"pages.notifications.form.address.description\"),\n\t\t\tfieldLabel: t(\"pages.notifications.form.address.optionAddress\"),\n\t\t\tplaceholder: t(\"pages.notifications.form.address.placeholderWebhook\"),\n\t\t};\n\t}, [watchedType, t]);\n\n\tconst onSubmit = async (data: NotificationFormData) => {\n\t\tconst result = isEditMode\n\t\t\t? await patch(`/notifications/${notificationId}`, data)\n\t\t\t: await post(\"/notifications\", data);\n\t\tif (result) {\n\t\t\tnavigate(\"/notifications\");\n\t\t}\n\t};\n\n\tconst handleTest = async () => {\n\t\tconst isValid = await trigger();\n\t\tif (!isValid) return;\n\t\tconst data = getValues();\n\t\tawait testPost(\"/notifications/test\", data);\n\t};\n\n\treturn (\n\t\t<BasePage\n\t\t\tcomponent=\"form\"\n\t\t\tonSubmit={handleSubmit(onSubmit)}\n\t\t>\n\t\t\t<ConfigBox\n\t\t\t\ttitle={t(\"pages.notifications.form.notificationName.title\")}\n\t\t\t\tsubtitle={t(\"pages.notifications.form.notificationName.description\")}\n\t\t\t\trightContent={\n\t\t\t\t\t<Controller\n\t\t\t\t\t\tname=\"notificationName\"\n\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\tdefaultValue={defaults.notificationName}\n\t\t\t\t\t\trender={({ field, fieldState }) => (\n\t\t\t\t\t\t\t<TextField\n\t\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\t\ttype=\"text\"\n\t\t\t\t\t\t\t\tfieldLabel={t(\"pages.notifications.form.notificationName.optionName\")}\n\t\t\t\t\t\t\t\tplaceholder={t(\"pages.notifications.form.notificationName.placeholder\")}\n\t\t\t\t\t\t\t\tfullWidth\n\t\t\t\t\t\t\t\terror={!!fieldState.error}\n\t\t\t\t\t\t\t\thelperText={fieldState.error?.message ?? \"\"}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t)}\n\t\t\t\t\t/>\n\t\t\t\t}\n\t\t\t/>\n\t\t\t<ConfigBox\n\t\t\t\ttitle={t(\"pages.notifications.form.type.title\")}\n\t\t\t\tsubtitle={t(\"pages.notifications.form.type.description\")}\n\t\t\t\trightContent={\n\t\t\t\t\t<Controller\n\t\t\t\t\t\tname=\"type\"\n\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\tdefaultValue={defaults.type}\n\t\t\t\t\t\trender={({ field, fieldState }) => (\n\t\t\t\t\t\t\t<Select\n\t\t\t\t\t\t\t\tvalue={field.value}\n\t\t\t\t\t\t\t\tfieldLabel={t(\"pages.notifications.form.type.optionType\")}\n\t\t\t\t\t\t\t\terror={!!fieldState.error}\n\t\t\t\t\t\t\t\tonChange={field.onChange}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{NotificationChannels.map((type: string) => (\n\t\t\t\t\t\t\t\t\t<MenuItem\n\t\t\t\t\t\t\t\t\t\tkey={type}\n\t\t\t\t\t\t\t\t\t\tvalue={type}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<Typography textTransform=\"capitalize\">{type}</Typography>\n\t\t\t\t\t\t\t\t\t</MenuItem>\n\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t</Select>\n\t\t\t\t\t\t)}\n\t\t\t\t\t/>\n\t\t\t\t}\n\t\t\t/>\n\t\t\t{watchedType !== \"matrix\" && (\n\t\t\t\t<ConfigBox\n\t\t\t\t\ttitle={addressConfig.title}\n\t\t\t\t\tsubtitle={addressConfig.description}\n\t\t\t\t\trightContent={\n\t\t\t\t\t\t<Controller\n\t\t\t\t\t\t\tname=\"address\"\n\t\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\t\tdefaultValue={defaults.address}\n\t\t\t\t\t\t\trender={({ field, fieldState }) => (\n\t\t\t\t\t\t\t\t<TextField\n\t\t\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\t\t\ttype=\"text\"\n\t\t\t\t\t\t\t\t\tfieldLabel={addressConfig.fieldLabel}\n\t\t\t\t\t\t\t\t\tplaceholder={addressConfig.placeholder}\n\t\t\t\t\t\t\t\t\tfullWidth\n\t\t\t\t\t\t\t\t\terror={!!fieldState.error}\n\t\t\t\t\t\t\t\t\thelperText={fieldState.error?.message ?? \"\"}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t/>\n\t\t\t\t\t}\n\t\t\t\t/>\n\t\t\t)}\n\t\t\t{watchedType === \"matrix\" && (\n\t\t\t\t<ConfigBox\n\t\t\t\t\ttitle={t(\"pages.notifications.form.matrix.title\")}\n\t\t\t\t\tsubtitle={t(\"pages.notifications.form.matrix.description\")}\n\t\t\t\t\trightContent={\n\t\t\t\t\t\t<Stack spacing={theme.spacing(8)}>\n\t\t\t\t\t\t\t<Controller\n\t\t\t\t\t\t\t\tname=\"homeserverUrl\"\n\t\t\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\t\t\tdefaultValue={defaults.homeserverUrl}\n\t\t\t\t\t\t\t\trender={({ field, fieldState }) => (\n\t\t\t\t\t\t\t\t\t<TextField\n\t\t\t\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\t\t\t\ttype=\"text\"\n\t\t\t\t\t\t\t\t\t\tfieldLabel={t(\"pages.notifications.form.homeServer.optionHomeServer\")}\n\t\t\t\t\t\t\t\t\t\tplaceholder={t(\"pages.notifications.form.homeServer.placeholder\")}\n\t\t\t\t\t\t\t\t\t\tfullWidth\n\t\t\t\t\t\t\t\t\t\terror={!!fieldState.error}\n\t\t\t\t\t\t\t\t\t\thelperText={fieldState.error?.message ?? \"\"}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t<Controller\n\t\t\t\t\t\t\t\tname=\"roomId\"\n\t\t\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\t\t\tdefaultValue={defaults.roomId}\n\t\t\t\t\t\t\t\trender={({ field, fieldState }) => (\n\t\t\t\t\t\t\t\t\t<TextField\n\t\t\t\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\t\t\t\ttype=\"text\"\n\t\t\t\t\t\t\t\t\t\tfieldLabel={t(\"pages.notifications.form.roomId.optionRoomId\")}\n\t\t\t\t\t\t\t\t\t\tplaceholder={t(\"pages.notifications.form.roomId.placeholder\")}\n\t\t\t\t\t\t\t\t\t\tfullWidth\n\t\t\t\t\t\t\t\t\t\terror={!!fieldState.error}\n\t\t\t\t\t\t\t\t\t\thelperText={fieldState.error?.message ?? \"\"}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t<Controller\n\t\t\t\t\t\t\t\tname=\"accessToken\"\n\t\t\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\t\t\tdefaultValue={defaults.accessToken}\n\t\t\t\t\t\t\t\trender={({ field, fieldState }) => (\n\t\t\t\t\t\t\t\t\t<TextField\n\t\t\t\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\t\t\t\ttype=\"text\"\n\t\t\t\t\t\t\t\t\t\tfieldLabel={t(\n\t\t\t\t\t\t\t\t\t\t\t\"pages.notifications.form.accessToken.optionAccessToken\"\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\tplaceholder={t(\"pages.notifications.form.accessToken.placeholder\")}\n\t\t\t\t\t\t\t\t\t\tfullWidth\n\t\t\t\t\t\t\t\t\t\terror={!!fieldState.error}\n\t\t\t\t\t\t\t\t\t\thelperText={fieldState.error?.message ?? \"\"}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</Stack>\n\t\t\t\t\t}\n\t\t\t\t/>\n\t\t\t)}\n\t\t\t<Stack\n\t\t\t\tdirection=\"row\"\n\t\t\t\tjustifyContent=\"flex-end\"\n\t\t\t\tspacing={theme.spacing(2)}\n\t\t\t>\n\t\t\t\t<Button\n\t\t\t\t\tvariant=\"contained\"\n\t\t\t\t\tcolor=\"primary\"\n\t\t\t\t\tonClick={handleTest}\n\t\t\t\t\tloading={isTesting}\n\t\t\t\t>\n\t\t\t\t\t{t(\"common.buttons.test\")}\n\t\t\t\t</Button>\n\t\t\t\t<Button\n\t\t\t\t\tloading={isSubmitting || isPatching}\n\t\t\t\t\ttype=\"submit\"\n\t\t\t\t\tvariant=\"contained\"\n\t\t\t\t\tcolor=\"primary\"\n\t\t\t\t>\n\t\t\t\t\t{t(\"common.buttons.save\")}\n\t\t\t\t</Button>\n\t\t\t</Stack>\n\t\t</BasePage>\n\t);\n};\n\nexport default NotificationsCreatePage;\n"
  },
  {
    "path": "client/src/Pages/Notifications/index.tsx",
    "content": "import { BasePageWithStates } from \"@/Components/design-elements\";\nimport { NotificationsTable } from \"@/Pages/Notifications/components/NotificationsTable\";\nimport { Dialog } from \"@/Components/inputs\";\nimport { HeaderCreate } from \"@/Components/common\";\n\nimport { useState } from \"react\";\nimport { useGet, useDelete } from \"@/Hooks/UseApi\";\nimport { useTranslation } from \"react-i18next\";\nimport type { Notification } from \"@/Types/Notification\";\nimport { useIsAdmin } from \"@/Hooks/useIsAdmin\";\n\nconst NotificationsPage = () => {\n\tconst { t } = useTranslation();\n\tconst isAdmin = useIsAdmin();\n\n\tconst [selectedChannel, setSelectedChannel] = useState<Notification | null>(null);\n\tconst isDialogOpen = Boolean(selectedChannel);\n\n\tconst {\n\t\tdata: notifications,\n\t\tisLoading,\n\t\tisValidating,\n\t\terror,\n\t\trefetch,\n\t} = useGet<Notification[]>(\"/notifications/team\", {}, { keepPreviousData: true });\n\n\tconst { deleteFn, loading: isDeleting } = useDelete();\n\n\tconst handleConfirm = async () => {\n\t\tif (!selectedChannel) return;\n\t\tawait deleteFn(`/notifications/${selectedChannel.id}`);\n\t\tsetSelectedChannel(null);\n\t\trefetch();\n\t};\n\n\tconst handleCancel = () => {\n\t\tsetSelectedChannel(null);\n\t};\n\n\treturn (\n\t\t<BasePageWithStates\n\t\t\tpage={t(\"pages.notifications.fallback.title\")}\n\t\t\tbullets={\n\t\t\t\tt(\"pages.notifications.fallback.checks\", { returnObjects: true }) as string[]\n\t\t\t}\n\t\t\tloading={isLoading || isValidating}\n\t\t\terror={!!error}\n\t\t\ttotalCount={notifications?.length ?? 0}\n\t\t\tactionButtonText={t(\"pages.notifications.fallback.actionButton\")}\n\t\t\tactionLink=\"/notifications/create\"\n\t\t>\n\t\t\t<HeaderCreate\n\t\t\t\tpath=\"/notifications/create\"\n\t\t\t\tisLoading={isLoading || isValidating}\n\t\t\t\tisAdmin={isAdmin}\n\t\t\t/>\n\t\t\t<NotificationsTable\n\t\t\t\tnotifications={notifications ?? []}\n\t\t\t\tsetSelectedChannel={setSelectedChannel}\n\t\t\t/>\n\t\t\t<Dialog\n\t\t\t\topen={isDialogOpen}\n\t\t\t\ttitle={t(\"common.dialogs.delete.title\")}\n\t\t\t\tcontent={t(\"common.dialogs.delete.description\")}\n\t\t\t\tonConfirm={handleConfirm}\n\t\t\t\tonCancel={handleCancel}\n\t\t\t\tloading={isDeleting}\n\t\t\t/>\n\t\t</BasePageWithStates>\n\t);\n};\n\nexport default NotificationsPage;\n"
  },
  {
    "path": "client/src/Pages/PageSpeed/Details/index.tsx",
    "content": "import { BasePage } from \"@/Components/design-elements\";\nimport { HeaderTimeRange } from \"@/Components/common\";\nimport type { PageSpeedDetailsResponse } from \"@/Types/Monitor\";\nimport Stack from \"@mui/material/Stack\";\nimport {\n\tHistogramPageSpeedDetails,\n\tPiePageSpeed,\n\tPiePageSpeedLegend,\n\tMonitorStatBoxes,\n\tHeaderMonitorControls,\n} from \"@/Components/monitors\";\n\nimport { useIsAdmin } from \"@/Hooks/useIsAdmin\";\nimport { useGet } from \"@/Hooks/UseApi\";\nimport { useParams } from \"react-router-dom\";\nimport { useTheme } from \"@mui/material\";\nimport { useState, useMemo } from \"react\";\n\nconst PageSpeedDetails = () => {\n\tconst { monitorId } = useParams();\n\tconst isAdmin = useIsAdmin();\n\tconst theme = useTheme();\n\tconst [dateRange, setDateRange] = useState<string>(\"day\");\n\n\tconst monitorDetailsUrl = useMemo(() => {\n\t\tif (!monitorId) {\n\t\t\treturn null;\n\t\t}\n\t\tconst params = new URLSearchParams();\n\t\tparams.append(\"dateRange\", dateRange);\n\t\treturn `/monitors/pagespeed/details/${monitorId}?${params.toString()}`;\n\t}, [monitorId, dateRange]);\n\n\tconst {\n\t\tdata: monitorData,\n\t\tisLoading,\n\t\terror,\n\t\trefetch,\n\t} = useGet<PageSpeedDetailsResponse>(\n\t\tmonitorDetailsUrl,\n\t\t{},\n\t\t{ keepPreviousData: true, refreshInterval: 30000 }\n\t);\n\n\tconst monitor = monitorData?.monitorData?.monitor;\n\tconst groupedChecks = monitorData?.monitorData?.groupedChecks || [];\n\tconst monitorStats = monitorData?.monitorStats || null;\n\n\treturn (\n\t\t<BasePage\n\t\t\tloading={isLoading}\n\t\t\terror={error}\n\t\t>\n\t\t\t<HeaderMonitorControls\n\t\t\t\tpath=\"pagespeed\"\n\t\t\t\tmonitor={monitor}\n\t\t\t\tisAdmin={isAdmin}\n\t\t\t\trefetch={refetch}\n\t\t\t/>\n\t\t\t<MonitorStatBoxes\n\t\t\t\tmonitor={monitor}\n\t\t\t\tmonitorStats={monitorStats}\n\t\t\t/>\n\t\t\t<HeaderTimeRange\n\t\t\t\tisLoading={isLoading}\n\t\t\t\thasDateRange={true}\n\t\t\t\tdateRange={dateRange}\n\t\t\t\tsetDateRange={setDateRange}\n\t\t\t/>\n\t\t\t<HistogramPageSpeedDetails\n\t\t\t\tchecks={groupedChecks}\n\t\t\t\trange={dateRange}\n\t\t\t/>\n\t\t\t<Stack\n\t\t\t\tdirection={{ xs: \"column\", md: \"row\" }}\n\t\t\t\tgap={theme.spacing(10)}\n\t\t\t>\n\t\t\t\t<PiePageSpeed latestCheck={monitor?.recentChecks?.[0]} />\n\t\t\t\t<PiePageSpeedLegend latestCheck={monitor?.recentChecks?.[0]} />\n\t\t\t</Stack>\n\t\t</BasePage>\n\t);\n};\nexport default PageSpeedDetails;\n"
  },
  {
    "path": "client/src/Pages/PageSpeed/Monitors/Components/PageSpeedMonitorsTable.tsx",
    "content": "import Stack from \"@mui/material/Stack\";\nimport Box from \"@mui/material/Box\";\nimport Typography from \"@mui/material/Typography\";\nimport { Table, Pagination, StatusLabel } from \"@/Components/design-elements\";\nimport { HistogramPageSpeed } from \"@/Components/monitors\";\nimport { ArrowDown, ArrowUp } from \"lucide-react\";\nimport type { Header } from \"@/Components/design-elements/Table\";\nimport { ActionsMenu } from \"@/Components/actions-menu\";\n\nimport { useTranslation } from \"react-i18next\";\nimport useMediaQuery from \"@mui/material/useMediaQuery\";\nimport { useTheme } from \"@mui/material/styles\";\nimport { useNavigate } from \"react-router-dom\";\nimport { usePatch } from \"@/Hooks/UseApi\";\n\nimport type { Monitor, MonitorWithChecks } from \"@/Types/Monitor\";\nimport type { ActionMenuItem } from \"@/Components/actions-menu\";\n\nexport const PageSpeedMonitorsTable = ({\n\tmonitors,\n\trefetch,\n\tsetSelectedMonitor,\n\tsortField,\n\tsetSortField,\n\tsortOrder,\n\tsetSortOrder,\n\tcount,\n\tpage,\n\tsetPage,\n\trowsPerPage,\n\tsetRowsPerPage,\n}: {\n\tmonitors: MonitorWithChecks[];\n\trefetch: Function;\n\tsetSelectedMonitor: Function;\n\tsortField: string;\n\tsetSortField: (field: string) => void;\n\tsortOrder: \"asc\" | \"desc\";\n\tsetSortOrder: (order: \"asc\" | \"desc\") => void;\n\tcount: number;\n\tpage: number;\n\tsetPage: (page: number) => void;\n\trowsPerPage: number;\n\tsetRowsPerPage: (rowsPerPage: number) => void;\n}) => {\n\tconst { t } = useTranslation();\n\tconst theme = useTheme();\n\tconst isSmall = useMediaQuery(theme.breakpoints.down(\"md\"));\n\tconst navigate = useNavigate();\n\tconst {\n\t\tpatch,\n\t\t// loading: isPatching,\n\t\t// error: postError,\n\t} = usePatch<any, Monitor>();\n\n\tconst handlePageChange = (\n\t\t_e: React.MouseEvent<HTMLButtonElement> | null,\n\t\tnewPage: number\n\t) => {\n\t\tsetPage(newPage);\n\t};\n\n\tconst handleRowsPerPageChange = (\n\t\te: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>\n\t) => {\n\t\tconst value = Number(e.target.value);\n\t\tsetPage(0);\n\t\tsetRowsPerPage(value);\n\t};\n\n\tconst handleSort = (e: any, field: string) => {\n\t\te.preventDefault();\n\t\te.stopPropagation();\n\t\tif (sortField === field) {\n\t\t\tconst newOrder = sortOrder === \"asc\" ? \"desc\" : \"asc\";\n\t\t\tsetSortOrder(newOrder);\n\t\t} else {\n\t\t\tsetSortField(field);\n\t\t\tsetSortOrder(\"asc\");\n\t\t}\n\t\trefetch();\n\t};\n\n\tconst getActions = (monitor: Monitor): ActionMenuItem[] => {\n\t\treturn [\n\t\t\t{\n\t\t\t\tid: 1,\n\t\t\t\tlabel: t(\"pages.common.monitors.actions.openSite\"),\n\t\t\t\taction: () => {\n\t\t\t\t\twindow.open(monitor.url, \"_blank\", \"noreferrer\");\n\t\t\t\t},\n\t\t\t\tcloseMenu: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 2,\n\t\t\t\tlabel: t(\"pages.common.monitors.actions.details\"),\n\t\t\t\taction: () => {\n\t\t\t\t\tnavigate(`${monitor.id}`);\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 3,\n\t\t\t\tlabel: t(\"pages.common.monitors.actions.incidents\"),\n\t\t\t\taction: () => {\n\t\t\t\t\tnavigate(`/incidents?monitorId=${monitor.id}`);\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 4,\n\t\t\t\tlabel: t(\"pages.common.monitors.actions.configure\"),\n\t\t\t\taction: () => {\n\t\t\t\t\tnavigate(`/pagespeed/configure/${monitor.id}`);\n\t\t\t\t},\n\t\t\t},\n\t\t\t// {\n\t\t\t//   id: 5,\n\t\t\t//   label: \"Clone\",\n\t\t\t//   action: () => {\n\n\t\t\t//   },\n\t\t\t// },\n\t\t\t{\n\t\t\t\tid: 6,\n\t\t\t\tlabel:\n\t\t\t\t\tmonitor.isActive === false\n\t\t\t\t\t\t? t(\"common.buttons.resume\")\n\t\t\t\t\t\t: t(\"common.buttons.pause\"),\n\t\t\t\taction: async () => {\n\t\t\t\t\tawait patch(`/monitors/${monitor.id}/active`);\n\t\t\t\t\trefetch();\n\t\t\t\t},\n\t\t\t\tcloseMenu: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 7,\n\t\t\t\tlabel: (\n\t\t\t\t\t<Typography color={theme.palette.error.main}>\n\t\t\t\t\t\t{t(\"common.buttons.delete\")}\n\t\t\t\t\t</Typography>\n\t\t\t\t),\n\t\t\t\taction: () => {\n\t\t\t\t\tsetSelectedMonitor(monitor);\n\t\t\t\t},\n\t\t\t\tcloseMenu: true,\n\t\t\t},\n\t\t];\n\t};\n\n\tconst getHeaders = () => {\n\t\tconst renderSortIcon = (isActive: boolean) => (\n\t\t\t<Box\n\t\t\t\twidth={16}\n\t\t\t\tdisplay=\"inline-flex\"\n\t\t\t\tjustifyContent=\"center\"\n\t\t\t>\n\t\t\t\t{isActive ? (\n\t\t\t\t\tsortOrder === \"asc\" ? (\n\t\t\t\t\t\t<ArrowUp size={16} />\n\t\t\t\t\t) : (\n\t\t\t\t\t\t<ArrowDown size={16} />\n\t\t\t\t\t)\n\t\t\t\t) : null}\n\t\t\t</Box>\n\t\t);\n\n\t\tconst headers: Header<Monitor>[] = [\n\t\t\t{\n\t\t\t\tid: \"name\",\n\t\t\t\tcontent: (\n\t\t\t\t\t<Stack\n\t\t\t\t\t\tgap={theme.spacing(4)}\n\t\t\t\t\t\tdirection={\"row\"}\n\t\t\t\t\t\talignItems={\"center\"}\n\t\t\t\t\t\tonClick={(e) => handleSort(e, \"name\")}\n\t\t\t\t\t\tsx={{ cursor: \"pointer\" }}\n\t\t\t\t\t>\n\t\t\t\t\t\t{t(\"common.table.headers.name\")}\n\t\t\t\t\t\t{renderSortIcon(sortField === \"name\")}\n\t\t\t\t\t</Stack>\n\t\t\t\t),\n\t\t\t\trender: (row) => {\n\t\t\t\t\treturn row.name;\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"status\",\n\t\t\t\tcontent: (\n\t\t\t\t\t<Stack\n\t\t\t\t\t\tgap={theme.spacing(4)}\n\t\t\t\t\t\tdirection={\"row\"}\n\t\t\t\t\t\tjustifyContent={\"center\"}\n\t\t\t\t\t\talignItems={\"center\"}\n\t\t\t\t\t\tonClick={(e) => handleSort(e, \"status\")}\n\t\t\t\t\t\tsx={{ cursor: \"pointer\" }}\n\t\t\t\t\t>\n\t\t\t\t\t\t{t(\"common.table.headers.status\")}\n\t\t\t\t\t\t{renderSortIcon(sortField === \"status\")}\n\t\t\t\t\t</Stack>\n\t\t\t\t),\n\t\t\t\trender: (row) => {\n\t\t\t\t\treturn <StatusLabel status={row.status} />;\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"histogram\",\n\t\t\t\tcontent: t(\"pages.pageSpeed.table.headers.pageSpeedScore\"),\n\t\t\t\trender: (row) => {\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<Stack alignItems={\"center\"}>\n\t\t\t\t\t\t\t<HistogramPageSpeed\n\t\t\t\t\t\t\t\tchecks={row.recentChecks}\n\t\t\t\t\t\t\t\tstatus={row.status}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</Stack>\n\t\t\t\t\t);\n\t\t\t\t},\n\t\t\t},\n\n\t\t\t{\n\t\t\t\tid: \"actions\",\n\t\t\t\tcontent: t(\"common.table.headers.actions\"),\n\t\t\t\trender: (row) => {\n\t\t\t\t\treturn <ActionsMenu items={getActions(row)} />;\n\t\t\t\t},\n\t\t\t},\n\t\t];\n\t\treturn headers;\n\t};\n\n\tlet headers = getHeaders();\n\n\tif (isSmall) {\n\t\theaders = headers.filter((h) => h.id !== \"histogram\");\n\t}\n\treturn (\n\t\t<Box>\n\t\t\t<Table\n\t\t\t\theaders={headers}\n\t\t\t\tdata={monitors}\n\t\t\t\tonRowClick={(row) => {\n\t\t\t\t\tnavigate(`/pagespeed/${row.id}`);\n\t\t\t\t}}\n\t\t\t/>\n\t\t\t<Pagination\n\t\t\t\tcomponent=\"div\"\n\t\t\t\tcount={count}\n\t\t\t\tpage={page}\n\t\t\t\trowsPerPage={rowsPerPage}\n\t\t\t\tonPageChange={handlePageChange}\n\t\t\t\tonRowsPerPageChange={handleRowsPerPageChange}\n\t\t\t\titemsOnPage={monitors.length}\n\t\t\t/>\n\t\t</Box>\n\t);\n};\n"
  },
  {
    "path": "client/src/Pages/PageSpeed/Monitors/index.tsx",
    "content": "import {\n\tMonitorBasePageWithStates,\n\tPageSpeedKeyPriorityFallback,\n} from \"@/Components/design-elements\";\nimport { Dialog } from \"@/Components/inputs\";\nimport { HeaderCreate } from \"@/Components/common\";\nimport { PageSpeedMonitorsTable } from \"@/Pages/PageSpeed/Monitors/Components/PageSpeedMonitorsTable\";\nimport type { Monitor } from \"@/Types/Monitor\";\n\nimport { useTranslation } from \"react-i18next\";\nimport { useMemo, useState } from \"react\";\nimport { useIsAdmin } from \"@/Hooks/useIsAdmin\";\nimport { useGet, useDelete } from \"@/Hooks/UseApi\";\nimport type { MonitorsWithChecksResponse } from \"@/Types/Monitor\";\nimport type { AppSettingsResponse } from \"@/Types/Settings\";\nimport { HeaderMonitorsSummary } from \"@/Components/monitors\";\n\nconst PageSpeedMonitorsPage = () => {\n\tconst { t } = useTranslation();\n\tconst isAdmin = useIsAdmin();\n\tconst { deleteFn, loading: isDeleting } = useDelete();\n\n\tconst settingsUrl = \"/settings\";\n\tconst {\n\t\tdata: settingsData,\n\t\tisLoading: settingsIsLoading,\n\t\terror: settingsError,\n\t} = useGet<AppSettingsResponse>(settingsUrl);\n\n\tconst [selectedMonitor, setSelectedMonitor] = useState<Monitor | null>(null);\n\tconst isDialogOpen = Boolean(selectedMonitor);\n\tconst [sortField, setSortField] = useState<string>(\"name\");\n\tconst [sortOrder, setSortOrder] = useState<\"asc\" | \"desc\">(\"asc\");\n\tconst [page, setPage] = useState(0);\n\tconst [rowsPerPage, setRowsPerPage] = useState(10);\n\n\tconst monitorsWithChecksUrl = useMemo(() => {\n\t\tconst params = new URLSearchParams();\n\t\tparams.append(\"type\", \"pagespeed\");\n\t\tparams.append(\"limit\", \"25\");\n\t\tif (page !== undefined) params.append(\"page\", String(page));\n\t\tif (rowsPerPage) params.append(\"rowsPerPage\", String(rowsPerPage));\n\t\tif (sortField) params.append(\"field\", sortField);\n\t\tif (sortOrder) params.append(\"order\", sortOrder);\n\t\treturn `/monitors/team/with-checks?${params.toString()}`;\n\t}, [page, rowsPerPage, sortField, sortOrder]);\n\n\tconst {\n\t\tdata: monitorsData,\n\t\tisLoading: monitorsIsLoading,\n\t\terror: monitorsError,\n\t\trefetch,\n\t} = useGet<MonitorsWithChecksResponse>(\n\t\tmonitorsWithChecksUrl,\n\t\t{},\n\t\t{ refreshInterval: 30000 }\n\t);\n\n\tconst monitors = monitorsData?.monitors;\n\tconst monitorsCount = monitorsData?.count ?? 0;\n\tconst summary = monitorsData?.summary ?? null;\n\n\tconst isLoading = monitorsIsLoading || settingsIsLoading;\n\n\tconst showApiKeyWarning = isAdmin && settingsData && !settingsData.pagespeedKeySet;\n\n\tconst handleConfirm = async () => {\n\t\tif (!selectedMonitor) return;\n\t\tawait deleteFn(`/monitors/${selectedMonitor.id}`);\n\t\tsetSelectedMonitor(null);\n\t\trefetch();\n\t};\n\n\tconst handleCancel = () => {\n\t\tsetSelectedMonitor(null);\n\t};\n\n\treturn (\n\t\t<MonitorBasePageWithStates\n\t\t\tloading={isLoading}\n\t\t\terror={monitorsError || settingsError}\n\t\t\ttotalCount={summary?.totalMonitors ?? 0}\n\t\t\tpage=\"pageSpeed\"\n\t\t\tactionLink=\"/pagespeed/create\"\n\t\t\tpriorityFallback={showApiKeyWarning ? <PageSpeedKeyPriorityFallback /> : undefined}\n\t\t>\n\t\t\t<HeaderCreate\n\t\t\t\tpath=\"/pagespeed/create\"\n\t\t\t\tisLoading={isLoading}\n\t\t\t\tisAdmin={isAdmin}\n\t\t\t/>\n\t\t\t<HeaderMonitorsSummary summary={summary} />\n\t\t\t<PageSpeedMonitorsTable\n\t\t\t\tmonitors={monitors || []}\n\t\t\t\trefetch={refetch}\n\t\t\t\tsetSelectedMonitor={setSelectedMonitor}\n\t\t\t\tsortField={sortField}\n\t\t\t\tsetSortField={setSortField}\n\t\t\t\tsortOrder={sortOrder}\n\t\t\t\tsetSortOrder={setSortOrder}\n\t\t\t\tcount={monitorsCount || 0}\n\t\t\t\tpage={page}\n\t\t\t\tsetPage={setPage}\n\t\t\t\trowsPerPage={rowsPerPage}\n\t\t\t\tsetRowsPerPage={setRowsPerPage}\n\t\t\t/>\n\t\t\t<Dialog\n\t\t\t\topen={isDialogOpen}\n\t\t\t\ttitle={t(\"common.dialogs.delete.title\")}\n\t\t\t\tcontent={t(\"common.dialogs.delete.description\")}\n\t\t\t\tonConfirm={handleConfirm}\n\t\t\t\tonCancel={handleCancel}\n\t\t\t\tloading={isDeleting}\n\t\t\t/>\n\t\t</MonitorBasePageWithStates>\n\t);\n};\n\nexport default PageSpeedMonitorsPage;\n"
  },
  {
    "path": "client/src/Pages/Settings/DummyChart.tsx",
    "content": "import Box from \"@mui/material/Box\";\nimport Typography from \"@mui/material/Typography\";\nimport { useTheme } from \"@mui/material/styles\";\nimport { HeatmapResponseTime, HistogramResponseTime } from \"@/Components/common\";\nimport type { CheckSnapshot } from \"@/Types/Check\";\n\ninterface DummyChartProps {\n\tchartType: string;\n}\n\nconst generateDummyChecks = (): CheckSnapshot[] => {\n\tconst checks: CheckSnapshot[] = [];\n\tfor (let i = 0; i < 25; i++) {\n\t\tconst isUp = Math.random() > 0.1;\n\t\tconst responseTime = Math.floor(Math.random() * 80) + 20;\n\t\tchecks.push({\n\t\t\tid: `dummy-${i}`,\n\t\t\tstatus: isUp,\n\t\t\tstatusCode: isUp ? 200 : 500,\n\t\t\tresponseTime: responseTime,\n\t\t\toriginalResponseTime: responseTime,\n\t\t\tmessage: \"\",\n\t\t\tcreatedAt: new Date(Date.now() - i * 60000).toISOString(),\n\t\t});\n\t}\n\treturn checks;\n};\n\nconst dummyChecks = generateDummyChecks();\n\nconst DummyChart = ({ chartType }: DummyChartProps) => {\n\tconst theme = useTheme();\n\n\treturn (\n\t\t<Box\n\t\t\tsx={{\n\t\t\t\tmt: theme.spacing(4),\n\t\t\t\tp: theme.spacing(4),\n\t\t\t\tborder: 1,\n\t\t\t\tborderColor: theme.palette.divider,\n\t\t\t\tborderRadius: theme.shape.borderRadius,\n\t\t\t\tbackgroundColor: theme.palette.background.paper,\n\t\t\t}}\n\t\t>\n\t\t\t<Typography\n\t\t\t\tvariant=\"body2\"\n\t\t\t\tcolor=\"text.secondary\"\n\t\t\t\tsx={{ mb: theme.spacing(2) }}\n\t\t\t>\n\t\t\t\tPreview\n\t\t\t</Typography>\n\t\t\t{chartType === \"histogram\" ? (\n\t\t\t\t<HistogramResponseTime checks={dummyChecks} />\n\t\t\t) : (\n\t\t\t\t<HeatmapResponseTime checks={dummyChecks} />\n\t\t\t)}\n\t\t</Box>\n\t);\n};\n\nexport default DummyChart;\n"
  },
  {
    "path": "client/src/Pages/Settings/index.tsx",
    "content": "import { BasePage, ConfigBox, TextLink } from \"@/Components/design-elements\";\nimport { Autocomplete, Select, Dialog, SwitchComponent } from \"@/Components/inputs\";\nimport { logger } from \"@/Utils/logger\";\nimport { LAYOUT } from \"@/Utils/Theme/constants\";\nimport {\n\tStack,\n\tuseTheme,\n\tMenuItem,\n\tLink,\n\tAlert,\n\ttype SelectChangeEvent,\n} from \"@mui/material\";\nimport { useEffect } from \"react\";\nimport { useForm } from \"react-hook-form\";\nimport { zodResolver } from \"@hookform/resolvers/zod\";\nimport { useTranslation } from \"react-i18next\";\nimport { useSelector, useDispatch } from \"react-redux\";\nimport DummyChart from \"@/Pages/Settings/DummyChart\";\nimport { useGet, usePatch, usePost, useLazyGet } from \"@/Hooks/UseApi\";\nimport { useToast } from \"@/Hooks/UseToast\";\nimport { useSettingsForm } from \"@/Hooks/useSettingsForm\";\nimport { useIsAdmin } from \"@/Hooks/useIsAdmin.js\";\nimport type { SettingsFormData, SettingsFormInput } from \"@/Validation/settings\";\nimport { useState } from \"react\";\nimport { Controller } from \"react-hook-form\";\nimport { TextField, Button, FieldLabel, SliderWithLabel } from \"@/Components/inputs\";\nimport { Box, Typography } from \"@mui/material\";\nimport { useDelete } from \"@/Hooks/UseApi\";\n\nimport {\n\tsetTimezone,\n\tsetMode,\n\tsetLanguage,\n\tsetChartType,\n\ttype ThemeMode,\n\ttype ChartType,\n} from \"@/Features/UI/uiSlice.js\";\nimport timezones from \"@/Utils/timezones.json\";\nimport type { RootState } from \"@/Types/state\";\nimport { CHECK_TTL_SENTINEL } from \"@/Types/Check\";\n\ninterface Timezone {\n\tid: string;\n\tname: string;\n}\n\ninterface SettingsResponse {\n\tsettings: any;\n\tpagespeedKeySet: boolean;\n\temailPasswordSet: boolean;\n}\n\nexport const SettingsPage = () => {\n\tconst theme = useTheme();\n\tconst { t, i18n } = useTranslation();\n\tconst dispatch = useDispatch();\n\tconst isAdmin = useIsAdmin();\n\tconst { toastError } = useToast();\n\t// Local state for demo monitors dialog\n\tconst [isDemoMonitorsDialogOpen, setIsDemoMonitorsDialogOpen] = useState(false);\n\tconst { post: postDemoMonitors, loading: isPostingDemoMonitors } = usePost();\n\tconst { deleteFn: deleteAllMonitors, loading: isDeletingAllMonitors } = useDelete();\n\t// Import monitors functionality\n\tconst { post: importMonitors, loading: isImportingMonitors } = usePost();\n\n\t// Fetch settings data from API\n\tconst { data: fetchedSettings } = useGet<SettingsResponse>(\"/settings\");\n\t// Form submission\n\tconst { patch, loading: isSaving } = usePatch<SettingsFormData, SettingsResponse>();\n\n\t// Local state for API key reset\n\tconst [isApiKeySet, setIsApiKeySet] = useState(\n\t\tfetchedSettings?.pagespeedKeySet ?? false\n\t);\n\tconst [apiKeyHasBeenReset, setApiKeyHasBeenReset] = useState(false);\n\t// Local state for email password reset\n\tconst [isEmailPasswordSet, setIsEmailPasswordSet] = useState(\n\t\tfetchedSettings?.emailPasswordSet ?? false\n\t);\n\tconst [emailPasswordHasBeenReset, setEmailPasswordHasBeenReset] = useState(false);\n\t// Test email functionality\n\tconst { post: sendTestEmail, loading: isSendingTestEmail } = usePost();\n\t// Local state for clear stats dialog\n\tconst [isStatsDialogOpen, setIsStatsDialogOpen] = useState(false);\n\tconst { deleteFn: deleteStats, loading: isDeletingStats } = useDelete();\n\t// Export monitors functionality\n\tconst { get: fetchMonitorsJson } = useLazyGet();\n\n\t// Initialize form with schema and defaults\n\tconst { schema, defaults } = useSettingsForm({ data: fetchedSettings?.settings });\n\n\tconst form = useForm<SettingsFormInput, unknown, SettingsFormData>({\n\t\tresolver: zodResolver(schema),\n\t\tdefaultValues: defaults,\n\t\tmode: \"onChange\",\n\t});\n\n\t// Reset form when defaults change\n\tuseEffect(() => {\n\t\tform.reset(defaults);\n\t}, [defaults, form]);\n\n\t// Update isApiKeySet when fetchedSettings changes\n\tuseEffect(() => {\n\t\tif (fetchedSettings) {\n\t\t\tsetIsApiKeySet(fetchedSettings.pagespeedKeySet);\n\t\t\tsetIsEmailPasswordSet(fetchedSettings.emailPasswordSet);\n\t\t}\n\t}, [fetchedSettings]);\n\n\tconst {\n\t\ttimezone: selectedTimezoneId,\n\t\tmode,\n\t\tlanguage = \"en\",\n\t\tchartType = \"histogram\",\n\t} = useSelector((state: RootState) => state.ui);\n\n\tconst user = useSelector((state: RootState) => state.auth.user);\n\n\t// Convert timezones to match AutoComplete format (id instead of _id)\n\tconst timezoneOptions: Timezone[] = timezones.map((tz) => ({\n\t\tid: tz._id,\n\t\tname: tz.name,\n\t}));\n\n\tconst selectedTimezone =\n\t\ttimezoneOptions.find((tz) => tz.id === selectedTimezoneId) ?? null;\n\n\tconst handleTimezoneChange = (newValue: Timezone | null) => {\n\t\tconst newId = newValue?.id ?? \"\";\n\t\tdispatch(setTimezone({ timezone: newId }));\n\t};\n\n\tconst handleModeChange = (e: SelectChangeEvent<ThemeMode>) => {\n\t\tdispatch(setMode(e.target.value));\n\t};\n\n\tconst handleLanguageChange = (e: SelectChangeEvent<string>) => {\n\t\tdispatch(setLanguage(e.target.value));\n\t};\n\n\tconst handleChartTypeChange = (e: SelectChangeEvent<ChartType>) => {\n\t\tdispatch(setChartType(e.target.value));\n\t};\n\n\tconst handleResetApiKey = () => {\n\t\tform.setValue(\"pagespeedApiKey\", \"\");\n\t\tsetApiKeyHasBeenReset(true);\n\t};\n\n\tconst handleResetEmailPassword = () => {\n\t\tform.setValue(\"systemEmailPassword\", \"\");\n\t\tsetEmailPasswordHasBeenReset(true);\n\t};\n\n\tconst handleSendTestEmail = async () => {\n\t\tconst formValues = form.getValues();\n\t\tif (!user) {\n\t\t\talert(\"User not authenticated\");\n\t\t\treturn;\n\t\t}\n\t\tif (\n\t\t\t!formValues.systemEmailHost ||\n\t\t\t!formValues.systemEmailPort ||\n\t\t\t!formValues.systemEmailAddress ||\n\t\t\t!formValues.systemEmailPassword\n\t\t) {\n\t\t\talert(\"Please fill in all required email fields before testing.\");\n\t\t\treturn;\n\t\t}\n\n\t\tawait sendTestEmail(\"/settings/test-email\", {\n\t\t\tto: user.email,\n\t\t\tsystemEmailHost: formValues.systemEmailHost,\n\t\t\tsystemEmailPort: formValues.systemEmailPort,\n\t\t\tsystemEmailAddress: formValues.systemEmailAddress,\n\t\t\tsystemEmailPassword: formValues.systemEmailPassword,\n\t\t\tsystemEmailSecure: formValues.systemEmailSecure,\n\t\t\tsystemEmailPool: formValues.systemEmailPool,\n\t\t\tsystemEmailIgnoreTLS: formValues.systemEmailIgnoreTLS,\n\t\t\tsystemEmailRequireTLS: formValues.systemEmailRequireTLS,\n\t\t\tsystemEmailRejectUnauthorized: formValues.systemEmailRejectUnauthorized,\n\t\t\t...(formValues.systemEmailUser && { systemEmailUser: formValues.systemEmailUser }),\n\t\t\t...(formValues.systemEmailTLSServername && {\n\t\t\t\tsystemEmailTLSServername: formValues.systemEmailTLSServername,\n\t\t\t}),\n\t\t\t...(formValues.systemEmailConnectionHost && {\n\t\t\t\tsystemEmailConnectionHost: formValues.systemEmailConnectionHost,\n\t\t\t}),\n\t\t});\n\t};\n\n\tconst handleClearStats = async () => {\n\t\tawait deleteStats(\"/checks/team\");\n\t\tsetIsStatsDialogOpen(false);\n\t};\n\n\tconst handleExportMonitors = async () => {\n\t\tconst res = await fetchMonitorsJson(\"/monitors/export/json\");\n\t\tconst json = res?.data ?? [];\n\t\tif (!json || json.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst blob = new Blob([JSON.stringify(json, null, 2)], {\n\t\t\ttype: \"application/json\",\n\t\t});\n\t\tconst url = URL.createObjectURL(blob);\n\n\t\tconst link = document.createElement(\"a\");\n\t\tlink.href = url;\n\t\tlink.download = \"monitors.json\";\n\t\tdocument.body.appendChild(link);\n\t\tlink.click();\n\t\tdocument.body.removeChild(link);\n\t\tURL.revokeObjectURL(url);\n\t};\n\n\tconst handleFileSelect = async (event: React.ChangeEvent<HTMLInputElement>) => {\n\t\tconst file = event.target.files?.[0];\n\t\tif (!file) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (file.type !== \"application/json\") {\n\t\t\ttoastError(\"Please select a valid JSON file\");\n\t\t\tevent.target.value = \"\";\n\t\t}\n\n\t\ttry {\n\t\t\tconst text = await file.text();\n\t\t\tconst monitors = JSON.parse(text);\n\n\t\t\tif (!Array.isArray(monitors)) {\n\t\t\t\ttoastError(\"Invalid file format: expected an array of monitors\");\n\t\t\t\tevent.target.value = \"\";\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tawait importMonitors(\"/monitors/import/json\", { monitors });\n\n\t\t\tevent.target.value = \"\";\n\t\t} catch (error) {\n\t\t\ttoastError(\"Error parsing JSON file. Please check the file format.\");\n\t\t\tevent.target.value = \"\";\n\t\t}\n\t};\n\n\tconst onSubmit = async (data: SettingsFormData) => {\n\t\t// Don't send pagespeedApiKey if it's already set and user hasn't clicked reset\n\t\tconst dataToSend = { ...data };\n\t\tif (isApiKeySet && !apiKeyHasBeenReset) {\n\t\t\tdelete (dataToSend as any).pagespeedApiKey;\n\t\t}\n\t\tif (isEmailPasswordSet && !emailPasswordHasBeenReset) {\n\t\t\tdelete (dataToSend as any).systemEmailPassword;\n\t\t}\n\n\t\tconst result = await patch(\"/settings\", dataToSend as SettingsFormData);\n\n\t\tif (result?.success) {\n\t\t\t// Update API key state from response\n\t\t\tif (result.data) {\n\t\t\t\tsetIsApiKeySet(result.data.pagespeedKeySet);\n\t\t\t\tsetApiKeyHasBeenReset(false);\n\t\t\t\tsetIsEmailPasswordSet(result.data.emailPasswordSet);\n\t\t\t\tsetEmailPasswordHasBeenReset(false);\n\t\t\t}\n\t\t}\n\t};\n\n\tconst onError = (errors: unknown) => {\n\t\tlogger.debug(\"Form validation errors\", errors);\n\t};\n\n\tconst languages = Object.keys(i18n.options.resources || {});\n\n\treturn (\n\t\t<BasePage\n\t\t\tcomponent=\"form\"\n\t\t\tonSubmit={form.handleSubmit(onSubmit, onError)}\n\t\t>\n\t\t\t<Stack gap={theme.spacing(LAYOUT.MD)}>\n\t\t\t\t<ConfigBox\n\t\t\t\t\ttitle={t(\"pages.settings.form.timezone.title\")}\n\t\t\t\t\tsubtitle={t(\"pages.settings.form.timezone.description\")}\n\t\t\t\t\trightContent={\n\t\t\t\t\t\t<Autocomplete\n\t\t\t\t\t\t\tvalue={selectedTimezone}\n\t\t\t\t\t\t\toptions={timezoneOptions}\n\t\t\t\t\t\t\tgetOptionLabel={(option: Timezone) => option.name}\n\t\t\t\t\t\t\tisOptionEqualToValue={(option: Timezone, value: Timezone) =>\n\t\t\t\t\t\t\t\toption.id === value.id\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tonChange={(_, newValue) => {\n\t\t\t\t\t\t\t\thandleTimezoneChange(newValue as Timezone | null);\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\tfieldLabel={t(\"pages.settings.form.timezone.option.timezone.label\")}\n\t\t\t\t\t\t/>\n\t\t\t\t\t}\n\t\t\t\t/>\n\t\t\t\t<ConfigBox\n\t\t\t\t\ttitle={t(\"pages.settings.form.ui.title\")}\n\t\t\t\t\tsubtitle={t(\"pages.settings.form.ui.description\")}\n\t\t\t\t\trightContent={\n\t\t\t\t\t\t<Stack gap={theme.spacing(LAYOUT.MD)}>\n\t\t\t\t\t\t\t<Select\n\t\t\t\t\t\t\t\tvalue={mode}\n\t\t\t\t\t\t\t\tonChange={handleModeChange}\n\t\t\t\t\t\t\t\tfieldLabel={t(\"pages.settings.form.ui.option.theme.label\")}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<MenuItem value=\"light\">\n\t\t\t\t\t\t\t\t\t{t(\"pages.settings.form.ui.option.theme.light\")}\n\t\t\t\t\t\t\t\t</MenuItem>\n\t\t\t\t\t\t\t\t<MenuItem value=\"dark\">\n\t\t\t\t\t\t\t\t\t{t(\"pages.settings.form.ui.option.theme.dark\")}\n\t\t\t\t\t\t\t\t</MenuItem>\n\t\t\t\t\t\t\t</Select>\n\t\t\t\t\t\t\t<Select\n\t\t\t\t\t\t\t\tvalue={language}\n\t\t\t\t\t\t\t\tonChange={handleLanguageChange}\n\t\t\t\t\t\t\t\tfieldLabel={t(\"pages.settings.form.ui.option.language.label\")}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{languages.map((lang) => (\n\t\t\t\t\t\t\t\t\t<MenuItem\n\t\t\t\t\t\t\t\t\t\tkey={lang}\n\t\t\t\t\t\t\t\t\t\tvalue={lang}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t{lang.toUpperCase()}\n\t\t\t\t\t\t\t\t\t</MenuItem>\n\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t</Select>\n\t\t\t\t\t\t\t<Select\n\t\t\t\t\t\t\t\tvalue={chartType}\n\t\t\t\t\t\t\t\tonChange={handleChartTypeChange}\n\t\t\t\t\t\t\t\tfieldLabel={t(\"pages.settings.form.ui.option.chartType.label\")}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<MenuItem value=\"histogram\">\n\t\t\t\t\t\t\t\t\t{t(\"pages.settings.form.ui.option.chartType.histogram\")}\n\t\t\t\t\t\t\t\t</MenuItem>\n\t\t\t\t\t\t\t\t<MenuItem value=\"heatmap\">\n\t\t\t\t\t\t\t\t\t{t(\"pages.settings.form.ui.option.chartType.heatmap\")}\n\t\t\t\t\t\t\t\t</MenuItem>\n\t\t\t\t\t\t\t</Select>\n\t\t\t\t\t\t\t<DummyChart chartType={chartType} />\n\t\t\t\t\t\t</Stack>\n\t\t\t\t\t}\n\t\t\t\t/>\n\t\t\t\t{isAdmin && (\n\t\t\t\t\t<ConfigBox\n\t\t\t\t\t\ttitle={t(\"pages.settings.form.pagespeed.title\")}\n\t\t\t\t\t\tsubtitle={t(\"pages.settings.form.pagespeed.description\")}\n\t\t\t\t\t\trightContent={\n\t\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t\t{(isApiKeySet === false || apiKeyHasBeenReset === true) && (\n\t\t\t\t\t\t\t\t\t<Controller\n\t\t\t\t\t\t\t\t\t\tname=\"pagespeedApiKey\"\n\t\t\t\t\t\t\t\t\t\tcontrol={form.control}\n\t\t\t\t\t\t\t\t\t\tdefaultValue={defaults.pagespeedApiKey}\n\t\t\t\t\t\t\t\t\t\trender={({ field, fieldState }) => (\n\t\t\t\t\t\t\t\t\t\t\t<TextField\n\t\t\t\t\t\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\t\t\t\t\t\tfieldLabel={t(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"pages.settings.form.pagespeed.option.apiKey.label\"\n\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\ttype=\"password\"\n\t\t\t\t\t\t\t\t\t\t\t\tplaceholder={t(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"pages.settings.form.pagespeed.option.apiKey.placeholder\"\n\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\terror={!!fieldState.error}\n\t\t\t\t\t\t\t\t\t\t\t\thelperText={fieldState.error?.message}\n\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t)}\n\n\t\t\t\t\t\t\t\t{isApiKeySet === true && apiKeyHasBeenReset === false && (\n\t\t\t\t\t\t\t\t\t<Box>\n\t\t\t\t\t\t\t\t\t\t<FieldLabel>\n\t\t\t\t\t\t\t\t\t\t\t{t(\"pages.settings.form.pagespeed.option.apiKey.labelSet\")}\n\t\t\t\t\t\t\t\t\t\t</FieldLabel>\n\t\t\t\t\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\t\t\t\t\tonClick={handleResetApiKey}\n\t\t\t\t\t\t\t\t\t\t\tvariant=\"contained\"\n\t\t\t\t\t\t\t\t\t\t\tcolor=\"error\"\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t{t(\"common.buttons.reset\")}\n\t\t\t\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t\t\t\t</Box>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t</>\n\t\t\t\t\t\t}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\n\t\t\t\t{/* URL Settings */}\n\t\t\t\t<ConfigBox\n\t\t\t\t\ttitle={t(\"pages.settings.form.url.title\")}\n\t\t\t\t\tsubtitle={t(\"pages.settings.form.url.description\")}\n\t\t\t\t\trightContent={\n\t\t\t\t\t\t<Controller\n\t\t\t\t\t\t\tname=\"showURL\"\n\t\t\t\t\t\t\tcontrol={form.control}\n\t\t\t\t\t\t\tdefaultValue={defaults.showURL}\n\t\t\t\t\t\t\trender={({ field, fieldState }) => (\n\t\t\t\t\t\t\t\t<Select\n\t\t\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\t\t\tvalue={field.value === undefined ? \"false\" : field.value.toString()}\n\t\t\t\t\t\t\t\t\tonChange={(e) => {\n\t\t\t\t\t\t\t\t\t\tconst value = e.target.value === \"true\";\n\t\t\t\t\t\t\t\t\t\tfield.onChange(value);\n\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\tfieldLabel={t(\"pages.settings.form.url.option.showURL.label\")}\n\t\t\t\t\t\t\t\t\terror={!!fieldState.error}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<MenuItem value=\"true\">\n\t\t\t\t\t\t\t\t\t\t{t(\"pages.settings.form.url.option.showURL.enabled\")}\n\t\t\t\t\t\t\t\t\t</MenuItem>\n\t\t\t\t\t\t\t\t\t<MenuItem value=\"false\">\n\t\t\t\t\t\t\t\t\t\t{t(\"pages.settings.form.url.option.showURL.disabled\")}\n\t\t\t\t\t\t\t\t\t</MenuItem>\n\t\t\t\t\t\t\t\t</Select>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t/>\n\t\t\t\t\t}\n\t\t\t\t/>\n\n\t\t\t\t{/* Clear All Stats */}\n\t\t\t\t{isAdmin && (\n\t\t\t\t\t<ConfigBox\n\t\t\t\t\t\ttitle={t(\"pages.settings.form.stats.title\")}\n\t\t\t\t\t\tsubtitle={t(\"pages.settings.form.stats.description\")}\n\t\t\t\t\t\trightContent={\n\t\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\t\tvariant=\"contained\"\n\t\t\t\t\t\t\t\tcolor=\"error\"\n\t\t\t\t\t\t\t\tonClick={() => setIsStatsDialogOpen(true)}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{t(\"common.buttons.clear\")}\n\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\n\t\t\t\t{/* Check Retention */}\n\t\t\t\t{isAdmin && (\n\t\t\t\t\t<ConfigBox\n\t\t\t\t\t\ttitle={t(\"pages.settings.form.retention.title\")}\n\t\t\t\t\t\tsubtitle={t(\"pages.settings.form.retention.description\")}\n\t\t\t\t\t\trightContent={\n\t\t\t\t\t\t\t<Controller\n\t\t\t\t\t\t\t\tname=\"checkTTL\"\n\t\t\t\t\t\t\t\tcontrol={form.control}\n\t\t\t\t\t\t\t\tdefaultValue={defaults.checkTTL}\n\t\t\t\t\t\t\t\trender={({ field }) => (\n\t\t\t\t\t\t\t\t\t<SliderWithLabel\n\t\t\t\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\t\t\t\tfieldLabel={t(\"pages.settings.form.retention.option.days.label\")}\n\t\t\t\t\t\t\t\t\t\tmin={1}\n\t\t\t\t\t\t\t\t\t\tmax={CHECK_TTL_SENTINEL}\n\t\t\t\t\t\t\t\t\t\tsliderMaxWidth={{ xs: \"100%\", md: \"50%\" }}\n\t\t\t\t\t\t\t\t\t\tvalue={field.value || 30}\n\t\t\t\t\t\t\t\t\t\tonChange={(_, value) => field.onChange(value)}\n\t\t\t\t\t\t\t\t\t\tvalueLabelDisplay=\"auto\"\n\t\t\t\t\t\t\t\t\t\tvalueLabelFormat={(value: number) =>\n\t\t\t\t\t\t\t\t\t\t\tvalue >= CHECK_TTL_SENTINEL\n\t\t\t\t\t\t\t\t\t\t\t\t? t(\"pages.settings.form.retention.option.days.unlimited\")\n\t\t\t\t\t\t\t\t\t\t\t\t: `${value}`\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\tformatDisplayValue={(value: number) =>\n\t\t\t\t\t\t\t\t\t\t\tvalue >= CHECK_TTL_SENTINEL\n\t\t\t\t\t\t\t\t\t\t\t\t? t(\"pages.settings.form.retention.option.days.unlimited\")\n\t\t\t\t\t\t\t\t\t\t\t\t: `${value}`\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\n\t\t\t\t{/* Global Thresholds */}\n\t\t\t\t{isAdmin && (\n\t\t\t\t\t<ConfigBox\n\t\t\t\t\t\ttitle={t(\"pages.settings.form.thresholds.title\")}\n\t\t\t\t\t\tsubtitle={t(\"pages.settings.form.thresholds.description\")}\n\t\t\t\t\t\trightContent={\n\t\t\t\t\t\t\t<Stack spacing={2}>\n\t\t\t\t\t\t\t\t<Controller\n\t\t\t\t\t\t\t\t\tname=\"globalThresholds.cpu\"\n\t\t\t\t\t\t\t\t\tcontrol={form.control}\n\t\t\t\t\t\t\t\t\tdefaultValue={defaults.globalThresholds?.cpu}\n\t\t\t\t\t\t\t\t\trender={({ field }) => (\n\t\t\t\t\t\t\t\t\t\t<SliderWithLabel\n\t\t\t\t\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\t\t\t\t\tfieldLabel={t(\"pages.settings.form.thresholds.option.cpu.label\")}\n\t\t\t\t\t\t\t\t\t\t\tmin={1}\n\t\t\t\t\t\t\t\t\t\t\tmax={100}\n\t\t\t\t\t\t\t\t\t\t\tsliderMaxWidth={{ xs: \"100%\", md: \"50%\" }}\n\t\t\t\t\t\t\t\t\t\t\tvalue={field.value || 1}\n\t\t\t\t\t\t\t\t\t\t\tonChange={(_, value) => field.onChange(value)}\n\t\t\t\t\t\t\t\t\t\t\tvalueLabelDisplay=\"auto\"\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t<Controller\n\t\t\t\t\t\t\t\t\tname=\"globalThresholds.memory\"\n\t\t\t\t\t\t\t\t\tcontrol={form.control}\n\t\t\t\t\t\t\t\t\tdefaultValue={defaults.globalThresholds?.memory}\n\t\t\t\t\t\t\t\t\trender={({ field }) => (\n\t\t\t\t\t\t\t\t\t\t<SliderWithLabel\n\t\t\t\t\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\t\t\t\t\tfieldLabel={t(\"pages.settings.form.thresholds.option.memory.label\")}\n\t\t\t\t\t\t\t\t\t\t\tmin={1}\n\t\t\t\t\t\t\t\t\t\t\tmax={100}\n\t\t\t\t\t\t\t\t\t\t\tsliderMaxWidth={{ xs: \"100%\", md: \"50%\" }}\n\t\t\t\t\t\t\t\t\t\t\tvalue={field.value || 1}\n\t\t\t\t\t\t\t\t\t\t\tonChange={(_, value) => field.onChange(value)}\n\t\t\t\t\t\t\t\t\t\t\tvalueLabelDisplay=\"auto\"\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t<Controller\n\t\t\t\t\t\t\t\t\tname=\"globalThresholds.disk\"\n\t\t\t\t\t\t\t\t\tcontrol={form.control}\n\t\t\t\t\t\t\t\t\tdefaultValue={defaults.globalThresholds?.disk}\n\t\t\t\t\t\t\t\t\trender={({ field }) => (\n\t\t\t\t\t\t\t\t\t\t<SliderWithLabel\n\t\t\t\t\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\t\t\t\t\tfieldLabel={t(\"pages.settings.form.thresholds.option.disk.label\")}\n\t\t\t\t\t\t\t\t\t\t\tmin={1}\n\t\t\t\t\t\t\t\t\t\t\tmax={100}\n\t\t\t\t\t\t\t\t\t\t\tsliderMaxWidth={{ xs: \"100%\", md: \"50%\" }}\n\t\t\t\t\t\t\t\t\t\t\tvalue={field.value || 1}\n\t\t\t\t\t\t\t\t\t\t\tonChange={(_, value) => field.onChange(value)}\n\t\t\t\t\t\t\t\t\t\t\tvalueLabelDisplay=\"auto\"\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t<Controller\n\t\t\t\t\t\t\t\t\tname=\"globalThresholds.temperature\"\n\t\t\t\t\t\t\t\t\tcontrol={form.control}\n\t\t\t\t\t\t\t\t\tdefaultValue={defaults.globalThresholds?.temperature}\n\t\t\t\t\t\t\t\t\trender={({ field }) => (\n\t\t\t\t\t\t\t\t\t\t<SliderWithLabel\n\t\t\t\t\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\t\t\t\t\tfieldLabel={t(\n\t\t\t\t\t\t\t\t\t\t\t\t\"pages.settings.form.thresholds.option.temperature.label\"\n\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\tmin={1}\n\t\t\t\t\t\t\t\t\t\t\tmax={150}\n\t\t\t\t\t\t\t\t\t\t\tsliderMaxWidth={{ xs: \"100%\", md: \"50%\" }}\n\t\t\t\t\t\t\t\t\t\t\tvalue={field.value || 1}\n\t\t\t\t\t\t\t\t\t\t\tonChange={(_, value) => field.onChange(value)}\n\t\t\t\t\t\t\t\t\t\t\tvalueLabelDisplay=\"auto\"\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t</Stack>\n\t\t\t\t\t\t}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\t\t\t</Stack>\n\n\t\t\t{/* Email Settings - Admin Only */}\n\t\t\t{isAdmin && (\n\t\t\t\t<ConfigBox\n\t\t\t\t\ttitle={t(\"pages.settings.form.email.title\")}\n\t\t\t\t\tsubtitle={t(\"pages.settings.form.email.description\")}\n\t\t\t\t\tleftContent={\n\t\t\t\t\t\t<Stack gap={theme.spacing(LAYOUT.MD)}>\n\t\t\t\t\t\t\t<TextLink\n\t\t\t\t\t\t\t\ttext={t(\"pages.settings.form.email.descriptionTransport\")}\n\t\t\t\t\t\t\t\tlinkText={t(\"pages.settings.form.email.descriptionTransportLink\")}\n\t\t\t\t\t\t\t\thref=\"https://nodemailer.com/smtp/\"\n\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t<Box\n\t\t\t\t\t\t\t\tcomponent=\"pre\"\n\t\t\t\t\t\t\t\tsx={{\n\t\t\t\t\t\t\t\t\tfontFamily: \"monospace\",\n\t\t\t\t\t\t\t\t\tp: 2,\n\t\t\t\t\t\t\t\t\tborderRadius: 1,\n\t\t\t\t\t\t\t\t\toverflow: \"auto\",\n\t\t\t\t\t\t\t\t\tbackgroundColor: theme.palette.mode === \"dark\" ? \"#1e1e1e\" : \"#f5f5f5\",\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<code>\n\t\t\t\t\t\t\t\t\t{JSON.stringify(\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\thost: form.watch(\"systemEmailHost\") || \"\",\n\t\t\t\t\t\t\t\t\t\t\tport: form.watch(\"systemEmailPort\") || \"\",\n\t\t\t\t\t\t\t\t\t\t\tsecure: form.watch(\"systemEmailSecure\") ?? false,\n\t\t\t\t\t\t\t\t\t\t\tauth: {\n\t\t\t\t\t\t\t\t\t\t\t\tuser:\n\t\t\t\t\t\t\t\t\t\t\t\t\tform.watch(\"systemEmailUser\") ||\n\t\t\t\t\t\t\t\t\t\t\t\t\tform.watch(\"systemEmailAddress\") ||\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"\",\n\t\t\t\t\t\t\t\t\t\t\t\tpass: \"<your_password>\",\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\tname: form.watch(\"systemEmailConnectionHost\") || \"localhost\",\n\t\t\t\t\t\t\t\t\t\t\tpool: form.watch(\"systemEmailPool\") ?? false,\n\t\t\t\t\t\t\t\t\t\t\ttls: {\n\t\t\t\t\t\t\t\t\t\t\t\trejectUnauthorized:\n\t\t\t\t\t\t\t\t\t\t\t\t\tform.watch(\"systemEmailRejectUnauthorized\") ?? true,\n\t\t\t\t\t\t\t\t\t\t\t\tignoreTLS: form.watch(\"systemEmailIgnoreTLS\") ?? false,\n\t\t\t\t\t\t\t\t\t\t\t\trequireTLS: form.watch(\"systemEmailRequireTLS\") ?? false,\n\t\t\t\t\t\t\t\t\t\t\t\tservername: form.watch(\"systemEmailTLSServername\") || \"\",\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\tnull,\n\t\t\t\t\t\t\t\t\t\t2\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t</code>\n\t\t\t\t\t\t\t</Box>\n\t\t\t\t\t\t</Stack>\n\t\t\t\t\t}\n\t\t\t\t\trightContent={\n\t\t\t\t\t\t<Stack gap={theme.spacing(LAYOUT.MD)}>\n\t\t\t\t\t\t\t{/* Email Host */}\n\t\t\t\t\t\t\t<Controller\n\t\t\t\t\t\t\t\tname=\"systemEmailHost\"\n\t\t\t\t\t\t\t\tcontrol={form.control}\n\t\t\t\t\t\t\t\trender={({ field, fieldState }) => (\n\t\t\t\t\t\t\t\t\t<TextField\n\t\t\t\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\t\t\t\tvalue={field.value ?? \"\"}\n\t\t\t\t\t\t\t\t\t\tfieldLabel={t(\"pages.settings.form.email.option.host.label\")}\n\t\t\t\t\t\t\t\t\t\tplaceholder={t(\"pages.settings.form.email.option.host.placeholder\")}\n\t\t\t\t\t\t\t\t\t\terror={!!fieldState.error}\n\t\t\t\t\t\t\t\t\t\thelperText={fieldState.error?.message}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t/>\n\n\t\t\t\t\t\t\t{/* Email Port */}\n\t\t\t\t\t\t\t<Controller\n\t\t\t\t\t\t\t\tname=\"systemEmailPort\"\n\t\t\t\t\t\t\t\tcontrol={form.control}\n\t\t\t\t\t\t\t\trender={({ field, fieldState }) => (\n\t\t\t\t\t\t\t\t\t<TextField\n\t\t\t\t\t\t\t\t\t\tname={field.name}\n\t\t\t\t\t\t\t\t\t\tref={field.ref}\n\t\t\t\t\t\t\t\t\t\tonBlur={field.onBlur}\n\t\t\t\t\t\t\t\t\t\tvalue={\n\t\t\t\t\t\t\t\t\t\t\tfield.value === undefined || field.value === 0 ? \"\" : field.value\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\tonChange={(e) => {\n\t\t\t\t\t\t\t\t\t\t\tconst val = e.target.value;\n\t\t\t\t\t\t\t\t\t\t\tfield.onChange(val === \"\" ? 0 : Number(val));\n\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\tfieldLabel={t(\"pages.settings.form.email.option.port.label\")}\n\t\t\t\t\t\t\t\t\t\ttype=\"number\"\n\t\t\t\t\t\t\t\t\t\tinputProps={{ min: 0 }}\n\t\t\t\t\t\t\t\t\t\tplaceholder={t(\"pages.settings.form.email.option.port.placeholder\")}\n\t\t\t\t\t\t\t\t\t\terror={!!fieldState.error}\n\t\t\t\t\t\t\t\t\t\thelperText={fieldState.error?.message}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t/>\n\n\t\t\t\t\t\t\t{/* Email Address */}\n\t\t\t\t\t\t\t<Controller\n\t\t\t\t\t\t\t\tname=\"systemEmailAddress\"\n\t\t\t\t\t\t\t\tcontrol={form.control}\n\t\t\t\t\t\t\t\trender={({ field, fieldState }) => (\n\t\t\t\t\t\t\t\t\t<TextField\n\t\t\t\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\t\t\t\tvalue={field.value ?? \"\"}\n\t\t\t\t\t\t\t\t\t\tfieldLabel={t(\"pages.settings.form.email.option.address.label\")}\n\t\t\t\t\t\t\t\t\t\tplaceholder={t(\n\t\t\t\t\t\t\t\t\t\t\t\"pages.settings.form.email.option.address.placeholder\"\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\ttype=\"email\"\n\t\t\t\t\t\t\t\t\t\terror={!!fieldState.error}\n\t\t\t\t\t\t\t\t\t\thelperText={fieldState.error?.message}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t/>\n\n\t\t\t\t\t\t\t{/* Email User (Optional) */}\n\t\t\t\t\t\t\t<Controller\n\t\t\t\t\t\t\t\tname=\"systemEmailUser\"\n\t\t\t\t\t\t\t\tcontrol={form.control}\n\t\t\t\t\t\t\t\trender={({ field, fieldState }) => (\n\t\t\t\t\t\t\t\t\t<TextField\n\t\t\t\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\t\t\t\tvalue={field.value ?? \"\"}\n\t\t\t\t\t\t\t\t\t\tfieldLabel={t(\"pages.settings.form.email.option.user.label\")}\n\t\t\t\t\t\t\t\t\t\tplaceholder={t(\"pages.settings.form.email.option.user.placeholder\")}\n\t\t\t\t\t\t\t\t\t\terror={!!fieldState.error}\n\t\t\t\t\t\t\t\t\t\thelperText={fieldState.error?.message}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t/>\n\n\t\t\t\t\t\t\t{/* Email Password with Reset Pattern */}\n\t\t\t\t\t\t\t{isEmailPasswordSet && !emailPasswordHasBeenReset ? (\n\t\t\t\t\t\t\t\t<Box>\n\t\t\t\t\t\t\t\t\t<FieldLabel>\n\t\t\t\t\t\t\t\t\t\t{t(\"pages.settings.form.email.option.password.labelSet\")}\n\t\t\t\t\t\t\t\t\t</FieldLabel>\n\t\t\t\t\t\t\t\t\t<Stack\n\t\t\t\t\t\t\t\t\t\tdirection=\"row\"\n\t\t\t\t\t\t\t\t\t\talignItems=\"center\"\n\t\t\t\t\t\t\t\t\t\tgap={theme.spacing(LAYOUT.XS)}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\t\t\t\t\tvariant=\"contained\"\n\t\t\t\t\t\t\t\t\t\t\tcolor=\"error\"\n\t\t\t\t\t\t\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t\t\t\t\t\t\tonClick={handleResetEmailPassword}\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t{t(\"common.buttons.reset\")}\n\t\t\t\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t\t\t\t</Stack>\n\t\t\t\t\t\t\t\t</Box>\n\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t<Controller\n\t\t\t\t\t\t\t\t\tname=\"systemEmailPassword\"\n\t\t\t\t\t\t\t\t\tcontrol={form.control}\n\t\t\t\t\t\t\t\t\trender={({ field, fieldState }) => (\n\t\t\t\t\t\t\t\t\t\t<TextField\n\t\t\t\t\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\t\t\t\t\tvalue={field.value ?? \"\"}\n\t\t\t\t\t\t\t\t\t\t\tfieldLabel={t(\"pages.settings.form.email.option.password.label\")}\n\t\t\t\t\t\t\t\t\t\t\ttype=\"password\"\n\t\t\t\t\t\t\t\t\t\t\tplaceholder={t(\n\t\t\t\t\t\t\t\t\t\t\t\t\"pages.settings.form.email.option.password.placeholder\"\n\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\terror={!!fieldState.error}\n\t\t\t\t\t\t\t\t\t\t\thelperText={fieldState.error?.message}\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t)}\n\n\t\t\t\t\t\t\t{/* TLS Servername (Optional) */}\n\t\t\t\t\t\t\t<Controller\n\t\t\t\t\t\t\t\tname=\"systemEmailTLSServername\"\n\t\t\t\t\t\t\t\tcontrol={form.control}\n\t\t\t\t\t\t\t\trender={({ field, fieldState }) => (\n\t\t\t\t\t\t\t\t\t<TextField\n\t\t\t\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\t\t\t\tvalue={field.value ?? \"\"}\n\t\t\t\t\t\t\t\t\t\tfieldLabel={t(\"pages.settings.form.email.option.tlsServername.label\")}\n\t\t\t\t\t\t\t\t\t\tplaceholder={t(\n\t\t\t\t\t\t\t\t\t\t\t\"pages.settings.form.email.option.tlsServername.placeholder\"\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\terror={!!fieldState.error}\n\t\t\t\t\t\t\t\t\t\thelperText={fieldState.error?.message}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t/>\n\n\t\t\t\t\t\t\t{/* Connection Host (Optional) */}\n\t\t\t\t\t\t\t<Controller\n\t\t\t\t\t\t\t\tname=\"systemEmailConnectionHost\"\n\t\t\t\t\t\t\t\tcontrol={form.control}\n\t\t\t\t\t\t\t\trender={({ field, fieldState }) => (\n\t\t\t\t\t\t\t\t\t<TextField\n\t\t\t\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\t\t\t\tvalue={field.value ?? \"\"}\n\t\t\t\t\t\t\t\t\t\tfieldLabel={t(\n\t\t\t\t\t\t\t\t\t\t\t\"pages.settings.form.email.option.connectionHost.label\"\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\tplaceholder={t(\n\t\t\t\t\t\t\t\t\t\t\t\"pages.settings.form.email.option.connectionHost.placeholder\"\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\terror={!!fieldState.error}\n\t\t\t\t\t\t\t\t\t\thelperText={fieldState.error?.message}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t/>\n\n\t\t\t\t\t\t\t{/* Boolean Switches */}\n\t\t\t\t\t\t\t<Box\n\t\t\t\t\t\t\t\tsx={{\n\t\t\t\t\t\t\t\t\tdisplay: \"flex\",\n\t\t\t\t\t\t\t\t\tflexDirection: \"column\",\n\t\t\t\t\t\t\t\t\tgap: theme.spacing(LAYOUT.XS),\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{[\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tname: \"systemEmailSecure\",\n\t\t\t\t\t\t\t\t\t\tlabel: t(\"pages.settings.form.email.option.secure.label\"),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tname: \"systemEmailPool\",\n\t\t\t\t\t\t\t\t\t\tlabel: t(\"pages.settings.form.email.option.pool.label\"),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tname: \"systemEmailIgnoreTLS\",\n\t\t\t\t\t\t\t\t\t\tlabel: t(\"pages.settings.form.email.option.ignoreTLS.label\"),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tname: \"systemEmailRequireTLS\",\n\t\t\t\t\t\t\t\t\t\tlabel: t(\"pages.settings.form.email.option.requireTLS.label\"),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tname: \"systemEmailRejectUnauthorized\",\n\t\t\t\t\t\t\t\t\t\tlabel: t(\"pages.settings.form.email.option.rejectUnauthorized.label\"),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t].map(({ name, label }) => (\n\t\t\t\t\t\t\t\t\t<Controller\n\t\t\t\t\t\t\t\t\t\tkey={name}\n\t\t\t\t\t\t\t\t\t\tname={name as any}\n\t\t\t\t\t\t\t\t\t\tcontrol={form.control}\n\t\t\t\t\t\t\t\t\t\trender={({ field }) => (\n\t\t\t\t\t\t\t\t\t\t\t<Box\n\t\t\t\t\t\t\t\t\t\t\t\tsx={{\n\t\t\t\t\t\t\t\t\t\t\t\t\tdisplay: \"flex\",\n\t\t\t\t\t\t\t\t\t\t\t\t\talignItems: \"center\",\n\t\t\t\t\t\t\t\t\t\t\t\t\tjustifyContent: \"space-between\",\n\t\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t<Typography>{label}</Typography>\n\t\t\t\t\t\t\t\t\t\t\t\t<SwitchComponent\n\t\t\t\t\t\t\t\t\t\t\t\t\tchecked={field.value ?? false}\n\t\t\t\t\t\t\t\t\t\t\t\t\tonChange={(e: React.ChangeEvent<HTMLInputElement>) =>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tfield.onChange(e.target.checked)\n\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t\t</Box>\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t</Box>\n\n\t\t\t\t\t\t\t{/* Test Email Button */}\n\t\t\t\t\t\t\t<Box>\n\t\t\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\t\t\tvariant=\"contained\"\n\t\t\t\t\t\t\t\t\tloading={isSendingTestEmail}\n\t\t\t\t\t\t\t\t\tonClick={handleSendTestEmail}\n\t\t\t\t\t\t\t\t\tdisabled={\n\t\t\t\t\t\t\t\t\t\t!form.watch(\"systemEmailHost\") ||\n\t\t\t\t\t\t\t\t\t\t!form.watch(\"systemEmailPort\") ||\n\t\t\t\t\t\t\t\t\t\t!form.watch(\"systemEmailAddress\") ||\n\t\t\t\t\t\t\t\t\t\t!form.watch(\"systemEmailPassword\")\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t{t(\"common.buttons.sendTestEmail\")}\n\t\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t\t</Box>\n\t\t\t\t\t\t</Stack>\n\t\t\t\t\t}\n\t\t\t\t/>\n\t\t\t)}\n\n\t\t\t{/* Demo Monitors - Admin Only */}\n\t\t\t{isAdmin && (\n\t\t\t\t<ConfigBox\n\t\t\t\t\ttitle={t(\"pages.settings.form.demoMonitors.title\")}\n\t\t\t\t\tsubtitle={t(\"pages.settings.form.demoMonitors.description\")}\n\t\t\t\t\trightContent={\n\t\t\t\t\t\t<Box>\n\t\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\t\tvariant=\"contained\"\n\t\t\t\t\t\t\t\tloading={isPostingDemoMonitors}\n\t\t\t\t\t\t\t\tonClick={async () => {\n\t\t\t\t\t\t\t\t\tawait postDemoMonitors(\"/monitors/demo\", {});\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{t(\"common.buttons.addDemo\")}\n\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t</Box>\n\t\t\t\t\t}\n\t\t\t\t/>\n\t\t\t)}\n\n\t\t\t{/* Remove All Monitors - Admin Only */}\n\t\t\t{isAdmin && (\n\t\t\t\t<ConfigBox\n\t\t\t\t\ttitle={t(\"pages.settings.form.removeMonitors.title\")}\n\t\t\t\t\tsubtitle={t(\"pages.settings.form.removeMonitors.description\")}\n\t\t\t\t\trightContent={\n\t\t\t\t\t\t<Box>\n\t\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\t\tvariant=\"contained\"\n\t\t\t\t\t\t\t\tcolor=\"error\"\n\t\t\t\t\t\t\t\tloading={isDeletingAllMonitors}\n\t\t\t\t\t\t\t\tonClick={() => setIsDemoMonitorsDialogOpen(true)}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{t(\"common.buttons.removeMonitors\")}\n\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t</Box>\n\t\t\t\t\t}\n\t\t\t\t/>\n\t\t\t)}\n\n\t\t\t{/* Export Monitors - Admin Only */}\n\t\t\t{isAdmin && (\n\t\t\t\t<ConfigBox\n\t\t\t\t\ttitle={t(\"pages.settings.form.importExportMonitors.title\")}\n\t\t\t\t\tsubtitle={t(\"pages.settings.form.importExportMonitors.description\")}\n\t\t\t\t\trightContent={\n\t\t\t\t\t\t<Stack\n\t\t\t\t\t\t\tgap={theme.spacing(LAYOUT.MD)}\n\t\t\t\t\t\t\tdirection={\"row\"}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<input\n\t\t\t\t\t\t\t\tid=\"monitor-import-input\"\n\t\t\t\t\t\t\t\ttype=\"file\"\n\t\t\t\t\t\t\t\taccept=\".json\"\n\t\t\t\t\t\t\t\tstyle={{ display: \"none\" }}\n\t\t\t\t\t\t\t\tonChange={handleFileSelect}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\t\tvariant=\"contained\"\n\t\t\t\t\t\t\t\tonClick={() => document.getElementById(\"monitor-import-input\")?.click()}\n\t\t\t\t\t\t\t\tdisabled={isImportingMonitors}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{t(\"common.buttons.importFromJSON\")}\n\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\t\tvariant=\"contained\"\n\t\t\t\t\t\t\t\tonClick={handleExportMonitors}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{t(\"common.buttons.exportToJSON\")}\n\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t</Stack>\n\t\t\t\t\t}\n\t\t\t\t/>\n\t\t\t)}\n\n\t\t\t{/* About */}\n\t\t\t<ConfigBox\n\t\t\t\ttitle={t(\"pages.settings.form.about.title\")}\n\t\t\t\tsubtitle=\"\"\n\t\t\t\trightContent={\n\t\t\t\t\t<Stack spacing={2}>\n\t\t\t\t\t\t<Typography variant=\"body1\">\n\t\t\t\t\t\t\t{t(\"common.appName\")} {__APP_VERSION__}\n\t\t\t\t\t\t</Typography>\n\t\t\t\t\t\t<Typography\n\t\t\t\t\t\t\tvariant=\"body2\"\n\t\t\t\t\t\t\tsx={{ opacity: 0.6 }}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{t(\"pages.settings.form.about.developedBy\")}\n\t\t\t\t\t\t</Typography>\n\t\t\t\t\t\t<Link\n\t\t\t\t\t\t\thref=\"https://github.com/bluewave-labs/checkmate\"\n\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\trel=\"noopener noreferrer\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\thttps://github.com/bluewave-labs/checkmate\n\t\t\t\t\t\t</Link>\n\t\t\t\t\t</Stack>\n\t\t\t\t}\n\t\t\t/>\n\n\t\t\t{/* Clear Stats Confirmation Dialog */}\n\t\t\t<Dialog\n\t\t\t\topen={isStatsDialogOpen}\n\t\t\t\ttitle={t(\"pages.settings.form.stats.dialog.title\")}\n\t\t\t\tcontent={t(\"pages.settings.form.stats.dialog.description\")}\n\t\t\t\tonCancel={() => setIsStatsDialogOpen(false)}\n\t\t\t\tonConfirm={handleClearStats}\n\t\t\t\tloading={isDeletingStats}\n\t\t\t/>\n\n\t\t\t{/* Delete All Monitors Confirmation Dialog */}\n\t\t\t<Dialog\n\t\t\t\topen={isDemoMonitorsDialogOpen}\n\t\t\t\ttitle={t(\"pages.settings.form.removeMonitors.dialog.title\")}\n\t\t\t\tcontent={t(\"pages.settings.form.removeMonitors.dialog.description\")}\n\t\t\t\tonCancel={() => setIsDemoMonitorsDialogOpen(false)}\n\t\t\t\tonConfirm={async () => {\n\t\t\t\t\tawait deleteAllMonitors(\"/monitors/\");\n\t\t\t\t\tsetIsDemoMonitorsDialogOpen(false);\n\t\t\t\t}}\n\t\t\t\tloading={isDeletingAllMonitors}\n\t\t\t/>\n\n\t\t\t{/* Sticky Save Button */}\n\t\t\t<Stack\n\t\t\t\tdirection=\"row\"\n\t\t\t\tjustifyContent=\"flex-end\"\n\t\t\t\tsx={{\n\t\t\t\t\tposition: \"sticky\",\n\t\t\t\t\tbottom: 0,\n\t\t\t\t\tbackgroundColor: theme.palette.background.paper,\n\t\t\t\t\tborderTop: `1px solid ${theme.palette.divider}`,\n\t\t\t\t\tpadding: theme.spacing(LAYOUT.MD),\n\t\t\t\t\tmarginLeft: theme.spacing(-LAYOUT.MD),\n\t\t\t\t\tmarginRight: theme.spacing(-LAYOUT.MD),\n\t\t\t\t\tmarginBottom: theme.spacing(-LAYOUT.MD),\n\t\t\t\t\tzIndex: 1000,\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t{/* Validation Error Display */}\n\t\t\t\t{Object.keys(form.formState.errors).length > 0 && (\n\t\t\t\t\t<Alert\n\t\t\t\t\t\tseverity=\"error\"\n\t\t\t\t\t\tsx={{ mb: 2, flexGrow: 1, mr: 2 }}\n\t\t\t\t\t>\n\t\t\t\t\t\t<Typography\n\t\t\t\t\t\t\tvariant=\"body2\"\n\t\t\t\t\t\t\tsx={{ fontWeight: 600, mb: 1 }}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{t(\"pages.settings.form.validation.errorMessage\")}\n\t\t\t\t\t\t</Typography>\n\t\t\t\t\t\t<Box\n\t\t\t\t\t\t\tcomponent=\"ul\"\n\t\t\t\t\t\t\tsx={{ m: 0, pl: 2 }}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{Object.entries(form.formState.errors).map(([field, error]) => {\n\t\t\t\t\t\t\t\tconst message =\n\t\t\t\t\t\t\t\t\ttypeof error === \"object\" && error?.message\n\t\t\t\t\t\t\t\t\t\t? error.message\n\t\t\t\t\t\t\t\t\t\t: \"Invalid value\";\n\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t<li key={field}>\n\t\t\t\t\t\t\t\t\t\t<Typography variant=\"body2\">\n\t\t\t\t\t\t\t\t\t\t\t<strong>{field}:</strong> {message}\n\t\t\t\t\t\t\t\t\t\t</Typography>\n\t\t\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t</Box>\n\t\t\t\t\t</Alert>\n\t\t\t\t)}\n\n\t\t\t\t<Button\n\t\t\t\t\tloading={isSaving}\n\t\t\t\t\ttype=\"submit\"\n\t\t\t\t\tvariant=\"contained\"\n\t\t\t\t\tcolor=\"primary\"\n\t\t\t\t\tdisabled={!form.formState.isValid}\n\t\t\t\t>\n\t\t\t\t\t{t(\"common.buttons.save\")}\n\t\t\t\t</Button>\n\t\t\t</Stack>\n\t\t</BasePage>\n\t);\n};\n\nexport default SettingsPage;\n"
  },
  {
    "path": "client/src/Pages/StatusPage/Create/Components/HeaderConfigStatusControls.tsx",
    "content": "import Stack from \"@mui/material/Stack\";\nimport { Icon } from \"@/Components/design-elements\";\nimport { Button } from \"@/Components/inputs\";\nimport { Trash } from \"lucide-react\";\n\nimport { useTranslation } from \"react-i18next\";\nimport { useTheme } from \"@mui/material/styles\";\n\ninterface HeaderConfigStatusControlsProps {\n\tonDelete: () => void;\n}\n\nexport const HeaderConfigStatusControls = ({\n\tonDelete,\n}: React.PropsWithChildren<HeaderConfigStatusControlsProps>) => {\n\tconst theme = useTheme();\n\tconst translate = useTranslation();\n\treturn (\n\t\t<Stack\n\t\t\tspacing={{ xs: theme.spacing(8), md: 0 }}\n\t\t\tdirection={{ xs: \"column\", md: \"row\" }}\n\t\t\talignItems={\"center\"}\n\t\t\tjustifyContent={\"end\"}\n\t\t>\n\t\t\t<Button\n\t\t\t\tvariant=\"contained\"\n\t\t\t\tcolor=\"error\"\n\t\t\t\tstartIcon={<Icon icon={Trash} />}\n\t\t\t\tonClick={onDelete}\n\t\t\t>\n\t\t\t\t{translate.t(\"common.buttons.delete\")}\n\t\t\t</Button>\n\t\t</Stack>\n\t);\n};\n"
  },
  {
    "path": "client/src/Pages/StatusPage/Create/index.tsx",
    "content": "import { BasePage, ConfigBox } from \"@/Components/design-elements\";\nimport Stack from \"@mui/material/Stack\";\nimport { logger } from \"@/Utils/logger\";\nimport { SPACING, LAYOUT } from \"@/Utils/Theme/constants\";\nimport Typography from \"@mui/material/Typography\";\nimport IconButton from \"@mui/material/IconButton\";\nimport FormControlLabel from \"@mui/material/FormControlLabel\";\nimport { Trash2, GripVertical } from \"lucide-react\";\nimport { DragDropContext, Droppable, Draggable } from \"@hello-pangea/dnd\";\nimport type { DropResult } from \"@hello-pangea/dnd\";\nimport {\n\tImageUpload,\n\tSwitchComponent,\n\tButton,\n\tTextField,\n\tAutocomplete,\n\tCheckbox,\n\tDialog,\n\tColorInput,\n} from \"@/Components/inputs\";\n\nimport { useTheme } from \"@mui/material/styles\";\nimport { useTranslation } from \"react-i18next\";\nimport { useEffect, useMemo, useState } from \"react\";\nimport { useForm, Controller } from \"react-hook-form\";\nimport { zodResolver } from \"@hookform/resolvers/zod\";\nimport { useStatusPageForm } from \"@/Hooks/useStatusPageForm\";\nimport type { StatusPageFormData } from \"@/Validation/statusPage\";\nimport { useGet, usePost, usePut, useDelete } from \"@/Hooks/UseApi\";\nimport type { Monitor } from \"@/Types/Monitor\";\nimport type { MonitorDisplayType, StatusPageResponse } from \"@/Types/StatusPage\";\nimport { getMonitorTypeLabel } from \"@/Types/StatusPage\";\nimport timezones from \"@/Utils/timezones.json\";\nimport { useNavigate, useParams } from \"react-router-dom\";\nimport axios from \"axios\";\nimport { HeaderConfigStatusControls } from \"./Components/HeaderConfigStatusControls\";\n\nconst monitorsUrl = (() => {\n\tconst params = new URLSearchParams();\n\t[\"http\", \"ping\", \"port\", \"docker\", \"game\", \"grpc\", \"websocket\", \"hardware\"].forEach(\n\t\t(type) => params.append(\"type\", type)\n\t);\n\treturn `/monitors/team?${params.toString()}`;\n})();\n\ninterface TimezoneOption {\n\t_id: string;\n\tname: string;\n}\n\nconst CreateStatusPage = () => {\n\tconst theme = useTheme();\n\tconst { t } = useTranslation();\n\tconst navigate = useNavigate();\n\tconst { url } = useParams<{ url: string }>();\n\n\tconst isCreate = typeof url === \"undefined\";\n\n\t// Fetch existing status page data when configuring\n\tconst { data: statusPageData, isLoading: isLoadingStatusPage } =\n\t\tuseGet<StatusPageResponse>(\n\t\t\tisCreate ? null : `/status-page/${url}?type=uptime&type=infrastructure`\n\t\t);\n\n\tconst { data: monitorsResponse } = useGet<Monitor[]>(monitorsUrl);\n\tconst monitors = monitorsResponse ?? [];\n\n\tconst { post, loading: isSubmittingPost } = usePost();\n\tconst { put, loading: isSubmittingPut } = usePut();\n\tconst { deleteFn, loading: isDeleting } = useDelete();\n\n\t// Delete dialog state\n\tconst [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false);\n\tconst isSubmitting = isSubmittingPost || isSubmittingPut;\n\n\tconst { schema, defaults } = useStatusPageForm({\n\t\tdata: statusPageData?.statusPage ?? null,\n\t\tmonitors: statusPageData?.monitors ?? null,\n\t});\n\n\tconst form = useForm<StatusPageFormData>({\n\t\tresolver: zodResolver(schema),\n\t\tdefaultValues: defaults,\n\t});\n\n\tconst { control, reset, handleSubmit } = form;\n\n\t// Reset form when defaults change (from fetched data)\n\tuseEffect(() => {\n\t\treset(defaults);\n\t}, [defaults, reset]);\n\n\tconst watchedMonitorIds: string[] = form.watch(\"monitors\") ?? [];\n\tconst computedTypes: MonitorDisplayType[] = useMemo(() => {\n\t\tconst selectedMonitors = (watchedMonitorIds ?? [])\n\t\t\t.map((id) => monitors.find((m) => m.id === id))\n\t\t\t.filter((m): m is Monitor => m !== undefined);\n\n\t\tconst typesSet = new Set<MonitorDisplayType>();\n\t\tselectedMonitors.forEach((m) => {\n\t\t\ttypesSet.add(m.type === \"hardware\" ? \"infrastructure\" : \"uptime\");\n\t\t});\n\n\t\treturn typesSet.size ? Array.from(typesSet) : [\"uptime\"];\n\t}, [watchedMonitorIds, monitors]);\n\n\tuseEffect(() => {\n\t\tform.setValue(\"type\", computedTypes);\n\t}, [computedTypes]);\n\n\tconst onError = (errors: any) => {\n\t\tlogger.debug(\"Status page validation errors\", errors);\n\t};\n\n\tconst handleDeleteClick = () => {\n\t\tsetIsDeleteDialogOpen(true);\n\t};\n\n\tconst handleDeleteConfirm = async () => {\n\t\tconst result = await deleteFn(`/status-page/${statusPageData?.statusPage?.id}`);\n\t\tif (result) {\n\t\t\tnavigate(\"/status\");\n\t\t}\n\t\tsetIsDeleteDialogOpen(false);\n\t};\n\n\tconst handleDeleteCancel = () => {\n\t\tsetIsDeleteDialogOpen(false);\n\t};\n\n\tconst onSubmit = async (data: StatusPageFormData) => {\n\t\tconst fd = new FormData();\n\t\tfd.append(\"isPublished\", String(data.isPublished));\n\t\tif (data.companyName) fd.append(\"companyName\", data.companyName);\n\t\tif (data.url) fd.append(\"url\", data.url);\n\t\tif (data.timezone) fd.append(\"timezone\", data.timezone);\n\t\tif (data.color) fd.append(\"color\", data.color);\n\t\tfd.append(\"showCharts\", String(data.showCharts));\n\t\tfd.append(\"showUptimePercentage\", String(data.showUptimePercentage));\n\t\tfd.append(\"showAdminLoginLink\", String(data.showAdminLoginLink));\n\t\tfd.append(\"showInfrastructure\", String(data.showInfrastructure));\n\n\t\tdata.monitors.forEach((monitorId) => {\n\t\t\tfd.append(\"monitors[]\", monitorId);\n\t\t});\n\n\t\tdata.type.forEach((type) => {\n\t\t\tfd.append(\"type[]\", type);\n\t\t});\n\n\t\t// Handle logo upload\n\t\tif (data.logo === null) {\n\t\t\t// Signal to remove the logo\n\t\t\tfd.append(\"removeLogo\", \"true\");\n\t\t} else if (data.logo?.data && data.logo.data !== \"\") {\n\t\t\tif (data.logo.data.startsWith(\"blob:\")) {\n\t\t\t\ttry {\n\t\t\t\t\tconst imageResult = await axios.get(data.logo.data, {\n\t\t\t\t\t\tresponseType: \"blob\",\n\t\t\t\t\t});\n\t\t\t\t\tfd.append(\"logo\", imageResult.data);\n\t\t\t\t\tURL.revokeObjectURL(data.logo.data);\n\t\t\t\t} catch (e) {\n\t\t\t\t\tlogger.error(\"Failed to fetch logo blob\", e instanceof Error ? e : undefined);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tlet result;\n\t\tif (isCreate) {\n\t\t\tresult = await post(\"/status-page\", fd, {\n\t\t\t\theaders: { \"Content-Type\": \"multipart/form-data\" },\n\t\t\t});\n\t\t} else {\n\t\t\tresult = await put(`/status-page/${statusPageData?.statusPage.id}`, fd, {\n\t\t\t\theaders: { \"Content-Type\": \"multipart/form-data\" },\n\t\t\t});\n\t\t}\n\n\t\tif (result) {\n\t\t\tnavigate(`/status/${data.url}`);\n\t\t}\n\t};\n\n\tif (!isCreate && isLoadingStatusPage) {\n\t\treturn <BasePage>Loading...</BasePage>;\n\t}\n\treturn (\n\t\t<BasePage\n\t\t\tcomponent=\"form\"\n\t\t\tonSubmit={handleSubmit(onSubmit, onError)}\n\t\t>\n\t\t\t{!isCreate && <HeaderConfigStatusControls onDelete={handleDeleteClick} />}\n\t\t\t<ConfigBox\n\t\t\t\ttitle={t(\"pages.statusPages.form.access.title\")}\n\t\t\t\tsubtitle={t(\"pages.statusPages.form.access.description\")}\n\t\t\t\trightContent={\n\t\t\t\t\t<Stack\n\t\t\t\t\t\tdirection=\"row\"\n\t\t\t\t\t\talignItems=\"center\"\n\t\t\t\t\t\tspacing={theme.spacing(SPACING.MD)}\n\t\t\t\t\t>\n\t\t\t\t\t\t<Controller\n\t\t\t\t\t\t\tname=\"isPublished\"\n\t\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\t\trender={({ field }) => (\n\t\t\t\t\t\t\t\t<SwitchComponent\n\t\t\t\t\t\t\t\t\tchecked={field.value ?? false}\n\t\t\t\t\t\t\t\t\tonChange={(e) => field.onChange(e.target.checked)}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<Typography>\n\t\t\t\t\t\t\t{t(\"pages.statusPages.form.access.option.published.name\")}\n\t\t\t\t\t\t</Typography>\n\t\t\t\t\t</Stack>\n\t\t\t\t}\n\t\t\t/>\n\t\t\t<ConfigBox\n\t\t\t\ttitle={t(\"pages.statusPages.form.basicInfo.title\")}\n\t\t\t\tsubtitle={t(\"pages.statusPages.form.basicInfo.description\")}\n\t\t\t\trightContent={\n\t\t\t\t\t<Stack spacing={theme.spacing(LAYOUT.MD)}>\n\t\t\t\t\t\t<Controller\n\t\t\t\t\t\t\tname=\"companyName\"\n\t\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\t\trender={({ field, fieldState }) => (\n\t\t\t\t\t\t\t\t<TextField\n\t\t\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\t\t\tfieldLabel={t(\"pages.statusPages.form.basicInfo.option.name.label\")}\n\t\t\t\t\t\t\t\t\tplaceholder={t(\n\t\t\t\t\t\t\t\t\t\t\"pages.statusPages.form.basicInfo.option.name.placeholder\"\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\terror={!!fieldState.error}\n\t\t\t\t\t\t\t\t\thelperText={fieldState.error?.message}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<Controller\n\t\t\t\t\t\t\tname=\"url\"\n\t\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\t\trender={({ field, fieldState }) => (\n\t\t\t\t\t\t\t\t<TextField\n\t\t\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\t\t\tfieldLabel={t(\"pages.statusPages.form.basicInfo.option.url.label\")}\n\t\t\t\t\t\t\t\t\tplaceholder={t(\n\t\t\t\t\t\t\t\t\t\t\"pages.statusPages.form.basicInfo.option.url.placeholder\"\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\terror={!!fieldState.error}\n\t\t\t\t\t\t\t\t\thelperText={fieldState.error?.message}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</Stack>\n\t\t\t\t}\n\t\t\t/>\n\t\t\t<ConfigBox\n\t\t\t\ttitle={t(\"pages.statusPages.form.monitors.title\")}\n\t\t\t\tsubtitle={t(\"pages.statusPages.form.monitors.description\")}\n\t\t\t\trightContent={\n\t\t\t\t\t<Controller\n\t\t\t\t\t\tname=\"monitors\"\n\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\trender={({ field, fieldState }) => {\n\t\t\t\t\t\t\tconst selectedMonitors = field.value\n\t\t\t\t\t\t\t\t.map((id: string) => monitors.find((m) => m.id === id))\n\t\t\t\t\t\t\t\t.filter((m): m is Monitor => m !== undefined);\n\n\t\t\t\t\t\t\tconst handleDragEnd = (result: DropResult) => {\n\t\t\t\t\t\t\t\tif (!result.destination) return;\n\t\t\t\t\t\t\t\tconst reordered = Array.from(field.value);\n\t\t\t\t\t\t\t\tconst [removed] = reordered.splice(result.source.index, 1);\n\t\t\t\t\t\t\t\treordered.splice(result.destination.index, 0, removed);\n\t\t\t\t\t\t\t\tfield.onChange(reordered);\n\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t<Stack spacing={theme.spacing(LAYOUT.MD)}>\n\t\t\t\t\t\t\t\t\t<Autocomplete\n\t\t\t\t\t\t\t\t\t\tmultiple\n\t\t\t\t\t\t\t\t\t\toptions={monitors}\n\t\t\t\t\t\t\t\t\t\tgetOptionLabel={(option: Monitor) => option.name}\n\t\t\t\t\t\t\t\t\t\tvalue={selectedMonitors}\n\t\t\t\t\t\t\t\t\t\tonChange={(_, newValue) => {\n\t\t\t\t\t\t\t\t\t\t\tfield.onChange(newValue.map((m: Monitor) => m.id));\n\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\tfieldLabel={t(\n\t\t\t\t\t\t\t\t\t\t\t\"pages.statusPages.form.monitors.option.monitors.label\"\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\trenderInput={(params) => (\n\t\t\t\t\t\t\t\t\t\t\t<TextField\n\t\t\t\t\t\t\t\t\t\t\t\t{...params}\n\t\t\t\t\t\t\t\t\t\t\t\tplaceholder={\n\t\t\t\t\t\t\t\t\t\t\t\t\tselectedMonitors.length === 0\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t? t(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"pages.statusPages.form.monitors.option.monitors.placeholder\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t: \"\"\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\terror={!!fieldState.error}\n\t\t\t\t\t\t\t\t\t\t\t\thelperText={fieldState.error?.message}\n\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t{selectedMonitors.length > 0 && (\n\t\t\t\t\t\t\t\t\t\t<DragDropContext onDragEnd={handleDragEnd}>\n\t\t\t\t\t\t\t\t\t\t\t<Droppable droppableId=\"monitors-list\">\n\t\t\t\t\t\t\t\t\t\t\t\t{(provided) => (\n\t\t\t\t\t\t\t\t\t\t\t\t\t<Stack\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{...provided.droppableProps}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tref={provided.innerRef}\n\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{selectedMonitors.map((monitor, index) => (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<Draggable\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tkey={monitor.id}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdraggableId={monitor.id}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tindex={index}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{(provided) => (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<Stack\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tref={provided.innerRef}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{...provided.draggableProps}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{...provided.dragHandleProps}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tdirection=\"row\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\talignItems=\"center\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tspacing={theme.spacing(LAYOUT.XS)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tpadding={theme.spacing(LAYOUT.XS)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tmarginTop={theme.spacing(SPACING.LG)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tborderRadius={1}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tsx={{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tborder: `1px solid ${theme.palette.divider}`,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tcursor: \"grab\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"&:active\": { cursor: \"grabbing\" },\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<GripVertical size={20} />\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<Typography\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tflexGrow={1}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>{`${monitor.name} (${getMonitorTypeLabel(monitor.type, t)})`}</Typography>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<IconButton\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tfield.onChange(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tfield.value.filter(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t(id: string) => id !== monitor.id\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\taria-label=\"Remove monitor\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<Trash2 size={16} />\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</IconButton>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</Stack>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</Draggable>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{provided.placeholder}\n\t\t\t\t\t\t\t\t\t\t\t\t\t</Stack>\n\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t</Droppable>\n\t\t\t\t\t\t\t\t\t\t</DragDropContext>\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t</Stack>\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}}\n\t\t\t\t\t/>\n\t\t\t\t}\n\t\t\t/>\n\t\t\t<ConfigBox\n\t\t\t\ttitle={t(\"pages.statusPages.form.timezone.title\")}\n\t\t\t\tsubtitle={t(\"pages.statusPages.form.timezone.description\")}\n\t\t\t\trightContent={\n\t\t\t\t\t<Controller\n\t\t\t\t\t\tname=\"timezone\"\n\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\trender={({ field }) => (\n\t\t\t\t\t\t\t<Autocomplete\n\t\t\t\t\t\t\t\toptions={timezones}\n\t\t\t\t\t\t\t\tgetOptionLabel={(option: TimezoneOption) => option.name}\n\t\t\t\t\t\t\t\tvalue={\n\t\t\t\t\t\t\t\t\ttimezones.find((tz: TimezoneOption) => tz._id === field.value) ?? null\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tonChange={(_, newValue: TimezoneOption | null) => {\n\t\t\t\t\t\t\t\t\tfield.onChange(newValue?._id ?? \"\");\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\tfieldLabel={t(\"pages.statusPages.form.timezone.option.timezone.label\")}\n\t\t\t\t\t\t\t\trenderInput={(params) => (\n\t\t\t\t\t\t\t\t\t<TextField\n\t\t\t\t\t\t\t\t\t\t{...params}\n\t\t\t\t\t\t\t\t\t\tplaceholder={t(\n\t\t\t\t\t\t\t\t\t\t\t\"pages.statusPages.form.timezone.option.timezone.placeholder\"\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t)}\n\t\t\t\t\t/>\n\t\t\t\t}\n\t\t\t/>\n\t\t\t<ConfigBox\n\t\t\t\ttitle={t(\"pages.statusPages.form.appearance.title\")}\n\t\t\t\tsubtitle={t(\"pages.statusPages.form.appearance.description\")}\n\t\t\t\trightContent={\n\t\t\t\t\t<Stack spacing={theme.spacing(LAYOUT.MD)}>\n\t\t\t\t\t\t<Stack alignItems={\"center\"}>\n\t\t\t\t\t\t\t<Controller\n\t\t\t\t\t\t\t\tname=\"logo\"\n\t\t\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\t\t\trender={({ field }) => (\n\t\t\t\t\t\t\t\t\t<ImageUpload\n\t\t\t\t\t\t\t\t\t\tsrc={field.value?.data}\n\t\t\t\t\t\t\t\t\t\tonChange={(file) => {\n\t\t\t\t\t\t\t\t\t\t\tif (file) {\n\t\t\t\t\t\t\t\t\t\t\t\tfield.onChange({\n\t\t\t\t\t\t\t\t\t\t\t\t\tdata: file.src,\n\t\t\t\t\t\t\t\t\t\t\t\t\tcontentType: file.file.type,\n\t\t\t\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\t\t\tfield.onChange(null);\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</Stack>\n\t\t\t\t\t\t<Controller\n\t\t\t\t\t\t\tname=\"color\"\n\t\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\t\trender={({ field }) => (\n\t\t\t\t\t\t\t\t<ColorInput\n\t\t\t\t\t\t\t\t\tformat=\"hex\"\n\t\t\t\t\t\t\t\t\tvalue={field.value}\n\t\t\t\t\t\t\t\t\tonChange={field.onChange}\n\t\t\t\t\t\t\t\t\tfieldLabel={t(\"pages.statusPages.form.appearance.option.color.label\")}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</Stack>\n\t\t\t\t}\n\t\t\t/>\n\t\t\t<ConfigBox\n\t\t\t\ttitle={t(\"pages.statusPages.form.features.title\")}\n\t\t\t\tsubtitle={t(\"pages.statusPages.form.features.description\")}\n\t\t\t\trightContent={\n\t\t\t\t\t<Stack spacing={theme.spacing(LAYOUT.MD)}>\n\t\t\t\t\t\t<Controller\n\t\t\t\t\t\t\tname=\"showCharts\"\n\t\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\t\trender={({ field }) => (\n\t\t\t\t\t\t\t\t<FormControlLabel\n\t\t\t\t\t\t\t\t\tcontrol={\n\t\t\t\t\t\t\t\t\t\t<Checkbox\n\t\t\t\t\t\t\t\t\t\t\tchecked={field.value}\n\t\t\t\t\t\t\t\t\t\t\tonChange={field.onChange}\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tlabel={t(\"pages.statusPages.form.features.option.showCharts.label\")}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<Controller\n\t\t\t\t\t\t\tname=\"showInfrastructure\"\n\t\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\t\trender={({ field }) => (\n\t\t\t\t\t\t\t\t<FormControlLabel\n\t\t\t\t\t\t\t\t\tcontrol={\n\t\t\t\t\t\t\t\t\t\t<Checkbox\n\t\t\t\t\t\t\t\t\t\t\tchecked={field.value}\n\t\t\t\t\t\t\t\t\t\t\tonChange={field.onChange}\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tlabel={t(\n\t\t\t\t\t\t\t\t\t\t\"pages.statusPages.form.features.option.showInfrastructure.label\"\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t{/* <Controller\n\t\t\t\t\t\t\tname=\"showUptimePercentage\"\n\t\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\t\trender={({ field }) => (\n\t\t\t\t\t\t\t\t<FormControlLabel\n\t\t\t\t\t\t\t\t\tcontrol={\n\t\t\t\t\t\t\t\t\t\t<Checkbox\n\t\t\t\t\t\t\t\t\t\t\tchecked={field.value}\n\t\t\t\t\t\t\t\t\t\t\tonChange={field.onChange}\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tlabel={t(\n\t\t\t\t\t\t\t\t\t\t\"pages.statusPages.form.features.option.showUptimePercentage.label\"\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<Controller\n\t\t\t\t\t\t\tname=\"showAdminLoginLink\"\n\t\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\t\trender={({ field }) => (\n\t\t\t\t\t\t\t\t<FormControlLabel\n\t\t\t\t\t\t\t\t\tcontrol={\n\t\t\t\t\t\t\t\t\t\t<Checkbox\n\t\t\t\t\t\t\t\t\t\t\tchecked={field.value}\n\t\t\t\t\t\t\t\t\t\t\tonChange={field.onChange}\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tlabel={t(\n\t\t\t\t\t\t\t\t\t\t\"pages.statusPages.form.features.option.showAdminLoginLink.label\"\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t/> */}\n\t\t\t\t\t</Stack>\n\t\t\t\t}\n\t\t\t/>\n\t\t\t<Stack\n\t\t\t\tdirection=\"row\"\n\t\t\t\tjustifyContent=\"flex-end\"\n\t\t\t>\n\t\t\t\t<Button\n\t\t\t\t\tloading={isSubmitting}\n\t\t\t\t\ttype=\"submit\"\n\t\t\t\t\tvariant=\"contained\"\n\t\t\t\t\tcolor=\"primary\"\n\t\t\t\t>\n\t\t\t\t\t{t(\"common.buttons.save\")}\n\t\t\t\t</Button>\n\t\t\t</Stack>\n\t\t\t<Dialog\n\t\t\t\topen={isDeleteDialogOpen}\n\t\t\t\ttitle={t(\"common.dialogs.delete.title\")}\n\t\t\t\tcontent={t(\"common.dialogs.delete.description\")}\n\t\t\t\tonConfirm={handleDeleteConfirm}\n\t\t\t\tonCancel={handleDeleteCancel}\n\t\t\t\tloading={isDeleting}\n\t\t\t/>\n\t\t</BasePage>\n\t);\n};\n\nexport default CreateStatusPage;\n"
  },
  {
    "path": "client/src/Pages/StatusPage/Status/Components/HeaderStatusPageControls.tsx",
    "content": "import Stack from \"@mui/material/Stack\";\nimport Box from \"@mui/material/Box\";\nimport Typography from \"@mui/material/Typography\";\nimport { Icon } from \"@/Components/design-elements\";\nimport { Button } from \"@/Components/inputs\";\nimport { Settings, ExternalLink } from \"lucide-react\";\n\nimport { useTheme } from \"@mui/material\";\nimport { useTranslation } from \"react-i18next\";\nimport { useNavigate } from \"react-router-dom\";\nimport type { StatusPage } from \"@/Types/StatusPage\";\n\ninterface HeaderStatusPageControlsProps {\n\tisAdmin: boolean;\n\tstatusPage: StatusPage;\n\tisPublic?: boolean;\n}\nexport const HeaderStatusPageControls = ({\n\tisAdmin,\n\tstatusPage,\n\tisPublic = false,\n}: HeaderStatusPageControlsProps) => {\n\tconst theme = useTheme();\n\tconst navigate = useNavigate();\n\tconst { t } = useTranslation();\n\treturn (\n\t\t<Stack\n\t\t\tdirection={\"row\"}\n\t\t\talignItems={\"center\"}\n\t\t\tjustifyContent={\"space-between\"}\n\t\t\tmb={4}\n\t\t>\n\t\t\t<Stack\n\t\t\t\tdirection=\"row\"\n\t\t\t\tgap={theme.spacing(4)}\n\t\t\t\talignItems=\"baseline\"\n\t\t\t>\n\t\t\t\t<Typography\n\t\t\t\t\tvariant=\"h1\"\n\t\t\t\t\toverflow=\"hidden\"\n\t\t\t\t\ttextOverflow=\"ellipsis\"\n\t\t\t\t\tsx={{\n\t\t\t\t\t\tmaxWidth: { xs: \"200px\", sm: \"100%\" },\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t{statusPage?.companyName}\n\t\t\t\t</Typography>\n\t\t\t\t{statusPage?.isPublished && !isPublic && (\n\t\t\t\t\t<>\n\t\t\t\t\t\t<Typography\n\t\t\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\t\t\twindow.open(\n\t\t\t\t\t\t\t\t\t`/status/public/${statusPage.url}`,\n\t\t\t\t\t\t\t\t\t\"_blank\",\n\t\t\t\t\t\t\t\t\t\"noopener,noreferrer\"\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\tsx={{\n\t\t\t\t\t\t\t\tborderBottom: 1,\n\t\t\t\t\t\t\t\tborderColor: \"transparent\",\n\t\t\t\t\t\t\t\t\":hover\": {\n\t\t\t\t\t\t\t\t\tcursor: \"pointer\",\n\t\t\t\t\t\t\t\t\tborderBottom: 1,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{t(\"components.headerStatusPageControls.publicLink\")}\n\t\t\t\t\t\t</Typography>\n\t\t\t\t\t\t<Box>\n\t\t\t\t\t\t\t<ExternalLink size={14} />\n\t\t\t\t\t\t</Box>\n\t\t\t\t\t</>\n\t\t\t\t)}\n\t\t\t</Stack>\n\t\t\t{isAdmin && !isPublic && (\n\t\t\t\t<Button\n\t\t\t\t\tvariant=\"contained\"\n\t\t\t\t\tcolor=\"secondary\"\n\t\t\t\t\tstartIcon={<Icon icon={Settings} />}\n\t\t\t\t\tonClick={() => navigate(`/status/configure/${statusPage.url}`)}\n\t\t\t\t>\n\t\t\t\t\t{t(\"common.buttons.configure\")}\n\t\t\t\t</Button>\n\t\t\t)}\n\t\t</Stack>\n\t);\n};\n"
  },
  {
    "path": "client/src/Pages/StatusPage/Status/Components/InfrastructureMetrics.tsx",
    "content": "import Stack from \"@mui/material/Stack\";\nimport Typography from \"@mui/material/Typography\";\nimport { Gauge } from \"@/Components/design-elements\";\nimport { useTheme } from \"@mui/material/styles\";\nimport { useTranslation } from \"react-i18next\";\nimport prettyBytes from \"pretty-bytes\";\nimport type { Monitor } from \"@/Types/Monitor\";\nimport Grid from \"@mui/material/Grid\";\nimport useMediaQuery from \"@mui/material/useMediaQuery\";\nimport Box from \"@mui/material/Box\";\nimport { LAYOUT, SPACING } from \"@/Utils/Theme/constants\";\n\nconst GAUGE_RADIUS = 60;\nconst GAUGE_STROKE_WIDTH = 12;\nconst PERCENTAGE_MULTIPLIER = 100;\n\ninterface StatusPageMonitor extends Monitor {\n\tchecks?: Monitor[\"recentChecks\"];\n}\n\ninterface MetricDetail {\n\tlabel: string;\n\tvalue: string;\n}\n\ninterface MetricConfig {\n\tkey: string;\n\tlabel: string;\n\thasData: boolean;\n\tprogress: number;\n\tdetails: MetricDetail[];\n}\n\nconst MetricDetailRow = ({ label, value }: MetricDetail) => {\n\tconst theme = useTheme();\n\treturn (\n\t\t<Stack\n\t\t\tdirection=\"row\"\n\t\t\tjustifyContent=\"space-between\"\n\t\t>\n\t\t\t<Typography\n\t\t\t\tvariant=\"body2\"\n\t\t\t\tcolor={theme.palette.text.secondary}\n\t\t\t>\n\t\t\t\t{label}\n\t\t\t</Typography>\n\t\t\t<Typography variant=\"body2\">{value}</Typography>\n\t\t</Stack>\n\t);\n};\n\ninterface MetricItemProps {\n\tlabel: string;\n\tprogress: number;\n\tdetails?: MetricDetail[];\n}\n\nconst MetricItem = ({ label, progress, details }: MetricItemProps) => {\n\tconst theme = useTheme();\n\tconst isSmall = useMediaQuery(theme.breakpoints.down(\"md\"));\n\treturn (\n\t\t<Grid\n\t\t\tsize={isSmall ? 12 : 4}\n\t\t\tsx={{\n\t\t\t\tdisplay: \"flex\",\n\t\t\t\tflexDirection: \"column\",\n\t\t\t\talignItems: \"center\",\n\t\t\t\ttextAlign: \"center\",\n\t\t\t\tgap: theme.spacing(SPACING.LG),\n\t\t\t\tpadding: theme.spacing(LAYOUT.XS),\n\t\t\t\tborderRight: isSmall ? \"none\" : `1px solid ${theme.palette.divider}`,\n\t\t\t\tborderBottom: isSmall ? `1px solid ${theme.palette.divider}` : \"none\",\n\t\t\t\t\"&:last-child\": {\n\t\t\t\t\tborderRight: \"none\",\n\t\t\t\t\tborderBottom: \"none\",\n\t\t\t\t\tpaddingBottom: theme.spacing(SPACING.LG),\n\t\t\t\t},\n\t\t\t}}\n\t\t>\n\t\t\t<Box\n\t\t\t\tdisplay=\"flex\"\n\t\t\t\tflexDirection=\"column\"\n\t\t\t\talignItems=\"center\"\n\t\t\t>\n\t\t\t\t<Gauge\n\t\t\t\t\tprogress={progress}\n\t\t\t\t\tradius={GAUGE_RADIUS}\n\t\t\t\t\tstrokeWidth={GAUGE_STROKE_WIDTH}\n\t\t\t\t/>\n\t\t\t\t<Typography variant=\"body2\">{label}</Typography>\n\t\t\t</Box>\n\t\t\t{details && details.length > 0 && (\n\t\t\t\t<Box\n\t\t\t\t\twidth=\"100%\"\n\t\t\t\t\tpaddingX={theme.spacing(LAYOUT.LG)}\n\t\t\t\t>\n\t\t\t\t\t{details.map((detail) => (\n\t\t\t\t\t\t<MetricDetailRow\n\t\t\t\t\t\t\tkey={detail.label}\n\t\t\t\t\t\t\tlabel={detail.label}\n\t\t\t\t\t\t\tvalue={detail.value}\n\t\t\t\t\t\t/>\n\t\t\t\t\t))}\n\t\t\t\t</Box>\n\t\t\t)}\n\t\t</Grid>\n\t);\n};\n\ntype LatestCheck = NonNullable<Monitor[\"recentChecks\"]>[number];\n\nconst buildCpuMetric = (\n\tcheck: LatestCheck,\n\tt: (key: string) => string\n): MetricConfig | null => {\n\tif (!check.cpu || typeof check.cpu.usage_percent !== \"number\") {\n\t\treturn null;\n\t}\n\tconst usagePercent = (check.cpu.usage_percent ?? 0) * PERCENTAGE_MULTIPLIER;\n\treturn {\n\t\tkey: \"cpu\",\n\t\tlabel: t(\"pages.statusPages.monitorsList.infrastructure.cpu\"),\n\t\thasData: true,\n\t\tprogress: usagePercent,\n\t\tdetails: [\n\t\t\t{\n\t\t\t\tlabel: t(\"pages.statusPages.monitorsList.infrastructure.usage\"),\n\t\t\t\tvalue: `${usagePercent.toFixed(2)}%`,\n\t\t\t},\n\t\t],\n\t};\n};\n\nconst buildMemoryMetric = (\n\tcheck: LatestCheck,\n\tt: (key: string) => string\n): MetricConfig | null => {\n\tif (\n\t\t!check.memory ||\n\t\ttypeof check.memory.usage_percent !== \"number\" ||\n\t\ttypeof check.memory.used_bytes !== \"number\" ||\n\t\ttypeof check.memory.total_bytes !== \"number\"\n\t) {\n\t\treturn null;\n\t}\n\treturn {\n\t\tkey: \"memory\",\n\t\tlabel: t(\"pages.statusPages.monitorsList.infrastructure.memory\"),\n\t\thasData: true,\n\t\tprogress: (check.memory.usage_percent ?? 0) * PERCENTAGE_MULTIPLIER,\n\t\tdetails: [\n\t\t\t{\n\t\t\t\tlabel: t(\"pages.statusPages.monitorsList.infrastructure.used\"),\n\t\t\t\tvalue: prettyBytes(check.memory.used_bytes ?? 0),\n\t\t\t},\n\t\t\t{\n\t\t\t\tlabel: t(\"pages.statusPages.monitorsList.infrastructure.total\"),\n\t\t\t\tvalue: prettyBytes(check.memory.total_bytes ?? 0),\n\t\t\t},\n\t\t],\n\t};\n};\n\nconst buildDiskMetric = (\n\tcheck: LatestCheck,\n\tt: (key: string) => string\n): MetricConfig | null => {\n\tif (!check.disk || check.disk.length === 0) {\n\t\treturn null;\n\t}\n\tconst disks = check.disk;\n\tconst avgUsagePercent =\n\t\t(disks.reduce((acc, disk) => acc + (disk?.usage_percent ?? 0), 0) / disks.length) *\n\t\tPERCENTAGE_MULTIPLIER;\n\tconst totalUsedBytes = disks.reduce((acc, disk) => acc + (disk?.used_bytes ?? 0), 0);\n\tconst totalTotalBytes = disks.reduce((acc, disk) => acc + (disk?.total_bytes ?? 0), 0);\n\n\treturn {\n\t\tkey: \"disk\",\n\t\tlabel: t(\"pages.statusPages.monitorsList.infrastructure.disk\"),\n\t\thasData: true,\n\t\tprogress: avgUsagePercent,\n\t\tdetails: [\n\t\t\t{\n\t\t\t\tlabel: t(\"pages.statusPages.monitorsList.infrastructure.used\"),\n\t\t\t\tvalue: prettyBytes(totalUsedBytes),\n\t\t\t},\n\t\t\t{\n\t\t\t\tlabel: t(\"pages.statusPages.monitorsList.infrastructure.total\"),\n\t\t\t\tvalue: prettyBytes(totalTotalBytes),\n\t\t\t},\n\t\t],\n\t};\n};\n\nexport const InfrastructureMetrics = ({ monitor }: { monitor: StatusPageMonitor }) => {\n\tconst theme = useTheme();\n\tconst { t } = useTranslation();\n\n\tconst latestCheck = monitor.recentChecks?.[0] ?? monitor.checks?.[0];\n\n\tif (!latestCheck) {\n\t\treturn (\n\t\t\t<Typography\n\t\t\t\tvariant=\"body2\"\n\t\t\t\tcolor={theme.palette.text.secondary}\n\t\t\t>\n\t\t\t\t{t(\"pages.statusPages.monitorsList.noData\")}\n\t\t\t</Typography>\n\t\t);\n\t}\n\n\tconst metrics: MetricConfig[] = [\n\t\tbuildCpuMetric(latestCheck, t),\n\t\tbuildMemoryMetric(latestCheck, t),\n\t\tbuildDiskMetric(latestCheck, t),\n\t].filter((m): m is MetricConfig => m !== null);\n\n\tif (metrics.length === 0) {\n\t\treturn (\n\t\t\t<Typography\n\t\t\t\tvariant=\"body2\"\n\t\t\t\tcolor={theme.palette.text.secondary}\n\t\t\t>\n\t\t\t\t{t(\"pages.statusPages.monitorsList.noData\")}\n\t\t\t</Typography>\n\t\t);\n\t}\n\n\treturn (\n\t\t<Grid\n\t\t\tcontainer\n\t\t\talignItems=\"center\"\n\t\t\tpadding={theme.spacing(LAYOUT.XS)}\n\t\t>\n\t\t\t{metrics.map(({ key, label, progress, details }) => (\n\t\t\t\t<MetricItem\n\t\t\t\t\tkey={key}\n\t\t\t\t\tlabel={label}\n\t\t\t\t\tprogress={progress}\n\t\t\t\t\tdetails={details}\n\t\t\t\t/>\n\t\t\t))}\n\t\t</Grid>\n\t);\n};\n"
  },
  {
    "path": "client/src/Pages/StatusPage/Status/Components/MonitorsList.tsx",
    "content": "import Stack from \"@mui/material/Stack\";\nimport { useTranslation } from \"react-i18next\";\nimport Box from \"@mui/material/Box\";\nimport Typography from \"@mui/material/Typography\";\nimport { HistogramResponseTime, HeatmapResponseTime } from \"@/Components/common\";\nimport { StatusLabel, BaseBox } from \"@/Components/design-elements\";\nimport { SwitchComponent } from \"@/Components/inputs\";\nimport { InfrastructureMetrics } from \"@/Pages/StatusPage/Status/Components/InfrastructureMetrics\";\n\nimport { useTheme, type Theme } from \"@mui/material/styles\";\nimport { useSelector } from \"react-redux\";\nimport { useState } from \"react\";\nimport type { Monitor } from \"@/Types/Monitor\";\nimport type { StatusPage } from \"@/Types/StatusPage\";\nimport { getMonitorTypeLabel } from \"@/Types/StatusPage\";\nimport type { RootState } from \"@/Types/state\";\nimport { LAYOUT, SPACING } from \"@/Utils/Theme/constants\";\n\ninterface StatusPageMonitor extends Monitor {\n\tchecks?: Monitor[\"recentChecks\"];\n}\n\ninterface MonitorsListProps {\n\tstatusPage: StatusPage;\n\tmonitors: StatusPageMonitor[];\n}\n\nconst getMonitorBadgeStyles = (monitorType: string, theme: Theme) => {\n\tconst bg =\n\t\tmonitorType === \"hardware\" ? theme.palette.info.light : theme.palette.success.light;\n\treturn {\n\t\tbackgroundColor: bg,\n\t\tcolor: theme.palette.background.paper,\n\t\tpadding: `${theme.spacing(SPACING.SM)} ${theme.spacing(SPACING.LG)}`,\n\t\tborderRadius: theme.shape.borderRadius,\n\t};\n};\n\nconst MonitorHeader = ({\n\tmonitor,\n\tshowURL,\n}: {\n\tmonitor: StatusPageMonitor;\n\tshowURL: boolean;\n}) => {\n\tconst theme = useTheme();\n\tconst { t } = useTranslation();\n\n\treturn (\n\t\t<Stack\n\t\t\tdirection=\"row\"\n\t\t\talignItems=\"center\"\n\t\t\tjustifyContent=\"space-between\"\n\t\t\tgap={theme.spacing(LAYOUT.XS)}\n\t\t\tmb={theme.spacing(LAYOUT.XS)}\n\t\t>\n\t\t\t<Box sx={{ overflow: \"hidden\", minWidth: 0, flex: 1 }}>\n\t\t\t\t<Stack\n\t\t\t\t\tdirection=\"row\"\n\t\t\t\t\talignItems=\"center\"\n\t\t\t\t\tgap={theme.spacing(SPACING.LG)}\n\t\t\t\t\tmb={theme.spacing(SPACING.SM)}\n\t\t\t\t>\n\t\t\t\t\t<Typography\n\t\t\t\t\t\tvariant=\"h6\"\n\t\t\t\t\t\tsx={{ overflow: \"hidden\", textOverflow: \"ellipsis\", whiteSpace: \"nowrap\" }}\n\t\t\t\t\t>\n\t\t\t\t\t\t{monitor.name}\n\t\t\t\t\t</Typography>\n\t\t\t\t\t<Typography\n\t\t\t\t\t\tvariant=\"caption\"\n\t\t\t\t\t\tsx={getMonitorBadgeStyles(monitor.type ?? \"\", theme)}\n\t\t\t\t\t>\n\t\t\t\t\t\t{getMonitorTypeLabel(monitor.type, t)}\n\t\t\t\t\t</Typography>\n\t\t\t\t</Stack>\n\t\t\t\t{showURL && monitor.url && (\n\t\t\t\t\t<Typography\n\t\t\t\t\t\tvariant=\"body2\"\n\t\t\t\t\t\tcolor={theme.palette.text.secondary}\n\t\t\t\t\t\tsx={{ overflow: \"hidden\", textOverflow: \"ellipsis\", whiteSpace: \"nowrap\" }}\n\t\t\t\t\t>\n\t\t\t\t\t\t{monitor.url}\n\t\t\t\t\t</Typography>\n\t\t\t\t)}\n\t\t\t</Box>\n\t\t\t<StatusLabel status={monitor.status} />\n\t\t</Stack>\n\t);\n};\n\nconst MonitorContent = ({\n\tmonitor,\n\tstatusPage,\n\tchartType,\n}: {\n\tmonitor: StatusPageMonitor;\n\tstatusPage: StatusPage;\n\tchartType: string;\n}) => {\n\tconst theme = useTheme();\n\n\tif (monitor.type === \"hardware\") {\n\t\tif (statusPage.showInfrastructure === false) return null;\n\t\treturn <InfrastructureMetrics monitor={monitor} />;\n\t}\n\n\tif (statusPage.showCharts === false) return null;\n\n\tconst checks = monitor.checks?.slice().reverse() ?? [];\n\treturn (\n\t\t<Box sx={{ overflow: \"hidden\", minWidth: 0, flex: 1, mb: theme.spacing(SPACING.LG) }}>\n\t\t\t{chartType === \"histogram\" ? (\n\t\t\t\t<HistogramResponseTime\n\t\t\t\t\theight={{ xs: 50, md: 100 }}\n\t\t\t\t\tgap={{ xs: theme.spacing(SPACING.SM), md: theme.spacing(LAYOUT.SM) }}\n\t\t\t\t\tchecks={checks}\n\t\t\t\t/>\n\t\t\t) : (\n\t\t\t\t<HeatmapResponseTime checks={checks} />\n\t\t\t)}\n\t\t</Box>\n\t);\n};\n\nexport const MonitorsList = ({ statusPage, monitors }: MonitorsListProps) => {\n\tconst theme = useTheme();\n\tconst { t } = useTranslation();\n\tconst showURL = useSelector((state: RootState) => state.ui?.showURL);\n\tconst [chartType, setChartType] = useState<\"histogram\" | \"heatmap\">(\"histogram\");\n\n\treturn (\n\t\t<Stack gap={theme.spacing(LAYOUT.MD)}>\n\t\t\t{statusPage.showCharts && (\n\t\t\t\t<Stack\n\t\t\t\t\tdirection=\"row\"\n\t\t\t\t\talignItems=\"center\"\n\t\t\t\t\tgap={theme.spacing(LAYOUT.SM)}\n\t\t\t\t>\n\t\t\t\t\t<Typography>{t(\"pages.statusPages.monitorsList.chartTypeHeatmap\")}</Typography>\n\t\t\t\t\t<SwitchComponent\n\t\t\t\t\t\tdualOption\n\t\t\t\t\t\tvalue={chartType}\n\t\t\t\t\t\tchecked={chartType === \"histogram\"}\n\t\t\t\t\t\tonChange={(e) => setChartType(e.target.checked ? \"histogram\" : \"heatmap\")}\n\t\t\t\t\t/>\n\t\t\t\t\t<Typography>\n\t\t\t\t\t\t{t(\"pages.statusPages.monitorsList.chartTypeHistogram\")}\n\t\t\t\t\t</Typography>\n\t\t\t\t</Stack>\n\t\t\t)}\n\n\t\t\t{monitors.map((monitor) => (\n\t\t\t\t<BaseBox\n\t\t\t\t\tkey={monitor.id}\n\t\t\t\t\tpadding={theme.spacing(LAYOUT.MD)}\n\t\t\t\t>\n\t\t\t\t\t<MonitorHeader\n\t\t\t\t\t\tmonitor={monitor}\n\t\t\t\t\t\tshowURL={showURL}\n\t\t\t\t\t/>\n\t\t\t\t\t<MonitorContent\n\t\t\t\t\t\tmonitor={monitor}\n\t\t\t\t\t\tstatusPage={statusPage}\n\t\t\t\t\t\tchartType={chartType}\n\t\t\t\t\t/>\n\t\t\t\t</BaseBox>\n\t\t\t))}\n\t\t</Stack>\n\t);\n};\n"
  },
  {
    "path": "client/src/Pages/StatusPage/Status/Components/StatusBar.tsx",
    "content": "import { AlertTriangle, CircleCheck } from \"lucide-react\";\nimport Stack from \"@mui/material/Stack\";\nimport Typography from \"@mui/material/Typography\";\n\nimport { useTranslation } from \"react-i18next\";\nimport type { Theme } from \"@mui/material\";\nimport { useTheme } from \"@mui/material\";\nimport type { Monitor } from \"@/Types/Monitor\";\n\nconst getMonitorStatus = (monitors: Monitor[], theme: Theme, t: Function) => {\n\tconst monitorsStatus: Record<string, any> = {\n\t\ticon: <AlertTriangle size={24} />,\n\t};\n\n\tif (monitors.every((monitor) => monitor.status === \"up\")) {\n\t\tmonitorsStatus.msg = t(\"pages.statusPages.statusBar.allUp\");\n\t\tmonitorsStatus.color = theme.palette.success.main;\n\t\tmonitorsStatus.icon = <CircleCheck size={24} />;\n\t\treturn monitorsStatus;\n\t} else if (monitors.every((monitor) => monitor.status === \"down\")) {\n\t\tmonitorsStatus.msg = t(\"pages.statusPages.statusBar.allDown\");\n\t\tmonitorsStatus.color = theme.palette.error.main;\n\t\treturn monitorsStatus;\n\t} else if (monitors.some((monitor) => monitor.status === \"down\")) {\n\t\tmonitorsStatus.msg = t(\"pages.statusPages.statusBar.degraded\");\n\t\tmonitorsStatus.color = theme.palette.warning.main;\n\t\treturn monitorsStatus;\n\t} else {\n\t\tmonitorsStatus.msg = t(\"pages.statusPages.statusBar.unknown\");\n\t\tmonitorsStatus.color = theme.palette.warning.main;\n\t\treturn monitorsStatus;\n\t}\n};\n\ninterface StatusBarProps {\n\tmonitors: Monitor[];\n}\n\nexport const StatusBar = ({ monitors }: StatusBarProps) => {\n\tconst theme = useTheme();\n\tconst { t } = useTranslation();\n\tconst monitorsStatus = getMonitorStatus(monitors, theme, t);\n\n\treturn (\n\t\t<Stack\n\t\t\tdirection=\"row\"\n\t\t\talignItems=\"center\"\n\t\t\tjustifyContent=\"center\"\n\t\t\tgap={theme.spacing(2)}\n\t\t\theight={theme.spacing(30)}\n\t\t\tbgcolor={monitorsStatus.color}\n\t\t\tborderRadius={theme.shape.borderRadius}\n\t\t>\n\t\t\t{monitorsStatus.icon}\n\t\t\t<Typography>{monitorsStatus.msg}</Typography>\n\t\t</Stack>\n\t);\n};\n"
  },
  {
    "path": "client/src/Pages/StatusPage/Status/index.tsx",
    "content": "import { BasePage, BaseFallback } from \"@/Components/design-elements\";\nimport { StatusBar } from \"@/Pages/StatusPage/Status/Components/StatusBar\";\nimport { MonitorsList } from \"@/Pages/StatusPage/Status/Components/MonitorsList\";\nimport Typography from \"@mui/material/Typography\";\nimport { Link } from \"react-router-dom\";\nimport Stack from \"@mui/material/Stack\";\nimport Box from \"@mui/material/Box\";\n\nimport { useMediaQuery, useTheme } from \"@mui/material\";\nimport { useTranslation } from \"react-i18next\";\nimport { useIsAdmin } from \"@/Hooks/useIsAdmin\";\nimport { useLocation, useParams } from \"react-router-dom\";\nimport { useGet } from \"@/Hooks/UseApi\";\nimport type { StatusPageResponse } from \"@/Types/StatusPage\";\nimport { HeaderStatusPageControls } from \"./Components/HeaderStatusPageControls\";\n\nconst StatusPageView = () => {\n\tconst theme = useTheme();\n\tconst { t } = useTranslation();\n\tconst { url } = useParams();\n\tconst isAdmin = useIsAdmin();\n\tconst location = useLocation();\n\tconst isSmall = useMediaQuery(theme.breakpoints.down(\"md\"));\n\tconst isPublic = location.pathname.startsWith(\"/status/public\");\n\n\tconst apiUrl = url ? `/status-page/${url}?type=uptime&type=infrastructure` : null;\n\n\tconst { data, isLoading, error } = useGet<StatusPageResponse>(\n\t\tapiUrl,\n\t\t{},\n\t\t{\n\t\t\trefreshInterval: 10000,\n\t\t}\n\t);\n\n\tconst statusPage = data?.statusPage;\n\tconst monitors = data?.monitors ?? [];\n\n\tif (!statusPage) return null;\n\n\tif (monitors.length === 0) {\n\t\treturn (\n\t\t\t<BasePage\n\t\t\t\tloading={isLoading}\n\t\t\t\terror={error}\n\t\t\t\tbreadcrumbOverride={isPublic ? [] : undefined}\n\t\t\t>\n\t\t\t\t<Stack alignItems={\"center\"}>\n\t\t\t\t\t<BaseFallback>\n\t\t\t\t\t\t<Typography\n\t\t\t\t\t\t\tvariant=\"h1\"\n\t\t\t\t\t\t\tmarginY={theme.spacing(4)}\n\t\t\t\t\t\t\tcolor={theme.palette.text.secondary}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{t(\"pages.statusPages.details.empty.title\")}\n\t\t\t\t\t\t</Typography>\n\t\t\t\t\t\t{isAdmin && (\n\t\t\t\t\t\t\t<Link to={`/status/configure/${url}`}>\n\t\t\t\t\t\t\t\t{t(\"pages.statusPages.details.empty.addMonitor\")}\n\t\t\t\t\t\t\t</Link>\n\t\t\t\t\t\t)}\n\t\t\t\t\t</BaseFallback>\n\t\t\t\t</Stack>\n\t\t\t</BasePage>\n\t\t);\n\t}\n\n\tlet sx: React.CSSProperties = {};\n\tif (isPublic) {\n\t\tsx.paddingTop = theme.spacing(20);\n\t\tsx.paddingLeft = isSmall ? \"5vw\" : \"20vw\";\n\t\tsx.paddingRight = isSmall ? \"5vw\" : \"20vw\";\n\t}\n\n\tconst logoSrc = statusPage.logo?.data\n\t\t? `data:${statusPage.logo.contentType};base64,${statusPage.logo.data}`\n\t\t: null;\n\n\treturn (\n\t\t<BasePage\n\t\t\tloading={isLoading}\n\t\t\terror={error}\n\t\t\tsx={sx}\n\t\t\tbreadcrumbOverride={isPublic ? [] : undefined}\n\t\t>\n\t\t\t<HeaderStatusPageControls\n\t\t\t\tisAdmin={isAdmin}\n\t\t\t\tstatusPage={statusPage}\n\t\t\t\tisPublic={isPublic}\n\t\t\t/>\n\t\t\t{logoSrc && (\n\t\t\t\t<Box\n\t\t\t\t\tcomponent=\"img\"\n\t\t\t\t\tsrc={logoSrc}\n\t\t\t\t\talignSelf={\"flex-start\"}\n\t\t\t\t\talt={statusPage.companyName}\n\t\t\t\t\tsx={{\n\t\t\t\t\t\tmaxHeight: 120,\n\t\t\t\t\t\tmaxWidth: \"100%\",\n\t\t\t\t\t\tobjectFit: \"contain\",\n\t\t\t\t\t\tmb: 2,\n\t\t\t\t\t}}\n\t\t\t\t/>\n\t\t\t)}\n\t\t\t<StatusBar monitors={monitors} />\n\t\t\t<MonitorsList\n\t\t\t\tstatusPage={statusPage}\n\t\t\t\tmonitors={monitors}\n\t\t\t/>\n\t\t</BasePage>\n\t);\n};\n\nexport default StatusPageView;\n"
  },
  {
    "path": "client/src/Pages/StatusPage/StatusPages/Components/StatusPagesTable.tsx",
    "content": "import Box from \"@mui/material/Box\";\nimport Stack from \"@mui/material/Stack\";\nimport Typography from \"@mui/material/Typography\";\nimport { Table, type Header, ValueLabel } from \"@/Components/design-elements\";\nimport { ActionsMenu, type ActionMenuItem } from \"@/Components/actions-menu\";\nimport { ExternalLink } from \"lucide-react\";\n\nimport { useTranslation } from \"react-i18next\";\nimport { useTheme } from \"@mui/material/styles\";\nimport { useNavigate } from \"react-router-dom\";\n\nimport type { StatusPage } from \"@/Types/StatusPage\";\n\ninterface StatusPagesTableProps {\n\tdata: StatusPage[];\n\tsetSelectedStatusPage: (statusPage: StatusPage | null) => void;\n}\n\nexport const StatusPagesTable = ({\n\tdata,\n\tsetSelectedStatusPage,\n}: StatusPagesTableProps) => {\n\tconst { t } = useTranslation();\n\tconst theme = useTheme();\n\tconst navigate = useNavigate();\n\n\tconst getActions = (row: StatusPage): ActionMenuItem[] => {\n\t\treturn [\n\t\t\t{\n\t\t\t\tid: 1,\n\t\t\t\tlabel: t(\"common.buttons.configure\"),\n\t\t\t\taction: () => {\n\t\t\t\t\tnavigate(`/status/configure/${row.url}`);\n\t\t\t\t},\n\t\t\t\tcloseMenu: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 2,\n\t\t\t\tlabel: (\n\t\t\t\t\t<Typography color={theme.palette.error.main}>\n\t\t\t\t\t\t{t(\"common.buttons.delete\")}\n\t\t\t\t\t</Typography>\n\t\t\t\t),\n\t\t\t\taction: () => setSelectedStatusPage(row),\n\t\t\t\tcloseMenu: true,\n\t\t\t},\n\t\t];\n\t};\n\n\tconst handleUrlClick = (e: React.MouseEvent, row: StatusPage) => {\n\t\tif (row.isPublished) {\n\t\t\te.stopPropagation();\n\t\t\tconst url = `/status/public/${row.url}`;\n\t\t\twindow.open(url, \"_blank\", \"noopener,noreferrer\");\n\t\t}\n\t};\n\n\tconst getHeaders = (): Header<StatusPage>[] => {\n\t\treturn [\n\t\t\t{\n\t\t\t\tid: \"name\",\n\t\t\t\tcontent: t(\"pages.statusPages.table.headers.name\"),\n\t\t\t\trender: (row) => row.companyName,\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"url\",\n\t\t\t\tcontent: t(\"pages.statusPages.table.headers.url\"),\n\t\t\t\trender: (row) => {\n\t\t\t\t\tconst content = row.isPublished\n\t\t\t\t\t\t? `/${row.url}`\n\t\t\t\t\t\t: t(\"pages.statusPages.table.unpublished\");\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<Stack\n\t\t\t\t\t\t\tdirection=\"row\"\n\t\t\t\t\t\t\talignItems=\"center\"\n\t\t\t\t\t\t\tjustifyContent=\"center\"\n\t\t\t\t\t\t\tgap={theme.spacing(2)}\n\t\t\t\t\t\t\tpaddingLeft={theme.spacing(2)}\n\t\t\t\t\t\t\tpaddingRight={theme.spacing(2)}\n\t\t\t\t\t\t\tonClick={(e) => handleUrlClick(e, row)}\n\t\t\t\t\t\t\tsx={{\n\t\t\t\t\t\t\t\t...(row.isPublished && {\n\t\t\t\t\t\t\t\t\tdisplay: \"inline-flex\",\n\t\t\t\t\t\t\t\t\t\":hover\": {\n\t\t\t\t\t\t\t\t\t\tcursor: \"pointer\",\n\t\t\t\t\t\t\t\t\t\tborderBottom: 1,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<Typography>{content}</Typography>\n\t\t\t\t\t\t\t{row.isPublished && <ExternalLink size={18} />}\n\t\t\t\t\t\t</Stack>\n\t\t\t\t\t);\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"type\",\n\t\t\t\tcontent: t(\"common.table.headers.type\"),\n\t\t\t\trender: (row) => row.type.join(\", \"),\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"status\",\n\t\t\t\tcontent: t(\"common.table.headers.status\"),\n\t\t\t\trender: (row) => {\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<ValueLabel\n\t\t\t\t\t\t\tvalue={row.isPublished ? \"positive\" : \"neutral\"}\n\t\t\t\t\t\t\ttext={\n\t\t\t\t\t\t\t\trow.isPublished\n\t\t\t\t\t\t\t\t\t? t(\"pages.statusPages.table.published\")\n\t\t\t\t\t\t\t\t\t: t(\"pages.statusPages.table.unpublished\")\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t/>\n\t\t\t\t\t);\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"actions\",\n\t\t\t\tcontent: t(\"common.table.headers.actions\"),\n\t\t\t\trender: (row) => {\n\t\t\t\t\treturn <ActionsMenu items={getActions(row)} />;\n\t\t\t\t},\n\t\t\t},\n\t\t];\n\t};\n\n\tconst handleRowClick = (statusPage: StatusPage) => {\n\t\tnavigate(`/status/${statusPage.url}`);\n\t};\n\n\treturn (\n\t\t<Box>\n\t\t\t<Table\n\t\t\t\theaders={getHeaders()}\n\t\t\t\tdata={data}\n\t\t\t\tonRowClick={handleRowClick}\n\t\t\t\temptyViewText={t(\"common.table.empty\")}\n\t\t\t/>\n\t\t</Box>\n\t);\n};\n\nexport default StatusPagesTable;\n"
  },
  {
    "path": "client/src/Pages/StatusPage/StatusPages/index.tsx",
    "content": "import { useState } from \"react\";\nimport { BasePageWithStates } from \"@/Components/design-elements\";\nimport { Dialog } from \"@/Components/inputs\";\nimport { StatusPagesTable } from \"./Components/StatusPagesTable\";\nimport { useGet, useDelete } from \"@/Hooks/UseApi\";\nimport type { StatusPage } from \"@/Types/StatusPage\";\nimport { useTranslation } from \"react-i18next\";\nimport { HeaderCreate } from \"@/Components/common\";\nimport { useIsAdmin } from \"@/Hooks/useIsAdmin\";\n\nconst StatusPages = () => {\n\tconst { t } = useTranslation();\n\n\tconst {\n\t\tdata: statusPages,\n\t\tisLoading,\n\t\terror,\n\t\trefetch,\n\t} = useGet<StatusPage[]>(\"/status-page/team\");\n\n\tconst { deleteFn, loading: isDeleting } = useDelete();\n\tconst [selectedStatusPage, setSelectedStatusPage] = useState<StatusPage | null>(null);\n\tconst isDialogOpen = Boolean(selectedStatusPage);\n\n\tconst isAdmin = useIsAdmin();\n\n\tconst handleConfirm = async () => {\n\t\tif (!selectedStatusPage) return;\n\t\tawait deleteFn(`/status-page/${selectedStatusPage.id}`);\n\t\tsetSelectedStatusPage(null);\n\t\trefetch();\n\t};\n\n\tconst handleCancel = () => {\n\t\tsetSelectedStatusPage(null);\n\t};\n\n\treturn (\n\t\t<BasePageWithStates\n\t\t\tpage={t(\"pages.statusPages.title\")}\n\t\t\tloading={isLoading}\n\t\t\tbullets={\n\t\t\t\tt(\"pages.statusPages.fallback.checks\", { returnObjects: true }) as string[]\n\t\t\t}\n\t\t\terror={!!error}\n\t\t\ttotalCount={statusPages?.length ?? 0}\n\t\t\tactionButtonText={t(\"pages.statusPages.fallback.actionButton\")}\n\t\t\tactionLink=\"/status/create\"\n\t\t>\n\t\t\t<HeaderCreate\n\t\t\t\tpath=\"/status/create\"\n\t\t\t\tisAdmin={isAdmin}\n\t\t\t/>\n\t\t\t<StatusPagesTable\n\t\t\t\tdata={statusPages ?? []}\n\t\t\t\tsetSelectedStatusPage={setSelectedStatusPage}\n\t\t\t/>\n\t\t\t<Dialog\n\t\t\t\topen={isDialogOpen}\n\t\t\t\ttitle={t(\"common.dialogs.delete.title\")}\n\t\t\t\tcontent={t(\"common.dialogs.delete.description\")}\n\t\t\t\tonConfirm={handleConfirm}\n\t\t\t\tonCancel={handleCancel}\n\t\t\t\tloading={isDeleting}\n\t\t\t/>\n\t\t</BasePageWithStates>\n\t);\n};\n\nexport default StatusPages;\n"
  },
  {
    "path": "client/src/Pages/Uptime/Details/Components/ChecksTable.tsx",
    "content": "import { Table, Pagination, StatusLabel } from \"@/Components/design-elements\";\nimport Box from \"@mui/material/Box\";\nimport type { Header } from \"@/Components/design-elements\";\nimport type { Check } from \"@/Types/Check\";\n\nimport { useNavigate } from \"react-router\";\nimport { useTranslation } from \"react-i18next\";\nimport { formatDateWithTz } from \"@/Utils/TimeUtils\";\nimport type { RootState } from \"@/Types/state\";\nimport { useSelector } from \"react-redux\";\n\nconst getHeaders = (t: Function, uiTimezone: string) => {\n\tconst headers: Header<Check>[] = [\n\t\t{\n\t\t\tid: \"status\",\n\t\t\tcontent: t(\"common.table.headers.status\"),\n\t\t\trender: (row) => {\n\t\t\t\treturn <StatusLabel status={row.status === true ? \"up\" : \"down\"} />;\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: \"date\",\n\t\t\tcontent: t(\"common.table.headers.dateTime\"),\n\t\t\trender: (row) => {\n\t\t\t\treturn formatDateWithTz(row.createdAt, \"ddd, MMMM D, YYYY, HH:mm A\", uiTimezone);\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: \"message\",\n\t\t\tcontent: t(\"common.table.headers.message\"),\n\t\t\trender: (row) => {\n\t\t\t\treturn row.message || \"N/A\";\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: \"statusCode\",\n\t\t\tcontent: t(\"pages.checks.table.headers.statusCode\"),\n\t\t\trender: (row) => {\n\t\t\t\treturn row.statusCode || \"N/A\";\n\t\t\t},\n\t\t},\n\t];\n\treturn headers;\n};\n\nexport const ChecksTable = ({\n\tchecks,\n\tcount,\n\tpage,\n\tsetPage,\n\trowsPerPage,\n\tsetRowsPerPage,\n}: {\n\tchecks: Check[];\n\tcount: number;\n\tpage: number;\n\tsetPage: (page: number) => void;\n\trowsPerPage: number;\n\tsetRowsPerPage: (rowsPerPage: number) => void;\n}) => {\n\tconst navigate = useNavigate();\n\tconst { t } = useTranslation();\n\tconst uiTimezone = useSelector((state: RootState) => state.ui.timezone);\n\tconst headers = getHeaders(t, uiTimezone);\n\n\tconst handlePageChange = (\n\t\t_e: React.MouseEvent<HTMLButtonElement> | null,\n\t\tnewPage: number\n\t) => {\n\t\tsetPage(newPage);\n\t};\n\n\tconst handleRowsPerPageChange = (\n\t\te: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>\n\t) => {\n\t\tconst value = Number(e.target.value);\n\t\tsetPage(0);\n\t\tsetRowsPerPage(value);\n\t};\n\n\treturn (\n\t\t<Box>\n\t\t\t<Table\n\t\t\t\theaders={headers}\n\t\t\t\tdata={checks}\n\t\t\t\tonRowClick={(row) => {\n\t\t\t\t\tnavigate(`/checks/${row.id}`);\n\t\t\t\t}}\n\t\t\t/>\n\t\t\t<Pagination\n\t\t\t\tcomponent=\"div\"\n\t\t\t\tcount={count}\n\t\t\t\tpage={page}\n\t\t\t\trowsPerPage={rowsPerPage}\n\t\t\t\tonPageChange={handlePageChange}\n\t\t\t\tonRowsPerPageChange={handleRowsPerPageChange}\n\t\t\t/>\n\t\t</Box>\n\t);\n};\n"
  },
  {
    "path": "client/src/Pages/Uptime/Details/Components/GeoChecksTable.tsx",
    "content": "import { Table, Pagination, StatusLabel } from \"@/Components/design-elements\";\nimport Box from \"@mui/material/Box\";\nimport type { Header } from \"@/Components/design-elements\";\nimport type { FlatGeoCheck } from \"@/Types/GeoCheck\";\nimport { useTranslation } from \"react-i18next\";\nimport { formatDateWithTz } from \"@/Utils/TimeUtils\";\nimport type { RootState } from \"@/Types/state\";\nimport { useSelector } from \"react-redux\";\nimport prettyMilliseconds from \"pretty-ms\";\n\nconst getHeaders = (t: Function, uiTimezone: string) => {\n\tconst headers: Header<FlatGeoCheck>[] = [\n\t\t{\n\t\t\tid: \"status\",\n\t\t\tcontent: t(\"common.table.headers.status\"),\n\t\t\trender: (row) => {\n\t\t\t\tconst status = row.status ? \"up\" : \"down\";\n\t\t\t\treturn <StatusLabel status={status} />;\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: \"date\",\n\t\t\tcontent: t(\"common.table.headers.dateTime\"),\n\t\t\trender: (row) => {\n\t\t\t\treturn formatDateWithTz(row.createdAt, \"ddd, MMMM D, YYYY, HH:mm A\", uiTimezone);\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: \"statusCode\",\n\t\t\tcontent: t(\"pages.checks.table.headers.statusCode\"),\n\t\t\trender: (row) => {\n\t\t\t\treturn row.statusCode || \"N/A\";\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: \"location\",\n\t\t\tcontent: t(\"pages.checks.table.headers.location\"),\n\t\t\trender: (row) => {\n\t\t\t\tconst location = row.location;\n\t\t\t\tif (!location) return \"N/A\";\n\t\t\t\tconst { continent, country, city } = location;\n\t\t\t\treturn `${continent} - ${country}, ${city}`;\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: \"responseTime\",\n\t\t\tcontent: t(\"common.table.headers.responseTime\"),\n\t\t\trender: (row) => {\n\t\t\t\tif (!row.timings?.total) return \"N/A\";\n\t\t\t\treturn prettyMilliseconds(row.timings.total, { compact: true });\n\t\t\t},\n\t\t},\n\t];\n\treturn headers;\n};\n\nexport const GeoChecksTable = ({\n\tgeoChecks,\n\tcount,\n\tpage,\n\tsetPage,\n\trowsPerPage,\n\tsetRowsPerPage,\n}: {\n\tgeoChecks: FlatGeoCheck[];\n\tcount: number;\n\tpage: number;\n\tsetPage: (page: number) => void;\n\trowsPerPage: number;\n\tsetRowsPerPage: (rowsPerPage: number) => void;\n}) => {\n\tconst { t } = useTranslation();\n\tconst uiTimezone = useSelector((state: RootState) => state.ui.timezone);\n\tconst headers = getHeaders(t, uiTimezone);\n\n\tconst handlePageChange = (\n\t\t_e: React.MouseEvent<HTMLButtonElement> | null,\n\t\tnewPage: number\n\t) => {\n\t\tsetPage(newPage);\n\t};\n\n\tconst handleRowsPerPageChange = (\n\t\te: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>\n\t) => {\n\t\tconst value = Number(e.target.value);\n\t\tsetPage(0);\n\t\tsetRowsPerPage(value);\n\t};\n\n\treturn (\n\t\t<Box>\n\t\t\t<Table\n\t\t\t\theaders={headers}\n\t\t\t\tdata={geoChecks}\n\t\t\t/>\n\t\t\t<Pagination\n\t\t\t\tcomponent=\"div\"\n\t\t\t\tcount={count}\n\t\t\t\tpage={page}\n\t\t\t\trowsPerPage={rowsPerPage}\n\t\t\t\tonPageChange={handlePageChange}\n\t\t\t\tonRowsPerPageChange={handleRowsPerPageChange}\n\t\t\t/>\n\t\t</Box>\n\t);\n};\n"
  },
  {
    "path": "client/src/Pages/Uptime/Details/index.tsx",
    "content": "import { BasePage } from \"@/Components/design-elements\";\nimport { HeaderTimeRange } from \"@/Components/common\";\nimport Stack from \"@mui/material/Stack\";\nimport {\n\tHistogramStatus,\n\tRadialAvgResponse,\n\tHistogramDetails,\n\tHeaderMonitorControls,\n\tHeaderGeoTabs,\n\tGeoChecksMap,\n} from \"@/Components/monitors\";\nimport { TrendingUp, AlertTriangle } from \"lucide-react\";\nimport { ChecksTable } from \"@/Pages/Uptime/Details/Components/ChecksTable\";\nimport { GeoChecksTable } from \"@/Pages/Uptime/Details/Components/GeoChecksTable\";\nimport { MonitorStatBoxes } from \"@/Components/monitors\";\n\nimport { useTheme } from \"@mui/material/styles\";\nimport { useIsAdmin } from \"@/Hooks/useIsAdmin\";\nimport { useState, useMemo } from \"react\";\nimport { useParams } from \"react-router-dom\";\nimport { useSelector } from \"react-redux\";\nimport { useGet } from \"@/Hooks/UseApi\";\nimport { type MonitorDetailsResponse, supportsGeoCheck } from \"@/Types/Monitor\";\nimport type { ChecksResponse } from \"@/Types/Check\";\nimport type {\n\tGeoChecksResult,\n\tFlatGeoChecksResponse,\n\tGeoContinent,\n} from \"@/Types/GeoCheck\";\nimport type { RootState } from \"@/Types/state\";\nimport { formatDateWithTz } from \"@/Utils/TimeUtils\";\nimport { t } from \"i18next\";\nimport { Typography } from \"@mui/material\";\n\nconst certificateDateFormat = \"MMM D, YYYY h A\";\n\ninterface CertificateResponse {\n\tcertificateDate: string;\n}\n\nconst UptimeDetailsPage = () => {\n\tconst theme = useTheme();\n\tconst isAdmin = useIsAdmin();\n\tconst { monitorId } = useParams<{ monitorId: string }>();\n\tconst uiTimezone = useSelector((state: RootState) => state.ui.timezone);\n\n\tconst [page, setPage] = useState<number>(0);\n\tconst [rowsPerPage, setRowsPerPage] = useState<number>(5);\n\tconst [geoPage, setGeoPage] = useState<number>(0);\n\tconst [geoRowsPerPage, setGeoRowsPerPage] = useState<number>(5);\n\tconst [dateRange, setDateRange] = useState<string>(\"recent\");\n\tconst [selectedLocation, setSelectedLocation] = useState<GeoContinent>(\"NA\");\n\n\tconst monitorDetailsUrl = useMemo(() => {\n\t\tif (!monitorId) {\n\t\t\treturn null;\n\t\t}\n\t\tconst params = new URLSearchParams();\n\t\tparams.append(\"dateRange\", dateRange);\n\t\tparams.append(\"normalize\", \"true\");\n\t\treturn `/monitors/uptime/details/${monitorId}?${params.toString()}`;\n\t}, [monitorId, dateRange]);\n\n\tconst {\n\t\tdata: monitorDetailsData,\n\t\tisLoading: monitorIsLoading,\n\t\trefetch: refetchMonitor,\n\t} = useGet<MonitorDetailsResponse>(\n\t\tmonitorDetailsUrl,\n\t\t{},\n\t\t{ refreshInterval: 10000, keepPreviousData: true, revalidateOnFocus: false }\n\t);\n\n\tconst monitorData = monitorDetailsData?.monitorData;\n\tconst monitor = monitorData?.monitor;\n\tconst monitorStats = monitorDetailsData?.monitorStats ?? null;\n\n\t// Certificate fetch - only for HTTP monitors\n\tconst certificateUrl = useMemo(() => {\n\t\tif (!monitorId || monitor?.type !== \"http\") {\n\t\t\treturn null;\n\t\t}\n\t\treturn `/monitors/certificate/${monitorId}`;\n\t}, [monitorId, monitor?.type]);\n\n\tconst { data: certificateData } = useGet<CertificateResponse>(\n\t\tcertificateUrl,\n\t\t{},\n\t\t{ revalidateOnFocus: false }\n\t);\n\n\tconst certificateExpiry = useMemo(() => {\n\t\tif (!certificateData?.certificateDate) {\n\t\t\treturn undefined;\n\t\t}\n\t\treturn (\n\t\t\tformatDateWithTz(\n\t\t\t\tcertificateData.certificateDate,\n\t\t\t\tcertificateDateFormat,\n\t\t\t\tuiTimezone\n\t\t\t) ?? \"N/A\"\n\t\t);\n\t}, [certificateData, uiTimezone]);\n\n\tconst checksUrl = useMemo(() => {\n\t\tif (!monitorId || !monitor?.type) {\n\t\t\treturn null;\n\t\t}\n\t\tconst params = new URLSearchParams();\n\t\tparams.append(\"type\", monitor.type);\n\t\tparams.append(\"sortOrder\", \"desc\");\n\t\tparams.append(\"dateRange\", dateRange);\n\t\tparams.append(\"page\", String(page));\n\t\tparams.append(\"rowsPerPage\", String(rowsPerPage));\n\t\treturn `/checks/${monitorId}?${params.toString()}`;\n\t}, [monitorId, monitor?.type, dateRange, page, rowsPerPage]);\n\n\tconst { data: checksData, isLoading: checksIsLoading } = useGet<ChecksResponse>(\n\t\tchecksUrl,\n\t\t{},\n\t\t{ keepPreviousData: true, revalidateOnFocus: false }\n\t);\n\n\tconst geoChecksUrl = useMemo(() => {\n\t\tif (!monitorId || !supportsGeoCheck(monitor?.type) || !monitor?.geoCheckEnabled) {\n\t\t\treturn null;\n\t\t}\n\t\tconst params = new URLSearchParams();\n\t\tparams.append(\"dateRange\", dateRange);\n\t\tparams.append(\"continent\", selectedLocation);\n\t\treturn `/monitors/${monitorId}/geo-checks?${params.toString()}`;\n\t}, [monitorId, monitor?.type, monitor?.geoCheckEnabled, dateRange, selectedLocation]);\n\n\tconst { data: geoGroupedData } = useGet<GeoChecksResult>(\n\t\tgeoChecksUrl,\n\t\t{},\n\t\t{ keepPreviousData: true, revalidateOnFocus: false }\n\t);\n\n\tconst geoGroupedChecks = geoGroupedData?.groupedGeoChecks ?? [];\n\n\t// Fetch paginated geo checks for the table\n\tconst geoChecksTableUrl = useMemo(() => {\n\t\tif (!monitorId || !supportsGeoCheck(monitor?.type) || !monitor?.geoCheckEnabled) {\n\t\t\treturn null;\n\t\t}\n\t\tconst params = new URLSearchParams();\n\t\tparams.append(\"sortOrder\", \"desc\");\n\t\tparams.append(\"dateRange\", dateRange);\n\t\tparams.append(\"page\", String(geoPage));\n\t\tparams.append(\"rowsPerPage\", String(geoRowsPerPage));\n\t\treturn `/geo-checks/${monitorId}?${params.toString()}`;\n\t}, [\n\t\tmonitorId,\n\t\tmonitor?.type,\n\t\tmonitor?.geoCheckEnabled,\n\t\tdateRange,\n\t\tgeoPage,\n\t\tgeoRowsPerPage,\n\t]);\n\n\tconst { data: geoChecksTableData } = useGet<FlatGeoChecksResponse>(\n\t\tgeoChecksTableUrl,\n\t\t{},\n\t\t{ keepPreviousData: true, revalidateOnFocus: false }\n\t);\n\n\tconst geoChecksForTable = geoChecksTableData?.geoChecks ?? [];\n\tconst geoChecksCount = geoChecksTableData?.geoChecksCount ?? 0;\n\n\tconst geoLocations = monitor?.geoCheckLocations;\n\n\tconst checks = checksData?.checks ?? [];\n\tconst checksCount = checksData?.checksCount ?? 0;\n\n\treturn (\n\t\t<BasePage>\n\t\t\t<HeaderMonitorControls\n\t\t\t\tpath=\"uptime\"\n\t\t\t\tmonitor={monitor}\n\t\t\t\tisAdmin={isAdmin}\n\t\t\t\trefetch={refetchMonitor}\n\t\t\t/>\n\t\t\t<MonitorStatBoxes\n\t\t\t\tmonitor={monitor}\n\t\t\t\tmonitorStats={monitorStats}\n\t\t\t\tcertificateExpiry={certificateExpiry}\n\t\t\t/>\n\t\t\t<HeaderTimeRange\n\t\t\t\tisLoading={monitorIsLoading || checksIsLoading}\n\t\t\t\thasDateRange={true}\n\t\t\t\tdateRange={dateRange}\n\t\t\t\tsetDateRange={setDateRange}\n\t\t\t/>\n\n\t\t\t<Stack\n\t\t\t\tdirection={{ xs: \"column\", md: \"row\" }}\n\t\t\t\tgap={theme.spacing(8)}\n\t\t\t>\n\t\t\t\t<HistogramStatus\n\t\t\t\t\ttitle={t(\"common.charts.labels.uptime\")}\n\t\t\t\t\ticon={<TrendingUp />}\n\t\t\t\t\tchecks={monitorData?.groupedUpChecks ?? []}\n\t\t\t\t\trange={dateRange}\n\t\t\t\t/>\n\t\t\t\t<HistogramStatus\n\t\t\t\t\ttitle={t(\"common.charts.labels.downtime\")}\n\t\t\t\t\ticon={<AlertTriangle />}\n\t\t\t\t\tchecks={monitorData?.groupedDownChecks ?? []}\n\t\t\t\t\trange={dateRange}\n\t\t\t\t/>\n\t\t\t\t<RadialAvgResponse\n\t\t\t\t\tavg={monitorStats?.avgResponseTime || 0}\n\t\t\t\t\tmax={500}\n\t\t\t\t/>\n\t\t\t</Stack>\n\t\t\t<HistogramDetails\n\t\t\t\tchecks={monitorData?.groupedChecks || []}\n\t\t\t\trange={dateRange}\n\t\t\t/>\n\t\t\t<ChecksTable\n\t\t\t\tchecks={checks}\n\t\t\t\tcount={checksCount}\n\t\t\t\tpage={page}\n\t\t\t\tsetPage={setPage}\n\t\t\t\trowsPerPage={rowsPerPage}\n\t\t\t\tsetRowsPerPage={setRowsPerPage}\n\t\t\t/>\n\n\t\t\t{monitor?.geoCheckEnabled && (\n\t\t\t\t<>\n\t\t\t\t\t<Typography variant=\"h1\">Location breakdown</Typography>\n\t\t\t\t\t<HeaderGeoTabs\n\t\t\t\t\t\tgeoCheckEnabled={monitor?.geoCheckEnabled ?? false}\n\t\t\t\t\t\tlocations={geoLocations}\n\t\t\t\t\t\tselectedLocation={selectedLocation}\n\t\t\t\t\t\tonLocationChange={setSelectedLocation}\n\t\t\t\t\t/>\n\t\t\t\t\t<HistogramDetails\n\t\t\t\t\t\tchecks={geoGroupedChecks}\n\t\t\t\t\t\trange={dateRange}\n\t\t\t\t\t/>\n\t\t\t\t\t<GeoChecksTable\n\t\t\t\t\t\tgeoChecks={geoChecksForTable}\n\t\t\t\t\t\tcount={geoChecksCount}\n\t\t\t\t\t\tpage={geoPage}\n\t\t\t\t\t\tsetPage={setGeoPage}\n\t\t\t\t\t\trowsPerPage={geoRowsPerPage}\n\t\t\t\t\t\tsetRowsPerPage={setGeoRowsPerPage}\n\t\t\t\t\t/>\n\t\t\t\t\t<GeoChecksMap geoChecks={geoChecksForTable} />\n\t\t\t\t</>\n\t\t\t)}\n\t\t</BasePage>\n\t);\n};\n\nexport default UptimeDetailsPage;\n"
  },
  {
    "path": "client/src/Pages/Uptime/Monitors/Components/UptimeMonitorsTable.tsx",
    "content": "import Stack from \"@mui/material/Stack\";\nimport Box from \"@mui/material/Box\";\nimport Typography from \"@mui/material/Typography\";\nimport {\n\tTable,\n\ttype Header,\n\tPagination,\n\tStatusLabel,\n} from \"@/Components/design-elements\";\nimport { HeatmapResponseTime, HistogramResponseTime } from \"@/Components/common\";\nimport { ActionsMenu } from \"@/Components/actions-menu\";\nimport { ArrowDown, ArrowUp } from \"lucide-react\";\n\nimport { useTranslation } from \"react-i18next\";\nimport { useTheme } from \"@mui/material/styles\";\nimport { useNavigate } from \"react-router-dom\";\nimport { usePost } from \"@/Hooks/UseApi\";\nimport { useSelector } from \"react-redux\";\n\nimport type { Monitor } from \"@/Types/Monitor\";\nimport type { ActionMenuItem } from \"@/Components/actions-menu\";\nimport type { RootState } from \"@/Types/state\";\n\nexport const MonitorTable = ({\n\tmonitors,\n\trefetch,\n\tsetSelectedMonitor,\n\tsortField,\n\tsetSortField,\n\tsortOrder,\n\tsetSortOrder,\n\tcount,\n\tpage,\n\tsetPage,\n\trowsPerPage,\n\tsetRowsPerPage,\n}: {\n\tmonitors: Monitor[];\n\trefetch: Function;\n\tsetSelectedMonitor: (monitor: Monitor | null) => void;\n\tsortField: string;\n\tsetSortField: (field: string) => void;\n\tsortOrder: \"asc\" | \"desc\";\n\tsetSortOrder: (order: \"asc\" | \"desc\") => void;\n\tcount: number;\n\tpage: number;\n\tsetPage: (page: number) => void;\n\trowsPerPage: number;\n\tsetRowsPerPage: (rowsPerPage: number) => void;\n}) => {\n\tconst { t } = useTranslation();\n\tconst theme = useTheme();\n\tconst navigate = useNavigate();\n\tconst chartType = useSelector((state: RootState) => state.ui?.chartType ?? \"histogram\");\n\tconst {\n\t\tpost,\n\t\t// loading: isPosting,\n\t\t// error: postError,\n\t} = usePost<any, Monitor>();\n\n\tconst handleSort = (e: any, field: string) => {\n\t\te.preventDefault();\n\t\te.stopPropagation();\n\t\tif (sortField === field) {\n\t\t\tconst newOrder = sortOrder === \"asc\" ? \"desc\" : \"asc\";\n\t\t\tsetSortOrder(newOrder);\n\t\t} else {\n\t\t\tsetSortField(field);\n\t\t\tsetSortOrder(\"asc\");\n\t\t}\n\t\trefetch();\n\t};\n\n\tconst getActions = (monitor: Monitor): ActionMenuItem[] => {\n\t\treturn [\n\t\t\t{\n\t\t\t\tid: 1,\n\t\t\t\tlabel: t(\"pages.common.monitors.actions.openSite\"),\n\t\t\t\taction: () => {\n\t\t\t\t\twindow.open(monitor.url, \"_blank\", \"noreferrer\");\n\t\t\t\t},\n\t\t\t\tcloseMenu: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 2,\n\t\t\t\tlabel: t(\"pages.common.monitors.actions.details\"),\n\t\t\t\taction: () => {\n\t\t\t\t\tnavigate(`${monitor.id}`);\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 3,\n\t\t\t\tlabel: t(\"pages.common.monitors.actions.incidents\"),\n\t\t\t\taction: () => {\n\t\t\t\t\tnavigate(`/incidents?monitorId=${monitor.id}`);\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 4,\n\t\t\t\tlabel: t(\"pages.common.monitors.actions.configure\"),\n\t\t\t\taction: () => {\n\t\t\t\t\tnavigate(`/uptime/configure/${monitor.id}`);\n\t\t\t\t},\n\t\t\t},\n\t\t\t// {\n\t\t\t//   id: 5,\n\t\t\t//   label: \"Clone\",\n\t\t\t//   action: () => {\n\n\t\t\t//   },\n\t\t\t// },\n\t\t\t{\n\t\t\t\tid: 6,\n\t\t\t\tlabel:\n\t\t\t\t\tmonitor.isActive === false\n\t\t\t\t\t\t? t(\"pages.common.monitors.actions.resume\")\n\t\t\t\t\t\t: t(\"pages.common.monitors.actions.pause\"),\n\t\t\t\taction: async () => {\n\t\t\t\t\tawait post(`/monitors/pause/${monitor.id}`, {});\n\t\t\t\t\trefetch();\n\t\t\t\t},\n\t\t\t\tcloseMenu: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 7,\n\t\t\t\tlabel: (\n\t\t\t\t\t<Typography color={theme.palette.error.main}>\n\t\t\t\t\t\t{t(\"pages.common.monitors.actions.delete\")}\n\t\t\t\t\t</Typography>\n\t\t\t\t),\n\t\t\t\taction: () => setSelectedMonitor(monitor),\n\t\t\t\tcloseMenu: true,\n\t\t\t},\n\t\t];\n\t};\n\n\tconst getHeaders = (chartType: string) => {\n\t\tconst renderSortIcon = (isActive: boolean) => (\n\t\t\t<Box\n\t\t\t\twidth={16}\n\t\t\t\tdisplay=\"inline-flex\"\n\t\t\t\tjustifyContent=\"center\"\n\t\t\t>\n\t\t\t\t{isActive ? (\n\t\t\t\t\tsortOrder === \"asc\" ? (\n\t\t\t\t\t\t<ArrowUp size={16} />\n\t\t\t\t\t) : (\n\t\t\t\t\t\t<ArrowDown size={16} />\n\t\t\t\t\t)\n\t\t\t\t) : null}\n\t\t\t</Box>\n\t\t);\n\t\tconst headers: Header<Monitor>[] = [\n\t\t\t{\n\t\t\t\tid: \"name\",\n\t\t\t\tcontent: (\n\t\t\t\t\t<Stack\n\t\t\t\t\t\tgap={theme.spacing(4)}\n\t\t\t\t\t\tdirection={\"row\"}\n\t\t\t\t\t\talignItems={\"center\"}\n\t\t\t\t\t\tonClick={(e) => handleSort(e, \"name\")}\n\t\t\t\t\t\tsx={{ cursor: \"pointer\" }}\n\t\t\t\t\t>\n\t\t\t\t\t\t{t(\"common.table.headers.name\")}\n\t\t\t\t\t\t{renderSortIcon(sortField === \"name\")}\n\t\t\t\t\t</Stack>\n\t\t\t\t),\n\n\t\t\t\trender: (row) => {\n\t\t\t\t\treturn row?.name;\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"status\",\n\t\t\t\tcontent: (\n\t\t\t\t\t<Stack\n\t\t\t\t\t\tgap={theme.spacing(4)}\n\t\t\t\t\t\tdirection={\"row\"}\n\t\t\t\t\t\tjustifyContent={\"center\"}\n\t\t\t\t\t\talignItems={\"center\"}\n\t\t\t\t\t\tonClick={(e) => handleSort(e, \"status\")}\n\t\t\t\t\t\tsx={{ cursor: \"pointer\" }}\n\t\t\t\t\t>\n\t\t\t\t\t\t<Box width={theme.spacing(8)} />\n\t\t\t\t\t\t{t(\"common.table.headers.status\")}\n\t\t\t\t\t\t{renderSortIcon(sortField === \"status\")}\n\t\t\t\t\t</Stack>\n\t\t\t\t),\n\t\t\t\trender: (row) => {\n\t\t\t\t\treturn <StatusLabel status={row.status} />;\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"histogram\",\n\t\t\t\tcontent: t(\"pages.uptime.table.headers.responseTime\"),\n\t\t\t\trender: (row) => {\n\t\t\t\t\tif (chartType === \"histogram\") {\n\t\t\t\t\t\treturn <HistogramResponseTime checks={row.recentChecks} />;\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn <HeatmapResponseTime checks={row.recentChecks} />;\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"type\",\n\t\t\t\tcontent: (\n\t\t\t\t\t<Stack\n\t\t\t\t\t\tgap={theme.spacing(4)}\n\t\t\t\t\t\tdirection={\"row\"}\n\t\t\t\t\t\tjustifyContent={\"center\"}\n\t\t\t\t\t\talignItems={\"center\"}\n\t\t\t\t\t\tonClick={(e) => handleSort(e, \"type\")}\n\t\t\t\t\t\tsx={{ cursor: \"pointer\" }}\n\t\t\t\t\t>\n\t\t\t\t\t\t<Box width={theme.spacing(8)} />\n\t\t\t\t\t\t{t(\"common.table.headers.type\")}\n\t\t\t\t\t\t{renderSortIcon(sortField === \"type\")}\n\t\t\t\t\t</Stack>\n\t\t\t\t),\n\t\t\t\trender: (row) => {\n\t\t\t\t\treturn row.type;\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"actions\",\n\t\t\t\tcontent: t(\"common.table.headers.actions\"),\n\t\t\t\trender: (row) => {\n\t\t\t\t\treturn <ActionsMenu items={getActions(row)} />;\n\t\t\t\t},\n\t\t\t},\n\t\t];\n\t\treturn headers;\n\t};\n\n\tconst headers = getHeaders(chartType);\n\n\treturn (\n\t\t<Box>\n\t\t\t<Table\n\t\t\t\theaders={headers}\n\t\t\t\tdata={monitors}\n\t\t\t\tonRowClick={(row) => {\n\t\t\t\t\tnavigate(`/uptime/${row.id}`);\n\t\t\t\t}}\n\t\t\t/>\n\t\t\t<Pagination\n\t\t\t\tcomponent=\"div\"\n\t\t\t\tcount={count}\n\t\t\t\tpage={page}\n\t\t\t\trowsPerPage={rowsPerPage}\n\t\t\t\tonPageChange={(_e, newPage) => setPage(newPage)}\n\t\t\t\tonRowsPerPageChange={(e) => setRowsPerPage(Number(e.target.value))}\n\t\t\t\titemsOnPage={monitors.length}\n\t\t\t/>\n\t\t</Box>\n\t);\n};\n"
  },
  {
    "path": "client/src/Pages/Uptime/Monitors/index.tsx",
    "content": "import { ControlsFilter, HeaderMonitorsSummary } from \"@/Components/monitors\";\nimport { MonitorBasePageWithStates } from \"@/Components/design-elements\";\nimport { TextField, Dialog } from \"@/Components/inputs\";\nimport Stack from \"@mui/material/Stack\";\nimport { MonitorTable } from \"@/Pages/Uptime/Monitors/Components/UptimeMonitorsTable\";\nimport { HeaderCreate } from \"@/Components/common\";\n\nimport { useTranslation } from \"react-i18next\";\nimport useMediaQuery from \"@mui/material/useMediaQuery\";\nimport { useGet, useDelete } from \"@/Hooks/UseApi\";\nimport type { Monitor, MonitorType, MonitorsWithChecksResponse } from \"@/Types/Monitor\";\nimport { useState, useMemo, useCallback } from \"react\";\nimport { useSelector, useDispatch } from \"react-redux\";\nimport { setRowsPerPage } from \"@/Features/UI/uiSlice.js\";\nimport { useIsAdmin } from \"@/Hooks/useIsAdmin\";\nimport type { RootState } from \"@/Types/state\";\nimport { useTheme } from \"@mui/material\";\nimport useDebounce from \"@/Hooks/useDebounce\";\n\nconst UptimeMonitorsPage = () => {\n\tconst { t } = useTranslation();\n\tconst theme = useTheme();\n\tconst isSmall = useMediaQuery(theme.breakpoints.down(\"md\"));\n\tconst dispatch = useDispatch();\n\tconst isAdmin = useIsAdmin();\n\t// Redux state\n\tconst rowsPerPage = useSelector(\n\t\t(state: RootState) => state.ui?.monitors?.rowsPerPage ?? 10\n\t);\n\n\t// Local state\n\tconst [selectedTypes, setSelectedTypes] = useState<MonitorType[]>([]);\n\tconst [selectedStatus, setSelectedStatus] = useState<string>(\"\");\n\tconst [selectedState, setSelectedState] = useState<string>(\"\");\n\tconst [page, setPage] = useState<number>(0);\n\tconst [search, setSearch] = useState<string>(\"\");\n\tconst [sortField, setSortField] = useState<string>(\"\");\n\tconst [sortOrder, setSortOrder] = useState<\"asc\" | \"desc\">(\"asc\");\n\tconst [selectedMonitor, setSelectedMonitor] = useState<Monitor | null>(null);\n\tconst isDialogOpen = Boolean(selectedMonitor);\n\n\tconst debouncedSearch = useDebounce<string>(search, 300);\n\n\t// Convert filter selections to API filter values\n\t// Status: pass \"up\"/\"down\" directly to the API\n\t// State: \"active\" -> true, \"paused\" -> false\n\tconst toFilterStatus = useMemo(() => {\n\t\tif (selectedStatus === \"up\") return \"up\";\n\t\tif (selectedStatus === \"down\") return \"down\";\n\t\treturn undefined;\n\t}, [selectedStatus]);\n\n\tconst toFilterActive = useMemo(() => {\n\t\tif (selectedState === \"active\") return \"true\";\n\t\tif (selectedState === \"paused\") return \"false\";\n\t\treturn undefined;\n\t}, [selectedState]);\n\n\t// Determine field and filter for the API request\n\t// Priority: status > isActive > search > sort\n\tconst filterLookup = new Map<string | undefined, string>([\n\t\t[toFilterStatus, \"status\"],\n\t\t[toFilterActive, \"isActive\"],\n\t]);\n\tconst activeFilter = [...filterLookup].find(([key]) => key !== undefined);\n\tconst field = activeFilter?.[1] || (debouncedSearch ? \"name\" : sortField || undefined);\n\tconst filter = activeFilter?.[0] || debouncedSearch;\n\n\t// Default to all types when none selected\n\tconst effectiveTypes =\n\t\tselectedTypes.length > 0\n\t\t\t? selectedTypes\n\t\t\t: [\"http\", \"ping\", \"docker\", \"port\", \"game\", \"grpc\", \"websocket\"];\n\n\t// Build URL for monitors with checks\n\tconst monitorsWithChecksUrl = useMemo(() => {\n\t\tconst params = new URLSearchParams();\n\t\teffectiveTypes.forEach((type) => params.append(\"type\", type));\n\t\tparams.append(\"limit\", \"25\");\n\t\tif (page !== undefined) params.append(\"page\", String(page));\n\t\tif (rowsPerPage) params.append(\"rowsPerPage\", String(rowsPerPage));\n\t\tif (filter) params.append(\"filter\", filter);\n\t\tif (field) params.append(\"field\", field);\n\t\tif (sortOrder) params.append(\"order\", sortOrder);\n\t\treturn `/monitors/team/with-checks?${params.toString()}`;\n\t}, [effectiveTypes, page, rowsPerPage, filter, field, sortOrder]);\n\n\tconst {\n\t\tdata: monitorsWithChecksData,\n\t\tisLoading: monitorsWithChecksLoading,\n\t\terror: monitorsWithChecksError,\n\t\trefetch,\n\t} = useGet<MonitorsWithChecksResponse>(\n\t\tmonitorsWithChecksUrl,\n\t\t{},\n\t\t{ refreshInterval: 5000, keepPreviousData: true }\n\t);\n\n\tconst {\n\t\tmonitors: monitorsWithChecks,\n\t\tsummary,\n\t\tcount,\n\t} = monitorsWithChecksData ?? { monitors: null, summary: null, count: 0 };\n\n\t// Delete hook\n\tconst { deleteFn, loading: isDeleting } = useDelete();\n\n\t// Handlers\n\tconst handleClearFilters = useCallback(() => {\n\t\tsetSelectedTypes([]);\n\t\tsetSelectedStatus(\"\");\n\t\tsetSelectedState(\"\");\n\t\tsetSearch(\"\");\n\t}, []);\n\n\tconst handleConfirm = async () => {\n\t\tif (!selectedMonitor) return;\n\t\tawait deleteFn(`/monitors/${selectedMonitor.id}`);\n\t\tsetSelectedMonitor(null);\n\t\trefetch();\n\t};\n\n\tconst handleCancel = () => {\n\t\tsetSelectedMonitor(null);\n\t};\n\n\tconst isLoading = monitorsWithChecksLoading;\n\n\t// Check if any filters are active\n\tconst hasActiveFilters = Boolean(\n\t\tselectedTypes.length > 0 || selectedStatus || selectedState || search\n\t);\n\n\t// Show empty state only when there are truly no monitors (not just filtered out)\n\t// If filters are active and count is 0, pass 1 to prevent empty state fallback\n\tconst effectiveTotalCount =\n\t\thasActiveFilters && (summary?.totalMonitors ?? 0) === 0\n\t\t\t? 1\n\t\t\t: (summary?.totalMonitors ?? 0);\n\n\treturn (\n\t\t<MonitorBasePageWithStates\n\t\t\tloading={isLoading}\n\t\t\terror={monitorsWithChecksError}\n\t\t\ttotalCount={effectiveTotalCount}\n\t\t\tpage=\"uptime\"\n\t\t\tactionLink=\"/uptime/create\"\n\t\t>\n\t\t\t<HeaderCreate\n\t\t\t\tpath=\"/uptime/create\"\n\t\t\t\tisLoading={isLoading}\n\t\t\t\tisAdmin={isAdmin}\n\t\t\t/>\n\n\t\t\t<HeaderMonitorsSummary summary={summary} />\n\n\t\t\t<Stack\n\t\t\t\tdirection={isSmall ? \"column\" : \"row\"}\n\t\t\t\tjustifyContent={isSmall ? \"flex-start\" : \"space-between\"}\n\t\t\t\tgap={theme.spacing(4)}\n\t\t\t>\n\t\t\t\t<ControlsFilter\n\t\t\t\t\tselectedTypes={selectedTypes}\n\t\t\t\t\tsetSelectedTypes={setSelectedTypes}\n\t\t\t\t\tselectedStatus={selectedStatus}\n\t\t\t\t\tsetSelectedStatus={setSelectedStatus}\n\t\t\t\t\tselectedState={selectedState}\n\t\t\t\t\tsetSelectedState={setSelectedState}\n\t\t\t\t\tonClearFilters={handleClearFilters}\n\t\t\t\t/>\n\t\t\t\t<TextField\n\t\t\t\t\tplaceholder={t(\"pages.uptime.filters.search.placeholder\")}\n\t\t\t\t\tvalue={search}\n\t\t\t\t\tonChange={(event) => {\n\t\t\t\t\t\tsetSearch(event.target.value);\n\t\t\t\t\t}}\n\t\t\t\t/>\n\t\t\t</Stack>\n\t\t\t<MonitorTable\n\t\t\t\tmonitors={monitorsWithChecks || []}\n\t\t\t\trefetch={refetch}\n\t\t\t\tsetSelectedMonitor={setSelectedMonitor}\n\t\t\t\tcount={count || 0}\n\t\t\t\tpage={page}\n\t\t\t\tsetPage={setPage}\n\t\t\t\trowsPerPage={rowsPerPage}\n\t\t\t\tsortField={sortField}\n\t\t\t\tsetSortField={setSortField}\n\t\t\t\tsortOrder={sortOrder}\n\t\t\t\tsetSortOrder={setSortOrder}\n\t\t\t\tsetRowsPerPage={(rowsPerPage: number) => {\n\t\t\t\t\tdispatch(\n\t\t\t\t\t\tsetRowsPerPage({\n\t\t\t\t\t\t\tvalue: rowsPerPage,\n\t\t\t\t\t\t\ttable: \"monitors\",\n\t\t\t\t\t\t})\n\t\t\t\t\t);\n\t\t\t\t\tsetPage(0);\n\t\t\t\t}}\n\t\t\t/>\n\t\t\t<Dialog\n\t\t\t\topen={isDialogOpen}\n\t\t\t\ttitle={t(\"common.dialogs.delete.title\")}\n\t\t\t\tcontent={t(\"common.dialogs.delete.description\")}\n\t\t\t\tonConfirm={handleConfirm}\n\t\t\t\tonCancel={handleCancel}\n\t\t\t\tloading={isDeleting}\n\t\t\t/>\n\t\t</MonitorBasePageWithStates>\n\t);\n};\n\nexport default UptimeMonitorsPage;\n"
  },
  {
    "path": "client/src/Routes/index.tsx",
    "content": "import { Navigate, Route, Routes as LibRoutes } from \"react-router\";\nimport RootLayout from \"@/Components/layout/RootLayout\";\nimport NotFound from \"@/Pages/NotFound\";\n\n// Auth\nimport AuthLogin from \"@/Pages/Auth/Login\";\nimport AuthRegister from \"@/Pages/Auth/Register\";\nimport AuthForgotPassword from \"@/Pages/Auth/Recovery\";\nimport AuthSetNewPassword from \"@/Pages/Auth/SetNewPassword\";\n\n// Uptime\nimport Uptime from \"@/Pages/Uptime/Monitors\";\nimport UptimeDetails from \"@/Pages/Uptime/Details\";\n\n// PageSpeed\nimport PageSpeed from \"@/Pages/PageSpeed/Monitors/\";\nimport PageSpeedDetails from \"@/Pages/PageSpeed/Details/\";\n\n// Infrastructure\nimport Infrastructure from \"@/Pages/Infrastructure/Monitors\";\nimport InfrastructureDetails from \"@/Pages/Infrastructure/Details\";\n\n// Checks\nimport Checks from \"@/Pages/Checks\";\n\n// Incidents\nimport Incidents from \"@/Pages/Incidents\";\n\n// Status pages\nimport CreateStatus from \"@/Pages/StatusPage/Create/\";\nimport StatusPages from \"@/Pages/StatusPage/StatusPages\";\nimport Status from \"@/Pages/StatusPage/Status\";\n\nimport Notifications from \"@/Pages/Notifications\";\nimport CreateNotifications from \"@/Pages/Notifications/create\";\n\n// Settings\nimport Account from \"@/Pages/Account\";\nimport EditUser from \"@/Pages/Account/EditUser\";\nimport Settings from \"@/Pages/Settings\";\n\nimport Maintenance from \"@/Pages/Maintenance\";\nimport CreateNewMaintenanceWindow from \"@/Pages/Maintenance/create\";\n\n// Logs & Diagnostics\nimport Logs from \"@/Pages/Logs\";\n\n// Routing\nimport { ProtectedRoute, RoleProtectedRoute } from \"@/Components/routing/RouteProtected\";\n\nimport CreateMonitor from \"@/Pages/CreateMonitor\";\n\nconst Routes = () => {\n\treturn (\n\t\t<LibRoutes>\n\t\t\t<Route\n\t\t\t\tpath=\"/\"\n\t\t\t\telement={\n\t\t\t\t\t<ProtectedRoute>\n\t\t\t\t\t\t<RootLayout />\n\t\t\t\t\t</ProtectedRoute>\n\t\t\t\t}\n\t\t\t>\n\t\t\t\t<Route\n\t\t\t\t\tpath=\"/\"\n\t\t\t\t\telement={<Navigate to=\"/uptime\" />}\n\t\t\t\t/>\n\t\t\t\t<Route\n\t\t\t\t\tpath=\"/uptime\"\n\t\t\t\t\telement={<Uptime />}\n\t\t\t\t/>\n\n\t\t\t\t<Route path=\"/uptime/bulk-import\" />\n\n\t\t\t\t<Route\n\t\t\t\t\tpath=\"/uptime/create\"\n\t\t\t\t\telement={<CreateMonitor />}\n\t\t\t\t/>\n\t\t\t\t<Route\n\t\t\t\t\tpath=\"/uptime/:monitorId/\"\n\t\t\t\t\telement={<UptimeDetails />}\n\t\t\t\t/>\n\t\t\t\t<Route\n\t\t\t\t\tpath=\"/uptime/configure/:monitorId/\"\n\t\t\t\t\telement={<CreateMonitor />}\n\t\t\t\t/>\n\n\t\t\t\t<Route\n\t\t\t\t\tpath=\"pagespeed\"\n\t\t\t\t\telement={<PageSpeed />}\n\t\t\t\t/>\n\t\t\t\t<Route\n\t\t\t\t\tpath=\"pagespeed/create\"\n\t\t\t\t\telement={<CreateMonitor />}\n\t\t\t\t/>\n\t\t\t\t<Route\n\t\t\t\t\tpath=\"pagespeed/:monitorId\"\n\t\t\t\t\telement={<PageSpeedDetails />}\n\t\t\t\t/>\n\t\t\t\t<Route\n\t\t\t\t\tpath=\"pagespeed/configure/:monitorId\"\n\t\t\t\t\telement={<CreateMonitor />}\n\t\t\t\t/>\n\t\t\t\t<Route\n\t\t\t\t\tpath=\"infrastructure\"\n\t\t\t\t\telement={<Infrastructure />}\n\t\t\t\t/>\n\t\t\t\t<Route\n\t\t\t\t\tpath=\"infrastructure/create\"\n\t\t\t\t\telement={<CreateMonitor />}\n\t\t\t\t/>\n\t\t\t\t<Route\n\t\t\t\t\tpath=\"/infrastructure/configure/:monitorId\"\n\t\t\t\t\telement={<CreateMonitor />}\n\t\t\t\t/>\n\t\t\t\t<Route\n\t\t\t\t\tpath=\"infrastructure/:monitorId\"\n\t\t\t\t\telement={<InfrastructureDetails />}\n\t\t\t\t/>\n\t\t\t\t<Route\n\t\t\t\t\tpath=\"checks/:monitorId?\"\n\t\t\t\t\telement={<Checks />}\n\t\t\t\t/>\n\t\t\t\t<Route\n\t\t\t\t\tpath=\"incidents/:monitorId?\"\n\t\t\t\t\telement={<Incidents />}\n\t\t\t\t/>\n\n\t\t\t\t<Route\n\t\t\t\t\tpath=\"status\"\n\t\t\t\t\telement={<StatusPages />}\n\t\t\t\t/>\n\n\t\t\t\t<Route\n\t\t\t\t\tpath=\"status/:url\"\n\t\t\t\t\telement={<Status />}\n\t\t\t\t/>\n\n\t\t\t\t<Route\n\t\t\t\t\tpath=\"status/create\"\n\t\t\t\t\telement={<CreateStatus />}\n\t\t\t\t/>\n\n\t\t\t\t<Route\n\t\t\t\t\tpath=\"status/configure/:url\"\n\t\t\t\t\telement={<CreateStatus />}\n\t\t\t\t/>\n\n\t\t\t\t<Route\n\t\t\t\t\tpath=\"notifications\"\n\t\t\t\t\telement={<Notifications />}\n\t\t\t\t/>\n\t\t\t\t<Route\n\t\t\t\t\tpath=\"notifications/create\"\n\t\t\t\t\telement={<CreateNotifications />}\n\t\t\t\t/>\n\n\t\t\t\t<Route\n\t\t\t\t\tpath=\"notifications/configure/:notificationId\"\n\t\t\t\t\telement={<CreateNotifications />}\n\t\t\t\t/>\n\n\t\t\t\t<Route\n\t\t\t\t\tpath=\"maintenance\"\n\t\t\t\t\telement={<Maintenance />}\n\t\t\t\t/>\n\t\t\t\t<Route\n\t\t\t\t\tpath=\"/maintenance/create/:maintenanceWindowId?\"\n\t\t\t\t\telement={<CreateNewMaintenanceWindow />}\n\t\t\t\t/>\n\t\t\t\t<Route\n\t\t\t\t\tpath=\"settings\"\n\t\t\t\t\telement={<Settings />}\n\t\t\t\t/>\n\n\t\t\t\t<Route\n\t\t\t\t\tpath=\"account/profile\"\n\t\t\t\t\telement={<Account open={\"profile\"} />}\n\t\t\t\t/>\n\t\t\t\t<Route\n\t\t\t\t\tpath=\"account/password\"\n\t\t\t\t\telement={<Account open={\"password\"} />}\n\t\t\t\t/>\n\t\t\t\t<Route\n\t\t\t\t\tpath=\"account/team\"\n\t\t\t\t\telement={<Account open={\"team\"} />}\n\t\t\t\t/>\n\t\t\t\t<Route\n\t\t\t\t\tpath=\"account/team/:userId\"\n\t\t\t\t\telement={\n\t\t\t\t\t\t<RoleProtectedRoute roles={[\"superadmin\"]}>\n\t\t\t\t\t\t\t<EditUser />\n\t\t\t\t\t\t</RoleProtectedRoute>\n\t\t\t\t\t}\n\t\t\t\t/>\n\n\t\t\t\t<Route\n\t\t\t\t\tpath=\"logs\"\n\t\t\t\t\telement={\n\t\t\t\t\t\t<RoleProtectedRoute roles={[\"admin\", \"superadmin\"]}>\n\t\t\t\t\t\t\t<Logs />\n\t\t\t\t\t\t</RoleProtectedRoute>\n\t\t\t\t\t}\n\t\t\t\t/>\n\t\t\t</Route>\n\n\t\t\t<Route\n\t\t\t\tpath=\"/login\"\n\t\t\t\telement={\n\t\t\t\t\t<>\n\t\t\t\t\t\t<AuthLogin />\n\t\t\t\t\t</>\n\t\t\t\t}\n\t\t\t/>\n\n\t\t\t<Route\n\t\t\t\tpath=\"/register\"\n\t\t\t\telement={<AuthRegister />}\n\t\t\t/>\n\n\t\t\t<Route\n\t\t\t\tpath=\"/register/:token\"\n\t\t\t\telement={<AuthRegister />}\n\t\t\t/>\n\n\t\t\t<Route\n\t\t\t\tpath=\"/forgot-password\"\n\t\t\t\telement={<AuthForgotPassword />}\n\t\t\t/>\n\t\t\t<Route\n\t\t\t\tpath=\"/set-new-password/:token\"\n\t\t\t\telement={<AuthSetNewPassword />}\n\t\t\t/>\n\t\t\t<Route\n\t\t\t\tpath=\"/status/public/:url\"\n\t\t\t\telement={<Status />}\n\t\t\t/>\n\n\t\t\t<Route\n\t\t\t\tpath=\"*\"\n\t\t\t\telement={<NotFound />}\n\t\t\t/>\n\t\t</LibRoutes>\n\t);\n};\n\nexport { Routes };\n"
  },
  {
    "path": "client/src/Types/Check.ts",
    "content": "export const CHECK_TTL_SENTINEL = 366;\n\nexport interface CheckMetadata {\n\tmonitorId: string;\n\tteamId: string;\n\ttype:\n\t\t| \"http\"\n\t\t| \"ping\"\n\t\t| \"pagespeed\"\n\t\t| \"hardware\"\n\t\t| \"docker\"\n\t\t| \"port\"\n\t\t| \"game\"\n\t\t| \"unknown\";\n}\n\nexport interface CheckCpuInfo {\n\tphysical_core?: number;\n\tlogical_core?: number;\n\tfrequency?: number;\n\tcurrent_frequency?: number;\n\ttemperature?: number[];\n\tfree_percent?: number;\n\tusage_percent?: number;\n}\n\nexport interface CheckMemoryInfo {\n\ttotal_bytes?: number;\n\tavailable_bytes?: number;\n\tused_bytes?: number;\n\tusage_percent?: number;\n}\n\nexport interface CheckHostInfo {\n\tos?: string;\n\tplatform?: string;\n\tkernel_version?: string;\n\tpretty_name?: string;\n}\n\nexport interface CheckCaptureInfo {\n\tversion?: string;\n\tmode?: string;\n}\n\nexport interface CheckDiskInfo {\n\tdevice?: string;\n\tmountpoint?: string;\n\ttotal_bytes?: number;\n\tfree_bytes?: number;\n\tused_bytes?: number;\n\tusage_percent?: number;\n\ttotal_inodes?: number;\n\tfree_inodes?: number;\n\tused_inodes?: number;\n\tinodes_usage_percent?: number;\n\tread_bytes?: number;\n\twrite_bytes?: number;\n\tread_time?: number;\n\twrite_time?: number;\n}\n\nexport interface CheckErrorInfo {\n\tmetric: string[];\n\terr: string;\n}\n\nexport interface CheckNetworkInterfaceInfo {\n\tname: string;\n\tbytes_sent: number;\n\tbytes_recv: number;\n\tpackets_sent: number;\n\tpackets_recv: number;\n\terr_in: number;\n\terr_out: number;\n\tdrop_in: number;\n\tdrop_out: number;\n\tfifo_in: number;\n\tfifo_out: number;\n}\n\nexport interface CheckAudits {\n\tcls?: ILighthouseAudit;\n\tsi?: ILighthouseAudit;\n\tfcp?: ILighthouseAudit;\n\tlcp?: ILighthouseAudit;\n\ttbt?: ILighthouseAudit;\n}\n\nexport interface ILighthouseAudit {\n\tid?: string;\n\ttitle?: string;\n\tscore?: number | null;\n\tdisplayValue?: string;\n\tnumericValue?: number;\n\tnumericUnit?: string;\n}\n\nexport interface CheckTimings {\n\tstart?: number;\n\tsocket?: number;\n\tlookup?: number;\n\tconnect?: number;\n\tsecureConnect?: number;\n\tupload?: number;\n\tresponse?: number;\n\tend?: number;\n\tabort?: number;\n\terror?: number;\n\tphases?: {\n\t\twait?: number;\n\t\tdns?: number;\n\t\ttcp?: number;\n\t\ttls?: number;\n\t\trequest?: number;\n\t\tfirstByte?: number;\n\t\tdownload?: number;\n\t\ttotal?: number;\n\t};\n}\n\nexport interface Check {\n\tid: string;\n\tmetadata: CheckMetadata;\n\tstatus: boolean;\n\tresponseTime: number;\n\ttimings?: CheckTimings;\n\tstatusCode: number;\n\tmessage: string;\n\tcpu?: CheckCpuInfo;\n\tmemory?: CheckMemoryInfo;\n\tdisk?: CheckDiskInfo[];\n\thost?: CheckHostInfo;\n\terrors?: CheckErrorInfo[];\n\tcapture?: CheckCaptureInfo;\n\tnet?: CheckNetworkInterfaceInfo[];\n\taccessibility?: number;\n\tbestPractices?: number;\n\tseo?: number;\n\tperformance?: number;\n\taudits?: CheckAudits;\n\tcreatedAt: string;\n\tupdatedAt: string;\n}\n\nexport interface GroupedCheck {\n\tbucketDate: string;\n\tavgResponseTime: number;\n\ttotalChecks: number;\n}\n\nexport interface PageSpeedGroupedCheck {\n\tbucketDate: string;\n\tperformance: number;\n\taccessibility: number;\n\tbestPractices: number;\n\tseo: number;\n\ttotalChecks: number;\n}\n\nexport interface LatestCheck {\n\tstatus: boolean;\n\tresponseTime: number;\n\tcheckedAt: string;\n\tid: string;\n}\n\nexport interface ChecksResponse {\n\tchecks: Check[];\n\tchecksCount: number;\n}\n\nexport type MonitorType =\n\t| \"http\"\n\t| \"ping\"\n\t| \"pagespeed\"\n\t| \"hardware\"\n\t| \"docker\"\n\t| \"port\"\n\t| \"game\"\n\t| \"unknown\";\n\nexport interface ChecksQueryResult {\n\tchecksCount: number;\n\tchecks: Check[];\n}\n\nexport interface PageSpeedChecksResult {\n\tmonitorType: \"pagespeed\";\n\tchecks: Check[];\n}\n\nexport interface HardwareChecksResult {\n\tmonitorType: \"hardware\";\n\taggregateData: {\n\t\ttotalChecks: number;\n\t};\n\tupChecks: {\n\t\ttotalChecks: number;\n\t};\n\tchecks: Array<{\n\t\tbucketDate: string;\n\t\tavgCpuUsage: number;\n\t\tavgMemoryUsage: number;\n\t\tavgTemperature: number[];\n\t\tdisks: Array<{\n\t\t\tname: string;\n\t\t\treadSpeed: number;\n\t\t\twriteSpeed: number;\n\t\t\ttotalBytes: number;\n\t\t\tfreeBytes: number;\n\t\t\tusagePercent: number;\n\t\t}>;\n\t\tnet: Array<{\n\t\t\tname: string;\n\t\t\tbytesSentPerSecond: number;\n\t\t\tdeltaBytesRecv: number;\n\t\t\tdeltaPacketsSent: number;\n\t\t\tdeltaPacketsRecv: number;\n\t\t\tdeltaErrIn: number;\n\t\t\tdeltaErrOut: number;\n\t\t\tdeltaDropIn: number;\n\t\t\tdeltaDropOut: number;\n\t\t\tdeltaFifoIn: number;\n\t\t\tdeltaFifoOut: number;\n\t\t}>;\n\t}>;\n}\n\nexport interface UptimeChecksResult {\n\tmonitorType: Exclude<MonitorType, \"hardware\" | \"pagespeed\">;\n\tgroupedChecks: GroupedCheck[];\n\tgroupedUpChecks: GroupedCheck[];\n\tgroupedDownChecks: GroupedCheck[];\n\tuptimePercentage: number;\n\tavgResponseTime: number;\n}\n\nexport interface ChecksSummary {\n\ttotalChecks: number;\n\tdownChecks: number;\n}\n\nexport type CheckSnapshot = Omit<Check, \"metadata\" | \"__v\" | \"updatedAt\"> & {\n\toriginalResponseTime: number;\n};\n\nexport interface HasResponseTime {\n\tresponseTime: number;\n}\n\nexport type NormalizedCheck<T extends HasResponseTime = Check> = T & {\n\toriginalResponseTime: number;\n};\n\nexport type NormalizedUptimeCheck<T extends GroupedCheck = GroupedCheck> = T & {\n\toriginalAvgResponseTime: number;\n};\n"
  },
  {
    "path": "client/src/Types/Diagnostics.ts",
    "content": "export interface Diagnostics {\n\tosStats: OsStats;\n\tmemoryUsage: MemoryUsage;\n\tcpuUsage: CpuUsage;\n\tv8HeapStats: V8HeapStats;\n\teventLoopDelayMs: number;\n\tuptimeMs: number;\n}\n\nexport interface OsStats {\n\tfreeMemoryBytes: number;\n\ttotalMemoryBytes: number;\n}\n\nexport interface MemoryUsage {\n\trss: number;\n\theapTotal: number;\n\theapUsed: number;\n\texternal: number;\n\tarrayBuffers: number;\n}\n\nexport interface CpuUsage {\n\tuserUsageMs: number;\n\tsystemUsageMs: number;\n\tusagePercentage: number;\n}\n\nexport interface V8HeapStats {\n\ttotalHeapSizeBytes: number;\n\tusedHeapSizeBytes: number;\n\theapSizeLimitBytes: number;\n}\n"
  },
  {
    "path": "client/src/Types/GeoCheck.ts",
    "content": "export const GeoContinents = [\"EU\", \"NA\", \"AS\", \"SA\", \"AF\", \"OC\"] as const;\nexport type GeoContinent = (typeof GeoContinents)[number];\n\nexport interface GeoCheckMetadata {\n\tmonitorId: string;\n\tteamId: string;\n\ttype: string;\n}\n\nexport interface GeoCheckTimings {\n\ttotal: number;\n\tdns: number;\n\ttcp: number;\n\ttls: number;\n\tfirstByte: number;\n\tdownload: number;\n}\n\nexport interface GeoCheckLocation {\n\tcontinent: GeoContinent;\n\tregion: string;\n\tcountry: string;\n\tstate: string;\n\tcity: string;\n\tlongitude: number;\n\tlatitude: number;\n}\n\nexport interface GeoCheckResult {\n\tlocation: GeoCheckLocation;\n\tstatus: boolean;\n\tstatusCode: number;\n\ttimings: GeoCheckTimings;\n}\n\nexport interface GeoCheck {\n\tid: string;\n\tmetadata: GeoCheckMetadata;\n\tresults: GeoCheckResult[];\n\texpiry: string;\n\t__v: number;\n\tcreatedAt: string;\n\tupdatedAt: string;\n}\n\nexport interface FlatGeoCheck {\n\tid: string;\n\tmonitorId: string;\n\tteamId: string;\n\ttype: string;\n\tlocation: GeoCheckLocation;\n\tstatus: boolean;\n\tstatusCode: number;\n\ttimings: GeoCheckTimings;\n\tcreatedAt: string;\n\tupdatedAt: string;\n}\n\nexport interface GroupedGeoCheck {\n\tbucketDate: string;\n\tcontinent: GeoContinent;\n\tavgResponseTime: number;\n\ttotalChecks: number;\n\tuptimePercentage: number;\n}\n\nexport interface GeoChecksResult {\n\tmonitorType: string;\n\tgroupedGeoChecks: GroupedGeoCheck[];\n}\n\nexport interface GeoChecksResponse {\n\tgeoChecks: GeoCheck[];\n\tgeoChecksCount: number;\n}\n\nexport interface FlatGeoChecksResponse {\n\tgeoChecks: FlatGeoCheck[];\n\tgeoChecksCount: number;\n}\n"
  },
  {
    "path": "client/src/Types/Incident.ts",
    "content": "export interface Incident {\n\tid: string;\n\tmonitorId: string;\n\tteamId: string;\n\tstartTime: string;\n\tendTime: string | null;\n\tstatus: boolean;\n\tmessage?: string | null;\n\tstatusCode?: number | null;\n\tresolutionType: \"automatic\" | \"manual\" | null;\n\tresolvedBy?: string | null;\n\tresolvedByEmail?: string | null;\n\tcomment?: string | null;\n\tcreatedAt: string;\n\tupdatedAt: string;\n}\n\nexport interface IncidentsResponse {\n\tincidents: Incident[];\n\tcount: number;\n}\n\nexport interface IncidentSummaryTopMonitor {\n\tmonitorId: string;\n\tmonitorName: string | null;\n\tincidentCount: number;\n}\n\nexport interface IncidentSummaryItem {\n\tid: string;\n\tmonitorId: string;\n\tmonitorName: string | null;\n\tstatus: boolean;\n\tstartTime: string;\n\tendTime: string | null;\n\tresolutionType: \"automatic\" | \"manual\" | null;\n\tmessage: string | null;\n\tstatusCode: number | null;\n\tcreatedAt: string;\n}\n\nexport interface IncidentSummary {\n\ttotal: number;\n\ttotalActive: number;\n\ttotalManualResolutions: number;\n\ttotalAutomaticResolutions: number;\n\tavgResolutionTimeHours: number;\n\ttopMonitor: IncidentSummaryTopMonitor | null;\n\tlatestIncidents: IncidentSummaryItem[];\n}\n"
  },
  {
    "path": "client/src/Types/Log.ts",
    "content": "export const LOG_LEVELS = [\"debug\", \"info\", \"warn\", \"error\"] as const;\nexport type LogLevel = (typeof LOG_LEVELS)[number];\nexport const LOG_LEVEL_OPTIONS = [\"all\", ...LOG_LEVELS] as const;\nexport type LogLevelOption = (typeof LOG_LEVEL_OPTIONS)[number];\nexport interface Log {\n\tmessage: string;\n\tservice?: string;\n\tmethod?: string;\n\tdetails?: Record<string, unknown>;\n\tstack?: string;\n\tlevel: LogLevel;\n\ttimestamp: string;\n}\n"
  },
  {
    "path": "client/src/Types/MaintenanceWindow.ts",
    "content": "export type DurationUnit = \"seconds\" | \"minutes\" | \"hours\" | \"days\";\n\nexport interface MaintenanceWindow {\n\tid: string;\n\tmonitorId: string;\n\tteamId: string;\n\tactive: boolean;\n\tname: string;\n\tduration: number;\n\tdurationUnit: DurationUnit;\n\trepeat: number;\n\tstart: string;\n\tend: string;\n\tcreatedAt: string;\n\tupdatedAt: string;\n}\n"
  },
  {
    "path": "client/src/Types/Monitor.ts",
    "content": "import type { GroupedCheck, CheckSnapshot } from \"@/Types/Check\";\nimport type { PageSpeedGroupedCheck } from \"@/Types/Check\";\nimport type { GeoContinent } from \"@/Types/GeoCheck\";\nexport type { GeoContinent } from \"@/Types/GeoCheck\";\n\nexport const MonitorTypes = [\n\t\"http\",\n\t\"ping\",\n\t\"pagespeed\",\n\t\"hardware\",\n\t\"docker\",\n\t\"port\",\n\t\"game\",\n\t\"grpc\",\n\t\"websocket\",\n\t\"unknown\",\n] as const;\nexport type MonitorType = (typeof MonitorTypes)[number];\n\nexport const GeoCheckSupportedTypes: readonly MonitorType[] = [\"http\", \"ping\"] as const;\n\nexport const supportsGeoCheck = (type: MonitorType | undefined): boolean => {\n\tif (!type) {\n\t\treturn false;\n\t}\n\treturn GeoCheckSupportedTypes.includes(type);\n};\n\nexport const MonitorStatuses = [\n\t\"up\",\n\t\"down\",\n\t\"paused\",\n\t\"initializing\",\n\t\"maintenance\",\n\t\"breached\",\n] as const;\nexport type MonitorStatus = (typeof MonitorStatuses)[number];\n\nexport type MonitorMatchMethod = \"equal\" | \"include\" | \"regex\" | \"\";\n\nexport interface Monitor {\n\tid: string;\n\tuserId: string;\n\tteamId: string;\n\tname: string;\n\tdescription?: string;\n\tstatus: MonitorStatus;\n\tstatusWindow: boolean[];\n\tstatusWindowSize: number;\n\tstatusWindowThreshold: number;\n\ttype: MonitorType;\n\tignoreTlsErrors: boolean;\n\tuseAdvancedMatching: boolean;\n\tjsonPath?: string;\n\texpectedValue?: string;\n\tmatchMethod?: MonitorMatchMethod;\n\turl: string;\n\tport?: number;\n\tisActive: boolean;\n\tinterval: number;\n\tuptimePercentage?: number;\n\tnotifications: string[];\n\tsecret?: string;\n\tcpuAlertThreshold: number;\n\tcpuAlertCounter: number;\n\tmemoryAlertThreshold: number;\n\tmemoryAlertCounter: number;\n\tdiskAlertThreshold: number;\n\tdiskAlertCounter: number;\n\ttempAlertThreshold: number;\n\ttempAlertCounter: number;\n\tselectedDisks: string[];\n\tgameId?: string;\n\tgrpcServiceName?: string;\n\tgroup: string | null;\n\tgeoCheckEnabled?: boolean;\n\tgeoCheckLocations?: GeoContinent[];\n\tgeoCheckInterval?: number;\n\trecentChecks: CheckSnapshot[];\n\tcreatedAt: string;\n\tupdatedAt: string;\n}\n\nexport type MonitorWithChecks = Monitor;\n\nexport interface MonitorsSummary {\n\ttotalMonitors: number;\n\tupMonitors: number;\n\tdownMonitors: number;\n\tpausedMonitors: number;\n\tinitializingMonitors: number;\n\tmaintenanceMonitors: number;\n\tbreachedMonitors: number;\n}\n\nexport interface MonitorsWithChecksResponse {\n\tcount: number;\n\tmonitors: MonitorWithChecks[];\n\tsummary: MonitorsSummary | null;\n}\n\nexport interface MonitorStats {\n\tid: string;\n\tmonitorId: string;\n\tavgResponseTime: number;\n\tmaxResponseTime: number;\n\ttotalChecks: number;\n\ttotalUpChecks: number;\n\ttotalDownChecks: number;\n\tuptimePercentage: number;\n\tlastCheckTimestamp: number;\n\tlastResponseTime: number;\n\ttimeOfLastFailure?: number;\n\tcreatedAt: string;\n\tupdatedAt: string;\n}\n\nexport interface MonitorData {\n\tmonitor: Monitor;\n\tgroupedChecks: GroupedCheck[];\n\tgroupedUpChecks: GroupedCheck[];\n\tgroupedDownChecks: GroupedCheck[];\n\tgroupedAvgResponseTime: number;\n\tgroupedUptimePercentage: number;\n}\n\nexport interface MonitorDetailsResponse {\n\tmonitorData: MonitorData;\n\tmonitorStats: MonitorStats | null;\n}\n\nexport interface PageSpeedDetailsResponse {\n\tmonitorData: {\n\t\tmonitor: Monitor;\n\t\tgroupedChecks: PageSpeedGroupedCheck[];\n\t};\n\tmonitorStats: MonitorStats | null;\n}\n\nexport interface HardwareDiskStats {\n\tname: string;\n\treadSpeed: number;\n\twriteSpeed: number;\n\ttotalBytes: number;\n\tfreeBytes: number;\n\tusagePercent: number;\n}\n\nexport interface HardwareNetStats {\n\tname: string;\n\tbytesSentPerSecond: number;\n\tdeltaBytesRecv: number;\n\tdeltaPacketsSent: number;\n\tdeltaPacketsRecv: number;\n\tdeltaErrIn: number;\n\tdeltaErrOut: number;\n\tdeltaDropIn: number;\n\tdeltaDropOut: number;\n\tdeltaFifoIn: number;\n\tdeltaFifoOut: number;\n}\n\nexport interface HardwareCheckStats {\n\tbucketDate: string;\n\tavgCpuUsage: number;\n\tavgMemoryUsage: number;\n\tavgTemperature: number[];\n\tdisks: HardwareDiskStats[];\n\tnet: HardwareNetStats[];\n}\n\nexport interface HardwareStats {\n\taggregateData: {\n\t\ttotalChecks: number;\n\t};\n\tupChecks: {\n\t\ttotalChecks: number;\n\t};\n\tchecks: HardwareCheckStats[];\n}\n\nexport interface HardwareDetailsResponse {\n\tmonitor: Monitor;\n\tstats: HardwareStats;\n\tmonitorStats: MonitorStats | null;\n}\n\nexport interface Game {\n\tname: string;\n\toptions?: {\n\t\tport?: number;\n\t};\n}\n\nexport type GamesMap = Record<string, Game>;\n"
  },
  {
    "path": "client/src/Types/Notification.ts",
    "content": "export const NotificationChannels = [\n\t\"email\",\n\t\"slack\",\n\t\"discord\",\n\t\"webhook\",\n\t\"pager_duty\",\n\t\"matrix\",\n\t\"teams\",\n] as const;\nexport type NotificationChannel = (typeof NotificationChannels)[number];\n\nexport interface Notification {\n\tid: string;\n\tuserId: string;\n\tteamId: string;\n\ttype: NotificationChannel;\n\tnotificationName: string;\n\taddress?: string;\n\tphone?: string;\n\thomeserverUrl?: string;\n\troomId?: string;\n\taccessToken?: string;\n\tcreatedAt: string;\n\tupdatedAt: string;\n}\n"
  },
  {
    "path": "client/src/Types/Queue.ts",
    "content": "import type { MonitorType } from \"./Monitor\";\n\nexport interface QueueJobFailure {\n\tmonitorId: string | number;\n\tmonitorUrl: string | null;\n\tmonitorType: MonitorType | null;\n\tfailedAt: number | null;\n\tfailCount: number;\n\tfailReason: string | null;\n}\n\nexport interface QueueMetrics {\n\tjobs: number;\n\tactiveJobs: number;\n\tfailingJobs: number;\n\tjobsWithFailures: QueueJobFailure[];\n\ttotalRuns: number;\n\ttotalFailures: number;\n}\n\nexport interface QueueJobSummary {\n\tmonitorId: string | number;\n\tmonitorUrl: string | null;\n\tmonitorType: MonitorType | null;\n\tmonitorInterval: number | null;\n\tactive: boolean;\n\tlockedAt: number | null;\n\trunCount: number;\n\tfailCount: number;\n\tfailReason: string | null;\n\tlastRunAt: number | null;\n\tlastFinishedAt: number | null;\n\tlastRunTook: number | null;\n\tlastFailedAt: number | null;\n}\n\nexport interface QueueData {\n\tjobs: QueueJobSummary[];\n\tmetrics: QueueMetrics;\n}\n"
  },
  {
    "path": "client/src/Types/Settings.ts",
    "content": "export interface SettingsThresholds {\n\tcpu?: number;\n\tmemory?: number;\n\tdisk?: number;\n\ttemperature?: number;\n}\n\nexport interface Settings {\n\tid: string;\n\tcheckTTL: number;\n\tlanguage: string;\n\tsystemEmailHost?: string;\n\tsystemEmailPort?: number;\n\tsystemEmailAddress?: string;\n\tsystemEmailUser?: string;\n\tsystemEmailConnectionHost?: string;\n\tsystemEmailTLSServername?: string;\n\tsystemEmailSecure: boolean;\n\tsystemEmailPool: boolean;\n\tsystemEmailIgnoreTLS: boolean;\n\tsystemEmailRequireTLS: boolean;\n\tsystemEmailRejectUnauthorized: boolean;\n\tshowURL: boolean;\n\tsingleton: boolean;\n\tglobalThresholds?: SettingsThresholds;\n\tcreatedAt: string;\n\tupdatedAt: string;\n}\n\nexport interface AppSettingsResponse {\n\tpagespeedKeySet: boolean;\n\temailPasswordSet: boolean;\n\tsettings: Settings;\n}\n"
  },
  {
    "path": "client/src/Types/StatusPage.ts",
    "content": "import type { Monitor, MonitorType } from \"@/Types/Monitor\";\nexport type MonitorDisplayType = \"uptime\" | \"infrastructure\";\n\nexport const MONITOR_TYPE_KEYS: Partial<Record<MonitorType, string>> = {\n\thttp: \"pages.common.monitors.monitorTypes.optionHttp\",\n\tping: \"pages.common.monitors.monitorTypes.optionPing\",\n\tdocker: \"pages.common.monitors.monitorTypes.optionDocker\",\n\tport: \"pages.common.monitors.monitorTypes.optionPort\",\n\tgame: \"pages.common.monitors.monitorTypes.optionGame\",\n\tgrpc: \"pages.common.monitors.monitorTypes.optionGrpc\",\n\twebsocket: \"pages.common.monitors.monitorTypes.optionWebSocket\",\n\thardware: \"pages.common.monitors.monitorTypes.optionHardware\",\n\tpagespeed: \"pages.common.monitors.monitorTypes.optionPagespeed\",\n};\n\nexport const getMonitorTypeLabel = (\n\ttype: MonitorType,\n\tt: (key: string) => string\n): string => {\n\tconst key = MONITOR_TYPE_KEYS[type];\n\treturn key ? t(key) : type;\n};\n\nexport interface StatusPage {\n\tid: string;\n\tuserId: string;\n\tteamId: string;\n\ttype: MonitorDisplayType[];\n\tcompanyName: string;\n\turl: string;\n\ttimezone?: string;\n\tcolor: string;\n\tmonitors: string[];\n\tsubMonitors: string[];\n\toriginalMonitors?: string[];\n\tlogo?: {\n\t\tdata: string;\n\t\tcontentType: string;\n\t} | null;\n\tisPublished: boolean;\n\tshowCharts: boolean;\n\tshowUptimePercentage: boolean;\n\tshowAdminLoginLink: boolean;\n\tshowInfrastructure: boolean;\n\tcustomCSS: string;\n\tcreatedAt: string;\n\tupdatedAt: string;\n}\n\nexport interface StatusPageResponse {\n\tstatusPage: StatusPage;\n\tmonitors: Monitor[];\n}\n"
  },
  {
    "path": "client/src/Types/User.ts",
    "content": "export const UserRoles = [\"user\", \"admin\", \"superadmin\", \"demo\"] as const;\nexport type UserRole = (typeof UserRoles)[number];\n\nexport interface UserProfileImage {\n\tdata?: Buffer;\n\tcontentType?: string;\n}\n\nexport interface User {\n\tid: string;\n\tfirstName: string;\n\tlastName: string;\n\temail: string;\n\tavatarImage?: string;\n\tprofileImage?: UserProfileImage;\n\tisActive: boolean;\n\tisVerified: boolean;\n\trole: UserRole[];\n\tteamId: string;\n\tcheckTTL?: number;\n\tcreatedAt: string;\n\tupdatedAt: string;\n}\n\nexport interface AuthResponse {\n\tuser: User;\n\ttoken: string;\n}\n"
  },
  {
    "path": "client/src/Types/env.d.ts",
    "content": "/// <reference types=\"vite/client\" />\n\ndeclare const __APP_VERSION__: string;\n\ninterface ImportMetaEnv {\n\treadonly VITE_APP_API_V2_BASE_URL?: string;\n\treadonly VITE_APP_LOG_LEVEL?: \"debug\" | \"info\" | \"warn\" | \"error\";\n}\n\ninterface ImportMeta {\n\treadonly env: ImportMetaEnv;\n}\n\ndeclare module \"*.svg?react\" {\n\timport * as React from \"react\";\n\tconst ReactComponent: React.FunctionComponent<\n\t\tReact.SVGProps<SVGSVGElement> & { title?: string }\n\t>;\n\texport default ReactComponent;\n}\n\ndeclare module \"*.css\" {\n\tconst content: string;\n\texport default content;\n}\n"
  },
  {
    "path": "client/src/Types/mui.d.ts",
    "content": "import \"@mui/material/Button\";\n\ndeclare module \"@mui/material/styles\" {\n\tinterface Palette {}\n\tinterface PaletteOptions {}\n}\n\ndeclare module \"@mui/material/Button\" {\n\tinterface ButtonPropsColorOverrides {\n\t\tneutral: true;\n\t}\n}\n\ndeclare module \"@mui/material/CircularProgress\" {\n\tinterface CircularProgressPropsColorOverrides {}\n}\n"
  },
  {
    "path": "client/src/Types/state.ts",
    "content": "import type { ChartType } from \"@/Features/UI/uiSlice\";\nimport type { User } from \"./User\";\n\nexport interface AuthState {\n\tisLoading: boolean;\n\tauthToken: string;\n\tuser: User | null;\n\tsuccess: boolean | null;\n\tmsg: string | null;\n}\n\nexport interface UIState {\n\tmonitors: {\n\t\trowsPerPage: number;\n\t};\n\tteam: {\n\t\trowsPerPage: number;\n\t};\n\tmaintenance: {\n\t\trowsPerPage: number;\n\t};\n\tinfrastructure: {\n\t\trowsPerPage: number;\n\t};\n\tlogs: {\n\t\trowsPerPage: number;\n\t};\n\tsidebar: {\n\t\tcollapsed: boolean;\n\t};\n\tmode: \"light\" | \"dark\";\n\tshowURL: boolean;\n\tgreeting: {\n\t\tindex: number;\n\t\tlastUpdate: string | null;\n\t};\n\ttimezone: string;\n\tdistributedUptimeEnabled: boolean;\n\tlanguage: string;\n\tstarPromptOpen: boolean;\n\tchartType: ChartType;\n}\n\nexport interface RootState {\n\tauth: AuthState;\n\tui: UIState;\n}\n"
  },
  {
    "path": "client/src/Utils/ApiClient.ts",
    "content": "import axios from \"axios\";\nimport type { AxiosError } from \"axios\";\nimport type { AxiosRequestConfig, AxiosResponse } from \"axios\";\n\nconst BASE_URL = import.meta.env.VITE_APP_API_BASE_URL;\n\nconst api = axios.create({\n\tbaseURL: BASE_URL,\n});\n\ntype StoreType = {\n\tgetState: () => { auth?: { authToken?: string } };\n};\n\nlet storeInstance: StoreType | null = null;\nlet interceptorsInitialized = false;\n\ntype ServerUnreachableCallback = (unreachable: boolean) => void;\nlet serverUnreachableCallback: ServerUnreachableCallback | null = null;\n\nexport const setServerUnreachableCallback = (\n\tcallback: ServerUnreachableCallback\n): void => {\n\tserverUnreachableCallback = callback;\n};\n\nexport const initApiClient = (store: StoreType): void => {\n\tstoreInstance = store;\n\n\tif (interceptorsInitialized) {\n\t\treturn;\n\t}\n\tinterceptorsInitialized = true;\n\n\tapi.interceptors.request.use(\n\t\t(config) => {\n\t\t\tconst authToken = storeInstance?.getState()?.auth?.authToken ?? \"\";\n\n\t\t\tconfig.headers.set(\"Authorization\", `Bearer ${authToken}`);\n\t\t\tif (!config.headers.has(\"Accept-Language\")) {\n\t\t\t\tconfig.headers.set(\"Accept-Language\", \"en\");\n\t\t\t}\n\n\t\t\treturn config;\n\t\t},\n\t\t(error) => {\n\t\t\treturn Promise.reject(error);\n\t\t}\n\t);\n\n\tconst onSuccess = (response: AxiosResponse) => {\n\t\t// Server is reachable, hide offline banner if shown\n\t\tserverUnreachableCallback?.(false);\n\t\treturn response;\n\t};\n\tconst onError = (error: AxiosError) => {\n\t\t// Handle network errors (server unreachable)\n\t\tif (error.code === \"ERR_NETWORK\") {\n\t\t\tserverUnreachableCallback?.(true);\n\t\t\treturn Promise.reject(error);\n\t\t}\n\n\t\tif (error.response?.status === 401) {\n\t\t\tif (window.location.pathname !== \"/login\") {\n\t\t\t\twindow.location.href = \"/login\";\n\t\t\t}\n\t\t}\n\t\treturn Promise.reject(error);\n\t};\n\n\tapi.interceptors.response.use(onSuccess, onError);\n};\n\nexport const get = <T>(\n\turl: string,\n\tconfig: AxiosRequestConfig = {}\n): Promise<AxiosResponse<T>> => api.get<T>(url, config);\n\nexport const post = <T>(\n\turl: string,\n\tdata: unknown,\n\tconfig: AxiosRequestConfig = {}\n): Promise<AxiosResponse<T>> => api.post<T>(url, data, config);\n\nexport const patch = <T>(\n\turl: string,\n\tdata: unknown,\n\tconfig: AxiosRequestConfig = {}\n): Promise<AxiosResponse<T>> => api.patch<T>(url, data, config);\n\nexport const put = <T>(\n\turl: string,\n\tdata: unknown,\n\tconfig: AxiosRequestConfig = {}\n): Promise<AxiosResponse<T>> => api.put<T>(url, data, config);\n\nexport const deleteOp = <T>(\n\turl: string,\n\tconfig: AxiosRequestConfig = {}\n): Promise<AxiosResponse<T>> => api.delete<T>(url, config);\n\nexport default api;\n"
  },
  {
    "path": "client/src/Utils/DataUtils.ts",
    "content": "const MIN_OUT = 10;\nconst MAX_OUT = 100;\n\nexport const normalizeResponseTimes = <T, K extends keyof T>(\n\tchecks: T[],\n\tkey: K\n): (T & { normalResponseTime: number })[] => {\n\tif (!Array.isArray(checks) || checks.length === 0)\n\t\treturn checks as (T & {\n\t\t\tnormalResponseTime: number;\n\t\t})[];\n\n\tif (checks.length === 1) {\n\t\treturn [\n\t\t\t{\n\t\t\t\t...checks[0],\n\t\t\t\tnormalResponseTime: 50,\n\t\t\t},\n\t\t];\n\t}\n\n\tconst getVal = (check: T): number => {\n\t\tconst v = check[key] as unknown;\n\t\treturn typeof v === \"number\" && Number.isFinite(v) ? v : 0;\n\t};\n\n\tconst { min, max } = checks.reduce(\n\t\t(acc, check) => {\n\t\t\tconst v = getVal(check);\n\t\t\tif (v > acc.max) acc.max = v;\n\t\t\tif (v < acc.min) acc.min = v;\n\t\t\treturn acc;\n\t\t},\n\t\t{ max: -Infinity, min: Infinity }\n\t);\n\n\tconst range = max - min || 1;\n\n\treturn checks.map((check) => ({\n\t\t...check,\n\t\tnormalResponseTime: MIN_OUT + ((getVal(check) - min) * (MAX_OUT - MIN_OUT)) / range,\n\t}));\n};\n\n// Interpolate color between three theme colors over 0-100 range.\n// 0-50 => start (success.light), 50-75 => mid (warning.light), 75-100 => end (error.light)\nexport const getResponseColor = (\n\tms: number,\n\tcolors: {\n\t\tstart: string | undefined;\n\t\tmid: string | undefined;\n\t\tend: string | undefined;\n\t}\n): string => {\n\t// New ranges with open high end:\n\t// 0–300ms: interpolate start (good) -> mid (warning)\n\t// 300–600ms: interpolate mid (warning) -> end (error)\n\t// >600ms: solid end (error)\n\tconst safe = { ...colors };\n\tif (!safe.start) safe.start = \"#4caf50\"; // fallback green\n\tif (!safe.mid) safe.mid = \"#ff9800\"; // fallback orange\n\tif (!safe.end) safe.end = \"#f44336\"; // fallback red\n\n\tconst toHex = (c: number) => c.toString(16).padStart(2, \"0\");\n\tconst clamp = (n: number) => Math.min(255, Math.max(0, Math.round(n)));\n\tconst rgbToHex = (r: number, g: number, b: number) =>\n\t\t`#${toHex(clamp(r))}${toHex(clamp(g))}${toHex(clamp(b))}`;\n\n\tconst normalizeToHex = (value: string) => {\n\t\tconst v = value.trim();\n\t\tif (v.startsWith(\"#\")) {\n\t\t\tconst h = v.slice(1);\n\t\t\tconst full =\n\t\t\t\th.length === 3\n\t\t\t\t\t? h\n\t\t\t\t\t\t\t.split(\"\")\n\t\t\t\t\t\t\t.map((c) => c + c)\n\t\t\t\t\t\t\t.join(\"\")\n\t\t\t\t\t: h.substring(0, 6);\n\t\t\treturn `#${full.toLowerCase()}`;\n\t\t}\n\t\tconst m = v\n\t\t\t.replace(/\\s+/g, \"\")\n\t\t\t.match(/^rgba?\\((\\d{1,3}),(\\d{1,3}),(\\d{1,3})(?:,(0|0?\\.\\d+|1))?\\)$/i);\n\t\tif (m) {\n\t\t\tconst r = parseInt(m[1], 10);\n\t\t\tconst g = parseInt(m[2], 10);\n\t\t\tconst b = parseInt(m[3], 10);\n\t\t\treturn rgbToHex(r, g, b);\n\t\t}\n\t\t// Fallback neutral\n\t\treturn \"#7f7f7f\";\n\t};\n\n\tconst parseHex = (hex: string) => {\n\t\tconst h = hex.replace(\"#\", \"\");\n\t\tconst full =\n\t\t\th.length === 3\n\t\t\t\t? h\n\t\t\t\t\t\t.split(\"\")\n\t\t\t\t\t\t.map((c) => c + c)\n\t\t\t\t\t\t.join(\"\")\n\t\t\t\t: h;\n\t\tconst n = parseInt(full, 16);\n\t\treturn { r: (n >> 16) & 255, g: (n >> 8) & 255, b: n & 255 };\n\t};\n\tconst mix = (a: number, b: number, t: number) => Math.round(a + (b - a) * t);\n\n\tconst v = Math.max(0, ms);\n\tif (v <= 300) {\n\t\tconst t = v / 300; // 0..1 from start->mid\n\t\tconst s = parseHex(normalizeToHex(safe.start));\n\t\tconst m = parseHex(normalizeToHex(safe.mid));\n\t\tconst r = mix(s.r, m.r, t);\n\t\tconst g = mix(s.g, m.g, t);\n\t\tconst b = mix(s.b, m.b, t);\n\t\treturn `#${toHex(r)}${toHex(g)}${toHex(b)}`;\n\t}\n\tif (v <= 600) {\n\t\tconst t = (v - 300) / 300; // 0..1 from mid->end\n\t\tconst m = parseHex(normalizeToHex(safe.mid));\n\t\tconst e = parseHex(normalizeToHex(safe.end));\n\t\tconst r = mix(m.r, e.r, t);\n\t\tconst g = mix(m.g, e.g, t);\n\t\tconst b = mix(m.b, e.b, t);\n\t\treturn `#${toHex(r)}${toHex(g)}${toHex(b)}`;\n\t}\n\treturn normalizeToHex(safe.end);\n};\n"
  },
  {
    "path": "client/src/Utils/FormatUtils.ts",
    "content": "/**\n * Intl.NumberFormat instance for percentage formatting.\n * Reused across all formatting calls for performance.\n */\nconst percentageFormatter = new Intl.NumberFormat(\"en-US\", {\n\tstyle: \"percent\",\n\tminimumFractionDigits: 1,\n\tmaximumFractionDigits: 1,\n});\n\n/**\n * Formats a decimal value as a percentage string.\n * @param value - Decimal value (e.g., 0.75 for 75%)\n * @returns Formatted percentage string (e.g., \"75.0%\")\n * @example\n * formatPercentage(0.75)   // \"75.0%\"\n * formatPercentage(1)      // \"100.0%\"\n * formatPercentage(0.5432) // \"54.3%\"\n */\nexport const formatPercentage = (value: number): string => {\n\tif (typeof value !== \"number\" || Number.isNaN(value)) {\n\t\treturn \"0.0%\";\n\t}\n\treturn percentageFormatter.format(value);\n};\n\n/**\n * Formats a whole number percentage value as a percentage string.\n * @param value - Whole number percentage (e.g., 75 for 75%)\n * @returns Formatted percentage string (e.g., \"75.0%\")\n * @example\n * formatPercentageFromWhole(75)    // \"75.0%\"\n * formatPercentageFromWhole(100)   // \"100.0%\"\n * formatPercentageFromWhole(54.32) // \"54.3%\"\n */\nexport const formatPercentageFromWhole = (value: number): string => {\n\treturn formatPercentage(value / 100);\n};\n\nexport const getPercentage = (value: number, total: number) => {\n\tif (!value || !total) return 0;\n\treturn (value / total) * 100;\n};\n"
  },
  {
    "path": "client/src/Utils/InfraUtils.ts",
    "content": "import type { CheckHostInfo } from \"@/Types/Check\";\n\nexport const getFrequency = (frequency: number | undefined): string => {\n\tif (!frequency) return \"N/A\";\n\tconst ghz = (frequency / 1000).toFixed(2);\n\treturn `${ghz} GHz`;\n};\n\nexport const getCores = (cores: number | undefined) => {\n\tif (!cores) return \"N/A\";\n\tif (cores === 1) return `${cores} core`;\n\treturn `${cores} cores`;\n};\n\nexport const getAvgTemp = (temps: number[]): string => {\n\tif (!temps || temps.length === 0) return \"N/A\";\n\tconst avgTemp = temps.reduce((a, b) => a + b, 0) / temps.length;\n\treturn `${avgTemp?.toFixed(2)} °C`;\n};\n\nexport const getOsAndPlatform = (hostInfo: CheckHostInfo | undefined): string => {\n\tif (!hostInfo) {\n\t\treturn \"N/A\";\n\t}\n\tconst os = hostInfo?.pretty_name || hostInfo?.os || \"N/A\";\n\tconst platform = hostInfo?.platform || \"N/A\";\n\treturn `${os} (${platform})`;\n};\n"
  },
  {
    "path": "client/src/Utils/MonitorUtils.ts",
    "content": "import type { MonitorStatus, MonitorType } from \"@/Types/Monitor\";\nimport type { PaletteKey } from \"@/Utils/Theme/Theme\";\nimport type { ValueType } from \"@/Components/design-elements/StatusLabel\";\n\nexport const getMonitorPath = (type: MonitorType): string => {\n\tconst pathMap: Record<MonitorType, string> = {\n\t\thttp: \"uptime\",\n\t\tport: \"uptime\",\n\t\tping: \"uptime\",\n\t\tgame: \"uptime\",\n\t\tgrpc: \"uptime\",\n\t\twebsocket: \"uptime\",\n\t\tunknown: \"uptime\",\n\t\tdocker: \"uptime\",\n\t\thardware: \"infrastructure\",\n\t\tpagespeed: \"pagespeed\",\n\t};\n\treturn pathMap[type];\n};\n\nexport const getStatusPalette = (status: MonitorStatus): PaletteKey => {\n\tif (status === \"up\") {\n\t\treturn \"success\";\n\t}\n\tif (status === \"down\") {\n\t\treturn \"error\";\n\t}\n\tif (status === \"breached\") {\n\t\treturn \"error\";\n\t}\n\treturn \"warning\";\n};\n\nexport const getValuePalette = (value: ValueType): PaletteKey => {\n\tconst paletteMap: Record<ValueType, PaletteKey> = {\n\t\tpositive: \"success\",\n\t\tnegative: \"error\",\n\t\tneutral: \"warning\",\n\t};\n\treturn paletteMap[value];\n};\n\nexport const getStatusColor = (status: MonitorStatus, theme: any): string => {\n\tif (status === \"up\") {\n\t\treturn theme.palette.success.light;\n\t}\n\n\tif (status === \"down\") {\n\t\treturn theme.palette.error.light;\n\t}\n\n\treturn theme.palette.warning.light;\n};\n\nexport const getResponseTimeColor = (responseTime: number): PaletteKey => {\n\tif (responseTime < 200) {\n\t\treturn \"success\";\n\t} else if (responseTime < 300) {\n\t\treturn \"warning\";\n\t} else {\n\t\treturn \"error\";\n\t}\n};\n\nexport const getInfraGaugeColor = (val: number, theme: any) => {\n\tif (val < 50) {\n\t\treturn theme.palette.success.main;\n\t} else if (val < 80) {\n\t\treturn theme.palette.warning.light;\n\t} else {\n\t\treturn theme.palette.error.light;\n\t}\n};\n\nexport const getPageSpeedPalette = (score: number): PaletteKey => {\n\tif (score >= 90) return \"success\";\n\telse if (score >= 50) return \"warning\";\n\telse return \"error\";\n};\n\nexport const formatUrl = (url: string, maxLength: number = 55) => {\n\tif (!url) return \"\";\n\n\tconst strippedUrl = url.replace(/^https?:\\/\\//, \"\");\n\treturn strippedUrl.length > maxLength\n\t\t? `${strippedUrl.slice(0, maxLength)}…`\n\t\t: strippedUrl;\n};\n"
  },
  {
    "path": "client/src/Utils/Theme/Palette.ts",
    "content": "const typographyBase = 13;\n\nexport const typographyLevels = {\n\tbase: typographyBase,\n\txs: `${(typographyBase - 4) / 16}rem`,\n\ts: `${(typographyBase - 2) / 16}rem`,\n\tm: `${typographyBase / 16}rem`,\n\tl: `${(typographyBase + 2) / 16}rem`,\n\txl: `${(typographyBase + 10) / 16}rem`,\n};\n\nexport const colors = {\n\tgray200: \"#EFEFEF\",\n\tgray700: \"#313131\",\n\tgray900: \"#151518\",\n\tgray850: \"#1c1c21\",\n\tblueBlueWave: \"#1570EF\",\n};\n\nexport const lightPalette = {\n\tprimary: {\n\t\tmain: colors.blueBlueWave,\n\t},\n\tsecondary: {\n\t\tmain: colors.gray200,\n\t},\n};\n\nexport const darkPalette = {\n\tprimary: {\n\t\tmain: colors.blueBlueWave,\n\t},\n\tsecondary: {\n\t\tmain: colors.gray700,\n\t},\n\tbackground: {\n\t\tdefault: colors.gray900,\n\t\tpaper: colors.gray850,\n\t},\n};\n"
  },
  {
    "path": "client/src/Utils/Theme/Theme.ts",
    "content": "import { createTheme } from \"@mui/material\";\nimport { lightPalette, darkPalette, typographyLevels } from \"@/Utils/Theme/Palette\";\n\nimport type { Theme } from \"@mui/material/styles\";\n\nexport type PaletteKey = {\n\t[K in keyof Theme[\"palette\"]]: Theme[\"palette\"][K] extends { main: any } ? K : never;\n}[keyof Theme[\"palette\"]];\n\nconst fontFamilyPrimary = \"system-ui, sans-serif\";\nconst shadow =\n\t\"0px 4px 24px -4px rgba(16, 24, 40, 0.08), 0px 3px 3px -3px rgba(16, 24, 40, 0.03)\";\n\nexport const theme = (mode: string, palette: any) =>\n\tcreateTheme({\n\t\tbreakpoints: {\n\t\t\tvalues: {\n\t\t\t\txs: 300,\n\t\t\t\tsm: 600,\n\t\t\t\tmd: 900,\n\t\t\t\tlg: 1200,\n\t\t\t\txl: 1536,\n\t\t\t},\n\t\t},\n\t\tspacing: 2,\n\t\tpalette: {\n\t\t\tmode: mode,\n\t\t\t...palette,\n\t\t},\n\t\ttypography: {\n\t\t\tfontFamily: fontFamilyPrimary,\n\t\t\tfontSize: typographyLevels.base,\n\t\t\th1: {\n\t\t\t\tfontSize: typographyLevels.xl,\n\t\t\t\tfontWeight: 500,\n\t\t\t},\n\t\t\th2: {\n\t\t\t\tfontSize: typographyLevels.l,\n\t\t\t\tfontWeight: 400,\n\t\t\t},\n\t\t\tbody1: {\n\t\t\t\tfontSize: typographyLevels.m,\n\t\t\t\tfontWeight: 400,\n\t\t\t},\n\t\t\tbody2: {\n\t\t\t\tfontSize: typographyLevels.s,\n\t\t\t\tfontWeight: 400,\n\t\t\t},\n\t\t},\n\n\t\tcomponents: {\n\t\t\tMuiTouchRipple: {\n\t\t\t\tstyleOverrides: {\n\t\t\t\t\troot: {\n\t\t\t\t\t\tdisplay: \"none\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tMuiButtonBase: {\n\t\t\t\tdefaultProps: {\n\t\t\t\t\tdisableRipple: true,\n\t\t\t\t\tdisableTouchRipple: true,\n\t\t\t\t},\n\t\t\t},\n\t\t\tMuiButton: {\n\t\t\t\tdefaultProps: {\n\t\t\t\t\tdisableRipple: true,\n\t\t\t\t\tdisableTouchRipple: true,\n\t\t\t\t\tdisableFocusRipple: true,\n\t\t\t\t},\n\t\t\t},\n\t\t\tMuiIconButton: {\n\t\t\t\tdefaultProps: {\n\t\t\t\t\tdisableRipple: true,\n\t\t\t\t\tdisableTouchRipple: true,\n\t\t\t\t\tdisableFocusRipple: true,\n\t\t\t\t},\n\t\t\t},\n\t\t\tMuiListItemButton: {\n\t\t\t\tdefaultProps: {\n\t\t\t\t\tdisableRipple: true,\n\t\t\t\t\tdisableTouchRipple: true,\n\t\t\t\t},\n\t\t\t},\n\t\t\tMuiTab: {\n\t\t\t\tdefaultProps: {\n\t\t\t\t\tdisableRipple: true,\n\t\t\t\t\tdisableTouchRipple: true,\n\t\t\t\t\tdisableFocusRipple: true,\n\t\t\t\t},\n\t\t\t},\n\t\t\tMuiToggleButton: {\n\t\t\t\tdefaultProps: {\n\t\t\t\t\tdisableRipple: true,\n\t\t\t\t\tdisableTouchRipple: true,\n\t\t\t\t\tdisableFocusRipple: true,\n\t\t\t\t},\n\t\t\t},\n\n\t\t\tMuiFormLabel: {\n\t\t\t\tstyleOverrides: {\n\t\t\t\t\troot: ({ theme }) => ({\n\t\t\t\t\t\tfontSize: typographyLevels.base,\n\t\t\t\t\t\t\"&.Mui-focused\": {\n\t\t\t\t\t\t\tcolor: theme.palette.secondary.contrastText,\n\t\t\t\t\t\t},\n\t\t\t\t\t}),\n\t\t\t\t},\n\t\t\t},\n\t\t\tMuiInputLabel: {\n\t\t\t\tstyleOverrides: {\n\t\t\t\t\troot: ({ theme }) => ({\n\t\t\t\t\t\ttop: `-${theme.spacing(4)}`,\n\t\t\t\t\t\t\"&.MuiInputLabel-shrink\": {\n\t\t\t\t\t\t\ttop: 0,\n\t\t\t\t\t\t},\n\t\t\t\t\t}),\n\t\t\t\t},\n\t\t\t},\n\n\t\t\tMuiOutlinedInput: {\n\t\t\t\tstyleOverrides: {\n\t\t\t\t\troot: {\n\t\t\t\t\t\t\"&.Mui-focused .MuiOutlinedInput-notchedOutline\": {\n\t\t\t\t\t\t\tborderColor: palette.primary.main,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\tMuiPaper: {\n\t\t\t\tstyleOverrides: {\n\t\t\t\t\troot: ({ theme }) => {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tmarginTop: 4,\n\t\t\t\t\t\t\tpadding: 0,\n\t\t\t\t\t\t\tborder: 1,\n\t\t\t\t\t\t\tborderStyle: \"solid\",\n\t\t\t\t\t\t\tborderColor: theme.palette.divider,\n\t\t\t\t\t\t\tborderRadius: 4,\n\t\t\t\t\t\t\tboxShadow: shadow,\n\t\t\t\t\t\t\tbackgroundColor: theme.palette.background.paper,\n\t\t\t\t\t\t\tbackgroundImage: \"none\",\n\t\t\t\t\t\t};\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tshape: {\n\t\t\tborderRadius: 2,\n\t\t},\n\t});\n\nexport const lightTheme = createTheme(theme(\"light\", lightPalette));\nexport const darkTheme = createTheme(theme(\"dark\", darkPalette));\n"
  },
  {
    "path": "client/src/Utils/Theme/constants.ts",
    "content": "export const SPACING = {\n\tXS: 0.5,\n\tSM: 1,\n\tMD: 1.5,\n\tLG: 2,\n\tXL: 2.5,\n\tXXL: 3,\n} as const;\n\nexport const LAYOUT = {\n\tXS: 4,\n\tSM: 6,\n\tMD: 8,\n\tLG: 10,\n\tXL: 12,\n\tXXL: 16,\n} as const;\n"
  },
  {
    "path": "client/src/Utils/TimeUtils.ts",
    "content": "import dayjs from \"dayjs\";\nimport duration from \"dayjs/plugin/duration\";\nimport utc from \"dayjs/plugin/utc\";\nimport timezone from \"dayjs/plugin/timezone\";\nimport customParseFormat from \"dayjs/plugin/customParseFormat\";\n\ndayjs.extend(utc);\ndayjs.extend(timezone);\ndayjs.extend(customParseFormat);\ndayjs.extend(duration);\n\nexport const MS_PER_SECOND = 1000;\nexport const MS_PER_MINUTE = 60 * MS_PER_SECOND;\nexport const MS_PER_HOUR = 60 * MS_PER_MINUTE;\nexport const MS_PER_DAY = 24 * MS_PER_HOUR;\nexport const MS_PER_WEEK = MS_PER_DAY * 7;\n\nexport const formatDateWithTz = (timestamp: string, format: string, timezone: string) => {\n\tif (!timestamp) {\n\t\treturn \"Unknown time\";\n\t}\n\tconst formattedDate = dayjs(timestamp).tz(timezone).format(format);\n\treturn formattedDate;\n};\n\nexport const tickDateFormatLookup = (range: string) => {\n\tconst tickFormatLookup: Record<string, string> = {\n\t\trecent: \"h:mm A\",\n\t\tday: \"h:mm A\",\n\t\tweek: \"MM/D, h:mm A\",\n\t\tmonth: \"ddd. M/D\",\n\t};\n\tconst format = tickFormatLookup[range];\n\tif (format === undefined) {\n\t\treturn \"\";\n\t}\n\treturn format;\n};\n\nexport const tooltipDateFormatLookup = (range: string) => {\n\tconst dateFormatLookup: Record<string, string> = {\n\t\trecent: \"ddd. MMMM D, YYYY, hh:mm A\",\n\t\tday: \"ddd. MMMM D, YYYY, hh:mm A\",\n\t\tweek: \"ddd. MMMM D, YYYY, hh:mm A\",\n\t\tmonth: \"ddd. MMMM D, YYYY\",\n\t};\n\tconst format = dateFormatLookup[range];\n\tif (format === undefined) {\n\t\treturn \"\";\n\t}\n\treturn format;\n};\n\nexport const formatTimestamp = (timestamp: string | number | null): string => {\n\tif (!timestamp) return \"-\";\n\tconst date = new Date(timestamp);\n\treturn date.toLocaleString();\n};\n"
  },
  {
    "path": "client/src/Utils/i18n.ts",
    "content": "import i18n from \"i18next\";\nimport { initReactI18next } from \"react-i18next\";\nimport type { Resource } from \"i18next\";\n\nconst primaryLanguage = \"en\";\n\ninterface TranslationModule {\n\tdefault?: Record<string, unknown>;\n\t[key: string]: unknown;\n}\n\n// Load all translation files eagerly\nconst translations = import.meta.glob<TranslationModule>(\"../locales/*.json\", {\n\teager: true,\n});\n\nconst resources: Resource = {};\nObject.keys(translations).forEach((path) => {\n\tconst match = path.match(/\\/([^/]+)\\.json$/);\n\tif (!match) return;\n\tconst langCode = match[1];\n\tresources[langCode] = {\n\t\ttranslation: translations[path].default ?? translations[path],\n\t};\n});\n\ni18n.use(initReactI18next).init({\n\tresources,\n\tlng: primaryLanguage,\n\tfallbackLng: primaryLanguage,\n\tdebug: import.meta.env.MODE === \"development\",\n\tns: [\"translation\"],\n\tdefaultNS: \"translation\",\n\tinterpolation: {\n\t\tescapeValue: false,\n\t},\n\treturnEmptyString: false,\n});\n\nexport default i18n;\n"
  },
  {
    "path": "client/src/Utils/logger.ts",
    "content": "import type { LogLevel } from \"@/Types/Log\";\n\ninterface LogContext {\n\t[key: string]: any;\n}\n\nconst LOG_LEVEL_PRIORITY: Record<LogLevel, number> = {\n\tdebug: 0,\n\tinfo: 1,\n\twarn: 2,\n\terror: 3,\n};\n\ninterface ErrorLogData {\n\ttimestamp: string;\n\tlevel: LogLevel;\n\tmessage: string;\n\terror?: {\n\t\tmessage: string;\n\t\tname: string;\n\t\tstack?: string;\n\t};\n\tcontext?: LogContext;\n\turl: string;\n\tuserAgent: string;\n}\n\nconst configuredLevel: LogLevel = import.meta.env.VITE_APP_LOG_LEVEL || \"error\";\nconst configuredPriority = LOG_LEVEL_PRIORITY[configuredLevel];\n\nconst shouldLog = (level: LogLevel): boolean => {\n\treturn LOG_LEVEL_PRIORITY[level] >= configuredPriority;\n};\n\nconst formatError = (error?: Error) => {\n\tif (!error) return undefined;\n\n\treturn {\n\t\tmessage: error.message,\n\t\tname: error.name,\n\t\tstack: error.stack,\n\t};\n};\n\nconst createLogData = (\n\tlevel: LogLevel,\n\tmessage: string,\n\terror?: Error,\n\tcontext?: LogContext\n): ErrorLogData => {\n\treturn {\n\t\ttimestamp: new Date().toISOString(),\n\t\tlevel,\n\t\tmessage,\n\t\terror: formatError(error),\n\t\tcontext,\n\t\turl: window.location.href,\n\t\tuserAgent: navigator.userAgent,\n\t};\n};\n\nconst error = (message: string, error?: Error, context?: LogContext): void => {\n\tif (!shouldLog(\"error\")) return;\n\n\tconst logData = createLogData(\"error\", message, error, context);\n\n\tif (configuredLevel === \"debug\") {\n\t\tconsole.group(`ERROR: ${message}`);\n\t\tif (error) {\n\t\t\tconsole.error(\"Error:\", error);\n\t\t}\n\t\tif (context && Object.keys(context).length > 0) {\n\t\t\tconsole.log(\"Context:\", context);\n\t\t}\n\t\tconsole.log(\"URL:\", logData.url);\n\t\tconsole.log(\"Timestamp:\", logData.timestamp);\n\t\tconsole.groupEnd();\n\t} else {\n\t\tconsole.error(JSON.stringify(logData));\n\t}\n};\n\nconst warn = (message: string, context?: LogContext): void => {\n\tif (!shouldLog(\"warn\")) return;\n\n\tconst logData = createLogData(\"warn\", message, undefined, context);\n\n\tif (configuredLevel === \"debug\") {\n\t\tconsole.group(`WARN: ${message}`);\n\t\tif (context && Object.keys(context).length > 0) {\n\t\t\tconsole.log(\"Context:\", context);\n\t\t}\n\t\tconsole.groupEnd();\n\t} else {\n\t\tconsole.warn(JSON.stringify(logData));\n\t}\n};\n\nconst debug = (message: string, data?: any): void => {\n\tif (!shouldLog(\"debug\")) return;\n\n\tconsole.group(`DEBUG: ${message}`);\n\tif (data !== undefined) {\n\t\tconsole.log(data);\n\t}\n\tconsole.groupEnd();\n};\n\nconst info = (message: string, data?: any): void => {\n\tif (!shouldLog(\"info\")) return;\n\n\tif (configuredLevel === \"debug\") {\n\t\tconsole.log(`INFO: ${message}`, data);\n\t} else {\n\t\tconst logData = {\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tlevel: \"info\" as LogLevel,\n\t\t\tmessage,\n\t\t\tdata,\n\t\t};\n\t\tconsole.log(JSON.stringify(logData));\n\t}\n};\n\nexport interface ILogger {\n\terror(message: string, error?: Error, context?: LogContext): void;\n\twarn(message: string, context?: LogContext): void;\n\tdebug(message: string, data?: any): void;\n\tinfo(message: string, data?: any): void;\n}\n\nexport const logger: ILogger = {\n\terror,\n\twarn,\n\tdebug,\n\tinfo,\n};\n"
  },
  {
    "path": "client/src/Utils/timezones.json",
    "content": "[\n\t{\n\t\t\"_id\": \"Africa/Abidjan\",\n\t\t\"name\": \"Africa/Abidjan\"\n\t},\n\t{\n\t\t\"_id\": \"Africa/Accra\",\n\t\t\"name\": \"Africa/Accra\"\n\t},\n\t{\n\t\t\"_id\": \"Africa/Addis_Ababa\",\n\t\t\"name\": \"Africa/Addis_Ababa\"\n\t},\n\t{\n\t\t\"_id\": \"Africa/Algiers\",\n\t\t\"name\": \"Africa/Algiers\"\n\t},\n\t{\n\t\t\"_id\": \"Africa/Asmara\",\n\t\t\"name\": \"Africa/Asmara\"\n\t},\n\t{\n\t\t\"_id\": \"Africa/Bamako\",\n\t\t\"name\": \"Africa/Bamako\"\n\t},\n\t{\n\t\t\"_id\": \"Africa/Bangui\",\n\t\t\"name\": \"Africa/Bangui\"\n\t},\n\t{\n\t\t\"_id\": \"Africa/Banjul\",\n\t\t\"name\": \"Africa/Banjul\"\n\t},\n\t{\n\t\t\"_id\": \"Africa/Bissau\",\n\t\t\"name\": \"Africa/Bissau\"\n\t},\n\t{\n\t\t\"_id\": \"Africa/Blantyre\",\n\t\t\"name\": \"Africa/Blantyre\"\n\t},\n\t{\n\t\t\"_id\": \"Africa/Brazzaville\",\n\t\t\"name\": \"Africa/Brazzaville\"\n\t},\n\t{\n\t\t\"_id\": \"Africa/Bujumbura\",\n\t\t\"name\": \"Africa/Bujumbura\"\n\t},\n\t{\n\t\t\"_id\": \"Africa/Cairo\",\n\t\t\"name\": \"Africa/Cairo\"\n\t},\n\t{\n\t\t\"_id\": \"Africa/Casablanca\",\n\t\t\"name\": \"Africa/Casablanca\"\n\t},\n\t{\n\t\t\"_id\": \"Africa/Ceuta\",\n\t\t\"name\": \"Africa/Ceuta\"\n\t},\n\t{\n\t\t\"_id\": \"Africa/Conakry\",\n\t\t\"name\": \"Africa/Conakry\"\n\t},\n\t{\n\t\t\"_id\": \"Africa/Dakar\",\n\t\t\"name\": \"Africa/Dakar\"\n\t},\n\t{\n\t\t\"_id\": \"Africa/Dar_es_Salaam\",\n\t\t\"name\": \"Africa/Dar_es_Salaam\"\n\t},\n\t{\n\t\t\"_id\": \"Africa/Djibouti\",\n\t\t\"name\": \"Africa/Djibouti\"\n\t},\n\t{\n\t\t\"_id\": \"Africa/Douala\",\n\t\t\"name\": \"Africa/Douala\"\n\t},\n\t{\n\t\t\"_id\": \"Africa/El_Aaiun\",\n\t\t\"name\": \"Africa/El_Aaiun\"\n\t},\n\t{\n\t\t\"_id\": \"Africa/Freetown\",\n\t\t\"name\": \"Africa/Freetown\"\n\t},\n\t{\n\t\t\"_id\": \"Africa/Gaborone\",\n\t\t\"name\": \"Africa/Gaborone\"\n\t},\n\t{\n\t\t\"_id\": \"Africa/Harare\",\n\t\t\"name\": \"Africa/Harare\"\n\t},\n\t{\n\t\t\"_id\": \"Africa/Johannesburg\",\n\t\t\"name\": \"Africa/Johannesburg\"\n\t},\n\t{\n\t\t\"_id\": \"Africa/Juba\",\n\t\t\"name\": \"Africa/Juba\"\n\t},\n\t{\n\t\t\"_id\": \"Africa/Kampala\",\n\t\t\"name\": \"Africa/Kampala\"\n\t},\n\t{\n\t\t\"_id\": \"Africa/Khartoum\",\n\t\t\"name\": \"Africa/Khartoum\"\n\t},\n\t{\n\t\t\"_id\": \"Africa/Kigali\",\n\t\t\"name\": \"Africa/Kigali\"\n\t},\n\t{\n\t\t\"_id\": \"Africa/Kinshasa\",\n\t\t\"name\": \"Africa/Kinshasa\"\n\t},\n\t{\n\t\t\"_id\": \"Africa/Lagos\",\n\t\t\"name\": \"Africa/Lagos\"\n\t},\n\t{\n\t\t\"_id\": \"Africa/Libreville\",\n\t\t\"name\": \"Africa/Libreville\"\n\t},\n\t{\n\t\t\"_id\": \"Africa/Lome\",\n\t\t\"name\": \"Africa/Lome\"\n\t},\n\t{\n\t\t\"_id\": \"Africa/Luanda\",\n\t\t\"name\": \"Africa/Luanda\"\n\t},\n\t{\n\t\t\"_id\": \"Africa/Lubumbashi\",\n\t\t\"name\": \"Africa/Lubumbashi\"\n\t},\n\t{\n\t\t\"_id\": \"Africa/Lusaka\",\n\t\t\"name\": \"Africa/Lusaka\"\n\t},\n\t{\n\t\t\"_id\": \"Africa/Malabo\",\n\t\t\"name\": \"Africa/Malabo\"\n\t},\n\t{\n\t\t\"_id\": \"Africa/Maputo\",\n\t\t\"name\": \"Africa/Maputo\"\n\t},\n\t{\n\t\t\"_id\": \"Africa/Maseru\",\n\t\t\"name\": \"Africa/Maseru\"\n\t},\n\t{\n\t\t\"_id\": \"Africa/Mbabane\",\n\t\t\"name\": \"Africa/Mbabane\"\n\t},\n\t{\n\t\t\"_id\": \"Africa/Mogadishu\",\n\t\t\"name\": \"Africa/Mogadishu\"\n\t},\n\t{\n\t\t\"_id\": \"Africa/Monrovia\",\n\t\t\"name\": \"Africa/Monrovia\"\n\t},\n\t{\n\t\t\"_id\": \"Africa/Nairobi\",\n\t\t\"name\": \"Africa/Nairobi\"\n\t},\n\t{\n\t\t\"_id\": \"Africa/Ndjamena\",\n\t\t\"name\": \"Africa/Ndjamena\"\n\t},\n\t{\n\t\t\"_id\": \"Africa/Niamey\",\n\t\t\"name\": \"Africa/Niamey\"\n\t},\n\t{\n\t\t\"_id\": \"Africa/Nouakchott\",\n\t\t\"name\": \"Africa/Nouakchott\"\n\t},\n\t{\n\t\t\"_id\": \"Africa/Ouagadougou\",\n\t\t\"name\": \"Africa/Ouagadougou\"\n\t},\n\t{\n\t\t\"_id\": \"Africa/Porto-Novo\",\n\t\t\"name\": \"Africa/Porto-Novo\"\n\t},\n\t{\n\t\t\"_id\": \"Africa/Sao_Tome\",\n\t\t\"name\": \"Africa/Sao_Tome\"\n\t},\n\t{\n\t\t\"_id\": \"Africa/Tripoli\",\n\t\t\"name\": \"Africa/Tripoli\"\n\t},\n\t{\n\t\t\"_id\": \"Africa/Tunis\",\n\t\t\"name\": \"Africa/Tunis\"\n\t},\n\t{\n\t\t\"_id\": \"Africa/Windhoek\",\n\t\t\"name\": \"Africa/Windhoek\"\n\t},\n\t{\n\t\t\"_id\": \"America/Adak\",\n\t\t\"name\": \"America/Adak\"\n\t},\n\t{\n\t\t\"_id\": \"America/Anchorage\",\n\t\t\"name\": \"America/Anchorage\"\n\t},\n\t{\n\t\t\"_id\": \"America/Anguilla\",\n\t\t\"name\": \"America/Anguilla\"\n\t},\n\t{\n\t\t\"_id\": \"America/Antigua\",\n\t\t\"name\": \"America/Antigua\"\n\t},\n\t{\n\t\t\"_id\": \"America/Araguaina\",\n\t\t\"name\": \"America/Araguaina\"\n\t},\n\t{\n\t\t\"_id\": \"America/Argentina/Buenos_Aires\",\n\t\t\"name\": \"America/Argentina/Buenos_Aires\"\n\t},\n\t{\n\t\t\"_id\": \"America/Argentina/Catamarca\",\n\t\t\"name\": \"America/Argentina/Catamarca\"\n\t},\n\t{\n\t\t\"_id\": \"America/Argentina/Cordoba\",\n\t\t\"name\": \"America/Argentina/Cordoba\"\n\t},\n\t{\n\t\t\"_id\": \"America/Argentina/Jujuy\",\n\t\t\"name\": \"America/Argentina/Jujuy\"\n\t},\n\t{\n\t\t\"_id\": \"America/Argentina/La_Rioja\",\n\t\t\"name\": \"America/Argentina/La_Rioja\"\n\t},\n\t{\n\t\t\"_id\": \"America/Argentina/Mendoza\",\n\t\t\"name\": \"America/Argentina/Mendoza\"\n\t},\n\t{\n\t\t\"_id\": \"America/Argentina/Rio_Gallegos\",\n\t\t\"name\": \"America/Argentina/Rio_Gallegos\"\n\t},\n\t{\n\t\t\"_id\": \"America/Argentina/Salta\",\n\t\t\"name\": \"America/Argentina/Salta\"\n\t},\n\t{\n\t\t\"_id\": \"America/Argentina/San_Juan\",\n\t\t\"name\": \"America/Argentina/San_Juan\"\n\t},\n\t{\n\t\t\"_id\": \"America/Argentina/San_Luis\",\n\t\t\"name\": \"America/Argentina/San_Luis\"\n\t},\n\t{\n\t\t\"_id\": \"America/Argentina/Tucuman\",\n\t\t\"name\": \"America/Argentina/Tucuman\"\n\t},\n\t{\n\t\t\"_id\": \"America/Argentina/Ushuaia\",\n\t\t\"name\": \"America/Argentina/Ushuaia\"\n\t},\n\t{\n\t\t\"_id\": \"America/Aruba\",\n\t\t\"name\": \"America/Aruba\"\n\t},\n\t{\n\t\t\"_id\": \"America/Asuncion\",\n\t\t\"name\": \"America/Asuncion\"\n\t},\n\t{\n\t\t\"_id\": \"America/Atikokan\",\n\t\t\"name\": \"America/Atikokan\"\n\t},\n\t{\n\t\t\"_id\": \"America/Bahia\",\n\t\t\"name\": \"America/Bahia\"\n\t},\n\t{\n\t\t\"_id\": \"America/Bahia_Banderas\",\n\t\t\"name\": \"America/Bahia_Banderas\"\n\t},\n\t{\n\t\t\"_id\": \"America/Barbados\",\n\t\t\"name\": \"America/Barbados\"\n\t},\n\t{\n\t\t\"_id\": \"America/Belem\",\n\t\t\"name\": \"America/Belem\"\n\t},\n\t{\n\t\t\"_id\": \"America/Belize\",\n\t\t\"name\": \"America/Belize\"\n\t},\n\t{\n\t\t\"_id\": \"America/Blanc-Sablon\",\n\t\t\"name\": \"America/Blanc-Sablon\"\n\t},\n\t{\n\t\t\"_id\": \"America/Boa_Vista\",\n\t\t\"name\": \"America/Boa_Vista\"\n\t},\n\t{\n\t\t\"_id\": \"America/Bogota\",\n\t\t\"name\": \"America/Bogota\"\n\t},\n\t{\n\t\t\"_id\": \"America/Boise\",\n\t\t\"name\": \"America/Boise\"\n\t},\n\t{\n\t\t\"_id\": \"America/Cambridge_Bay\",\n\t\t\"name\": \"America/Cambridge_Bay\"\n\t},\n\t{\n\t\t\"_id\": \"America/Campo_Grande\",\n\t\t\"name\": \"America/Campo_Grande\"\n\t},\n\t{\n\t\t\"_id\": \"America/Cancun\",\n\t\t\"name\": \"America/Cancun\"\n\t},\n\t{\n\t\t\"_id\": \"America/Caracas\",\n\t\t\"name\": \"America/Caracas\"\n\t},\n\t{\n\t\t\"_id\": \"America/Cayenne\",\n\t\t\"name\": \"America/Cayenne\"\n\t},\n\t{\n\t\t\"_id\": \"America/Cayman\",\n\t\t\"name\": \"America/Cayman\"\n\t},\n\t{\n\t\t\"_id\": \"America/Chicago\",\n\t\t\"name\": \"America/Chicago\"\n\t},\n\t{\n\t\t\"_id\": \"America/Chihuahua\",\n\t\t\"name\": \"America/Chihuahua\"\n\t},\n\t{\n\t\t\"_id\": \"America/Costa_Rica\",\n\t\t\"name\": \"America/Costa_Rica\"\n\t},\n\t{\n\t\t\"_id\": \"America/Creston\",\n\t\t\"name\": \"America/Creston\"\n\t},\n\t{\n\t\t\"_id\": \"America/Cuiaba\",\n\t\t\"name\": \"America/Cuiaba\"\n\t},\n\t{\n\t\t\"_id\": \"America/Curacao\",\n\t\t\"name\": \"America/Curacao\"\n\t},\n\t{\n\t\t\"_id\": \"America/Danmarkshavn\",\n\t\t\"name\": \"America/Danmarkshavn\"\n\t},\n\t{\n\t\t\"_id\": \"America/Dawson\",\n\t\t\"name\": \"America/Dawson\"\n\t},\n\t{\n\t\t\"_id\": \"America/Dawson_Creek\",\n\t\t\"name\": \"America/Dawson_Creek\"\n\t},\n\t{\n\t\t\"_id\": \"America/Denver\",\n\t\t\"name\": \"America/Denver\"\n\t},\n\t{\n\t\t\"_id\": \"America/Detroit\",\n\t\t\"name\": \"America/Detroit\"\n\t},\n\t{\n\t\t\"_id\": \"America/Dominica\",\n\t\t\"name\": \"America/Dominica\"\n\t},\n\t{\n\t\t\"_id\": \"America/Edmonton\",\n\t\t\"name\": \"America/Edmonton\"\n\t},\n\t{\n\t\t\"_id\": \"America/Eirunepe\",\n\t\t\"name\": \"America/Eirunepe\"\n\t},\n\t{\n\t\t\"_id\": \"America/El_Salvador\",\n\t\t\"name\": \"America/El_Salvador\"\n\t},\n\t{\n\t\t\"_id\": \"America/Fort_Nelson\",\n\t\t\"name\": \"America/Fort_Nelson\"\n\t},\n\t{\n\t\t\"_id\": \"America/Fortaleza\",\n\t\t\"name\": \"America/Fortaleza\"\n\t},\n\t{\n\t\t\"_id\": \"America/Glace_Bay\",\n\t\t\"name\": \"America/Glace_Bay\"\n\t},\n\t{\n\t\t\"_id\": \"America/Godthab\",\n\t\t\"name\": \"America/Godthab\"\n\t},\n\t{\n\t\t\"_id\": \"America/Goose_Bay\",\n\t\t\"name\": \"America/Goose_Bay\"\n\t},\n\t{\n\t\t\"_id\": \"America/Grand_Turk\",\n\t\t\"name\": \"America/Grand_Turk\"\n\t},\n\t{\n\t\t\"_id\": \"America/Grenada\",\n\t\t\"name\": \"America/Grenada\"\n\t},\n\t{\n\t\t\"_id\": \"America/Guadeloupe\",\n\t\t\"name\": \"America/Guadeloupe\"\n\t},\n\t{\n\t\t\"_id\": \"America/Guatemala\",\n\t\t\"name\": \"America/Guatemala\"\n\t},\n\t{\n\t\t\"_id\": \"America/Guayaquil\",\n\t\t\"name\": \"America/Guayaquil\"\n\t},\n\t{\n\t\t\"_id\": \"America/Guyana\",\n\t\t\"name\": \"America/Guyana\"\n\t},\n\t{\n\t\t\"_id\": \"America/Halifax\",\n\t\t\"name\": \"America/Halifax\"\n\t},\n\t{\n\t\t\"_id\": \"America/Havana\",\n\t\t\"name\": \"America/Havana\"\n\t},\n\t{\n\t\t\"_id\": \"America/Hermosillo\",\n\t\t\"name\": \"America/Hermosillo\"\n\t},\n\t{\n\t\t\"_id\": \"America/Indiana/Indianapolis\",\n\t\t\"name\": \"America/Indiana/Indianapolis\"\n\t},\n\t{\n\t\t\"_id\": \"America/Indiana/Knox\",\n\t\t\"name\": \"America/Indiana/Knox\"\n\t},\n\t{\n\t\t\"_id\": \"America/Indiana/Marengo\",\n\t\t\"name\": \"America/Indiana/Marengo\"\n\t},\n\t{\n\t\t\"_id\": \"America/Indiana/Petersburg\",\n\t\t\"name\": \"America/Indiana/Petersburg\"\n\t},\n\t{\n\t\t\"_id\": \"America/Indiana/Tell_City\",\n\t\t\"name\": \"America/Indiana/Tell_City\"\n\t},\n\t{\n\t\t\"_id\": \"America/Indiana/Vevay\",\n\t\t\"name\": \"America/Indiana/Vevay\"\n\t},\n\t{\n\t\t\"_id\": \"America/Indiana/Vincennes\",\n\t\t\"name\": \"America/Indiana/Vincennes\"\n\t},\n\t{\n\t\t\"_id\": \"America/Indiana/Winamac\",\n\t\t\"name\": \"America/Indiana/Winamac\"\n\t},\n\t{\n\t\t\"_id\": \"America/Inuvik\",\n\t\t\"name\": \"America/Inuvik\"\n\t},\n\t{\n\t\t\"_id\": \"America/Iqaluit\",\n\t\t\"name\": \"America/Iqaluit\"\n\t},\n\t{\n\t\t\"_id\": \"America/Jamaica\",\n\t\t\"name\": \"America/Jamaica\"\n\t},\n\t{\n\t\t\"_id\": \"America/Juneau\",\n\t\t\"name\": \"America/Juneau\"\n\t},\n\t{\n\t\t\"_id\": \"America/Kentucky/Louisville\",\n\t\t\"name\": \"America/Kentucky/Louisville\"\n\t},\n\t{\n\t\t\"_id\": \"America/Kentucky/Monticello\",\n\t\t\"name\": \"America/Kentucky/Monticello\"\n\t},\n\t{\n\t\t\"_id\": \"America/Kralendijk\",\n\t\t\"name\": \"America/Kralendijk\"\n\t},\n\t{\n\t\t\"_id\": \"America/La_Paz\",\n\t\t\"name\": \"America/La_Paz\"\n\t},\n\t{\n\t\t\"_id\": \"America/Lima\",\n\t\t\"name\": \"America/Lima\"\n\t},\n\t{\n\t\t\"_id\": \"America/Los_Angeles\",\n\t\t\"name\": \"America/Los_Angeles\"\n\t},\n\t{\n\t\t\"_id\": \"America/Lower_Princes\",\n\t\t\"name\": \"America/Lower_Princes\"\n\t},\n\t{\n\t\t\"_id\": \"America/Maceio\",\n\t\t\"name\": \"America/Maceio\"\n\t},\n\t{\n\t\t\"_id\": \"America/Managua\",\n\t\t\"name\": \"America/Managua\"\n\t},\n\t{\n\t\t\"_id\": \"America/Manaus\",\n\t\t\"name\": \"America/Manaus\"\n\t},\n\t{\n\t\t\"_id\": \"America/Marigot\",\n\t\t\"name\": \"America/Marigot\"\n\t},\n\t{\n\t\t\"_id\": \"America/Martinique\",\n\t\t\"name\": \"America/Martinique\"\n\t},\n\t{\n\t\t\"_id\": \"America/Matamoros\",\n\t\t\"name\": \"America/Matamoros\"\n\t},\n\t{\n\t\t\"_id\": \"America/Mazatlan\",\n\t\t\"name\": \"America/Mazatlan\"\n\t},\n\t{\n\t\t\"_id\": \"America/Menominee\",\n\t\t\"name\": \"America/Menominee\"\n\t},\n\t{\n\t\t\"_id\": \"America/Merida\",\n\t\t\"name\": \"America/Merida\"\n\t},\n\t{\n\t\t\"_id\": \"America/Metlakatla\",\n\t\t\"name\": \"America/Metlakatla\"\n\t},\n\t{\n\t\t\"_id\": \"America/Mexico_City\",\n\t\t\"name\": \"America/Mexico_City\"\n\t},\n\t{\n\t\t\"_id\": \"America/Miquelon\",\n\t\t\"name\": \"America/Miquelon\"\n\t},\n\t{\n\t\t\"_id\": \"America/Moncton\",\n\t\t\"name\": \"America/Moncton\"\n\t},\n\t{\n\t\t\"_id\": \"America/Monterrey\",\n\t\t\"name\": \"America/Monterrey\"\n\t},\n\t{\n\t\t\"_id\": \"America/Montevideo\",\n\t\t\"name\": \"America/Montevideo\"\n\t},\n\t{\n\t\t\"_id\": \"America/Montserrat\",\n\t\t\"name\": \"America/Montserrat\"\n\t},\n\t{\n\t\t\"_id\": \"America/Nassau\",\n\t\t\"name\": \"America/Nassau\"\n\t},\n\t{\n\t\t\"_id\": \"America/New_York\",\n\t\t\"name\": \"America/New_York\"\n\t},\n\t{\n\t\t\"_id\": \"America/Nipigon\",\n\t\t\"name\": \"America/Nipigon\"\n\t},\n\t{\n\t\t\"_id\": \"America/Nome\",\n\t\t\"name\": \"America/Nome\"\n\t},\n\t{\n\t\t\"_id\": \"America/Noronha\",\n\t\t\"name\": \"America/Noronha\"\n\t},\n\t{\n\t\t\"_id\": \"America/North_Dakota/Beulah\",\n\t\t\"name\": \"America/North_Dakota/Beulah\"\n\t},\n\t{\n\t\t\"_id\": \"America/North_Dakota/Center\",\n\t\t\"name\": \"America/North_Dakota/Center\"\n\t},\n\t{\n\t\t\"_id\": \"America/North_Dakota/New_Salem\",\n\t\t\"name\": \"America/North_Dakota/New_Salem\"\n\t},\n\t{\n\t\t\"_id\": \"America/Ojinaga\",\n\t\t\"name\": \"America/Ojinaga\"\n\t},\n\t{\n\t\t\"_id\": \"America/Panama\",\n\t\t\"name\": \"America/Panama\"\n\t},\n\t{\n\t\t\"_id\": \"America/Pangnirtung\",\n\t\t\"name\": \"America/Pangnirtung\"\n\t},\n\t{\n\t\t\"_id\": \"America/Paramaribo\",\n\t\t\"name\": \"America/Paramaribo\"\n\t},\n\t{\n\t\t\"_id\": \"America/Phoenix\",\n\t\t\"name\": \"America/Phoenix\"\n\t},\n\t{\n\t\t\"_id\": \"America/Port_of_Spain\",\n\t\t\"name\": \"America/Port_of_Spain\"\n\t},\n\t{\n\t\t\"_id\": \"America/Port-au-Prince\",\n\t\t\"name\": \"America/Port-au-Prince\"\n\t},\n\t{\n\t\t\"_id\": \"America/Porto_Velho\",\n\t\t\"name\": \"America/Porto_Velho\"\n\t},\n\t{\n\t\t\"_id\": \"America/Puerto_Rico\",\n\t\t\"name\": \"America/Puerto_Rico\"\n\t},\n\t{\n\t\t\"_id\": \"America/Punta_Arenas\",\n\t\t\"name\": \"America/Punta_Arenas\"\n\t},\n\t{\n\t\t\"_id\": \"America/Rainy_River\",\n\t\t\"name\": \"America/Rainy_River\"\n\t},\n\t{\n\t\t\"_id\": \"America/Rankin_Inlet\",\n\t\t\"name\": \"America/Rankin_Inlet\"\n\t},\n\t{\n\t\t\"_id\": \"America/Recife\",\n\t\t\"name\": \"America/Recife\"\n\t},\n\t{\n\t\t\"_id\": \"America/Regina\",\n\t\t\"name\": \"America/Regina\"\n\t},\n\t{\n\t\t\"_id\": \"America/Resolute\",\n\t\t\"name\": \"America/Resolute\"\n\t},\n\t{\n\t\t\"_id\": \"America/Rio_Branco\",\n\t\t\"name\": \"America/Rio_Branco\"\n\t},\n\t{\n\t\t\"_id\": \"America/Santarem\",\n\t\t\"name\": \"America/Santarem\"\n\t},\n\t{\n\t\t\"_id\": \"America/Santiago\",\n\t\t\"name\": \"America/Santiago\"\n\t},\n\t{\n\t\t\"_id\": \"America/Santo_Domingo\",\n\t\t\"name\": \"America/Santo_Domingo\"\n\t},\n\t{\n\t\t\"_id\": \"America/Sao_Paulo\",\n\t\t\"name\": \"America/Sao_Paulo\"\n\t},\n\t{\n\t\t\"_id\": \"America/Scoresbysund\",\n\t\t\"name\": \"America/Scoresbysund\"\n\t},\n\t{\n\t\t\"_id\": \"America/Sitka\",\n\t\t\"name\": \"America/Sitka\"\n\t},\n\t{\n\t\t\"_id\": \"America/St_Barthelemy\",\n\t\t\"name\": \"America/St_Barthelemy\"\n\t},\n\t{\n\t\t\"_id\": \"America/St_Johns\",\n\t\t\"name\": \"America/St_Johns\"\n\t},\n\t{\n\t\t\"_id\": \"America/St_Kitts\",\n\t\t\"name\": \"America/St_Kitts\"\n\t},\n\t{\n\t\t\"_id\": \"America/St_Lucia\",\n\t\t\"name\": \"America/St_Lucia\"\n\t},\n\t{\n\t\t\"_id\": \"America/St_Thomas\",\n\t\t\"name\": \"America/St_Thomas\"\n\t},\n\t{\n\t\t\"_id\": \"America/St_Vincent\",\n\t\t\"name\": \"America/St_Vincent\"\n\t},\n\t{\n\t\t\"_id\": \"America/Swift_Current\",\n\t\t\"name\": \"America/Swift_Current\"\n\t},\n\t{\n\t\t\"_id\": \"America/Tegucigalpa\",\n\t\t\"name\": \"America/Tegucigalpa\"\n\t},\n\t{\n\t\t\"_id\": \"America/Thule\",\n\t\t\"name\": \"America/Thule\"\n\t},\n\t{\n\t\t\"_id\": \"America/Thunder_Bay\",\n\t\t\"name\": \"America/Thunder_Bay\"\n\t},\n\t{\n\t\t\"_id\": \"America/Tijuana\",\n\t\t\"name\": \"America/Tijuana\"\n\t},\n\t{\n\t\t\"_id\": \"America/Toronto\",\n\t\t\"name\": \"America/Toronto\"\n\t},\n\t{\n\t\t\"_id\": \"America/Tortola\",\n\t\t\"name\": \"America/Tortola\"\n\t},\n\t{\n\t\t\"_id\": \"America/Vancouver\",\n\t\t\"name\": \"America/Vancouver\"\n\t},\n\t{\n\t\t\"_id\": \"America/Whitehorse\",\n\t\t\"name\": \"America/Whitehorse\"\n\t},\n\t{\n\t\t\"_id\": \"America/Winnipeg\",\n\t\t\"name\": \"America/Winnipeg\"\n\t},\n\t{\n\t\t\"_id\": \"America/Yakutat\",\n\t\t\"name\": \"America/Yakutat\"\n\t},\n\t{\n\t\t\"_id\": \"America/Yellowknife\",\n\t\t\"name\": \"America/Yellowknife\"\n\t},\n\t{\n\t\t\"_id\": \"Antarctica/Casey\",\n\t\t\"name\": \"Antarctica/Casey\"\n\t},\n\t{\n\t\t\"_id\": \"Antarctica/Davis\",\n\t\t\"name\": \"Antarctica/Davis\"\n\t},\n\t{\n\t\t\"_id\": \"Antarctica/DumontDUrville\",\n\t\t\"name\": \"Antarctica/DumontDUrville\"\n\t},\n\t{\n\t\t\"_id\": \"Antarctica/Macquarie\",\n\t\t\"name\": \"Antarctica/Macquarie\"\n\t},\n\t{\n\t\t\"_id\": \"Antarctica/Mawson\",\n\t\t\"name\": \"Antarctica/Mawson\"\n\t},\n\t{\n\t\t\"_id\": \"Antarctica/McMurdo\",\n\t\t\"name\": \"Antarctica/McMurdo\"\n\t},\n\t{\n\t\t\"_id\": \"Antarctica/Palmer\",\n\t\t\"name\": \"Antarctica/Palmer\"\n\t},\n\t{\n\t\t\"_id\": \"Antarctica/Rothera\",\n\t\t\"name\": \"Antarctica/Rothera\"\n\t},\n\t{\n\t\t\"_id\": \"Antarctica/Syowa\",\n\t\t\"name\": \"Antarctica/Syowa\"\n\t},\n\t{\n\t\t\"_id\": \"Antarctica/Troll\",\n\t\t\"name\": \"Antarctica/Troll\"\n\t},\n\t{\n\t\t\"_id\": \"Antarctica/Vostok\",\n\t\t\"name\": \"Antarctica/Vostok\"\n\t},\n\t{\n\t\t\"_id\": \"Arctic/Longyearbyen\",\n\t\t\"name\": \"Arctic/Longyearbyen\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Aden\",\n\t\t\"name\": \"Asia/Aden\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Almaty\",\n\t\t\"name\": \"Asia/Almaty\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Amman\",\n\t\t\"name\": \"Asia/Amman\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Anadyr\",\n\t\t\"name\": \"Asia/Anadyr\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Aqtau\",\n\t\t\"name\": \"Asia/Aqtau\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Aqtobe\",\n\t\t\"name\": \"Asia/Aqtobe\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Ashgabat\",\n\t\t\"name\": \"Asia/Ashgabat\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Atyrau\",\n\t\t\"name\": \"Asia/Atyrau\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Baghdad\",\n\t\t\"name\": \"Asia/Baghdad\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Bahrain\",\n\t\t\"name\": \"Asia/Bahrain\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Baku\",\n\t\t\"name\": \"Asia/Baku\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Bangkok\",\n\t\t\"name\": \"Asia/Bangkok\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Barnaul\",\n\t\t\"name\": \"Asia/Barnaul\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Beirut\",\n\t\t\"name\": \"Asia/Beirut\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Bishkek\",\n\t\t\"name\": \"Asia/Bishkek\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Brunei\",\n\t\t\"name\": \"Asia/Brunei\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Chita\",\n\t\t\"name\": \"Asia/Chita\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Choibalsan\",\n\t\t\"name\": \"Asia/Choibalsan\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Colombo\",\n\t\t\"name\": \"Asia/Colombo\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Damascus\",\n\t\t\"name\": \"Asia/Damascus\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Dhaka\",\n\t\t\"name\": \"Asia/Dhaka\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Dili\",\n\t\t\"name\": \"Asia/Dili\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Dubai\",\n\t\t\"name\": \"Asia/Dubai\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Dushanbe\",\n\t\t\"name\": \"Asia/Dushanbe\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Famagusta\",\n\t\t\"name\": \"Asia/Famagusta\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Gaza\",\n\t\t\"name\": \"Asia/Gaza\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Hebron\",\n\t\t\"name\": \"Asia/Hebron\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Ho_Chi_Minh\",\n\t\t\"name\": \"Asia/Ho_Chi_Minh\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Hong_Kong\",\n\t\t\"name\": \"Asia/Hong_Kong\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Hovd\",\n\t\t\"name\": \"Asia/Hovd\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Irkutsk\",\n\t\t\"name\": \"Asia/Irkutsk\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Jakarta\",\n\t\t\"name\": \"Asia/Jakarta\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Jayapura\",\n\t\t\"name\": \"Asia/Jayapura\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Jerusalem\",\n\t\t\"name\": \"Asia/Jerusalem\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Kabul\",\n\t\t\"name\": \"Asia/Kabul\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Kamchatka\",\n\t\t\"name\": \"Asia/Kamchatka\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Karachi\",\n\t\t\"name\": \"Asia/Karachi\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Kathmandu\",\n\t\t\"name\": \"Asia/Kathmandu\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Khandyga\",\n\t\t\"name\": \"Asia/Khandyga\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Kolkata\",\n\t\t\"name\": \"Asia/Kolkata\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Krasnoyarsk\",\n\t\t\"name\": \"Asia/Krasnoyarsk\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Kuala_Lumpur\",\n\t\t\"name\": \"Asia/Kuala_Lumpur\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Kuching\",\n\t\t\"name\": \"Asia/Kuching\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Kuwait\",\n\t\t\"name\": \"Asia/Kuwait\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Macau\",\n\t\t\"name\": \"Asia/Macau\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Magadan\",\n\t\t\"name\": \"Asia/Magadan\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Makassar\",\n\t\t\"name\": \"Asia/Makassar\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Manila\",\n\t\t\"name\": \"Asia/Manila\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Muscat\",\n\t\t\"name\": \"Asia/Muscat\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Nicosia\",\n\t\t\"name\": \"Asia/Nicosia\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Novokuznetsk\",\n\t\t\"name\": \"Asia/Novokuznetsk\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Novosibirsk\",\n\t\t\"name\": \"Asia/Novosibirsk\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Omsk\",\n\t\t\"name\": \"Asia/Omsk\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Oral\",\n\t\t\"name\": \"Asia/Oral\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Phnom_Penh\",\n\t\t\"name\": \"Asia/Phnom_Penh\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Pontianak\",\n\t\t\"name\": \"Asia/Pontianak\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Pyongyang\",\n\t\t\"name\": \"Asia/Pyongyang\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Qatar\",\n\t\t\"name\": \"Asia/Qatar\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Qostanay\",\n\t\t\"name\": \"Asia/Qostanay\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Qyzylorda\",\n\t\t\"name\": \"Asia/Qyzylorda\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Riyadh\",\n\t\t\"name\": \"Asia/Riyadh\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Sakhalin\",\n\t\t\"name\": \"Asia/Sakhalin\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Samarkand\",\n\t\t\"name\": \"Asia/Samarkand\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Seoul\",\n\t\t\"name\": \"Asia/Seoul\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Shanghai\",\n\t\t\"name\": \"Asia/Shanghai\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Singapore\",\n\t\t\"name\": \"Asia/Singapore\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Srednekolymsk\",\n\t\t\"name\": \"Asia/Srednekolymsk\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Taipei\",\n\t\t\"name\": \"Asia/Taipei\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Tashkent\",\n\t\t\"name\": \"Asia/Tashkent\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Tbilisi\",\n\t\t\"name\": \"Asia/Tbilisi\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Tehran\",\n\t\t\"name\": \"Asia/Tehran\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Thimphu\",\n\t\t\"name\": \"Asia/Thimphu\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Tokyo\",\n\t\t\"name\": \"Asia/Tokyo\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Tomsk\",\n\t\t\"name\": \"Asia/Tomsk\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Ulaanbaatar\",\n\t\t\"name\": \"Asia/Ulaanbaatar\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Urumqi\",\n\t\t\"name\": \"Asia/Urumqi\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Ust-Nera\",\n\t\t\"name\": \"Asia/Ust-Nera\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Vientiane\",\n\t\t\"name\": \"Asia/Vientiane\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Vladivostok\",\n\t\t\"name\": \"Asia/Vladivostok\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Yakutsk\",\n\t\t\"name\": \"Asia/Yakutsk\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Yangon\",\n\t\t\"name\": \"Asia/Yangon\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Yekaterinburg\",\n\t\t\"name\": \"Asia/Yekaterinburg\"\n\t},\n\t{\n\t\t\"_id\": \"Asia/Yerevan\",\n\t\t\"name\": \"Asia/Yerevan\"\n\t},\n\t{\n\t\t\"_id\": \"Atlantic/Azores\",\n\t\t\"name\": \"Atlantic/Azores\"\n\t},\n\t{\n\t\t\"_id\": \"Atlantic/Bermuda\",\n\t\t\"name\": \"Atlantic/Bermuda\"\n\t},\n\t{\n\t\t\"_id\": \"Atlantic/Canary\",\n\t\t\"name\": \"Atlantic/Canary\"\n\t},\n\t{\n\t\t\"_id\": \"Atlantic/Cape_Verde\",\n\t\t\"name\": \"Atlantic/Cape_Verde\"\n\t},\n\t{\n\t\t\"_id\": \"Atlantic/Faroe\",\n\t\t\"name\": \"Atlantic/Faroe\"\n\t},\n\t{\n\t\t\"_id\": \"Atlantic/Madeira\",\n\t\t\"name\": \"Atlantic/Madeira\"\n\t},\n\t{\n\t\t\"_id\": \"Atlantic/Reykjavik\",\n\t\t\"name\": \"Atlantic/Reykjavik\"\n\t},\n\t{\n\t\t\"_id\": \"Atlantic/South_Georgia\",\n\t\t\"name\": \"Atlantic/South_Georgia\"\n\t},\n\t{\n\t\t\"_id\": \"Atlantic/St_Helena\",\n\t\t\"name\": \"Atlantic/St_Helena\"\n\t},\n\t{\n\t\t\"_id\": \"Atlantic/Stanley\",\n\t\t\"name\": \"Atlantic/Stanley\"\n\t},\n\t{\n\t\t\"_id\": \"Australia/Adelaide\",\n\t\t\"name\": \"Australia/Adelaide\"\n\t},\n\t{\n\t\t\"_id\": \"Australia/Brisbane\",\n\t\t\"name\": \"Australia/Brisbane\"\n\t},\n\t{\n\t\t\"_id\": \"Australia/Broken_Hill\",\n\t\t\"name\": \"Australia/Broken_Hill\"\n\t},\n\t{\n\t\t\"_id\": \"Australia/Currie\",\n\t\t\"name\": \"Australia/Currie\"\n\t},\n\t{\n\t\t\"_id\": \"Australia/Darwin\",\n\t\t\"name\": \"Australia/Darwin\"\n\t},\n\t{\n\t\t\"_id\": \"Australia/Eucla\",\n\t\t\"name\": \"Australia/Eucla\"\n\t},\n\t{\n\t\t\"_id\": \"Australia/Hobart\",\n\t\t\"name\": \"Australia/Hobart\"\n\t},\n\t{\n\t\t\"_id\": \"Australia/Lindeman\",\n\t\t\"name\": \"Australia/Lindeman\"\n\t},\n\t{\n\t\t\"_id\": \"Australia/Lord_Howe\",\n\t\t\"name\": \"Australia/Lord_Howe\"\n\t},\n\t{\n\t\t\"_id\": \"Australia/Melbourne\",\n\t\t\"name\": \"Australia/Melbourne\"\n\t},\n\t{\n\t\t\"_id\": \"Australia/Perth\",\n\t\t\"name\": \"Australia/Perth\"\n\t},\n\t{\n\t\t\"_id\": \"Australia/Sydney\",\n\t\t\"name\": \"Australia/Sydney\"\n\t},\n\t{\n\t\t\"_id\": \"Europe/Amsterdam\",\n\t\t\"name\": \"Europe/Amsterdam\"\n\t},\n\t{\n\t\t\"_id\": \"Europe/Andorra\",\n\t\t\"name\": \"Europe/Andorra\"\n\t},\n\t{\n\t\t\"_id\": \"Europe/Astrakhan\",\n\t\t\"name\": \"Europe/Astrakhan\"\n\t},\n\t{\n\t\t\"_id\": \"Europe/Athens\",\n\t\t\"name\": \"Europe/Athens\"\n\t},\n\t{\n\t\t\"_id\": \"Europe/Belgrade\",\n\t\t\"name\": \"Europe/Belgrade\"\n\t},\n\t{\n\t\t\"_id\": \"Europe/Berlin\",\n\t\t\"name\": \"Europe/Berlin\"\n\t},\n\t{\n\t\t\"_id\": \"Europe/Bratislava\",\n\t\t\"name\": \"Europe/Bratislava\"\n\t},\n\t{\n\t\t\"_id\": \"Europe/Brussels\",\n\t\t\"name\": \"Europe/Brussels\"\n\t},\n\t{\n\t\t\"_id\": \"Europe/Bucharest\",\n\t\t\"name\": \"Europe/Bucharest\"\n\t},\n\t{\n\t\t\"_id\": \"Europe/Budapest\",\n\t\t\"name\": \"Europe/Budapest\"\n\t},\n\t{\n\t\t\"_id\": \"Europe/Chisinau\",\n\t\t\"name\": \"Europe/Chisinau\"\n\t},\n\t{\n\t\t\"_id\": \"Europe/Copenhagen\",\n\t\t\"name\": \"Europe/Copenhagen\"\n\t},\n\t{\n\t\t\"_id\": \"Europe/Dublin\",\n\t\t\"name\": \"Europe/Dublin\"\n\t},\n\t{\n\t\t\"_id\": \"Europe/Gibraltar\",\n\t\t\"name\": \"Europe/Gibraltar\"\n\t},\n\t{\n\t\t\"_id\": \"Europe/Guernsey\",\n\t\t\"name\": \"Europe/Guernsey\"\n\t},\n\t{\n\t\t\"_id\": \"Europe/Helsinki\",\n\t\t\"name\": \"Europe/Helsinki\"\n\t},\n\t{\n\t\t\"_id\": \"Europe/Isle_of_Man\",\n\t\t\"name\": \"Europe/Isle_of_Man\"\n\t},\n\t{\n\t\t\"_id\": \"Europe/Istanbul\",\n\t\t\"name\": \"Europe/Istanbul\"\n\t},\n\t{\n\t\t\"_id\": \"Europe/Jersey\",\n\t\t\"name\": \"Europe/Jersey\"\n\t},\n\t{\n\t\t\"_id\": \"Europe/Kaliningrad\",\n\t\t\"name\": \"Europe/Kaliningrad\"\n\t},\n\t{\n\t\t\"_id\": \"Europe/Kirov\",\n\t\t\"name\": \"Europe/Kirov\"\n\t},\n\t{\n\t\t\"_id\": \"Europe/Kyiv\",\n\t\t\"name\": \"Europe/Kyiv\"\n\t},\n\t{\n\t\t\"_id\": \"Europe/Lisbon\",\n\t\t\"name\": \"Europe/Lisbon\"\n\t},\n\t{\n\t\t\"_id\": \"Europe/Ljubljana\",\n\t\t\"name\": \"Europe/Ljubljana\"\n\t},\n\t{\n\t\t\"_id\": \"Europe/London\",\n\t\t\"name\": \"Europe/London\"\n\t},\n\t{\n\t\t\"_id\": \"Europe/Luxembourg\",\n\t\t\"name\": \"Europe/Luxembourg\"\n\t},\n\t{\n\t\t\"_id\": \"Europe/Madrid\",\n\t\t\"name\": \"Europe/Madrid\"\n\t},\n\t{\n\t\t\"_id\": \"Europe/Malta\",\n\t\t\"name\": \"Europe/Malta\"\n\t},\n\t{\n\t\t\"_id\": \"Europe/Mariehamn\",\n\t\t\"name\": \"Europe/Mariehamn\"\n\t},\n\t{\n\t\t\"_id\": \"Europe/Minsk\",\n\t\t\"name\": \"Europe/Minsk\"\n\t},\n\t{\n\t\t\"_id\": \"Europe/Monaco\",\n\t\t\"name\": \"Europe/Monaco\"\n\t},\n\t{\n\t\t\"_id\": \"Europe/Moscow\",\n\t\t\"name\": \"Europe/Moscow\"\n\t},\n\t{\n\t\t\"_id\": \"Europe/Oslo\",\n\t\t\"name\": \"Europe/Oslo\"\n\t},\n\t{\n\t\t\"_id\": \"Europe/Paris\",\n\t\t\"name\": \"Europe/Paris\"\n\t},\n\t{\n\t\t\"_id\": \"Europe/Podgorica\",\n\t\t\"name\": \"Europe/Podgorica\"\n\t},\n\t{\n\t\t\"_id\": \"Europe/Prague\",\n\t\t\"name\": \"Europe/Prague\"\n\t},\n\t{\n\t\t\"_id\": \"Europe/Riga\",\n\t\t\"name\": \"Europe/Riga\"\n\t},\n\t{\n\t\t\"_id\": \"Europe/Rome\",\n\t\t\"name\": \"Europe/Rome\"\n\t},\n\t{\n\t\t\"_id\": \"Europe/Samara\",\n\t\t\"name\": \"Europe/Samara\"\n\t},\n\t{\n\t\t\"_id\": \"Europe/San_Marino\",\n\t\t\"name\": \"Europe/San_Marino\"\n\t},\n\t{\n\t\t\"_id\": \"Europe/Sarajevo\",\n\t\t\"name\": \"Europe/Sarajevo\"\n\t},\n\t{\n\t\t\"_id\": \"Europe/Saratov\",\n\t\t\"name\": \"Europe/Saratov\"\n\t},\n\t{\n\t\t\"_id\": \"Europe/Simferopol\",\n\t\t\"name\": \"Europe/Simferopol\"\n\t},\n\t{\n\t\t\"_id\": \"Europe/Skopje\",\n\t\t\"name\": \"Europe/Skopje\"\n\t},\n\t{\n\t\t\"_id\": \"Europe/Sofia\",\n\t\t\"name\": \"Europe/Sofia\"\n\t},\n\t{\n\t\t\"_id\": \"Europe/Stockholm\",\n\t\t\"name\": \"Europe/Stockholm\"\n\t},\n\t{\n\t\t\"_id\": \"Europe/Tallinn\",\n\t\t\"name\": \"Europe/Tallinn\"\n\t},\n\t{\n\t\t\"_id\": \"Europe/Tirane\",\n\t\t\"name\": \"Europe/Tirane\"\n\t},\n\t{\n\t\t\"_id\": \"Europe/Ulyanovsk\",\n\t\t\"name\": \"Europe/Ulyanovsk\"\n\t},\n\t{\n\t\t\"_id\": \"Europe/Uzhgorod\",\n\t\t\"name\": \"Europe/Uzhgorod\"\n\t},\n\t{\n\t\t\"_id\": \"Europe/Vaduz\",\n\t\t\"name\": \"Europe/Vaduz\"\n\t},\n\t{\n\t\t\"_id\": \"Europe/Vatican\",\n\t\t\"name\": \"Europe/Vatican\"\n\t},\n\t{\n\t\t\"_id\": \"Europe/Vienna\",\n\t\t\"name\": \"Europe/Vienna\"\n\t},\n\t{\n\t\t\"_id\": \"Europe/Vilnius\",\n\t\t\"name\": \"Europe/Vilnius\"\n\t},\n\t{\n\t\t\"_id\": \"Europe/Volgograd\",\n\t\t\"name\": \"Europe/Volgograd\"\n\t},\n\t{\n\t\t\"_id\": \"Europe/Warsaw\",\n\t\t\"name\": \"Europe/Warsaw\"\n\t},\n\t{\n\t\t\"_id\": \"Europe/Zagreb\",\n\t\t\"name\": \"Europe/Zagreb\"\n\t},\n\t{\n\t\t\"_id\": \"Europe/Zaporizhzhia\",\n\t\t\"name\": \"Europe/Zaporizhzhia\"\n\t},\n\t{\n\t\t\"_id\": \"Europe/Zurich\",\n\t\t\"name\": \"Europe/Zurich\"\n\t},\n\t{\n\t\t\"_id\": \"Indian/Antananarivo\",\n\t\t\"name\": \"Indian/Antananarivo\"\n\t},\n\t{\n\t\t\"_id\": \"Indian/Chagos\",\n\t\t\"name\": \"Indian/Chagos\"\n\t},\n\t{\n\t\t\"_id\": \"Indian/Christmas\",\n\t\t\"name\": \"Indian/Christmas\"\n\t},\n\t{\n\t\t\"_id\": \"Indian/Cocos\",\n\t\t\"name\": \"Indian/Cocos\"\n\t},\n\t{\n\t\t\"_id\": \"Indian/Comoro\",\n\t\t\"name\": \"Indian/Comoro\"\n\t},\n\t{\n\t\t\"_id\": \"Indian/Kerguelen\",\n\t\t\"name\": \"Indian/Kerguelen\"\n\t},\n\t{\n\t\t\"_id\": \"Indian/Mahe\",\n\t\t\"name\": \"Indian/Mahe\"\n\t},\n\t{\n\t\t\"_id\": \"Indian/Maldives\",\n\t\t\"name\": \"Indian/Maldives\"\n\t},\n\t{\n\t\t\"_id\": \"Indian/Mauritius\",\n\t\t\"name\": \"Indian/Mauritius\"\n\t},\n\t{\n\t\t\"_id\": \"Indian/Mayotte\",\n\t\t\"name\": \"Indian/Mayotte\"\n\t},\n\t{\n\t\t\"_id\": \"Indian/Reunion\",\n\t\t\"name\": \"Indian/Reunion\"\n\t},\n\t{\n\t\t\"_id\": \"Pacific/Apia\",\n\t\t\"name\": \"Pacific/Apia\"\n\t},\n\t{\n\t\t\"_id\": \"Pacific/Auckland\",\n\t\t\"name\": \"Pacific/Auckland\"\n\t},\n\t{\n\t\t\"_id\": \"Pacific/Bougainville\",\n\t\t\"name\": \"Pacific/Bougainville\"\n\t},\n\t{\n\t\t\"_id\": \"Pacific/Chatham\",\n\t\t\"name\": \"Pacific/Chatham\"\n\t},\n\t{\n\t\t\"_id\": \"Pacific/Chuuk\",\n\t\t\"name\": \"Pacific/Chuuk\"\n\t},\n\t{\n\t\t\"_id\": \"Pacific/Easter\",\n\t\t\"name\": \"Pacific/Easter\"\n\t},\n\t{\n\t\t\"_id\": \"Pacific/Efate\",\n\t\t\"name\": \"Pacific/Efate\"\n\t},\n\t{\n\t\t\"_id\": \"Pacific/Enderbury\",\n\t\t\"name\": \"Pacific/Enderbury\"\n\t},\n\t{\n\t\t\"_id\": \"Pacific/Fakaofo\",\n\t\t\"name\": \"Pacific/Fakaofo\"\n\t},\n\t{\n\t\t\"_id\": \"Pacific/Fiji\",\n\t\t\"name\": \"Pacific/Fiji\"\n\t},\n\t{\n\t\t\"_id\": \"Pacific/Funafuti\",\n\t\t\"name\": \"Pacific/Funafuti\"\n\t},\n\t{\n\t\t\"_id\": \"Pacific/Galapagos\",\n\t\t\"name\": \"Pacific/Galapagos\"\n\t},\n\t{\n\t\t\"_id\": \"Pacific/Gambier\",\n\t\t\"name\": \"Pacific/Gambier\"\n\t},\n\t{\n\t\t\"_id\": \"Pacific/Guadalcanal\",\n\t\t\"name\": \"Pacific/Guadalcanal\"\n\t},\n\t{\n\t\t\"_id\": \"Pacific/Guam\",\n\t\t\"name\": \"Pacific/Guam\"\n\t},\n\t{\n\t\t\"_id\": \"Pacific/Honolulu\",\n\t\t\"name\": \"Pacific/Honolulu\"\n\t},\n\t{\n\t\t\"_id\": \"Pacific/Kiritimati\",\n\t\t\"name\": \"Pacific/Kiritimati\"\n\t},\n\t{\n\t\t\"_id\": \"Pacific/Kosrae\",\n\t\t\"name\": \"Pacific/Kosrae\"\n\t},\n\t{\n\t\t\"_id\": \"Pacific/Kwajalein\",\n\t\t\"name\": \"Pacific/Kwajalein\"\n\t},\n\t{\n\t\t\"_id\": \"Pacific/Majuro\",\n\t\t\"name\": \"Pacific/Majuro\"\n\t},\n\t{\n\t\t\"_id\": \"Pacific/Marquesas\",\n\t\t\"name\": \"Pacific/Marquesas\"\n\t},\n\t{\n\t\t\"_id\": \"Pacific/Midway\",\n\t\t\"name\": \"Pacific/Midway\"\n\t},\n\t{\n\t\t\"_id\": \"Pacific/Nauru\",\n\t\t\"name\": \"Pacific/Nauru\"\n\t},\n\t{\n\t\t\"_id\": \"Pacific/Niue\",\n\t\t\"name\": \"Pacific/Niue\"\n\t},\n\t{\n\t\t\"_id\": \"Pacific/Norfolk\",\n\t\t\"name\": \"Pacific/Norfolk\"\n\t},\n\t{\n\t\t\"_id\": \"Pacific/Noumea\",\n\t\t\"name\": \"Pacific/Noumea\"\n\t},\n\t{\n\t\t\"_id\": \"Pacific/Pago_Pago\",\n\t\t\"name\": \"Pacific/Pago_Pago\"\n\t},\n\t{\n\t\t\"_id\": \"Pacific/Palau\",\n\t\t\"name\": \"Pacific/Palau\"\n\t},\n\t{\n\t\t\"_id\": \"Pacific/Pitcairn\",\n\t\t\"name\": \"Pacific/Pitcairn\"\n\t},\n\t{\n\t\t\"_id\": \"Pacific/Pohnpei\",\n\t\t\"name\": \"Pacific/Pohnpei\"\n\t},\n\t{\n\t\t\"_id\": \"Pacific/Port_Moresby\",\n\t\t\"name\": \"Pacific/Port_Moresby\"\n\t},\n\t{\n\t\t\"_id\": \"Pacific/Rarotonga\",\n\t\t\"name\": \"Pacific/Rarotonga\"\n\t},\n\t{\n\t\t\"_id\": \"Pacific/Saipan\",\n\t\t\"name\": \"Pacific/Saipan\"\n\t},\n\t{\n\t\t\"_id\": \"Pacific/Tahiti\",\n\t\t\"name\": \"Pacific/Tahiti\"\n\t},\n\t{\n\t\t\"_id\": \"Pacific/Tarawa\",\n\t\t\"name\": \"Pacific/Tarawa\"\n\t},\n\t{\n\t\t\"_id\": \"Pacific/Tongatapu\",\n\t\t\"name\": \"Pacific/Tongatapu\"\n\t},\n\t{\n\t\t\"_id\": \"Pacific/Wake\",\n\t\t\"name\": \"Pacific/Wake\"\n\t},\n\t{\n\t\t\"_id\": \"Pacific/Wallis\",\n\t\t\"name\": \"Pacific/Wallis\"\n\t}\n]\n"
  },
  {
    "path": "client/src/Utils/toastUtils.jsx",
    "content": "import PropTypes from \"prop-types\";\nimport { toast, Slide } from \"react-toastify\";\nimport Toast from \"../Components/v1/Toast\";\n/**\n * @param {object} props\n * @param {'info' | 'error' | 'warning'} - The variant of the alert (e.g., \"info\", \"error\").\n * @param {string} props.title - The title of the alert.\n * @param {string} props.body - The body/content of the alert.\n * @param {boolean} props.hasIcon - Whether the alert should include an icon.\n * @param {object} [props.config] - Additional configuration props for the toast.\n */\n\nexport const createToast = ({\n\tvariant = \"info\",\n\ttitle,\n\tbody,\n\thasDismiss = false,\n\thasIcon = false,\n\tconfig = {},\n}) => {\n\tconst toastConfig = {\n\t\tposition: \"top-right\",\n\t\tautoClose: 3000,\n\t\thideProgressBar: true,\n\t\tcloseButton: false,\n\t\ttransition: Slide,\n\t\t...config,\n\t};\n\n\ttoast(\n\t\t({ closeToast }) => (\n\t\t\t<Toast\n\t\t\t\tvariant={variant}\n\t\t\t\ttitle={title}\n\t\t\t\tbody={body}\n\t\t\t\tisToast={true}\n\t\t\t\tonClick={closeToast}\n\t\t\t\thasDismiss={hasDismiss}\n\t\t\t\thasIcon={hasIcon}\n\t\t\t/>\n\t\t),\n\t\ttoastConfig\n\t);\n};\n\ncreateToast.propTypes = {\n\tvariant: PropTypes.oneOf([\"info\", \"error\", \"warning\"]),\n\ttitle: PropTypes.string,\n\tbody: PropTypes.string.isRequired,\n\thasIcon: PropTypes.bool,\n\thasDismiss: PropTypes.bool,\n\tconfig: PropTypes.object,\n};\n"
  },
  {
    "path": "client/src/Validation/addTeamMember.ts",
    "content": "import { z } from \"zod\";\nimport { registerSchema } from \"@/Validation/register\";\nimport { UserRoles } from \"@/Types/User\";\n\nexport const addTeamMemberSchema = registerSchema.extend({\n\trole: z.array(z.enum(UserRoles)).min(1, \"Please select a role\"),\n});\n\nexport type AddTeamMemberFormData = z.infer<typeof addTeamMemberSchema>;\n"
  },
  {
    "path": "client/src/Validation/editUser.ts",
    "content": "import { z } from \"zod\";\nimport { namePattern } from \"@/Validation/patterns\";\nimport { UserRoles } from \"@/Types/User\";\n\nexport const editUserSchema = z.object({\n\tfirstName: z\n\t\t.string()\n\t\t.min(1, \"First name is required\")\n\t\t.max(50, \"First name must be 50 characters or less\")\n\t\t.regex(namePattern, \"First name contains invalid characters\"),\n\tlastName: z\n\t\t.string()\n\t\t.min(1, \"Last name is required\")\n\t\t.max(50, \"Last name must be 50 characters or less\")\n\t\t.regex(namePattern, \"Last name contains invalid characters\"),\n\trole: z.array(z.enum(UserRoles)).min(1, \"At least one role is required\"),\n});\n\nexport type EditUserFormData = z.infer<typeof editUserSchema>;\n"
  },
  {
    "path": "client/src/Validation/invite.ts",
    "content": "import { z } from \"zod\";\nimport { UserRoles } from \"@/Types/User\";\n\nexport const inviteSchema = z.object({\n\temail: z.email(\"Please enter a valid email address\"),\n\trole: z.array(z.enum(UserRoles)).min(1, \"Please select a role\"),\n});\n\nexport type InviteFormData = z.infer<typeof inviteSchema>;\n"
  },
  {
    "path": "client/src/Validation/login.ts",
    "content": "import { z } from \"zod\";\n\nexport const loginSchema = z.object({\n\temail: z\n\t\t.email(\"Please enter a valid email address\")\n\t\t.min(1, \"Please enter your email address\")\n\t\t.transform((val) => val.toLowerCase().trim()),\n\tpassword: z.string().min(1, \"Please enter your password\"),\n});\n\nexport type LoginFormData = z.infer<typeof loginSchema>;\n"
  },
  {
    "path": "client/src/Validation/maintenanceWindow.ts",
    "content": "import { z } from \"zod\";\nimport dayjs from \"dayjs\";\n\nexport const repeatOptions = [\n\t{ id: \"none\", name: \"Don't repeat\", value: 0 },\n\t{ id: \"daily\", name: \"Repeat daily\", value: 86400000 },\n\t{ id: \"weekly\", name: \"Repeat weekly\", value: 604800000 },\n] as const;\n\nexport const durationUnitOptions = [\n\t{ id: \"seconds\", name: \"seconds\", multiplier: 1000 },\n\t{ id: \"minutes\", name: \"minutes\", multiplier: 60000 },\n\t{ id: \"hours\", name: \"hours\", multiplier: 3600000 },\n\t{ id: \"days\", name: \"days\", multiplier: 86400000 },\n] as const;\n\nexport const maintenanceWindowSchema = z\n\t.object({\n\t\tname: z\n\t\t\t.string()\n\t\t\t.min(1, \"Name is required\")\n\t\t\t.max(100, \"Name must be at most 100 characters\"),\n\t\trepeat: z.string(),\n\t\tstartDate: z.string().min(1, \"Start date is required\"),\n\t\tstartTime: z.string().min(1, \"Start time is required\"),\n\t\tduration: z.number().int().min(1, \"Duration must be at least 1\"),\n\t\tdurationUnit: z.string(),\n\t\tmonitors: z.array(z.string()).min(1, \"At least one monitor is required\"),\n\t})\n\t.refine(\n\t\t(data) => {\n\t\t\tconst startDateTime = dayjs(data.startDate)\n\t\t\t\t.set(\"hour\", parseInt(data.startTime.split(\":\")[0], 10))\n\t\t\t\t.set(\"minute\", parseInt(data.startTime.split(\":\")[1], 10));\n\t\t\treturn startDateTime.isAfter(dayjs());\n\t\t},\n\t\t{\n\t\t\tmessage: \"Start date and time must be in the future\",\n\t\t\tpath: [\"startDate\"],\n\t\t}\n\t);\n\nexport type MaintenanceWindowFormData = z.infer<typeof maintenanceWindowSchema>;\n"
  },
  {
    "path": "client/src/Validation/monitor.ts",
    "content": "import { z } from \"zod\";\nimport { GeoContinents } from \"@/Types/GeoCheck\";\n\n// URL schema with custom error message\nconst urlSchema = z.url({ message: \"Please enter a valid URL\" });\n\n// Common base schema for all monitor types\nconst baseSchema = z.object({\n\tname: z\n\t\t.string()\n\t\t.min(1, \"Monitor name is required\")\n\t\t.max(50, \"Monitor name must be at most 50 characters\"),\n\tdescription: z.string().optional(),\n\tinterval: z.number().min(15000, \"Interval must be at least 15 seconds\"),\n\tnotifications: z.array(z.string()),\n\tstatusWindowSize: z\n\t\t.number({ message: \"Status window size is required\" })\n\t\t.min(1, \"Status window size must be at least 1\")\n\t\t.max(25, \"Status window size must be at most 25\"),\n\tstatusWindowThreshold: z\n\t\t.number({ message: \"Threshold percentage is required\" })\n\t\t.min(1, \"Incident percentage must be at least 1\")\n\t\t.max(100, \"Incident percentage must be at most 100\"),\n\tgeoCheckEnabled: z.boolean().optional(),\n\tgeoCheckLocations: z.array(z.enum(GeoContinents)).optional(),\n\tgeoCheckInterval: z\n\t\t.number()\n\t\t.min(300000, \"Interval must be at least 5 minutes\")\n\t\t.optional(),\n});\n\n// HTTP monitor schema\nconst httpSchema = baseSchema.extend({\n\ttype: z.literal(\"http\"),\n\turl: urlSchema,\n\tignoreTlsErrors: z.boolean(),\n\tuseAdvancedMatching: z.boolean(),\n\tmatchMethod: z.enum([\"equal\", \"include\", \"regex\", \"\"]).optional(),\n\texpectedValue: z.string().optional(),\n\tjsonPath: z.string().optional(),\n});\n\n// Ping monitor schema\nconst pingSchema = baseSchema.extend({\n\ttype: z.literal(\"ping\"),\n\turl: z.string().min(1, \"Host is required\"),\n});\n\n// Port monitor schema\nconst portSchema = baseSchema.extend({\n\ttype: z.literal(\"port\"),\n\turl: z.string().min(1, \"Host is required\"),\n\tport: z\n\t\t.number()\n\t\t.min(1, \"Port must be at least 1\")\n\t\t.max(65535, \"Port must be at most 65535\"),\n});\n\n// Docker monitor schema\nconst dockerSchema = baseSchema.extend({\n\ttype: z.literal(\"docker\"),\n\turl: z.string().min(1, \"Container ID is required\"),\n});\n\n// Game server monitor schema\nconst gameSchema = baseSchema.extend({\n\ttype: z.literal(\"game\"),\n\turl: z.string().min(1, \"Host is required\"),\n\tport: z\n\t\t.number()\n\t\t.min(1, \"Port must be at least 1\")\n\t\t.max(65535, \"Port must be at most 65535\"),\n\tgameId: z.string().min(1, \"Game type is required\"),\n});\n\n// gRPC monitor schema\nconst grpcSchema = baseSchema.extend({\n\ttype: z.literal(\"grpc\"),\n\turl: z.string().min(1, \"Host is required\"),\n\tport: z\n\t\t.number()\n\t\t.min(1, \"Port must be at least 1\")\n\t\t.max(65535, \"Port must be at most 65535\"),\n\tgrpcServiceName: z.string().optional(),\n\tignoreTlsErrors: z.boolean(),\n});\n\n// PageSpeed monitor schema\nconst pagespeedSchema = baseSchema.extend({\n\ttype: z.literal(\"pagespeed\"),\n\turl: urlSchema,\n});\n\n// Hardware/Infrastructure monitor schema\nconst hardwareSchema = baseSchema.extend({\n\ttype: z.literal(\"hardware\"),\n\turl: urlSchema,\n\tsecret: z.string({ message: \"Secret is required\" }).min(1, \"Secret is required\"),\n\tcpuAlertThreshold: z\n\t\t.number()\n\t\t.min(0, \"CPU threshold must be at least 0\")\n\t\t.max(100, \"CPU threshold must be at most 100\"),\n\tmemoryAlertThreshold: z\n\t\t.number()\n\t\t.min(0, \"Memory threshold must be at least 0\")\n\t\t.max(100, \"Memory threshold must be at most 100\"),\n\tdiskAlertThreshold: z\n\t\t.number()\n\t\t.min(0, \"Disk threshold must be at least 0\")\n\t\t.max(100, \"Disk threshold must be at most 100\"),\n\ttempAlertThreshold: z\n\t\t.number()\n\t\t.min(0, \"Temperature threshold must be at least 0\")\n\t\t.max(150, \"Temperature threshold must be at most 150\"),\n\tselectedDisks: z.array(z.string()),\n});\n\n// WebSocket monitor schema\nconst websocketSchema = baseSchema.extend({\n\ttype: z.literal(\"websocket\"),\n\turl: z.string().min(1, \"WebSocket URL is required\"),\n\tignoreTlsErrors: z.boolean(),\n});\n\n// Discriminated union of all monitor types\nexport const monitorSchema = z.discriminatedUnion(\"type\", [\n\thttpSchema,\n\tpingSchema,\n\tportSchema,\n\tdockerSchema,\n\tgameSchema,\n\tgrpcSchema,\n\tpagespeedSchema,\n\thardwareSchema,\n\twebsocketSchema,\n]);\n\nexport type MonitorFormData = z.infer<typeof monitorSchema>;\n\n// Type-specific schemas exported for individual use\nexport {\n\thttpSchema,\n\tpingSchema,\n\tportSchema,\n\tdockerSchema,\n\tgameSchema,\n\tgrpcSchema,\n\tpagespeedSchema,\n\thardwareSchema,\n\twebsocketSchema,\n};\n"
  },
  {
    "path": "client/src/Validation/notifications.ts",
    "content": "import { z } from \"zod\";\n\nconst baseSchema = z.object({\n\tnotificationName: z\n\t\t.string()\n\t\t.min(1, \"Notification name is required\")\n\t\t.max(100, \"Notification name must be at most 100 characters\"),\n});\n\nconst emailSchema = baseSchema.extend({\n\ttype: z.literal(\"email\"),\n\taddress: z\n\t\t.string()\n\t\t.min(1, \"Email is required\")\n\t\t.email(\"Please enter a valid email address\"),\n});\n\nconst slackSchema = baseSchema.extend({\n\ttype: z.literal(\"slack\"),\n\taddress: z.string().min(1, \"Webhook URL is required\").url(\"Please enter a valid URL\"),\n});\n\nconst discordSchema = baseSchema.extend({\n\ttype: z.literal(\"discord\"),\n\taddress: z.string().min(1, \"Webhook URL is required\").url(\"Please enter a valid URL\"),\n});\n\nconst webhookSchema = baseSchema.extend({\n\ttype: z.literal(\"webhook\"),\n\taddress: z.string().min(1, \"Webhook URL is required\").url(\"Please enter a valid URL\"),\n});\n\nconst pagerDutySchema = baseSchema.extend({\n\ttype: z.literal(\"pager_duty\"),\n\taddress: z.string().min(1, \"Integration key is required\"),\n});\n\nconst matrixSchema = baseSchema.extend({\n\ttype: z.literal(\"matrix\"),\n\thomeserverUrl: z\n\t\t.string()\n\t\t.min(1, \"Homeserver URL is required\")\n\t\t.url(\"Please enter a valid URL\"),\n\troomId: z.string().min(1, \"Room ID is required\"),\n\taccessToken: z.string().min(1, \"Access token is required\"),\n});\n\nconst teamsSchema = baseSchema.extend({\n\ttype: z.literal(\"teams\"),\n\taddress: z.string().min(1, \"Webhook URL is required\").url(\"Please enter a valid URL\"),\n});\n\nexport const notificationSchema = z.discriminatedUnion(\"type\", [\n\temailSchema,\n\tslackSchema,\n\tdiscordSchema,\n\twebhookSchema,\n\tpagerDutySchema,\n\tmatrixSchema,\n\tteamsSchema,\n]);\n\nexport type NotificationFormData = z.infer<typeof notificationSchema>;\n"
  },
  {
    "path": "client/src/Validation/password.ts",
    "content": "import { z } from \"zod\";\nimport { specialCharPattern } from \"@/Validation/patterns\";\n\nexport const passwordSchema = z\n\t.object({\n\t\tcurrentPassword: z.string().min(1, \"Current password is required\"),\n\t\tnewPassword: z\n\t\t\t.string()\n\t\t\t.min(1, \"New password is required\")\n\t\t\t.min(8, \"Password must be at least 8 characters\")\n\t\t\t.refine((val) => /[A-Z]/.test(val), \"Password must contain an uppercase letter\")\n\t\t\t.refine((val) => /[a-z]/.test(val), \"Password must contain a lowercase letter\")\n\t\t\t.refine((val) => /\\d/.test(val), \"Password must contain a number\")\n\t\t\t.refine(\n\t\t\t\t(val) => specialCharPattern.test(val),\n\t\t\t\t\"Password must contain a special character\"\n\t\t\t),\n\t\tconfirm: z.string().min(1, \"Please confirm your new password\"),\n\t})\n\t.refine((data) => data.newPassword === data.confirm, {\n\t\tmessage: \"Passwords do not match\",\n\t\tpath: [\"confirm\"],\n\t});\n\nexport type PasswordFormData = z.infer<typeof passwordSchema>;\n"
  },
  {
    "path": "client/src/Validation/patterns.ts",
    "content": "export const specialCharPattern = /[!?@#$%^&*()\\-_=+[\\]{};:'\",.<>~`|\\\\/]/;\n\n// Unicode-aware name pattern (allows letters, marks, apostrophes, parentheses, hyphens, periods, spaces)\nexport const namePattern = /^[\\p{L}\\p{M}''()\\-\\. ]+$/u;\n"
  },
  {
    "path": "client/src/Validation/profile.ts",
    "content": "import { z } from \"zod\";\nimport { namePattern } from \"@/Validation/patterns\";\n\nexport const profileSchema = z.object({\n\tfirstName: z\n\t\t.string()\n\t\t.min(1, \"First name is required\")\n\t\t.max(50, \"First name must be 50 characters or less\")\n\t\t.regex(namePattern, \"First name contains invalid characters\"),\n\tlastName: z\n\t\t.string()\n\t\t.min(1, \"Last name is required\")\n\t\t.max(50, \"Last name must be 50 characters or less\")\n\t\t.regex(namePattern, \"Last name contains invalid characters\"),\n\tprofileImage: z.instanceof(File).optional().nullable(),\n\tdeleteProfileImage: z.boolean().optional(),\n});\n\nexport type ProfileFormData = z.infer<typeof profileSchema>;\n"
  },
  {
    "path": "client/src/Validation/recovery.ts",
    "content": "import { z } from \"zod\";\n\nexport const recoverySchema = z.object({\n\temail: z\n\t\t.email(\"Please enter a valid email address\")\n\t\t.min(1, \"Please enter your email address\")\n\t\t.transform((val) => val.toLowerCase().trim()),\n});\n\nexport type RecoveryFormData = z.infer<typeof recoverySchema>;\n"
  },
  {
    "path": "client/src/Validation/register.ts",
    "content": "import { z } from \"zod\";\nimport { specialCharPattern, namePattern } from \"@/Validation/patterns\";\n\nexport const registerSchema = z\n\t.object({\n\t\tfirstName: z\n\t\t\t.string()\n\t\t\t.min(1, \"First name is required\")\n\t\t\t.max(50, \"First name must be 50 characters or less\")\n\t\t\t.regex(namePattern, \"First name contains invalid characters\")\n\t\t\t.transform((val) => val.trim()),\n\t\tlastName: z\n\t\t\t.string()\n\t\t\t.min(1, \"Last name is required\")\n\t\t\t.max(50, \"Last name must be 50 characters or less\")\n\t\t\t.regex(namePattern, \"Last name contains invalid characters\")\n\t\t\t.transform((val) => val.trim()),\n\t\temail: z\n\t\t\t.email(\"Please enter a valid email address\")\n\t\t\t.min(1, \"Email is required\")\n\t\t\t.transform((val) => val.toLowerCase().trim()),\n\t\tpassword: z\n\t\t\t.string()\n\t\t\t.min(1, \"Password is required\")\n\t\t\t.min(8, \"Password must be at least 8 characters\")\n\t\t\t.refine((val) => /[A-Z]/.test(val), \"Password must contain an uppercase letter\")\n\t\t\t.refine((val) => /[a-z]/.test(val), \"Password must contain a lowercase letter\")\n\t\t\t.refine((val) => /\\d/.test(val), \"Password must contain a number\")\n\t\t\t.refine(\n\t\t\t\t(val) => specialCharPattern.test(val),\n\t\t\t\t\"Password must contain a special character\"\n\t\t\t),\n\t\tconfirm: z.string().min(1, \"Please confirm your password\"),\n\t})\n\t.refine((data) => data.password === data.confirm, {\n\t\tmessage: \"Passwords do not match\",\n\t\tpath: [\"confirm\"],\n\t});\n\nexport type RegisterFormData = z.infer<typeof registerSchema>;\n"
  },
  {
    "path": "client/src/Validation/setNewPassword.ts",
    "content": "import { z } from \"zod\";\nimport { specialCharPattern } from \"@/Validation/patterns\";\n\nexport const setNewPasswordSchema = z\n\t.object({\n\t\tpassword: z\n\t\t\t.string()\n\t\t\t.min(1, \"Password is required\")\n\t\t\t.min(8, \"Password must be at least 8 characters\")\n\t\t\t.refine((val) => /[A-Z]/.test(val), \"Password must contain an uppercase letter\")\n\t\t\t.refine((val) => /[a-z]/.test(val), \"Password must contain a lowercase letter\")\n\t\t\t.refine((val) => /\\d/.test(val), \"Password must contain a number\")\n\t\t\t.refine(\n\t\t\t\t(val) => specialCharPattern.test(val),\n\t\t\t\t\"Password must contain a special character\"\n\t\t\t),\n\t\tconfirm: z.string().min(1, \"Please confirm your password\"),\n\t})\n\t.refine((data) => data.password === data.confirm, {\n\t\tmessage: \"Passwords do not match\",\n\t\tpath: [\"confirm\"],\n\t});\n\nexport type SetNewPasswordFormData = z.infer<typeof setNewPasswordSchema>;\n"
  },
  {
    "path": "client/src/Validation/settings.ts",
    "content": "import { CHECK_TTL_SENTINEL } from \"@/Types/Check\";\nimport { z } from \"zod\";\n\nexport const settingsSchema = z.object({\n\tsystemEmailIgnoreTLS: z.boolean(),\n\tsystemEmailRequireTLS: z.boolean(),\n\tsystemEmailRejectUnauthorized: z.boolean(),\n\tsystemEmailConnectionHost: z\n\t\t.string()\n\t\t.transform((val) => (val.trim() === \"\" ? null : val.trim()))\n\t\t.optional(),\n\tsystemEmailSecure: z.boolean().optional(),\n\tsystemEmailPool: z.boolean().optional(),\n\tshowURL: z.boolean().optional(),\n\tcheckTTL: z\n\t\t.number()\n\t\t.int()\n\t\t.min(1, \"Please enter a value\")\n\t\t.max(CHECK_TTL_SENTINEL, `Maximum ${CHECK_TTL_SENTINEL}`),\n\tpagespeedApiKey: z\n\t\t.string()\n\t\t.transform((val) => (val.trim() === \"\" ? null : val.trim()))\n\t\t.optional(),\n\tsystemEmailHost: z\n\t\t.string()\n\t\t.regex(/^[a-zA-Z0-9.-]*$/, \"Invalid hostname or IP address\")\n\t\t.transform((val) => (val.trim() === \"\" ? null : val.trim()))\n\t\t.optional(),\n\tsystemEmailPort: z.number().int().min(1).max(65535).optional(),\n\tsystemEmailAddress: z\n\t\t.email(\"Please enter a valid email address\")\n\t\t.or(z.literal(\"\"))\n\t\t.transform((val) => (val === \"\" ? null : val.toLowerCase().trim()))\n\t\t.optional(),\n\tsystemEmailUser: z\n\t\t.string()\n\t\t.transform((val) => (val.trim() === \"\" ? null : val.trim()))\n\t\t.optional(),\n\tsystemEmailPassword: z\n\t\t.string()\n\t\t.transform((val) => (val.trim() === \"\" ? null : val.trim()))\n\t\t.optional(),\n\tsystemEmailTLSServername: z\n\t\t.string()\n\t\t.transform((val) => (val.trim() === \"\" ? null : val.trim()))\n\t\t.optional(),\n\tglobalThresholds: z.object({\n\t\tcpu: z.number().int().min(1).max(100),\n\t\tmemory: z.number().int().min(1).max(100),\n\t\tdisk: z.number().int().min(1).max(100),\n\t\ttemperature: z.number().int().min(1).max(150),\n\t}),\n});\n\nexport type SettingsFormInput = z.input<typeof settingsSchema>;\nexport type SettingsFormData = z.infer<typeof settingsSchema>;\n"
  },
  {
    "path": "client/src/Validation/statusPage.ts",
    "content": "import { z } from \"zod\";\n\nexport const statusPageSchema = z.object({\n\tcompanyName: z\n\t\t.string()\n\t\t.min(1, \"Company name is required\")\n\t\t.max(100, \"Company name must be at most 100 characters\"),\n\turl: z\n\t\t.string()\n\t\t.min(1, \"URL is required\")\n\t\t.max(50, \"URL must be at most 50 characters\")\n\t\t.regex(\n\t\t\t/^[a-z0-9-]+$/,\n\t\t\t\"URL can only contain lowercase letters, numbers, and hyphens\"\n\t\t),\n\ttimezone: z.string().optional(),\n\ttype: z\n\t\t.array(z.enum([\"uptime\", \"infrastructure\"]))\n\t\t.min(1, \"At least one type is required\"),\n\tcolor: z.string().min(1, \"Color is required\"),\n\tmonitors: z.array(z.string()).min(1, \"At least one monitor is required\"),\n\tisPublished: z.boolean(),\n\tshowCharts: z.boolean(),\n\tshowUptimePercentage: z.boolean(),\n\tshowAdminLoginLink: z.boolean(),\n\tshowInfrastructure: z.boolean(),\n\tcustomCSS: z.string().optional(),\n\tlogo: z\n\t\t.object({\n\t\t\tdata: z.string(),\n\t\t\tcontentType: z.string(),\n\t\t})\n\t\t.nullable()\n\t\t.optional(),\n});\n\nexport type StatusPageFormData = z.infer<typeof statusPageSchema>;\n"
  },
  {
    "path": "client/src/Validation/validation.js",
    "content": "import joi from \"joi\";\nimport dayjs from \"dayjs\";\nexport const ROLES = {\n\tSUPERADMIN: \"superadmin\",\n\tADMIN: \"admin\",\n\tUSER: \"user\",\n\tDEMO: \"demo\",\n};\n\nexport const VALID_ROLES = [ROLES.ADMIN, ROLES.USER, ROLES.DEMO];\n\nexport const EDITABLE_ROLES = [\n\t{ role: ROLES.ADMIN, _id: ROLES.ADMIN },\n\t{ role: ROLES.USER, _id: ROLES.USER },\n];\n\nconst THRESHOLD_COMMON_BASE_MSG = \"Threshold must be a number.\";\n\nconst nameSchema = joi\n\t.string()\n\t.max(50)\n\t.trim()\n\t.pattern(/^[\\p{L}\\p{M}''()\\-\\. ]+$/u)\n\t.messages({\n\t\t\"string.empty\": \"auth.common.inputs.firstName.errors.empty\",\n\t\t\"string.max\": \"auth.common.inputs.firstName.errors.length\",\n\t\t\"string.pattern.base\": \"auth.common.inputs.firstName.errors.pattern\",\n\t});\n\nconst lastnameSchema = joi\n\t.string()\n\t.max(50)\n\t.trim()\n\t.pattern(/^[\\p{L}\\p{M}''()\\-\\. ]+$/u)\n\t.messages({\n\t\t\"string.empty\": \"auth.common.inputs.lastName.errors.empty\",\n\t\t\"string.max\": \"auth.common.inputs.lastName.errors.length\",\n\t\t\"string.pattern.base\": \"auth.common.inputs.lastName.errors.pattern\",\n\t});\n\nconst newPasswordSchema = joi\n\t.string()\n\t.trim()\n\t.min(8)\n\t.custom((value, helpers) => {\n\t\tif (!/[A-Z]/.test(value)) {\n\t\t\treturn helpers.error(\"uppercase\");\n\t\t}\n\t\treturn value;\n\t})\n\t.custom((value, helpers) => {\n\t\tif (!/[a-z]/.test(value)) {\n\t\t\treturn helpers.error(\"lowercase\");\n\t\t}\n\t\treturn value;\n\t})\n\t.custom((value, helpers) => {\n\t\tif (!/\\d/.test(value)) {\n\t\t\treturn helpers.error(\"number\");\n\t\t}\n\t\treturn value;\n\t})\n\t.custom((value, helpers) => {\n\t\tif (!/[!?@#$%^&*()\\-_=+[\\]{};:'\",.<>~`|\\\\/]/.test(value)) {\n\t\t\treturn helpers.error(\"special\");\n\t\t}\n\t\treturn value;\n\t})\n\t.messages({\n\t\t\"string.empty\": \"auth.common.inputs.password.errors.empty\",\n\t\t\"string.min\": \"auth.common.inputs.password.errors.length\",\n\t\tuppercase: \"auth.common.inputs.password.errors.uppercase\",\n\t\tlowercase: \"auth.common.inputs.password.errors.lowercase\",\n\t\tnumber: \"auth.common.inputs.password.errors.number\",\n\t\tspecial: \"auth.common.inputs.password.errors.special\",\n\t});\n\nconst newOrChangedCredentials = joi.object({\n\tfirstName: nameSchema,\n\tlastName: lastnameSchema,\n\temail: joi\n\t\t.string()\n\t\t.trim()\n\t\t.email({ tlds: { allow: false } })\n\t\t.lowercase()\n\t\t.messages({\n\t\t\t\"string.empty\": \"auth.common.inputs.email.errors.empty\",\n\t\t\t\"string.email\": \"auth.common.inputs.email.errors.invalid\",\n\t\t}),\n\tpassword: newPasswordSchema,\n\tnewPassword: newPasswordSchema,\n\tconfirm: joi\n\t\t.string()\n\t\t.trim()\n\t\t.custom((value, helpers) => {\n\t\t\tconst { password } = helpers.prefs.context;\n\t\t\tif (value !== password) {\n\t\t\t\treturn helpers.error(\"different\");\n\t\t\t}\n\t\t\treturn value;\n\t\t})\n\t\t.messages({\n\t\t\t\"string.empty\": \"auth.common.inputs.passwordConfirm.errors.empty\",\n\t\t\tdifferent: \"auth.common.inputs.passwordConfirm.errors.different\",\n\t\t}),\n\trole: joi.array(),\n\tteamId: joi.string().allow(\"\").optional(),\n\tinviteToken: joi.string().allow(\"\"),\n});\n\nconst loginCredentials = joi.object({\n\temail: joi\n\t\t.string()\n\t\t.trim()\n\t\t.email({ tlds: { allow: false } })\n\t\t.lowercase()\n\t\t.messages({\n\t\t\t\"string.empty\": \"auth.common.inputs.email.errors.empty\",\n\t\t\t\"string.email\": \"auth.common.inputs.email.errors.invalid\",\n\t\t}),\n\tpassword: joi.string().messages({\n\t\t\"string.empty\": \"auth.common.inputs.password.errors.empty\",\n\t}),\n});\n\nconst monitorValidation = joi.object({\n\tid: joi.string(),\n\tuserId: joi.string(),\n\tteamId: joi.string(),\n\tstatusWindowSize: joi.number().min(1).max(20).default(5).messages({\n\t\t\"number.base\": \"Status window size must be a number.\",\n\t\t\"number.min\": \"Status window size must be at least 1.\",\n\t\t\"number.max\": \"Status window size must be at most 20.\",\n\t}),\n\tstatusWindowThreshold: joi.number().min(1).max(100).default(60).messages({\n\t\t\"number.base\": \"Incident percentage must be a number.\",\n\t\t\"number.min\": \"Incident percentage must be at least 1.\",\n\t\t\"number.max\": \"Incident percentage must be at most 100.\",\n\t}),\n\turl: joi.when(\"type\", {\n\t\tis: \"docker\",\n\t\tthen: joi\n\t\t\t.string()\n\t\t\t.trim()\n\t\t\t.regex(\n\t\t\t\t/^(\\/+)?([a-zA-Z0-9][a-zA-Z0-9_.-]*[a-zA-Z0-9]|[a-zA-Z0-9]+|[a-f0-9]{12,64})$/\n\t\t\t)\n\t\t\t.messages({\n\t\t\t\t\"string.empty\": \"This field is required.\",\n\t\t\t\t\"string.pattern.base\": \"Please enter a valid container name or ID.\",\n\t\t\t}),\n\t\totherwise: joi\n\t\t\t.string()\n\t\t\t.trim()\n\t\t\t.custom((value, helpers) => {\n\t\t\t\t// Regex from https://gist.github.com/dperini/729294\n\t\t\t\tvar urlRegex = new RegExp(\n\t\t\t\t\t\"^\" +\n\t\t\t\t\t\t// protocol identifier (optional)\n\t\t\t\t\t\t// short syntax // still required\n\t\t\t\t\t\t\"(?:(?:https?|ftp):\\\\/\\\\/)?\" +\n\t\t\t\t\t\t// user:pass BasicAuth (optional)\n\t\t\t\t\t\t\"(?:\" +\n\t\t\t\t\t\t// IP address dotted notation octets\n\t\t\t\t\t\t// excludes loopback network 0.0.0.0\n\t\t\t\t\t\t// excludes reserved space >= 224.0.0.0\n\t\t\t\t\t\t// excludes network & broadcast addresses\n\t\t\t\t\t\t// (first & last IP address of each class)\n\t\t\t\t\t\t\"(?:[1-9]\\\\d?|1\\\\d\\\\d|2[01]\\\\d|22[0-3])\" +\n\t\t\t\t\t\t\"(?:\\\\.(?:1?\\\\d{1,2}|2[0-4]\\\\d|25[0-5])){2}\" +\n\t\t\t\t\t\t\"(?:\\\\.(?:[1-9]\\\\d?|1\\\\d\\\\d|2[0-4]\\\\d|25[0-4]))\" +\n\t\t\t\t\t\t\"|\" +\n\t\t\t\t\t\t// host & domain names, may end with dot\n\t\t\t\t\t\t// can be replaced by a shortest alternative\n\t\t\t\t\t\t// (?![-_])(?:[-\\\\w\\\\u00a1-\\\\uffff]{0,63}[^-_]\\\\.)+\n\t\t\t\t\t\t\"(?:\" +\n\t\t\t\t\t\t// Single hostname without dots (like localhost)\n\t\t\t\t\t\t\"[a-z0-9\\\\u00a1-\\\\uffff][a-z0-9\\\\u00a1-\\\\uffff_-]{0,62}\" +\n\t\t\t\t\t\t\"|\" +\n\t\t\t\t\t\t// Domain with dots\n\t\t\t\t\t\t\"(?:\" +\n\t\t\t\t\t\t\"(?:\" +\n\t\t\t\t\t\t\"[a-z0-9\\\\u00a1-\\\\uffff]\" +\n\t\t\t\t\t\t\"[a-z0-9\\\\u00a1-\\\\uffff_-]{0,62}\" +\n\t\t\t\t\t\t\")?\" +\n\t\t\t\t\t\t\"[a-z0-9\\\\u00a1-\\\\uffff]\\\\.\" +\n\t\t\t\t\t\t\")+\" +\n\t\t\t\t\t\t// TLD identifier name, may end with dot\n\t\t\t\t\t\t\"(?:[a-z\\\\u00a1-\\\\uffff]{2,}\\\\.?)\" +\n\t\t\t\t\t\t\")\" +\n\t\t\t\t\t\t\")\" +\n\t\t\t\t\t\t// port number (optional)\n\t\t\t\t\t\t\"(?::\\\\d{2,5})?\" +\n\t\t\t\t\t\t// resource path (optional)\n\t\t\t\t\t\t\"(?:[/?#]\\\\S*)?\" +\n\t\t\t\t\t\t\"$\",\n\t\t\t\t\t\"i\"\n\t\t\t\t);\n\t\t\t\tif (!urlRegex.test(value)) {\n\t\t\t\t\treturn helpers.error(\"string.invalidUrl\");\n\t\t\t\t}\n\n\t\t\t\treturn value;\n\t\t\t})\n\t\t\t.messages({\n\t\t\t\t\"string.empty\": \"This field is required.\",\n\t\t\t\t\"string.uri\": \"The URL you provided is not valid.\",\n\t\t\t\t\"string.invalidUrl\": \"Please enter a valid URL with optional port\",\n\t\t\t}),\n\t}),\n\tport: joi\n\t\t.number()\n\t\t.integer()\n\t\t.min(1)\n\t\t.max(65535)\n\t\t.when(\"type\", {\n\t\t\tis: joi.valid(\"port\", \"game\"),\n\t\t\tthen: joi.required().messages({\n\t\t\t\t\"number.base\": \"Port must be a number.\",\n\t\t\t\t\"number.min\": \"Port must be at least 1.\",\n\t\t\t\t\"number.max\": \"Port must be at most 65535.\",\n\t\t\t\t\"any.required\": \"Port is required for port and game monitors.\",\n\t\t\t}),\n\t\t\totherwise: joi.optional(),\n\t\t}),\n\tname: joi.string().trim().max(50).allow(\"\").messages({\n\t\t\"string.max\": \"This field should not exceed the 50 characters limit.\",\n\t}),\n\ttype: joi.string().trim().messages({ \"string.empty\": \"This field is required.\" }),\n\tignoreTlsErrors: joi.boolean(),\n\tinterval: joi.number().messages({\n\t\t\"number.base\": \"Frequency must be a number.\",\n\t\t\"any.required\": \"Frequency is required.\",\n\t}),\n\texpectedValue: joi.string().allow(null, \"\"),\n\tjsonPath: joi.string().allow(null, \"\"),\n\tmatchMethod: joi.string().allow(null, \"\"),\n\tgameId: joi.when(\"type\", {\n\t\tis: \"game\",\n\t\tthen: joi.string().required().messages({\n\t\t\t\"string.empty\": \"Game selection is required for game monitors.\",\n\t\t\t\"any.required\": \"Game selection is required for game monitors.\",\n\t\t}),\n\t\totherwise: joi.string().allow(null, \"\"),\n\t}),\n});\n\nconst imageValidation = joi.object({\n\ttype: joi.string().valid(\"image/jpeg\", \"image/png\").messages({\n\t\t\"any.only\": \"Invalid file format.\",\n\t\t\"string.empty\": \"File type required.\",\n\t}),\n\tsize: joi\n\t\t.number()\n\t\t.max(3 * 1024 * 1024)\n\t\t.messages({\n\t\t\t\"number.base\": \"File size must be a number.\",\n\t\t\t\"number.max\": \"File size must be less than 3 MB.\",\n\t\t\t\"number.empty\": \"File size required.\",\n\t\t}),\n});\n\nconst logoImageValidation = joi\n\t.object({\n\t\tsrc: joi.string(),\n\t\tname: joi.string(),\n\t\ttype: joi\n\t\t\t.string()\n\t\t\t.valid(\"image/jpeg\", \"image/png\")\n\t\t\t.allow(null) // Allow null and empty string\n\t\t\t.messages({\n\t\t\t\t\"any.only\": \"Invalid file format.\",\n\t\t\t\t\"string.empty\": \"File type required.\",\n\t\t\t})\n\t\t\t.optional(),\n\t\tsize: joi\n\t\t\t.number()\n\t\t\t.max(3000000)\n\t\t\t.allow(null) // Allow null and empty string\n\t\t\t.messages({\n\t\t\t\t\"number.base\": \"File size must be a number.\",\n\t\t\t\t\"number.max\": \"File size must be less than 3MB.\",\n\t\t\t\t\"number.empty\": \"File size required.\",\n\t\t\t})\n\t\t\t.optional(),\n\t})\n\t.allow(null)\n\t.optional(); // Make entire object optional\n\nconst statusPageValidation = joi.object({\n\ttype: joi\n\t\t.alternatives()\n\t\t.try(\n\t\t\tjoi.string().valid(\"uptime\", \"infrastructure\"),\n\t\t\tjoi.array().items(joi.string().valid(\"uptime\", \"infrastructure\"))\n\t\t)\n\t\t.required(),\n\tisPublished: joi.bool(),\n\tcompanyName: joi\n\t\t.string()\n\t\t.trim()\n\t\t.messages({ \"string.empty\": \"Company name is required.\" }),\n\turl: joi\n\t\t.string()\n\t\t.pattern(/^[a-zA-Z0-9_-]+$/) // Only allow alphanumeric, underscore, and hyphen\n\t\t.required()\n\t\t.messages({\n\t\t\t\"string.pattern.base\":\n\t\t\t\t\"URL can only contain letters, numbers, underscores, and hyphens\",\n\t\t}),\n\ttimezone: joi.string().trim().messages({ \"string.empty\": \"Timezone is required.\" }),\n\tcolor: joi.string().trim().messages({ \"string.empty\": \"Color is required.\" }),\n\ttheme: joi.string(),\n\tmonitors: joi.array().min(1).required().messages({\n\t\t\"string.pattern.base\": \"Must be a valid monitor ID\",\n\t\t\"array.base\": \"Monitors must be an array\",\n\t\t\"array.min\": \"At least one monitor is required\",\n\t\t\"array.empty\": \"At least one monitor is required\",\n\t\t\"any.required\": \"At least one monitor is required\",\n\t}),\n\tsubMonitors: joi.array().optional(),\n\tlogo: logoImageValidation,\n\tshowUptimePercentage: joi.boolean(),\n\tshowCharts: joi.boolean(),\n\tshowAdminLoginLink: joi.boolean(),\n\tshowInfrastructure: joi.boolean(),\n});\n\nconst settingsValidation = joi.object({\n\tcheckTTL: joi.number().required().messages({\n\t\t\"string.empty\": \"Please enter a value\",\n\t\t\"number.base\": \"Please enter a valid number\",\n\t\t\"any.required\": \"Please enter a value\",\n\t}),\n\tpagespeedApiKey: joi.string().allow(\"\").optional(),\n\tlanguage: joi.string().required(),\n\ttimezone: joi.string().allow(\"\").optional(),\n\tsystemEmailHost: joi.string().allow(\"\"),\n\tsystemEmailPort: joi.number().allow(null, \"\"),\n\tsystemEmailSecure: joi.boolean().optional(),\n\tsystemEmailPool: joi.boolean().optional(),\n\tsystemEmailAddress: joi.string().allow(\"\"),\n\tsystemEmailPassword: joi.string().allow(\"\"),\n\tsystemEmailUser: joi.string().allow(\"\"),\n\tsystemEmailConnectionHost: joi.string().allow(\"\").optional(),\n\tsystemEmailTLSServername: joi.string().allow(\"\"),\n\tsystemEmailIgnoreTLS: joi.boolean(),\n\tsystemEmailRequireTLS: joi.boolean(),\n\tsystemEmailRejectUnauthorized: joi.boolean(),\n\tshowURL: joi.boolean().optional(),\n\tglobalThresholds: joi\n\t\t.object({\n\t\t\tcpu: joi.number().min(1).max(100).allow(\"\").optional(),\n\t\t\tmemory: joi.number().min(1).max(100).allow(\"\").optional(),\n\t\t\tdisk: joi.number().min(1).max(100).allow(\"\").optional(),\n\t\t\ttemperature: joi.number().min(1).max(150).allow(\"\").optional(),\n\t\t})\n\t\t.optional(),\n});\n\nconst dayjsValidator = (value, helpers) => {\n\tif (!dayjs(value).isValid()) {\n\t\treturn helpers.error(\"any.invalid\");\n\t}\n\treturn value;\n};\n\nconst maintenanceWindowValidation = joi.object({\n\trepeat: joi.string(),\n\tstartDate: joi.custom(dayjsValidator, \"Day.js date validation\"),\n\tstartTime: joi.custom(dayjsValidator, \"Day.js date validation\"),\n\tduration: joi.number().integer().min(0),\n\tdurationUnit: joi.string(),\n\tname: joi.string(),\n\tmonitors: joi.array().min(1),\n});\n\nconst advancedSettingsValidation = joi.object({\n\tapiBaseUrl: joi.string().uri({ allowRelative: true }).trim().messages({\n\t\t\"string.empty\": \"API base url is required.\",\n\t\t\"string.uri\": \"The URL you provided is not valid.\",\n\t}),\n\tlogLevel: joi.string().valid(\"debug\", \"none\", \"error\", \"warn\").allow(\"\"),\n\tsystemEmailHost: joi.string().allow(\"\"),\n\tsystemEmailPort: joi.number().allow(null, \"\"),\n\tsystemEmailAddress: joi.string().allow(\"\"),\n\tsystemEmailPassword: joi.string().allow(\"\"),\n\tsystemEmailConnectionHost: joi.string().allow(\"\"),\n\tjwtTTLNum: joi.number().messages({\n\t\t\"number.base\": \"JWT TTL is required.\",\n\t}),\n\tjwtTTLUnits: joi\n\t\t.string()\n\t\t.trim()\n\t\t.custom((value, helpers) => {\n\t\t\tif (![\"days\", \"hours\"].includes(value)) {\n\t\t\t\treturn helpers.message(\"JWT TTL unit is required.\");\n\t\t\t}\n\t\t\treturn value;\n\t\t}),\n\tdbType: joi.string().trim().messages({\n\t\t\"string.empty\": \"DB type is required.\",\n\t}),\n\tredisHost: joi.string().trim().messages({\n\t\t\"string.empty\": \"Redis host is required.\",\n\t}),\n\tredisPort: joi.number().allow(null, \"\"),\n\tpagespeedApiKey: joi.string().allow(\"\"),\n});\n\nconst infrastructureMonitorValidation = joi.object({\n\turl: joi\n\t\t.string()\n\t\t.trim()\n\t\t.custom((value, helpers) => {\n\t\t\tconst urlRegex =\n\t\t\t\t/^(https?:\\/\\/)?(([0-9]{1,3}\\.){3}[0-9]{1,3}|[\\da-z\\.-]+)(\\.[a-z\\.]{2,6})?(:(\\d+))?([\\/\\w \\.-]*)*\\/?$/i;\n\n\t\t\tif (!urlRegex.test(value)) {\n\t\t\t\treturn helpers.error(\"string.invalidUrl\");\n\t\t\t}\n\n\t\t\treturn value;\n\t\t})\n\t\t.messages({\n\t\t\t\"string.empty\": \"This field is required.\",\n\t\t\t\"string.uri\": \"The URL you provided is not valid.\",\n\t\t\t\"string.invalidUrl\": \"Please enter a valid URL with optional port\",\n\t\t}),\n\tname: joi.string().trim().max(50).allow(\"\").messages({\n\t\t\"string.max\": \"This field should not exceed the 50 characters limit.\",\n\t}),\n\tsecret: joi.string().trim().messages({ \"string.empty\": \"This field is required.\" }),\n\tusage_cpu: joi.number().messages({\n\t\t\"number.base\": THRESHOLD_COMMON_BASE_MSG,\n\t}),\n\tcpu: joi.boolean(),\n\tmemory: joi.boolean(),\n\tdisk: joi.boolean(),\n\ttemperature: joi.boolean(),\n\tusage_memory: joi.number().messages({\n\t\t\"number.base\": THRESHOLD_COMMON_BASE_MSG,\n\t}),\n\tusage_disk: joi.number().messages({\n\t\t\"number.base\": THRESHOLD_COMMON_BASE_MSG,\n\t}),\n\tusage_temperature: joi.number().messages({\n\t\t\"number.base\": \"Temperature must be a number.\",\n\t}),\n\t// usage_system: joi.number().messages({\n\t// \t\"number.base\": \"System load must be a number.\",\n\t// }),\n\t// usage_swap: joi.number().messages({\n\t// \t\"number.base\": \"Swap used must be a number.\",\n\t// }),\n\tinterval: joi.number().messages({\n\t\t\"number.base\": \"Frequency must be a number.\",\n\t\t\"any.required\": \"Frequency is required.\",\n\t}),\n\tstatusWindowSize: joi.number().min(1).max(20).messages({\n\t\t\"number.base\": \"Status window size must be a number.\",\n\t\t\"number.min\": \"Status window size must be at least 1.\",\n\t\t\"number.max\": \"Status window size cannot exceed 20.\",\n\t}),\n\tstatusWindowThreshold: joi.number().min(1).max(100).messages({\n\t\t\"number.base\": \"Status window threshold must be a number.\",\n\t\t\"number.min\": \"Status window threshold must be at least 1%.\",\n\t\t\"number.max\": \"Status window threshold cannot exceed 100%.\",\n\t}),\n\tnotifications: joi.array().items(joi.string()),\n\tselectedDisks: joi.array().items(joi.string()).optional(),\n});\n\nconst notificationValidation = joi.object({\n\tnotificationName: joi.string().required().messages({\n\t\t\"string.empty\": \"Notification name is required\",\n\t\t\"any.required\": \"Notification name is required\",\n\t}),\n\n\ttype: joi\n\t\t.string()\n\t\t.valid(\"email\", \"webhook\", \"slack\", \"discord\", \"pager_duty\", \"matrix\")\n\t\t.required()\n\t\t.messages({\n\t\t\t\"string.empty\": \"Notification type is required\",\n\t\t\t\"any.required\": \"Notification type is required\",\n\t\t\t\"any.only\": \"Notification type must be email, webhook, or pager_duty\",\n\t\t}),\n\n\taddress: joi.when(\"type\", {\n\t\tswitch: [\n\t\t\t{\n\t\t\t\tis: \"email\",\n\t\t\t\tthen: joi\n\t\t\t\t\t.string()\n\t\t\t\t\t.email({ tlds: { allow: false } })\n\t\t\t\t\t.required()\n\t\t\t\t\t.messages({\n\t\t\t\t\t\t\"string.empty\": \"E-mail address cannot be empty\",\n\t\t\t\t\t\t\"any.required\": \"E-mail address is required\",\n\t\t\t\t\t\t\"string.email\": \"Please enter a valid e-mail address\",\n\t\t\t\t\t}),\n\t\t\t},\n\t\t\t{\n\t\t\t\tis: \"pager_duty\",\n\t\t\t\tthen: joi.string().required().messages({\n\t\t\t\t\t\"string.empty\": \"PagerDuty routing key cannot be empty\",\n\t\t\t\t\t\"any.required\": \"PagerDuty routing key is required\",\n\t\t\t\t}),\n\t\t\t},\n\t\t\t{\n\t\t\t\tis: joi.valid(\"webhook\", \"slack\", \"discord\"),\n\t\t\t\tthen: joi.string().uri().required().messages({\n\t\t\t\t\t\"string.empty\": \"Webhook URL cannot be empty\",\n\t\t\t\t\t\"any.required\": \"Webhook URL is required\",\n\t\t\t\t\t\"string.uri\": \"Please enter a valid Webhook URL\",\n\t\t\t\t}),\n\t\t\t},\n\t\t\t{\n\t\t\t\tis: \"matrix\",\n\t\t\t\tthen: joi.string().allow(\"\").optional(),\n\t\t\t},\n\t\t],\n\t}),\n\n\thomeserverUrl: joi.when(\"type\", {\n\t\tis: \"matrix\",\n\t\tthen: joi.string().uri().required().messages({\n\t\t\t\"string.empty\": \"Homeserver URL cannot be empty\",\n\t\t\t\"any.required\": \"Homeserver URL is required\",\n\t\t\t\"string.uri\": \"Please enter a valid Homeserver URL\",\n\t\t}),\n\t\totherwise: joi.string().allow(\"\").optional(),\n\t}),\n\n\troomId: joi.when(\"type\", {\n\t\tis: \"matrix\",\n\t\tthen: joi.string().required().messages({\n\t\t\t\"string.empty\": \"Room ID cannot be empty\",\n\t\t\t\"any.required\": \"Room ID is required\",\n\t\t}),\n\t\totherwise: joi.string().allow(\"\").optional(),\n\t}),\n\n\taccessToken: joi.when(\"type\", {\n\t\tis: \"matrix\",\n\t\tthen: joi.string().required().messages({\n\t\t\t\"string.empty\": \"Access Token cannot be empty\",\n\t\t\t\"any.required\": \"Access Token is required\",\n\t\t}),\n\t\totherwise: joi.string().allow(\"\").optional(),\n\t}),\n});\n\nconst editUserValidation = joi.object({\n\tfirstName: nameSchema,\n\tlastName: lastnameSchema,\n\trole: joi\n\t\t.array()\n\t\t.items(joi.string().valid(...Object.values(ROLES)))\n\t\t.min(1)\n\t\t.messages({\n\t\t\t\"array.min\": \"auth.common.fields.role.errors.min\",\n\t\t}),\n\temail: joi\n\t\t.string()\n\t\t.required()\n\t\t.trim()\n\t\t.email({ tlds: { allow: false } })\n\t\t.lowercase(),\n});\n\nexport {\n\tnewOrChangedCredentials,\n\tloginCredentials,\n\timageValidation,\n\tmonitorValidation,\n\tsettingsValidation,\n\tmaintenanceWindowValidation,\n\tadvancedSettingsValidation,\n\tinfrastructureMonitorValidation,\n\tstatusPageValidation,\n\tlogoImageValidation,\n\tnotificationValidation,\n\teditUserValidation,\n};\n"
  },
  {
    "path": "client/src/index.css",
    "content": "@import url(\"https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap\");\n\n* {\n\tbox-sizing: border-box;\n}\n\nhtml,\nbody {\n\toverscroll-behavior: none;\n}\n\nhtml {\n\tscroll-behavior: smooth;\n}\n\n:root {\n\tfont-synthesis: none;\n\ttext-rendering: optimizeLegibility;\n\t-webkit-font-smoothing: antialiased;\n\t-moz-osx-font-smoothing: grayscale;\n}\n"
  },
  {
    "path": "client/src/locales/ar.json",
    "content": "{\n\t\"submit\": \"\",\n\t\"title\": \"\",\n\t\"distributedStatusHeaderText\": \"\",\n\t\"distributedStatusSubHeaderText\": \"\",\n\t\"settingsDisabled\": \"\",\n\t\"settingsSuccessSaved\": \"\",\n\t\"settingsFailedToSave\": \"\",\n\t\"settingsStatsCleared\": \"\",\n\t\"settingsFailedToClearStats\": \"\",\n\t\"settingsMonitorsDeleted\": \"\",\n\t\"settingsFailedToDeleteMonitors\": \"\",\n\t\"starPromptTitle\": \"\",\n\t\"starPromptDescription\": \"\",\n\t\"https\": \"\",\n\t\"http\": \"\",\n\t\"monitor\": \"\",\n\t\"aboutus\": \"\",\n\t\"now\": \"\",\n\t\"delete\": \"\",\n\t\"configure\": \"\",\n\t\"responseTime\": \"\",\n\t\"ms\": \"\",\n\t\"bar\": \"\",\n\t\"area\": \"\",\n\t\"country\": \"\",\n\t\"city\": \"\",\n\t\"response\": \"\",\n\t\"monitorStatusUp\": \"\",\n\t\"monitorStatusDown\": \"\",\n\t\"webhookSendSuccess\": \"\",\n\t\"webhookSendError\": \"\",\n\t\"webhookUnsupportedPlatform\": \"\",\n\t\"distributedRightCategoryTitle\": \"\",\n\t\"distributedStatusServerMonitors\": \"\",\n\t\"distributedStatusServerMonitorsDescription\": \"\",\n\t\"distributedUptimeCreateSelectURL\": \"\",\n\t\"distributedUptimeCreateChecks\": \"\",\n\t\"distributedUptimeCreateChecksDescription\": \"\",\n\t\"distributedUptimeCreateIncidentNotification\": \"\",\n\t\"distributedUptimeCreateIncidentDescription\": \"\",\n\t\"distributedUptimeCreateAdvancedSettings\": \"\",\n\t\"distributedUptimeDetailsNoMonitorHistory\": \"\",\n\t\"distributedUptimeDetailsStatusHeaderUptime\": \"\",\n\t\"distributedUptimeDetailsStatusHeaderLastUpdate\": \"\",\n\t\"notifications\": {\n\t\t\"enableNotifications\": \"\",\n\t\t\"testNotification\": \"\",\n\t\t\"addOrEditNotifications\": \"\",\n\t\t\"slack\": {\n\t\t\t\"label\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"webhookLabel\": \"\",\n\t\t\t\"webhookPlaceholder\": \"\",\n\t\t\t\"webhookRequired\": \"\"\n\t\t},\n\t\t\"discord\": {\n\t\t\t\"label\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"webhookLabel\": \"\",\n\t\t\t\"webhookPlaceholder\": \"\",\n\t\t\t\"webhookRequired\": \"\"\n\t\t},\n\t\t\"telegram\": {\n\t\t\t\"label\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"tokenLabel\": \"\",\n\t\t\t\"tokenPlaceholder\": \"\",\n\t\t\t\"chatIdLabel\": \"\",\n\t\t\t\"chatIdPlaceholder\": \"\",\n\t\t\t\"fieldsRequired\": \"\"\n\t\t},\n\t\t\"webhook\": {\n\t\t\t\"label\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"urlLabel\": \"\",\n\t\t\t\"urlPlaceholder\": \"\",\n\t\t\t\"urlRequired\": \"\"\n\t\t},\n\t\t\"testNotificationDevelop\": \"\",\n\t\t\"integrationButton\": \"\",\n\t\t\"testSuccess\": \"\",\n\t\t\"testFailed\": \"\",\n\t\t\"unsupportedType\": \"\",\n\t\t\"networkError\": \"\",\n\t\t\"fallback\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"checks\": [\"\"],\n\t\t\t\"actionButton\": \"\"\n\t\t},\n\t\t\"createButton\": \"\",\n\t\t\"createTitle\": \"\",\n\t\t\"create\": {\n\t\t\t\"success\": \"\",\n\t\t\t\"failed\": \"\"\n\t\t},\n\t\t\"fetch\": {\n\t\t\t\"success\": \"\",\n\t\t\t\"failed\": \"\"\n\t\t},\n\t\t\"delete\": {\n\t\t\t\"success\": \"\",\n\t\t\t\"failed\": \"\"\n\t\t},\n\t\t\"edit\": {\n\t\t\t\"success\": \"\",\n\t\t\t\"failed\": \"\"\n\t\t},\n\t\t\"test\": {\n\t\t\t\"success\": \"\",\n\t\t\t\"failed\": \"\"\n\t\t}\n\t},\n\t\"testLocale\": \"\",\n\t\"add\": \"\",\n\t\"monitors\": \"\",\n\t\"distributedUptimeStatusCreateStatusPage\": \"\",\n\t\"distributedUptimeStatusCreateStatusPageAccess\": \"\",\n\t\"distributedUptimeStatusCreateStatusPageReady\": \"\",\n\t\"distributedUptimeStatusBasicInfoHeader\": \"\",\n\t\"distributedUptimeStatusBasicInfoDescription\": \"\",\n\t\"distributedUptimeStatusLogoHeader\": \"\",\n\t\"distributedUptimeStatusLogoDescription\": \"\",\n\t\"distributedUptimeStatusLogoUploadButton\": \"\",\n\t\"distributedUptimeStatusStandardMonitorsHeader\": \"\",\n\t\"distributedUptimeStatusStandardMonitorsDescription\": \"\",\n\t\"distributedUptimeStatusCreateYour\": \"\",\n\t\"distributedUptimeStatusEditYour\": \"\",\n\t\"distributedUptimeStatusPublishedLabel\": \"\",\n\t\"distributedUptimeStatusCompanyNameLabel\": \"\",\n\t\"distributedUptimeStatusPageAddressLabel\": \"\",\n\t\"distributedUptimeStatus30Days\": \"\",\n\t\"distributedUptimeStatus60Days\": \"\",\n\t\"distributedUptimeStatus90Days\": \"\",\n\t\"distributedUptimeStatusPageNotSetUp\": \"\",\n\t\"distributedUptimeStatusContactAdmin\": \"\",\n\t\"distributedUptimeStatusPageNotPublic\": \"\",\n\t\"distributedUptimeStatusPageDeleteDialog\": \"\",\n\t\"distributedUptimeStatusPageDeleteConfirm\": \"\",\n\t\"distributedUptimeStatusPageDeleteDescription\": \"\",\n\t\"distributedUptimeStatusDevices\": \"\",\n\t\"distributedUptimeStatusUpt\": \"\",\n\t\"distributedUptimeStatusUptBurned\": \"\",\n\t\"distributedUptimeStatusUptLogo\": \"\",\n\t\"incidentsTableNoIncidents\": \"\",\n\t\"incidentsTablePaginationLabel\": \"\",\n\t\"incidentsTableMonitorName\": \"\",\n\t\"incidentsTableStatus\": \"\",\n\t\"incidentsTableDateTime\": \"\",\n\t\"incidentsTableStatusCode\": \"\",\n\t\"incidentsTableMessage\": \"\",\n\t\"incidentsOptionsHeader\": \"\",\n\t\"incidentsOptionsHeaderFilterBy\": \"\",\n\t\"incidentsOptionsHeaderFilterAll\": \"\",\n\t\"incidentsOptionsHeaderFilterDown\": \"\",\n\t\"incidentsOptionsHeaderFilterCannotResolve\": \"\",\n\t\"incidentsOptionsHeaderShow\": \"\",\n\t\"incidentsOptionsHeaderLastHour\": \"\",\n\t\"incidentsOptionsHeaderLastDay\": \"\",\n\t\"incidentsOptionsHeaderLastWeek\": \"\",\n\t\"incidentsOptionsPlaceholderAllServers\": \"\",\n\t\"infrastructureCreateYour\": \"\",\n\t\"infrastructureCreateGeneralSettingsDescription\": \"\",\n\t\"infrastructureServerRequirement\": \"\",\n\t\"infrastructureCustomizeAlerts\": \"\",\n\t\"infrastructureAlertNotificationDescription\": \"\",\n\t\"infrastructureCreateMonitor\": \"\",\n\t\"infrastructureProtocol\": \"\",\n\t\"infrastructureServerUrlLabel\": \"\",\n\t\"infrastructureDisplayNameLabel\": \"\",\n\t\"infrastructureAuthorizationSecretLabel\": \"\",\n\t\"gb\": \"\",\n\t\"mb\": \"\",\n\t\"mem\": \"\",\n\t\"memoryUsage\": \"\",\n\t\"cpu\": \"\",\n\t\"cpuUsage\": \"\",\n\t\"cpuTemperature\": \"\",\n\t\"diskUsage\": \"\",\n\t\"used\": \"\",\n\t\"total\": \"\",\n\t\"cores\": \"\",\n\t\"frequency\": \"\",\n\t\"status\": \"\",\n\t\"cpuPhysical\": \"\",\n\t\"cpuLogical\": \"\",\n\t\"cpuFrequency\": \"\",\n\t\"avgCpuTemperature\": \"\",\n\t\"memory\": \"\",\n\t\"disk\": \"\",\n\t\"uptime\": \"\",\n\t\"os\": \"\",\n\t\"host\": \"\",\n\t\"actions\": \"\",\n\t\"integrations\": \"\",\n\t\"integrationsPrism\": \"\",\n\t\"integrationsSlack\": \"\",\n\t\"integrationsSlackInfo\": \"\",\n\t\"integrationsDiscord\": \"\",\n\t\"integrationsDiscordInfo\": \"\",\n\t\"integrationsZapier\": \"\",\n\t\"integrationsZapierInfo\": \"\",\n\t\"commonSave\": \"\",\n\t\"createYour\": \"\",\n\t\"createMonitor\": \"\",\n\t\"pause\": \"\",\n\t\"resume\": \"\",\n\t\"editing\": \"\",\n\t\"url\": \"\",\n\t\"access\": \"\",\n\t\"timezone\": \"\",\n\t\"features\": \"\",\n\t\"administrator\": \"\",\n\t\"loginHere\": \"\",\n\t\"displayName\": \"\",\n\t\"urlMonitor\": \"\",\n\t\"portToMonitor\": \"\",\n\t\"websiteMonitoring\": \"\",\n\t\"websiteMonitoringDescription\": \"\",\n\t\"pingMonitoring\": \"\",\n\t\"pingMonitoringDescription\": \"\",\n\t\"dockerContainerMonitoring\": \"\",\n\t\"dockerContainerMonitoringDescription\": \"\",\n\t\"portMonitoring\": \"\",\n\t\"portMonitoringDescription\": \"\",\n\t\"createMaintenanceWindow\": \"\",\n\t\"createMaintenance\": \"\",\n\t\"editMaintenance\": \"\",\n\t\"maintenanceWindowName\": \"\",\n\t\"friendlyNameInput\": \"\",\n\t\"friendlyNamePlaceholder\": \"\",\n\t\"maintenanceRepeat\": \"\",\n\t\"maintenance\": \"\",\n\t\"duration\": \"\",\n\t\"addMonitors\": \"\",\n\t\"window\": \"\",\n\t\"cancel\": \"\",\n\t\"message\": \"\",\n\t\"low\": \"\",\n\t\"high\": \"\",\n\t\"statusCode\": \"\",\n\t\"date&Time\": \"\",\n\t\"type\": \"\",\n\t\"statusPageName\": \"\",\n\t\"publicURL\": \"\",\n\t\"repeat\": \"\",\n\t\"edit\": \"\",\n\t\"createA\": \"\",\n\t\"remove\": \"\",\n\t\"maintenanceWindowDescription\": \"\",\n\t\"startTime\": \"\",\n\t\"timeZoneInfo\": \"\",\n\t\"monitorsToApply\": \"\",\n\t\"nextWindow\": \"\",\n\t\"notFoundButton\": \"\",\n\t\"pageSpeedConfigureSettingsDescription\": \"\",\n\t\"monitorDisplayName\": \"\",\n\t\"whenNewIncident\": \"\",\n\t\"notifySMS\": \"\",\n\t\"notifyEmails\": \"\",\n\t\"seperateEmails\": \"\",\n\t\"checkFrequency\": \"\",\n\t\"matchMethod\": \"\",\n\t\"expectedValue\": \"\",\n\t\"deleteDialogTitle\": \"\",\n\t\"deleteDialogDescription\": \"\",\n\t\"pageSpeedMonitor\": \"\",\n\t\"shown\": \"\",\n\t\"ago\": \"\",\n\t\"companyName\": \"\",\n\t\"pageSpeedDetailsPerformanceReport\": \"\",\n\t\"pageSpeedDetailsPerformanceReportCalculator\": \"\",\n\t\"checkingEvery\": \"\",\n\t\"statusPageCreateSettings\": \"\",\n\t\"basicInformation\": \"\",\n\t\"statusPageCreateBasicInfoDescription\": \"\",\n\t\"statusPageCreateSelectTimeZoneDescription\": \"\",\n\t\"statusPageCreateAppearanceDescription\": \"\",\n\t\"statusPageCreateSettingsCheckboxLabel\": \"\",\n\t\"statusPageCreateBasicInfoStatusPageAddress\": \"\",\n\t\"statusPageCreateTabsContent\": \"\",\n\t\"statusPageCreateTabsContentDescription\": \"\",\n\t\"statusPageCreateTabsContentFeaturesDescription\": \"\",\n\t\"showCharts\": \"\",\n\t\"showUptimePercentage\": \"\",\n\t\"removeLogo\": \"\",\n\t\"statusPageStatus\": \"\",\n\t\"statusPageStatusContactAdmin\": \"\",\n\t\"statusPageStatusNotPublic\": \"\",\n\t\"statusPageStatusNoPage\": \"\",\n\t\"statusPageStatusServiceStatus\": \"\",\n\t\"deleteStatusPage\": \"\",\n\t\"deleteStatusPageConfirm\": \"\",\n\t\"deleteStatusPageDescription\": \"\",\n\t\"uptimeCreate\": \"\",\n\t\"uptimeCreateJsonPath\": \"\",\n\t\"uptimeCreateJsonPathQuery\": \"\",\n\t\"maintenanceTableActionMenuDialogTitle\": \"\",\n\t\"infrastructureEditYour\": \"\",\n\t\"infrastructureEditMonitor\": \"\",\n\t\"infrastructureMonitorCreated\": \"\",\n\t\"infrastructureMonitorUpdated\": \"\",\n\t\"errorInvalidTypeId\": \"\",\n\t\"errorInvalidFieldId\": \"\",\n\t\"inviteNoTokenFound\": \"\",\n\t\"pageSpeedWarning\": \"\",\n\t\"pageSpeedLearnMoreLink\": \"\",\n\t\"pageSpeedAddApiKey\": \"\",\n\t\"update\": \"\",\n\t\"invalidFileFormat\": \"\",\n\t\"invalidFileSize\": \"\",\n\t\"ClickUpload\": \"\",\n\t\"DragandDrop\": \"\",\n\t\"MaxSize\": \"\",\n\t\"SupportedFormats\": \"\",\n\t\"FirstName\": \"\",\n\t\"LastName\": \"\",\n\t\"EmailDescriptionText\": \"\",\n\t\"YourPhoto\": \"\",\n\t\"PhotoDescriptionText\": \"\",\n\t\"save\": \"\",\n\t\"DeleteDescriptionText\": \"\",\n\t\"DeleteAccountWarning\": \"\",\n\t\"DeleteWarningTitle\": \"\",\n\t\"bulkImport\": {\n\t\t\"title\": \"\",\n\t\t\"selectFileTips\": \"\",\n\t\t\"selectFileDescription\": \"\",\n\t\t\"selectFile\": \"\",\n\t\t\"parsingFailed\": \"\",\n\t\t\"uploadSuccess\": \"\",\n\t\t\"validationFailed\": \"\",\n\t\t\"noFileSelected\": \"\",\n\t\t\"fallbackPage\": \"\",\n\t\t\"invalidFileType\": \"\",\n\t\t\"uploadFailed\": \"\"\n\t},\n\t\"DeleteAccountTitle\": \"\",\n\t\"DeleteAccountButton\": \"\",\n\t\"publicLink\": \"\",\n\t\"maskedPageSpeedKeyPlaceholder\": \"\",\n\t\"reset\": \"\",\n\t\"ignoreTLSError\": \"\",\n\t\"tlsErrorIgnored\": \"\",\n\t\"ignoreTLSErrorDescription\": \"\",\n\t\"createNew\": \"\",\n\t\"greeting\": {\n\t\t\"prepend\": \"\",\n\t\t\"append\": \"\",\n\t\t\"overview\": \"\"\n\t},\n\t\"roles\": {\n\t\t\"superAdmin\": \"\",\n\t\t\"admin\": \"\",\n\t\t\"teamMember\": \"\",\n\t\t\"demoUser\": \"\"\n\t},\n\t\"teamPanel\": {\n\t\t\"teamMembers\": \"\",\n\t\t\"filter\": {\n\t\t\t\"all\": \"\",\n\t\t\t\"member\": \"\"\n\t\t},\n\t\t\"inviteTeamMember\": \"\",\n\t\t\"inviteNewTeamMember\": \"\",\n\t\t\"inviteDescription\": \"\",\n\t\t\"email\": \"\",\n\t\t\"selectRole\": \"\",\n\t\t\"inviteLink\": \"\",\n\t\t\"cancel\": \"\",\n\t\t\"noMembers\": \"\",\n\t\t\"getToken\": \"\",\n\t\t\"emailToken\": \"\",\n\t\t\"table\": {\n\t\t\t\"name\": \"\",\n\t\t\t\"email\": \"\",\n\t\t\t\"role\": \"\",\n\t\t\t\"created\": \"\"\n\t\t},\n\t\t\"addTeamMember\": {\n\t\t\t\"addMemberMenu\": \"\",\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"addButton\": \"\"\n\t\t},\n\t\t\"register\": \"\",\n\t\t\"registerToast\": {\n\t\t\t\"success\": \"\",\n\t\t\t\"dbUserExists\": \"\",\n\t\t\t\"unknownError\": \"\"\n\t\t},\n\t\t\"registerTeamMember\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"auth\": {\n\t\t\t\t\"common\": {\n\t\t\t\t\t\"inputs\": {\n\t\t\t\t\t\t\"firstName\": {\n\t\t\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\t\t\"empty\": \"\",\n\t\t\t\t\t\t\t\t\"pattern\": \"\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"lastName\": {\n\t\t\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\t\t\"empty\": \"\",\n\t\t\t\t\t\t\t\t\"pattern\": \"\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"email\": {\n\t\t\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\t\t\"empty\": \"\",\n\t\t\t\t\t\t\t\t\"invalid\": \"\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"role\": {\n\t\t\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\t\t\"empty\": \"\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"role\": \"\",\n\t\t\"changeTeamPassword\": {\n\t\t\t\"changePasswordMenu\": \"\",\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"success\": \"\"\n\t\t}\n\t},\n\t\"monitorState\": {\n\t\t\"paused\": \"\",\n\t\t\"resumed\": \"\",\n\t\t\"active\": \"\"\n\t},\n\t\"menu\": {\n\t\t\"uptime\": \"\",\n\t\t\"pagespeed\": \"\",\n\t\t\"infrastructure\": \"\",\n\t\t\"incidents\": \"\",\n\t\t\"statusPages\": \"\",\n\t\t\"maintenance\": \"\",\n\t\t\"integrations\": \"\",\n\t\t\"settings\": \"\",\n\t\t\"support\": \"\",\n\t\t\"discussions\": \"\",\n\t\t\"docs\": \"\",\n\t\t\"changelog\": \"\",\n\t\t\"profile\": \"\",\n\t\t\"password\": \"\",\n\t\t\"team\": \"\",\n\t\t\"logOut\": \"\",\n\t\t\"notifications\": \"\",\n\t\t\"logs\": \"\"\n\t},\n\t\"settingsEmailUser\": \"\",\n\t\"state\": \"\",\n\t\"statusBreadCrumbsStatusPages\": \"\",\n\t\"statusBreadCrumbsDetails\": \"\",\n\t\"commonSaving\": \"\",\n\t\"navControls\": \"\",\n\t\"incidentsPageTitle\": \"\",\n\t\"passwordPanel\": {\n\t\t\"passwordChangedSuccess\": \"\",\n\t\t\"passwordInputIncorrect\": \"\",\n\t\t\"currentPassword\": \"\",\n\t\t\"enterCurrentPassword\": \"\",\n\t\t\"newPassword\": \"\",\n\t\t\"enterNewPassword\": \"\",\n\t\t\"confirmNewPassword\": \"\",\n\t\t\"passwordRequirements\": \"\",\n\t\t\"saving\": \"\"\n\t},\n\t\"emailSent\": \"\",\n\t\"failedToSendEmail\": \"\",\n\t\"settingsTestEmailSuccess\": \"\",\n\t\"settingsTestEmailFailed\": \"\",\n\t\"settingsTestEmailFailedWithReason\": \"\",\n\t\"settingsTestEmailUnknownError\": \"\",\n\t\"statusMsg\": {\n\t\t\"paused\": \"\",\n\t\t\"up\": \"\",\n\t\t\"down\": \"\",\n\t\t\"pending\": \"\"\n\t},\n\t\"uptimeGeneralInstructions\": {\n\t\t\"http\": \"\",\n\t\t\"ping\": \"\",\n\t\t\"docker\": \"\",\n\t\t\"port\": \"\",\n\t\t\"game\": \"\",\n\t\t\"https\": \"\"\n\t},\n\t\"common\": {\n\t\t\"appName\": \"\",\n\t\t\"monitoringAgentName\": \"\",\n\t\t\"buttons\": {\n\t\t\t\"toggleTheme\": \"\"\n\t\t},\n\t\t\"toasts\": {\n\t\t\t\"networkError\": \"\",\n\t\t\t\"checkConnection\": \"\",\n\t\t\t\"unknownError\": \"\"\n\t\t}\n\t},\n\t\"auth\": {\n\t\t\"common\": {\n\t\t\t\"navigation\": {\n\t\t\t\t\"continue\": \"\",\n\t\t\t\t\"back\": \"\"\n\t\t\t},\n\t\t\t\"inputs\": {\n\t\t\t\t\"email\": {\n\t\t\t\t\t\"label\": \"\",\n\t\t\t\t\t\"placeholder\": \"\",\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"\",\n\t\t\t\t\t\t\"invalid\": \"\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"password\": {\n\t\t\t\t\t\"label\": \"\",\n\t\t\t\t\t\"rules\": {\n\t\t\t\t\t\t\"length\": {\n\t\t\t\t\t\t\t\"beginning\": \"\",\n\t\t\t\t\t\t\t\"highlighted\": \"\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"special\": {\n\t\t\t\t\t\t\t\"beginning\": \"\",\n\t\t\t\t\t\t\t\"highlighted\": \"\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"number\": {\n\t\t\t\t\t\t\t\"beginning\": \"\",\n\t\t\t\t\t\t\t\"highlighted\": \"\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"uppercase\": {\n\t\t\t\t\t\t\t\"beginning\": \"\",\n\t\t\t\t\t\t\t\"highlighted\": \"\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"lowercase\": {\n\t\t\t\t\t\t\t\"beginning\": \"\",\n\t\t\t\t\t\t\t\"highlighted\": \"\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"match\": {\n\t\t\t\t\t\t\t\"beginning\": \"\",\n\t\t\t\t\t\t\t\"highlighted\": \"\"\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"\",\n\t\t\t\t\t\t\"length\": \"\",\n\t\t\t\t\t\t\"uppercase\": \"\",\n\t\t\t\t\t\t\"lowercase\": \"\",\n\t\t\t\t\t\t\"number\": \"\",\n\t\t\t\t\t\t\"special\": \"\",\n\t\t\t\t\t\t\"incorrect\": \"\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"passwordConfirm\": {\n\t\t\t\t\t\"label\": \"\",\n\t\t\t\t\t\"placeholder\": \"\",\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"\",\n\t\t\t\t\t\t\"different\": \"\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"firstName\": {\n\t\t\t\t\t\"label\": \"\",\n\t\t\t\t\t\"placeholder\": \"\",\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"\",\n\t\t\t\t\t\t\"length\": \"\",\n\t\t\t\t\t\t\"pattern\": \"\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"lastName\": {\n\t\t\t\t\t\"label\": \"\",\n\t\t\t\t\t\"placeholder\": \"\",\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"\",\n\t\t\t\t\t\t\"length\": \"\",\n\t\t\t\t\t\t\"pattern\": \"\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"errors\": {\n\t\t\t\t\"validation\": \"\"\n\t\t\t},\n\t\t\t\"fields\": {\n\t\t\t\t\"password\": {\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"incorrect\": \"\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"role\": {\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"min\": \"\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"login\": {\n\t\t\t\"heading\": \"\",\n\t\t\t\"subheadings\": {\n\t\t\t\t\"stepOne\": \"\",\n\t\t\t\t\"stepTwo\": \"\"\n\t\t\t},\n\t\t\t\"links\": {\n\t\t\t\t\"forgotPassword\": \"\",\n\t\t\t\t\"register\": \"\",\n\t\t\t\t\"forgotPasswordLink\": \"\",\n\t\t\t\t\"registerLink\": \"\"\n\t\t\t},\n\t\t\t\"toasts\": {\n\t\t\t\t\"success\": \"\",\n\t\t\t\t\"incorrectPassword\": \"\"\n\t\t\t},\n\t\t\t\"errors\": {\n\t\t\t\t\"password\": {\n\t\t\t\t\t\"incorrect\": \"\"\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"welcome\": \"\"\n\t\t},\n\t\t\"registration\": {\n\t\t\t\"heading\": {\n\t\t\t\t\"superAdmin\": \"\",\n\t\t\t\t\"user\": \"\"\n\t\t\t},\n\t\t\t\"subheadings\": {\n\t\t\t\t\"stepOne\": \"\",\n\t\t\t\t\"stepTwo\": \"\",\n\t\t\t\t\"stepThree\": \"\"\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\t\"superAdmin\": \"\",\n\t\t\t\t\"user\": \"\"\n\t\t\t},\n\t\t\t\"gettingStartedButton\": {\n\t\t\t\t\"superAdmin\": \"\",\n\t\t\t\t\"user\": \"\"\n\t\t\t},\n\t\t\t\"termsAndPolicies\": \"\",\n\t\t\t\"links\": {\n\t\t\t\t\"login\": \"\"\n\t\t\t},\n\t\t\t\"toasts\": {\n\t\t\t\t\"success\": \"\"\n\t\t\t},\n\t\t\t\"welcome\": \"\"\n\t\t},\n\t\t\"forgotPassword\": {\n\t\t\t\"heading\": \"\",\n\t\t\t\"subheadings\": {\n\t\t\t\t\"stepOne\": \"\",\n\t\t\t\t\"stepTwo\": \"\",\n\t\t\t\t\"stepThree\": \"\",\n\t\t\t\t\"stepFour\": \"\"\n\t\t\t},\n\t\t\t\"buttons\": {\n\t\t\t\t\"openEmail\": \"\",\n\t\t\t\t\"resetPassword\": \"\"\n\t\t\t},\n\t\t\t\"imageAlts\": {\n\t\t\t\t\"passwordKey\": \"\",\n\t\t\t\t\"email\": \"\",\n\t\t\t\t\"lock\": \"\",\n\t\t\t\t\"passwordConfirm\": \"\"\n\t\t\t},\n\t\t\t\"links\": {\n\t\t\t\t\"login\": \"\",\n\t\t\t\t\"resend\": \"\"\n\t\t\t},\n\t\t\t\"toasts\": {\n\t\t\t\t\"sent\": \"\",\n\t\t\t\t\"emailNotFound\": \"\",\n\t\t\t\t\"redirect\": \"\",\n\t\t\t\t\"success\": \"\",\n\t\t\t\t\"error\": \"\"\n\t\t\t}\n\t\t}\n\t},\n\t\"errorPages\": {\n\t\t\"serverUnreachable\": {\n\t\t\t\"toasts\": {\n\t\t\t\t\"reconnected\": \"\",\n\t\t\t\t\"stillUnreachable\": \"\"\n\t\t\t},\n\t\t\t\"alertBox\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"retryButton\": {\n\t\t\t\t\"default\": \"\",\n\t\t\t\t\"processing\": \"\"\n\t\t\t}\n\t\t}\n\t},\n\t\"createNotifications\": {\n\t\t\"title\": \"\",\n\t\t\"nameSettings\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"nameLabel\": \"\",\n\t\t\t\"namePlaceholder\": \"\"\n\t\t},\n\t\t\"typeSettings\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"typeLabel\": \"\"\n\t\t},\n\t\t\"emailSettings\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"emailLabel\": \"\",\n\t\t\t\"emailPlaceholder\": \"\"\n\t\t},\n\t\t\"slackSettings\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"webhookLabel\": \"\",\n\t\t\t\"webhookPlaceholder\": \"\"\n\t\t},\n\t\t\"pagerdutySettings\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"integrationKeyLabel\": \"\",\n\t\t\t\"integrationKeyPlaceholder\": \"\"\n\t\t},\n\t\t\"discordSettings\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"webhookLabel\": \"\",\n\t\t\t\"webhookPlaceholder\": \"\"\n\t\t},\n\t\t\"webhookSettings\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"webhookLabel\": \"\",\n\t\t\t\"webhookPlaceholder\": \"\"\n\t\t},\n\t\t\"testNotification\": \"\",\n\t\t\"dialogDeleteTitle\": \"\",\n\t\t\"dialogDeleteConfirm\": \"\"\n\t},\n\t\"notificationConfig\": {\n\t\t\"title\": \"\",\n\t\t\"description\": \"\"\n\t},\n\t\"monitorStatus\": {\n\t\t\"checkingEvery\": \"\",\n\t\t\"withCaptureAgent\": \"\",\n\t\t\"up\": \"\",\n\t\t\"down\": \"\",\n\t\t\"paused\": \"\"\n\t},\n\t\"advancedMatching\": \"\",\n\t\"sendTestNotifications\": \"\",\n\t\"selectAll\": \"\",\n\t\"showAdminLoginLink\": \"\",\n\t\"logsPage\": {\n\t\t\"title\": \"\",\n\t\t\"description\": \"\",\n\t\t\"tabs\": {\n\t\t\t\"queue\": \"\",\n\t\t\t\"logs\": \"\",\n\t\t\t\"diagnostics\": \"\"\n\t\t},\n\t\t\"toast\": {\n\t\t\t\"fetchLogsSuccess\": \"\"\n\t\t},\n\t\t\"logLevelSelect\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"values\": {\n\t\t\t\t\"all\": \"\",\n\t\t\t\t\"info\": \"\",\n\t\t\t\t\"warn\": \"\",\n\t\t\t\t\"error\": \"\",\n\t\t\t\t\"debug\": \"\"\n\t\t\t}\n\t\t}\n\t},\n\t\"queuePage\": {\n\t\t\"title\": \"\",\n\t\t\"refreshButton\": \"\",\n\t\t\"flushButton\": \"\",\n\t\t\"jobTable\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"idHeader\": \"\",\n\t\t\t\"urlHeader\": \"\",\n\t\t\t\"typeHeader\": \"\",\n\t\t\t\"activeHeader\": \"\",\n\t\t\t\"lockedAtHeader\": \"\",\n\t\t\t\"runCountHeader\": \"\",\n\t\t\t\"failCountHeader\": \"\",\n\t\t\t\"lastRunHeader\": \"\",\n\t\t\t\"lastFinishedAtHeader\": \"\",\n\t\t\t\"lastRunTookHeader\": \"\",\n\t\t\t\"intervalHeader\": \"\"\n\t\t},\n\t\t\"metricsTable\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"metricHeader\": \"\",\n\t\t\t\"valueHeader\": \"\"\n\t\t},\n\t\t\"failedJobTable\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"monitorIdHeader\": \"\",\n\t\t\t\"monitorUrlHeader\": \"\",\n\t\t\t\"failCountHeader\": \"\",\n\t\t\t\"failedAtHeader\": \"\",\n\t\t\t\"failReasonHeader\": \"\"\n\t\t}\n\t},\n\t\"export\": {\n\t\t\"title\": \"\",\n\t\t\"success\": \"\",\n\t\t\"failed\": \"\"\n\t},\n\t\"monitorActions\": {\n\t\t\"title\": \"\",\n\t\t\"import\": \"\",\n\t\t\"export\": \"\",\n\t\t\"deleteSuccess\": \"\",\n\t\t\"deleteFailed\": \"\",\n\t\t\"details\": \"\"\n\t},\n\t\"settingsPage\": {\n\t\t\"aboutSettings\": {\n\t\t\t\"labelDevelopedBy\": \"\",\n\t\t\t\"labelVersion\": \"\",\n\t\t\t\"title\": \"\"\n\t\t},\n\t\t\"demoMonitorsSettings\": {\n\t\t\t\"buttonAddMonitors\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"title\": \"\"\n\t\t},\n\t\t\"emailSettings\": {\n\t\t\t\"buttonSendTestEmail\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"descriptionTransport\": \"\",\n\t\t\t\"labelAddress\": \"\",\n\t\t\t\"labelConnectionHost\": \"\",\n\t\t\t\"labelHost\": \"\",\n\t\t\t\"labelIgnoreTLS\": \"\",\n\t\t\t\"labelPassword\": \"\",\n\t\t\t\"labelPasswordSet\": \"\",\n\t\t\t\"labelPool\": \"\",\n\t\t\t\"labelPort\": \"\",\n\t\t\t\"labelRejectUnauthorized\": \"\",\n\t\t\t\"labelRequireTLS\": \"\",\n\t\t\t\"labelSecure\": \"\",\n\t\t\t\"labelTLSServername\": \"\",\n\t\t\t\"labelUser\": \"\",\n\t\t\t\"linkTransport\": \"\",\n\t\t\t\"placeholderUser\": \"\",\n\t\t\t\"title\": \"\",\n\t\t\t\"toastEmailRequiredFieldsError\": \"\"\n\t\t},\n\t\t\"pageSpeedSettings\": {\n\t\t\t\"description\": \"\",\n\t\t\t\"labelApiKeySet\": \"\",\n\t\t\t\"labelApiKey\": \"\",\n\t\t\t\"title\": \"\"\n\t\t},\n\t\t\"saveButtonLabel\": \"\",\n\t\t\"statsSettings\": {\n\t\t\t\"clearAllStatsButton\": \"\",\n\t\t\t\"clearAllStatsDescription\": \"\",\n\t\t\t\"clearAllStatsDialogConfirm\": \"\",\n\t\t\t\"clearAllStatsDialogDescription\": \"\",\n\t\t\t\"clearAllStatsDialogTitle\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"labelTTL\": \"\",\n\t\t\t\"labelTTLOptional\": \"\",\n\t\t\t\"title\": \"\"\n\t\t},\n\t\t\"systemResetSettings\": {\n\t\t\t\"buttonRemoveAllMonitors\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"dialogConfirm\": \"\",\n\t\t\t\"dialogDescription\": \"\",\n\t\t\t\"dialogTitle\": \"\",\n\t\t\t\"title\": \"\"\n\t\t},\n\t\t\"timezoneSettings\": {\n\t\t\t\"description\": \"\",\n\t\t\t\"label\": \"\",\n\t\t\t\"title\": \"\"\n\t\t},\n\t\t\"title\": \"\",\n\t\t\"uiSettings\": {\n\t\t\t\"description\": \"\",\n\t\t\t\"labelLanguage\": \"\",\n\t\t\t\"labelTheme\": \"\",\n\t\t\t\"title\": \"\"\n\t\t},\n\t\t\"urlSettings\": {\n\t\t\t\"description\": \"\",\n\t\t\t\"label\": \"\",\n\t\t\t\"selectDisabled\": \"\",\n\t\t\t\"selectEnabled\": \"\",\n\t\t\t\"title\": \"\"\n\t\t},\n\t\t\"globalThresholds\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\"\n\t\t}\n\t},\n\t\"statusPageCreate\": {\n\t\t\"buttonSave\": \"\"\n\t},\n\t\"incidentsOptionsHeaderFilterResolved\": \"\",\n\t\"settingsSave\": \"\",\n\t\"statusPageCreateAppearanceTitle\": \"\",\n\t\"confirmPassword\": \"\",\n\t\"monitorHooks\": {\n\t\t\"failureAddDemoMonitors\": \"\",\n\t\t\"successAddDemoMonitors\": \"\"\n\t},\n\t\"settingsAppearance\": \"\",\n\t\"settingsDisplayTimezone\": \"\",\n\t\"settingsGeneralSettings\": \"\",\n\t\"incidentsOptionsHeaderTotalIncidents\": \"\",\n\t\"statusPage\": {\n\t\t\"deleteSuccess\": \"\",\n\t\t\"deleteFailed\": \"\",\n\t\t\"createSuccess\": \"\",\n\t\t\"updateSuccess\": \"\",\n\t\t\"generalSettings\": \"\",\n\t\t\"contents\": \"\",\n\t\t\"fallback\": {\n\t\t\t\"checks\": [\"\"],\n\t\t\t\"title\": \"\",\n\t\t\t\"actionButton\": \"\"\n\t\t}\n\t},\n\t\"testNotificationsDisabled\": \"\",\n\t\"incidentsTableResolvedAt\": \"\",\n\t\"incidentsTableActionResolve\": \"\",\n\t\"checkHooks\": {\n\t\t\"failureResolveOne\": \"\",\n\t\t\"failureResolveAll\": \"\",\n\t\t\"failureResolveMonitor\": \"\"\n\t},\n\t\"checkFormError\": \"\",\n\t\"diagnosticsPage\": {\n\t\t\"diagnosticDescription\": \"\",\n\t\t\"statsDescription\": \"\",\n\t\t\"gauges\": {\n\t\t\t\"heapAllocationTitle\": \"\",\n\t\t\t\"heapAllocationSubtitle\": \"\",\n\t\t\t\"heapUsageTitle\": \"\",\n\t\t\t\"heapUsageSubtitle\": \"\",\n\t\t\t\"heapUtilizationTitle\": \"\",\n\t\t\t\"heapUtilizationSubtitle\": \"\",\n\t\t\t\"instantCpuUsageTitle\": \"\",\n\t\t\t\"instantCpuUsageSubtitle\": \"\"\n\t\t},\n\t\t\"stats\": {\n\t\t\t\"eventLoopDelayTitle\": \"\",\n\t\t\t\"uptimeTitle\": \"\",\n\t\t\t\"usedHeapSizeTitle\": \"\",\n\t\t\t\"totalHeapSizeTitle\": \"\",\n\t\t\t\"osMemoryLimitTitle\": \"\"\n\t\t}\n\t},\n\t\"pageSpeedLighthouseAPI\": \"\",\n\t\"time\": {\n\t\t\"threeMinutes\": \"\",\n\t\t\"fiveMinutes\": \"\",\n\t\t\"tenMinutes\": \"\",\n\t\t\"twentyMinutes\": \"\",\n\t\t\"oneHour\": \"\",\n\t\t\"oneDay\": \"\",\n\t\t\"oneWeek\": \"\",\n\t\t\"fourMinutes\": \"\",\n\t\t\"oneMinute\": \"\",\n\t\t\"twoMinutes\": \"\",\n\t\t\"fifteenSeconds\": \"\",\n\t\t\"thirtySeconds\": \"\"\n\t},\n\t\"general\": {\n\t\t\"noOptionsFound\": \"\"\n\t},\n\t\"infrastructureMonitor\": {\n\t\t\"fallback\": {\n\t\t\t\"checks\": [\"\"],\n\t\t\t\"title\": \"\",\n\t\t\t\"actionButton\": \"\"\n\t\t}\n\t},\n\t\"maintenanceWindow\": {\n\t\t\"fallback\": {\n\t\t\t\"checks\": [\"\"],\n\t\t\t\"title\": \"\",\n\t\t\t\"actionButton\": \"\"\n\t\t}\n\t},\n\t\"pageSpeed\": {\n\t\t\"fallback\": {\n\t\t\t\"checks\": [\"\"],\n\t\t\t\"title\": \"\",\n\t\t\t\"actionButton\": \"\"\n\t\t}\n\t},\n\t\"uptimeMonitor\": {\n\t\t\"fallback\": {\n\t\t\t\"checks\": [\"\"],\n\t\t\t\"title\": \"\",\n\t\t\t\"actionButton\": \"\"\n\t\t}\n\t},\n\t\"editUserPage\": {\n\t\t\"form\": {\n\t\t\t\"email\": \"\",\n\t\t\t\"firstName\": \"\",\n\t\t\t\"lastName\": \"\",\n\t\t\t\"role\": \"\",\n\t\t\t\"save\": \"\"\n\t\t},\n\t\t\"table\": {\n\t\t\t\"actionHeader\": \"\",\n\t\t\t\"roleHeader\": \"\"\n\t\t},\n\t\t\"title\": \"\",\n\t\t\"toast\": {\n\t\t\t\"successUserUpdate\": \"\",\n\t\t\t\"validationErrors\": \"\"\n\t\t}\n\t},\n\t\"incidentsPageActionResolveMonitor\": \"\",\n\t\"incidentsPageActionResolveAll\": \"\",\n\t\"matchMethodOptions\": {\n\t\t\"equal\": \"\",\n\t\t\"equalPlaceholder\": \"\",\n\t\t\"include\": \"\",\n\t\t\"includePlaceholder\": \"\",\n\t\t\"regex\": \"\",\n\t\t\"regexPlaceholder\": \"\",\n\t\t\"text\": \"\"\n\t},\n\t\"monitorType\": {\n\t\t\"docker\": {\n\t\t\t\"label\": \"\",\n\t\t\t\"namePlaceholder\": \"\",\n\t\t\t\"placeholder\": \"\"\n\t\t},\n\t\t\"http\": {\n\t\t\t\"label\": \"\",\n\t\t\t\"namePlaceholder\": \"\",\n\t\t\t\"placeholder\": \"\"\n\t\t},\n\t\t\"ping\": {\n\t\t\t\"label\": \"\",\n\t\t\t\"namePlaceholder\": \"\",\n\t\t\t\"placeholder\": \"\"\n\t\t},\n\t\t\"port\": {\n\t\t\t\"label\": \"\",\n\t\t\t\"namePlaceholder\": \"\",\n\t\t\t\"placeholder\": \"\"\n\t\t},\n\t\t\"game\": {\n\t\t\t\"label\": \"\",\n\t\t\t\"namePlaceholder\": \"\",\n\t\t\t\"placeholder\": \"\"\n\t\t}\n\t},\n\t\"uptimeAdvancedMatching\": {\n\t\t\"jsonPath\": \"\"\n\t},\n\t\"bytesPerSecond\": \"\",\n\t\"bytesReceived\": \"\",\n\t\"bytesSent\": \"\",\n\t\"chooseGame\": \"\",\n\t\"createMonitorPage\": {\n\t\t\"incidentConfigDescription\": \"\",\n\t\t\"incidentConfigStatusWindowLabel\": \"\",\n\t\t\"incidentConfigStatusWindowThresholdLabel\": \"\",\n\t\t\"incidentConfigTitle\": \"\",\n\t\t\"incidentConfigDescriptionV2\": \"\",\n\t\t\"incidentConfigStatusCheckNumber\": \"\",\n\t\t\"intervalTitle\": \"\",\n\t\t\"intervalDescription\": \"\"\n\t},\n\t\"dataRate\": \"\",\n\t\"dataReceived\": \"\",\n\t\"dataSent\": \"\",\n\t\"details\": \"\",\n\t\"drops\": \"\",\n\t\"errors\": \"\",\n\t\"errorsIn\": \"\",\n\t\"errorsOut\": \"\",\n\t\"gameServerMonitoring\": \"\",\n\t\"gameServerMonitoringDescription\": \"\",\n\t\"network\": \"\",\n\t\"networkDrops\": \"\",\n\t\"networkErrors\": \"\",\n\t\"networkInterface\": \"\",\n\t\"noNetworkStatsAvailable\": \"\",\n\t\"packetsPerSecond\": \"\",\n\t\"packetsReceived\": \"\",\n\t\"packetsReceivedRate\": \"\",\n\t\"packetsSent\": \"\",\n\t\"rate\": \"\",\n\t\"selectInterface\": \"\"\n}\n"
  },
  {
    "path": "client/src/locales/cs.json",
    "content": "{\n\t\"submit\": \"Odeslat\",\n\t\"title\": \"\",\n\t\"distributedStatusHeaderText\": \"\",\n\t\"distributedStatusSubHeaderText\": \"\",\n\t\"settingsDisabled\": \"Vypnuto\",\n\t\"settingsSuccessSaved\": \"Nastavení bylo úspěšně uloženo\",\n\t\"settingsFailedToSave\": \"Nepodařilo se uložit nastavení\",\n\t\"settingsStatsCleared\": \"\",\n\t\"settingsFailedToClearStats\": \"\",\n\t\"settingsMonitorsDeleted\": \"\",\n\t\"settingsFailedToDeleteMonitors\": \"\",\n\t\"starPromptTitle\": \"\",\n\t\"starPromptDescription\": \"\",\n\t\"https\": \"\",\n\t\"http\": \"\",\n\t\"monitor\": \"\",\n\t\"aboutus\": \"\",\n\t\"now\": \"\",\n\t\"delete\": \"\",\n\t\"configure\": \"\",\n\t\"responseTime\": \"\",\n\t\"ms\": \"\",\n\t\"bar\": \"\",\n\t\"area\": \"\",\n\t\"country\": \"\",\n\t\"city\": \"\",\n\t\"response\": \"\",\n\t\"monitorStatusUp\": \"\",\n\t\"monitorStatusDown\": \"\",\n\t\"webhookSendSuccess\": \"\",\n\t\"webhookSendError\": \"\",\n\t\"webhookUnsupportedPlatform\": \"\",\n\t\"distributedRightCategoryTitle\": \"\",\n\t\"distributedStatusServerMonitors\": \"\",\n\t\"distributedStatusServerMonitorsDescription\": \"\",\n\t\"distributedUptimeCreateSelectURL\": \"\",\n\t\"distributedUptimeCreateChecks\": \"\",\n\t\"distributedUptimeCreateChecksDescription\": \"\",\n\t\"distributedUptimeCreateIncidentNotification\": \"\",\n\t\"distributedUptimeCreateIncidentDescription\": \"\",\n\t\"distributedUptimeCreateAdvancedSettings\": \"\",\n\t\"distributedUptimeDetailsNoMonitorHistory\": \"\",\n\t\"distributedUptimeDetailsStatusHeaderUptime\": \"\",\n\t\"distributedUptimeDetailsStatusHeaderLastUpdate\": \"\",\n\t\"notifications\": {\n\t\t\"enableNotifications\": \"\",\n\t\t\"testNotification\": \"\",\n\t\t\"addOrEditNotifications\": \"\",\n\t\t\"slack\": {\n\t\t\t\"label\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"webhookLabel\": \"\",\n\t\t\t\"webhookPlaceholder\": \"\",\n\t\t\t\"webhookRequired\": \"\"\n\t\t},\n\t\t\"discord\": {\n\t\t\t\"label\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"webhookLabel\": \"\",\n\t\t\t\"webhookPlaceholder\": \"\",\n\t\t\t\"webhookRequired\": \"\"\n\t\t},\n\t\t\"telegram\": {\n\t\t\t\"label\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"tokenLabel\": \"\",\n\t\t\t\"tokenPlaceholder\": \"\",\n\t\t\t\"chatIdLabel\": \"\",\n\t\t\t\"chatIdPlaceholder\": \"\",\n\t\t\t\"fieldsRequired\": \"\"\n\t\t},\n\t\t\"webhook\": {\n\t\t\t\"label\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"urlLabel\": \"\",\n\t\t\t\"urlPlaceholder\": \"\",\n\t\t\t\"urlRequired\": \"\"\n\t\t},\n\t\t\"testNotificationDevelop\": \"\",\n\t\t\"integrationButton\": \"\",\n\t\t\"testSuccess\": \"\",\n\t\t\"testFailed\": \"\",\n\t\t\"unsupportedType\": \"\",\n\t\t\"networkError\": \"\",\n\t\t\"fallback\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"checks\": [\"\"],\n\t\t\t\"actionButton\": \"\"\n\t\t},\n\t\t\"createButton\": \"\",\n\t\t\"createTitle\": \"\",\n\t\t\"create\": {\n\t\t\t\"success\": \"\",\n\t\t\t\"failed\": \"\"\n\t\t},\n\t\t\"fetch\": {\n\t\t\t\"success\": \"\",\n\t\t\t\"failed\": \"\"\n\t\t},\n\t\t\"delete\": {\n\t\t\t\"success\": \"\",\n\t\t\t\"failed\": \"\"\n\t\t},\n\t\t\"edit\": {\n\t\t\t\"success\": \"\",\n\t\t\t\"failed\": \"\"\n\t\t},\n\t\t\"test\": {\n\t\t\t\"success\": \"\",\n\t\t\t\"failed\": \"\"\n\t\t}\n\t},\n\t\"testLocale\": \"\",\n\t\"add\": \"\",\n\t\"monitors\": \"\",\n\t\"distributedUptimeStatusCreateStatusPage\": \"\",\n\t\"distributedUptimeStatusCreateStatusPageAccess\": \"\",\n\t\"distributedUptimeStatusCreateStatusPageReady\": \"\",\n\t\"distributedUptimeStatusBasicInfoHeader\": \"\",\n\t\"distributedUptimeStatusBasicInfoDescription\": \"\",\n\t\"distributedUptimeStatusLogoHeader\": \"\",\n\t\"distributedUptimeStatusLogoDescription\": \"\",\n\t\"distributedUptimeStatusLogoUploadButton\": \"\",\n\t\"distributedUptimeStatusStandardMonitorsHeader\": \"\",\n\t\"distributedUptimeStatusStandardMonitorsDescription\": \"\",\n\t\"distributedUptimeStatusCreateYour\": \"\",\n\t\"distributedUptimeStatusEditYour\": \"\",\n\t\"distributedUptimeStatusPublishedLabel\": \"\",\n\t\"distributedUptimeStatusCompanyNameLabel\": \"\",\n\t\"distributedUptimeStatusPageAddressLabel\": \"\",\n\t\"distributedUptimeStatus30Days\": \"\",\n\t\"distributedUptimeStatus60Days\": \"\",\n\t\"distributedUptimeStatus90Days\": \"\",\n\t\"distributedUptimeStatusPageNotSetUp\": \"\",\n\t\"distributedUptimeStatusContactAdmin\": \"\",\n\t\"distributedUptimeStatusPageNotPublic\": \"\",\n\t\"distributedUptimeStatusPageDeleteDialog\": \"\",\n\t\"distributedUptimeStatusPageDeleteConfirm\": \"\",\n\t\"distributedUptimeStatusPageDeleteDescription\": \"\",\n\t\"distributedUptimeStatusDevices\": \"\",\n\t\"distributedUptimeStatusUpt\": \"\",\n\t\"distributedUptimeStatusUptBurned\": \"\",\n\t\"distributedUptimeStatusUptLogo\": \"\",\n\t\"incidentsTableNoIncidents\": \"\",\n\t\"incidentsTablePaginationLabel\": \"\",\n\t\"incidentsTableMonitorName\": \"\",\n\t\"incidentsTableStatus\": \"\",\n\t\"incidentsTableDateTime\": \"\",\n\t\"incidentsTableStatusCode\": \"\",\n\t\"incidentsTableMessage\": \"\",\n\t\"incidentsOptionsHeader\": \"\",\n\t\"incidentsOptionsHeaderFilterBy\": \"\",\n\t\"incidentsOptionsHeaderFilterAll\": \"\",\n\t\"incidentsOptionsHeaderFilterDown\": \"\",\n\t\"incidentsOptionsHeaderFilterCannotResolve\": \"\",\n\t\"incidentsOptionsHeaderShow\": \"\",\n\t\"incidentsOptionsHeaderLastHour\": \"\",\n\t\"incidentsOptionsHeaderLastDay\": \"\",\n\t\"incidentsOptionsHeaderLastWeek\": \"\",\n\t\"incidentsOptionsPlaceholderAllServers\": \"\",\n\t\"infrastructureCreateYour\": \"\",\n\t\"infrastructureCreateGeneralSettingsDescription\": \"\",\n\t\"infrastructureServerRequirement\": \"\",\n\t\"infrastructureCustomizeAlerts\": \"\",\n\t\"infrastructureAlertNotificationDescription\": \"\",\n\t\"infrastructureCreateMonitor\": \"\",\n\t\"infrastructureProtocol\": \"\",\n\t\"infrastructureServerUrlLabel\": \"\",\n\t\"infrastructureDisplayNameLabel\": \"\",\n\t\"infrastructureAuthorizationSecretLabel\": \"\",\n\t\"gb\": \"\",\n\t\"mb\": \"\",\n\t\"mem\": \"\",\n\t\"memoryUsage\": \"\",\n\t\"cpu\": \"\",\n\t\"cpuUsage\": \"\",\n\t\"cpuTemperature\": \"\",\n\t\"diskUsage\": \"\",\n\t\"used\": \"\",\n\t\"total\": \"\",\n\t\"cores\": \"\",\n\t\"frequency\": \"\",\n\t\"status\": \"\",\n\t\"cpuPhysical\": \"\",\n\t\"cpuLogical\": \"\",\n\t\"cpuFrequency\": \"\",\n\t\"avgCpuTemperature\": \"\",\n\t\"memory\": \"\",\n\t\"disk\": \"\",\n\t\"uptime\": \"\",\n\t\"os\": \"\",\n\t\"host\": \"\",\n\t\"actions\": \"\",\n\t\"integrations\": \"\",\n\t\"integrationsPrism\": \"\",\n\t\"integrationsSlack\": \"\",\n\t\"integrationsSlackInfo\": \"\",\n\t\"integrationsDiscord\": \"\",\n\t\"integrationsDiscordInfo\": \"\",\n\t\"integrationsZapier\": \"\",\n\t\"integrationsZapierInfo\": \"\",\n\t\"commonSave\": \"\",\n\t\"createYour\": \"\",\n\t\"createMonitor\": \"\",\n\t\"pause\": \"\",\n\t\"resume\": \"\",\n\t\"editing\": \"\",\n\t\"url\": \"\",\n\t\"access\": \"\",\n\t\"timezone\": \"\",\n\t\"features\": \"\",\n\t\"administrator\": \"\",\n\t\"loginHere\": \"\",\n\t\"displayName\": \"\",\n\t\"urlMonitor\": \"\",\n\t\"portToMonitor\": \"\",\n\t\"websiteMonitoring\": \"\",\n\t\"websiteMonitoringDescription\": \"\",\n\t\"pingMonitoring\": \"\",\n\t\"pingMonitoringDescription\": \"\",\n\t\"dockerContainerMonitoring\": \"\",\n\t\"dockerContainerMonitoringDescription\": \"\",\n\t\"portMonitoring\": \"\",\n\t\"portMonitoringDescription\": \"\",\n\t\"createMaintenanceWindow\": \"\",\n\t\"createMaintenance\": \"\",\n\t\"editMaintenance\": \"\",\n\t\"maintenanceWindowName\": \"\",\n\t\"friendlyNameInput\": \"\",\n\t\"friendlyNamePlaceholder\": \"\",\n\t\"maintenanceRepeat\": \"\",\n\t\"maintenance\": \"\",\n\t\"duration\": \"\",\n\t\"addMonitors\": \"\",\n\t\"window\": \"\",\n\t\"cancel\": \"\",\n\t\"message\": \"\",\n\t\"low\": \"\",\n\t\"high\": \"\",\n\t\"statusCode\": \"\",\n\t\"date&Time\": \"\",\n\t\"type\": \"\",\n\t\"statusPageName\": \"\",\n\t\"publicURL\": \"\",\n\t\"repeat\": \"\",\n\t\"edit\": \"\",\n\t\"createA\": \"\",\n\t\"remove\": \"\",\n\t\"maintenanceWindowDescription\": \"\",\n\t\"startTime\": \"\",\n\t\"timeZoneInfo\": \"\",\n\t\"monitorsToApply\": \"\",\n\t\"nextWindow\": \"\",\n\t\"notFoundButton\": \"\",\n\t\"pageSpeedConfigureSettingsDescription\": \"\",\n\t\"monitorDisplayName\": \"\",\n\t\"whenNewIncident\": \"\",\n\t\"notifySMS\": \"\",\n\t\"notifyEmails\": \"\",\n\t\"seperateEmails\": \"\",\n\t\"checkFrequency\": \"\",\n\t\"matchMethod\": \"\",\n\t\"expectedValue\": \"\",\n\t\"deleteDialogTitle\": \"\",\n\t\"deleteDialogDescription\": \"\",\n\t\"pageSpeedMonitor\": \"\",\n\t\"shown\": \"\",\n\t\"ago\": \"\",\n\t\"companyName\": \"\",\n\t\"pageSpeedDetailsPerformanceReport\": \"\",\n\t\"pageSpeedDetailsPerformanceReportCalculator\": \"\",\n\t\"checkingEvery\": \"\",\n\t\"statusPageCreateSettings\": \"\",\n\t\"basicInformation\": \"\",\n\t\"statusPageCreateBasicInfoDescription\": \"\",\n\t\"statusPageCreateSelectTimeZoneDescription\": \"\",\n\t\"statusPageCreateAppearanceDescription\": \"\",\n\t\"statusPageCreateSettingsCheckboxLabel\": \"\",\n\t\"statusPageCreateBasicInfoStatusPageAddress\": \"\",\n\t\"statusPageCreateTabsContent\": \"\",\n\t\"statusPageCreateTabsContentDescription\": \"\",\n\t\"statusPageCreateTabsContentFeaturesDescription\": \"\",\n\t\"showCharts\": \"\",\n\t\"showUptimePercentage\": \"\",\n\t\"removeLogo\": \"\",\n\t\"statusPageStatus\": \"\",\n\t\"statusPageStatusContactAdmin\": \"\",\n\t\"statusPageStatusNotPublic\": \"\",\n\t\"statusPageStatusNoPage\": \"\",\n\t\"statusPageStatusServiceStatus\": \"\",\n\t\"deleteStatusPage\": \"\",\n\t\"deleteStatusPageConfirm\": \"\",\n\t\"deleteStatusPageDescription\": \"\",\n\t\"uptimeCreate\": \"\",\n\t\"uptimeCreateJsonPath\": \"\",\n\t\"uptimeCreateJsonPathQuery\": \"\",\n\t\"maintenanceTableActionMenuDialogTitle\": \"\",\n\t\"infrastructureEditYour\": \"\",\n\t\"infrastructureEditMonitor\": \"\",\n\t\"infrastructureMonitorCreated\": \"\",\n\t\"infrastructureMonitorUpdated\": \"\",\n\t\"errorInvalidTypeId\": \"\",\n\t\"errorInvalidFieldId\": \"\",\n\t\"inviteNoTokenFound\": \"\",\n\t\"pageSpeedWarning\": \"\",\n\t\"pageSpeedLearnMoreLink\": \"\",\n\t\"pageSpeedAddApiKey\": \"\",\n\t\"update\": \"\",\n\t\"invalidFileFormat\": \"\",\n\t\"invalidFileSize\": \"\",\n\t\"ClickUpload\": \"\",\n\t\"DragandDrop\": \"\",\n\t\"MaxSize\": \"\",\n\t\"SupportedFormats\": \"\",\n\t\"FirstName\": \"\",\n\t\"LastName\": \"\",\n\t\"EmailDescriptionText\": \"\",\n\t\"YourPhoto\": \"\",\n\t\"PhotoDescriptionText\": \"\",\n\t\"save\": \"\",\n\t\"DeleteDescriptionText\": \"\",\n\t\"DeleteAccountWarning\": \"\",\n\t\"DeleteWarningTitle\": \"\",\n\t\"bulkImport\": {\n\t\t\"title\": \"\",\n\t\t\"selectFileTips\": \"\",\n\t\t\"selectFileDescription\": \"\",\n\t\t\"selectFile\": \"\",\n\t\t\"parsingFailed\": \"\",\n\t\t\"uploadSuccess\": \"\",\n\t\t\"validationFailed\": \"\",\n\t\t\"noFileSelected\": \"\",\n\t\t\"fallbackPage\": \"\",\n\t\t\"invalidFileType\": \"\",\n\t\t\"uploadFailed\": \"\"\n\t},\n\t\"DeleteAccountTitle\": \"\",\n\t\"DeleteAccountButton\": \"\",\n\t\"publicLink\": \"\",\n\t\"maskedPageSpeedKeyPlaceholder\": \"\",\n\t\"reset\": \"\",\n\t\"ignoreTLSError\": \"\",\n\t\"tlsErrorIgnored\": \"\",\n\t\"ignoreTLSErrorDescription\": \"\",\n\t\"createNew\": \"\",\n\t\"greeting\": {\n\t\t\"prepend\": \"\",\n\t\t\"append\": \"\",\n\t\t\"overview\": \"\"\n\t},\n\t\"roles\": {\n\t\t\"superAdmin\": \"\",\n\t\t\"admin\": \"\",\n\t\t\"teamMember\": \"\",\n\t\t\"demoUser\": \"\"\n\t},\n\t\"teamPanel\": {\n\t\t\"teamMembers\": \"\",\n\t\t\"filter\": {\n\t\t\t\"all\": \"\",\n\t\t\t\"member\": \"\"\n\t\t},\n\t\t\"inviteTeamMember\": \"\",\n\t\t\"inviteNewTeamMember\": \"\",\n\t\t\"inviteDescription\": \"\",\n\t\t\"email\": \"\",\n\t\t\"selectRole\": \"\",\n\t\t\"inviteLink\": \"\",\n\t\t\"cancel\": \"\",\n\t\t\"noMembers\": \"\",\n\t\t\"getToken\": \"\",\n\t\t\"emailToken\": \"\",\n\t\t\"table\": {\n\t\t\t\"name\": \"\",\n\t\t\t\"email\": \"\",\n\t\t\t\"role\": \"\",\n\t\t\t\"created\": \"\"\n\t\t},\n\t\t\"addTeamMember\": {\n\t\t\t\"addMemberMenu\": \"\",\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"addButton\": \"\"\n\t\t},\n\t\t\"register\": \"\",\n\t\t\"registerToast\": {\n\t\t\t\"success\": \"\",\n\t\t\t\"dbUserExists\": \"\",\n\t\t\t\"unknownError\": \"\"\n\t\t},\n\t\t\"registerTeamMember\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"auth\": {\n\t\t\t\t\"common\": {\n\t\t\t\t\t\"inputs\": {\n\t\t\t\t\t\t\"firstName\": {\n\t\t\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\t\t\"empty\": \"\",\n\t\t\t\t\t\t\t\t\"pattern\": \"\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"lastName\": {\n\t\t\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\t\t\"empty\": \"\",\n\t\t\t\t\t\t\t\t\"pattern\": \"\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"email\": {\n\t\t\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\t\t\"empty\": \"\",\n\t\t\t\t\t\t\t\t\"invalid\": \"\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"role\": {\n\t\t\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\t\t\"empty\": \"\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"role\": \"\",\n\t\t\"changeTeamPassword\": {\n\t\t\t\"changePasswordMenu\": \"\",\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"success\": \"\"\n\t\t}\n\t},\n\t\"monitorState\": {\n\t\t\"paused\": \"\",\n\t\t\"resumed\": \"\",\n\t\t\"active\": \"\"\n\t},\n\t\"menu\": {\n\t\t\"uptime\": \"\",\n\t\t\"pagespeed\": \"\",\n\t\t\"infrastructure\": \"\",\n\t\t\"incidents\": \"\",\n\t\t\"statusPages\": \"\",\n\t\t\"maintenance\": \"\",\n\t\t\"integrations\": \"\",\n\t\t\"settings\": \"\",\n\t\t\"support\": \"\",\n\t\t\"discussions\": \"\",\n\t\t\"docs\": \"\",\n\t\t\"changelog\": \"\",\n\t\t\"profile\": \"\",\n\t\t\"password\": \"\",\n\t\t\"team\": \"\",\n\t\t\"logOut\": \"\",\n\t\t\"notifications\": \"\",\n\t\t\"logs\": \"\"\n\t},\n\t\"settingsEmailUser\": \"\",\n\t\"state\": \"\",\n\t\"statusBreadCrumbsStatusPages\": \"\",\n\t\"statusBreadCrumbsDetails\": \"\",\n\t\"commonSaving\": \"\",\n\t\"navControls\": \"\",\n\t\"incidentsPageTitle\": \"\",\n\t\"passwordPanel\": {\n\t\t\"passwordChangedSuccess\": \"\",\n\t\t\"passwordInputIncorrect\": \"\",\n\t\t\"currentPassword\": \"\",\n\t\t\"enterCurrentPassword\": \"\",\n\t\t\"newPassword\": \"\",\n\t\t\"enterNewPassword\": \"\",\n\t\t\"confirmNewPassword\": \"\",\n\t\t\"passwordRequirements\": \"\",\n\t\t\"saving\": \"\"\n\t},\n\t\"emailSent\": \"\",\n\t\"failedToSendEmail\": \"\",\n\t\"settingsTestEmailSuccess\": \"\",\n\t\"settingsTestEmailFailed\": \"\",\n\t\"settingsTestEmailFailedWithReason\": \"\",\n\t\"settingsTestEmailUnknownError\": \"\",\n\t\"statusMsg\": {\n\t\t\"paused\": \"\",\n\t\t\"up\": \"\",\n\t\t\"down\": \"\",\n\t\t\"pending\": \"\"\n\t},\n\t\"uptimeGeneralInstructions\": {\n\t\t\"http\": \"\",\n\t\t\"ping\": \"\",\n\t\t\"docker\": \"\",\n\t\t\"port\": \"\",\n\t\t\"game\": \"\",\n\t\t\"https\": \"\"\n\t},\n\t\"common\": {\n\t\t\"appName\": \"Checkmate\",\n\t\t\"monitoringAgentName\": \"Capture\",\n\t\t\"buttons\": {\n\t\t\t\"toggleTheme\": \"Přepnout mezi světlým a tmavým motivem\"\n\t\t},\n\t\t\"toasts\": {\n\t\t\t\"networkError\": \"Chyba připojení k síti\",\n\t\t\t\"checkConnection\": \"Zkontrolujte prosím své připojení k síti\",\n\t\t\t\"unknownError\": \"Nastala neznámá chyba\"\n\t\t}\n\t},\n\t\"auth\": {\n\t\t\"common\": {\n\t\t\t\"navigation\": {\n\t\t\t\t\"continue\": \"Pokračovat\",\n\t\t\t\t\"back\": \"Zpět\"\n\t\t\t},\n\t\t\t\"inputs\": {\n\t\t\t\t\"email\": {\n\t\t\t\t\t\"label\": \"E-mail\",\n\t\t\t\t\t\"placeholder\": \"jan.novak@domena.cz\",\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"Zadejte prosím e-mailovou adresu\",\n\t\t\t\t\t\t\"invalid\": \"Překontrolujte si prosím správnost zadané e-mailové adresy\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"password\": {\n\t\t\t\t\t\"label\": \"Heslo\",\n\t\t\t\t\t\"rules\": {\n\t\t\t\t\t\t\"length\": {\n\t\t\t\t\t\t\t\"beginning\": \"Heslo musí být dlouhé alespoň\",\n\t\t\t\t\t\t\t\"highlighted\": \"8 znaků\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"special\": {\n\t\t\t\t\t\t\t\"beginning\": \"Heslo musí obsahovat alespoň\",\n\t\t\t\t\t\t\t\"highlighted\": \"1 speciální znak\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"number\": {\n\t\t\t\t\t\t\t\"beginning\": \"Heslo musí obsahovat alespoň\",\n\t\t\t\t\t\t\t\"highlighted\": \"1 číslo\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"uppercase\": {\n\t\t\t\t\t\t\t\"beginning\": \"Heslo musí obsahovat alespoň\",\n\t\t\t\t\t\t\t\"highlighted\": \"1 velké písmeno\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"lowercase\": {\n\t\t\t\t\t\t\t\"beginning\": \"Heslo musí obsahovat alespoň\",\n\t\t\t\t\t\t\t\"highlighted\": \"1 malé písmeno\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"match\": {\n\t\t\t\t\t\t\t\"beginning\": \"Obě hesla se\",\n\t\t\t\t\t\t\t\"highlighted\": \"musí shodovat\"\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"Zadejte prosím heslo\",\n\t\t\t\t\t\t\"length\": \"Heslo musí být dlouhé alespoň 8 znaků\",\n\t\t\t\t\t\t\"uppercase\": \"Heslo musí obsahovat alespoň 1 velké písmeno\",\n\t\t\t\t\t\t\"lowercase\": \"Heslo musí obsahovat alespoň 1 malé písmeno\",\n\t\t\t\t\t\t\"number\": \"Heslo musí obsahovat alespoň 1 číslo\",\n\t\t\t\t\t\t\"special\": \"Heslo musí obsahovat alespoň 1 speciální znak\",\n\t\t\t\t\t\t\"incorrect\": \"Zadané heslo neodpovídá tomu, co bylo nastaveno\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"passwordConfirm\": {\n\t\t\t\t\t\"label\": \"Potvrzení hesla\",\n\t\t\t\t\t\"placeholder\": \"Pro ověření správnosti zadejte heslo ještě jednou\",\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"Zadejte prosím své heslo ještě jednou, aby mohla být potvrzena jeho správnost (odhalí překlepy)\",\n\t\t\t\t\t\t\"different\": \"Zadaná hesla se liší, takže je nejspíše jedno z nich špatně zapsané\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"firstName\": {\n\t\t\t\t\t\"label\": \"Jméno\",\n\t\t\t\t\t\"placeholder\": \"Jan\",\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"Zadejte prosím své křestní jméno\",\n\t\t\t\t\t\t\"length\": \"Jméno se musí vejít do 50 znaků\",\n\t\t\t\t\t\t\"pattern\": \"Součástí jména mohou být pouze písmena, mezery apostrofy nebo spojovníky\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"lastName\": {\n\t\t\t\t\t\"label\": \"Příjmení\",\n\t\t\t\t\t\"placeholder\": \"Novák\",\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"Zadejte prosím své příjmení\",\n\t\t\t\t\t\t\"length\": \"Příjmení se musí vejít do 50 znaků\",\n\t\t\t\t\t\t\"pattern\": \"Součástí příjmení mohou být pouze písmena, mezery apostrofy nebo spojovníky\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"errors\": {\n\t\t\t\t\"validation\": \"Nastala chyba při ověřování dat.\"\n\t\t\t},\n\t\t\t\"fields\": {\n\t\t\t\t\"password\": {\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"incorrect\": \"\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"role\": {\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"min\": \"\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"login\": {\n\t\t\t\"heading\": \"Přihlášení\",\n\t\t\t\"subheadings\": {\n\t\t\t\t\"stepOne\": \"Zadejte svůj e-mail\",\n\t\t\t\t\"stepTwo\": \"Zadejte své heslo\"\n\t\t\t},\n\t\t\t\"links\": {\n\t\t\t\t\"forgotPassword\": \"Zapomněli jste heslo? <a>Obnovte si ho</a>\",\n\t\t\t\t\"register\": \"Ještě nemáte účet? <a>Zaregistrujte se</a>\",\n\t\t\t\t\"forgotPasswordLink\": \"\",\n\t\t\t\t\"registerLink\": \"\"\n\t\t\t},\n\t\t\t\"toasts\": {\n\t\t\t\t\"success\": \"Vítejte zpět\",\n\t\t\t\t\"incorrectPassword\": \"Nesprávné heslo\"\n\t\t\t},\n\t\t\t\"errors\": {\n\t\t\t\t\"password\": {\n\t\t\t\t\t\"incorrect\": \"\"\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"welcome\": \"\"\n\t\t},\n\t\t\"registration\": {\n\t\t\t\"heading\": {\n\t\t\t\t\"superAdmin\": \"Vytvoření superadministrátora\",\n\t\t\t\t\"user\": \"Registrace\"\n\t\t\t},\n\t\t\t\"subheadings\": {\n\t\t\t\t\"stepOne\": \"Zadejte své osobní údaje\",\n\t\t\t\t\"stepTwo\": \"Zadejte svůj e-mail\",\n\t\t\t\t\"stepThree\": \"Nastavte si heslo\"\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\t\"superAdmin\": \"Pro začátek vytvořte účet superadministrátora\",\n\t\t\t\t\"user\": \"Zaregistrujte se jako uživatel a požádejte svého superadministrátora, aby vám přidělil oprávnění k hlídačům\"\n\t\t\t},\n\t\t\t\"gettingStartedButton\": {\n\t\t\t\t\"superAdmin\": \"Vytvořit účet superadministrátora\",\n\t\t\t\t\"user\": \"Zaregistrovat se jako běžný uživatel\"\n\t\t\t},\n\t\t\t\"termsAndPolicies\": \"Vytvořením účtu souhlasíte s našimi <a1>Podmínkami použití</a1> (anglicky) a <a2>Podmínkami zpracování osobních údajů</a2> (anglicky).\",\n\t\t\t\"links\": {\n\t\t\t\t\"login\": \"Máte již vytvořený účet? <a>Přihlašte se</a>\"\n\t\t\t},\n\t\t\t\"toasts\": {\n\t\t\t\t\"success\": \"Vítejte! Váš účet byl úspěšně vytvořen.\"\n\t\t\t},\n\t\t\t\"welcome\": \"\"\n\t\t},\n\t\t\"forgotPassword\": {\n\t\t\t\"heading\": \"Zapomenuté heslo\",\n\t\t\t\"subheadings\": {\n\t\t\t\t\"stepOne\": \"Nebojte se, zašleme vám pokyny pro obnovení hesla.\",\n\t\t\t\t\"stepTwo\": \"Odkaz pro obnovení hesla byl odeslán na <email/>\",\n\t\t\t\t\"stepThree\": \"Nové heslo se musí lišit od těch, které jste již použili.\",\n\t\t\t\t\"stepFour\": \"Heslo bylo úspěšně obnoveno. Klepněte na tlačítko a dojde k čarovnému přihlášení.\"\n\t\t\t},\n\t\t\t\"buttons\": {\n\t\t\t\t\"openEmail\": \"Otevřít e-mailovou aplikaci\",\n\t\t\t\t\"resetPassword\": \"Obnovit heslo\"\n\t\t\t},\n\t\t\t\"imageAlts\": {\n\t\t\t\t\"passwordKey\": \"Ikonka přístupového klíče\",\n\t\t\t\t\"email\": \"Ikonka e-mailu\",\n\t\t\t\t\"lock\": \"Ikonka zámku\",\n\t\t\t\t\"passwordConfirm\": \"Ikonka potvrzeného hesla\"\n\t\t\t},\n\t\t\t\"links\": {\n\t\t\t\t\"login\": \"Vrátit se k <a>Přihlášení</a>\",\n\t\t\t\t\"resend\": \"Nedorazil vám e-mail? <a>Klepněte pro opětovné zaslání</a>\"\n\t\t\t},\n\t\t\t\"toasts\": {\n\t\t\t\t\"sent\": \"Instrukce vám dorazí na <email/>.\",\n\t\t\t\t\"emailNotFound\": \"Nepodařilo se nalézt e-mailovou adresu.\",\n\t\t\t\t\"redirect\": \"Přesměrování proběhne za <seconds/>...\",\n\t\t\t\t\"success\": \"Heslo bylo úspěšně obnoveno.\",\n\t\t\t\t\"error\": \"Obnova hesla se nepodařila. Zkuste to prosím znovu nebo kontaktujte podporu.\"\n\t\t\t}\n\t\t}\n\t},\n\t\"errorPages\": {\n\t\t\"serverUnreachable\": {\n\t\t\t\"toasts\": {\n\t\t\t\t\"reconnected\": \"Podařilo se úspěšně obnovit spojení se serverem\",\n\t\t\t\t\"stillUnreachable\": \"Server je stále nedosažitelný. Zkuste to prosím později.\"\n\t\t\t},\n\t\t\t\"alertBox\": \"Chyba připojení k serveru\",\n\t\t\t\"description\": \"Nepodařilo se připojit k serveru. Zkontrolujte si prosím internetové připojení a pokud problém přetrvává, ověřte konfiguraci aplikace Checkmate.\",\n\t\t\t\"retryButton\": {\n\t\t\t\t\"default\": \"Zkusit se znovu připojit\",\n\t\t\t\t\"processing\": \"Probíhá připojování…\"\n\t\t\t}\n\t\t}\n\t},\n\t\"createNotifications\": {\n\t\t\"title\": \"\",\n\t\t\"nameSettings\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"nameLabel\": \"\",\n\t\t\t\"namePlaceholder\": \"\"\n\t\t},\n\t\t\"typeSettings\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"typeLabel\": \"\"\n\t\t},\n\t\t\"emailSettings\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"emailLabel\": \"\",\n\t\t\t\"emailPlaceholder\": \"\"\n\t\t},\n\t\t\"slackSettings\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"webhookLabel\": \"\",\n\t\t\t\"webhookPlaceholder\": \"\"\n\t\t},\n\t\t\"pagerdutySettings\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"integrationKeyLabel\": \"\",\n\t\t\t\"integrationKeyPlaceholder\": \"\"\n\t\t},\n\t\t\"discordSettings\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"webhookLabel\": \"\",\n\t\t\t\"webhookPlaceholder\": \"\"\n\t\t},\n\t\t\"webhookSettings\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"webhookLabel\": \"\",\n\t\t\t\"webhookPlaceholder\": \"\"\n\t\t},\n\t\t\"testNotification\": \"\",\n\t\t\"dialogDeleteTitle\": \"\",\n\t\t\"dialogDeleteConfirm\": \"\"\n\t},\n\t\"notificationConfig\": {\n\t\t\"title\": \"\",\n\t\t\"description\": \"\"\n\t},\n\t\"monitorStatus\": {\n\t\t\"checkingEvery\": \"\",\n\t\t\"withCaptureAgent\": \"\",\n\t\t\"up\": \"\",\n\t\t\"down\": \"\",\n\t\t\"paused\": \"\"\n\t},\n\t\"advancedMatching\": \"\",\n\t\"sendTestNotifications\": \"\",\n\t\"selectAll\": \"\",\n\t\"showAdminLoginLink\": \"\",\n\t\"logsPage\": {\n\t\t\"title\": \"\",\n\t\t\"description\": \"\",\n\t\t\"tabs\": {\n\t\t\t\"queue\": \"\",\n\t\t\t\"logs\": \"\",\n\t\t\t\"diagnostics\": \"\"\n\t\t},\n\t\t\"toast\": {\n\t\t\t\"fetchLogsSuccess\": \"\"\n\t\t},\n\t\t\"logLevelSelect\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"values\": {\n\t\t\t\t\"all\": \"\",\n\t\t\t\t\"info\": \"\",\n\t\t\t\t\"warn\": \"\",\n\t\t\t\t\"error\": \"\",\n\t\t\t\t\"debug\": \"\"\n\t\t\t}\n\t\t}\n\t},\n\t\"queuePage\": {\n\t\t\"title\": \"\",\n\t\t\"refreshButton\": \"\",\n\t\t\"flushButton\": \"\",\n\t\t\"jobTable\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"idHeader\": \"\",\n\t\t\t\"urlHeader\": \"\",\n\t\t\t\"typeHeader\": \"\",\n\t\t\t\"activeHeader\": \"\",\n\t\t\t\"lockedAtHeader\": \"\",\n\t\t\t\"runCountHeader\": \"\",\n\t\t\t\"failCountHeader\": \"\",\n\t\t\t\"lastRunHeader\": \"\",\n\t\t\t\"lastFinishedAtHeader\": \"\",\n\t\t\t\"lastRunTookHeader\": \"\",\n\t\t\t\"intervalHeader\": \"\"\n\t\t},\n\t\t\"metricsTable\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"metricHeader\": \"\",\n\t\t\t\"valueHeader\": \"\"\n\t\t},\n\t\t\"failedJobTable\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"monitorIdHeader\": \"\",\n\t\t\t\"monitorUrlHeader\": \"\",\n\t\t\t\"failCountHeader\": \"\",\n\t\t\t\"failedAtHeader\": \"\",\n\t\t\t\"failReasonHeader\": \"\"\n\t\t}\n\t},\n\t\"export\": {\n\t\t\"title\": \"\",\n\t\t\"success\": \"\",\n\t\t\"failed\": \"\"\n\t},\n\t\"monitorActions\": {\n\t\t\"title\": \"\",\n\t\t\"import\": \"\",\n\t\t\"export\": \"\",\n\t\t\"deleteSuccess\": \"\",\n\t\t\"deleteFailed\": \"\",\n\t\t\"details\": \"\"\n\t},\n\t\"settingsPage\": {\n\t\t\"aboutSettings\": {\n\t\t\t\"labelDevelopedBy\": \"\",\n\t\t\t\"labelVersion\": \"\",\n\t\t\t\"title\": \"\"\n\t\t},\n\t\t\"demoMonitorsSettings\": {\n\t\t\t\"buttonAddMonitors\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"title\": \"\"\n\t\t},\n\t\t\"emailSettings\": {\n\t\t\t\"buttonSendTestEmail\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"descriptionTransport\": \"\",\n\t\t\t\"labelAddress\": \"\",\n\t\t\t\"labelConnectionHost\": \"\",\n\t\t\t\"labelHost\": \"\",\n\t\t\t\"labelIgnoreTLS\": \"\",\n\t\t\t\"labelPassword\": \"\",\n\t\t\t\"labelPasswordSet\": \"\",\n\t\t\t\"labelPool\": \"\",\n\t\t\t\"labelPort\": \"\",\n\t\t\t\"labelRejectUnauthorized\": \"\",\n\t\t\t\"labelRequireTLS\": \"\",\n\t\t\t\"labelSecure\": \"\",\n\t\t\t\"labelTLSServername\": \"\",\n\t\t\t\"labelUser\": \"\",\n\t\t\t\"linkTransport\": \"\",\n\t\t\t\"placeholderUser\": \"\",\n\t\t\t\"title\": \"\",\n\t\t\t\"toastEmailRequiredFieldsError\": \"\"\n\t\t},\n\t\t\"pageSpeedSettings\": {\n\t\t\t\"description\": \"\",\n\t\t\t\"labelApiKeySet\": \"\",\n\t\t\t\"labelApiKey\": \"\",\n\t\t\t\"title\": \"\"\n\t\t},\n\t\t\"saveButtonLabel\": \"\",\n\t\t\"statsSettings\": {\n\t\t\t\"clearAllStatsButton\": \"\",\n\t\t\t\"clearAllStatsDescription\": \"\",\n\t\t\t\"clearAllStatsDialogConfirm\": \"\",\n\t\t\t\"clearAllStatsDialogDescription\": \"\",\n\t\t\t\"clearAllStatsDialogTitle\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"labelTTL\": \"\",\n\t\t\t\"labelTTLOptional\": \"\",\n\t\t\t\"title\": \"\"\n\t\t},\n\t\t\"systemResetSettings\": {\n\t\t\t\"buttonRemoveAllMonitors\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"dialogConfirm\": \"\",\n\t\t\t\"dialogDescription\": \"\",\n\t\t\t\"dialogTitle\": \"\",\n\t\t\t\"title\": \"\"\n\t\t},\n\t\t\"timezoneSettings\": {\n\t\t\t\"description\": \"\",\n\t\t\t\"label\": \"\",\n\t\t\t\"title\": \"\"\n\t\t},\n\t\t\"title\": \"\",\n\t\t\"uiSettings\": {\n\t\t\t\"description\": \"\",\n\t\t\t\"labelLanguage\": \"\",\n\t\t\t\"labelTheme\": \"\",\n\t\t\t\"title\": \"\"\n\t\t},\n\t\t\"urlSettings\": {\n\t\t\t\"description\": \"\",\n\t\t\t\"label\": \"\",\n\t\t\t\"selectDisabled\": \"\",\n\t\t\t\"selectEnabled\": \"\",\n\t\t\t\"title\": \"\"\n\t\t},\n\t\t\"globalThresholds\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\"\n\t\t}\n\t},\n\t\"statusPageCreate\": {\n\t\t\"buttonSave\": \"\"\n\t},\n\t\"incidentsOptionsHeaderFilterResolved\": \"\",\n\t\"settingsSave\": \"\",\n\t\"statusPageCreateAppearanceTitle\": \"\",\n\t\"confirmPassword\": \"\",\n\t\"monitorHooks\": {\n\t\t\"failureAddDemoMonitors\": \"\",\n\t\t\"successAddDemoMonitors\": \"\"\n\t},\n\t\"settingsAppearance\": \"\",\n\t\"settingsDisplayTimezone\": \"\",\n\t\"settingsGeneralSettings\": \"\",\n\t\"incidentsOptionsHeaderTotalIncidents\": \"\",\n\t\"statusPage\": {\n\t\t\"deleteSuccess\": \"\",\n\t\t\"deleteFailed\": \"\",\n\t\t\"createSuccess\": \"\",\n\t\t\"updateSuccess\": \"\",\n\t\t\"generalSettings\": \"\",\n\t\t\"contents\": \"\",\n\t\t\"fallback\": {\n\t\t\t\"checks\": [\"\"],\n\t\t\t\"title\": \"\",\n\t\t\t\"actionButton\": \"\"\n\t\t}\n\t},\n\t\"testNotificationsDisabled\": \"\",\n\t\"incidentsTableResolvedAt\": \"\",\n\t\"incidentsTableActionResolve\": \"\",\n\t\"checkHooks\": {\n\t\t\"failureResolveOne\": \"\",\n\t\t\"failureResolveAll\": \"\",\n\t\t\"failureResolveMonitor\": \"\"\n\t},\n\t\"checkFormError\": \"\",\n\t\"diagnosticsPage\": {\n\t\t\"diagnosticDescription\": \"\",\n\t\t\"statsDescription\": \"\",\n\t\t\"gauges\": {\n\t\t\t\"heapAllocationTitle\": \"\",\n\t\t\t\"heapAllocationSubtitle\": \"\",\n\t\t\t\"heapUsageTitle\": \"\",\n\t\t\t\"heapUsageSubtitle\": \"\",\n\t\t\t\"heapUtilizationTitle\": \"\",\n\t\t\t\"heapUtilizationSubtitle\": \"\",\n\t\t\t\"instantCpuUsageTitle\": \"\",\n\t\t\t\"instantCpuUsageSubtitle\": \"\"\n\t\t},\n\t\t\"stats\": {\n\t\t\t\"eventLoopDelayTitle\": \"\",\n\t\t\t\"uptimeTitle\": \"\",\n\t\t\t\"usedHeapSizeTitle\": \"\",\n\t\t\t\"totalHeapSizeTitle\": \"\",\n\t\t\t\"osMemoryLimitTitle\": \"\"\n\t\t}\n\t},\n\t\"pageSpeedLighthouseAPI\": \"\",\n\t\"time\": {\n\t\t\"threeMinutes\": \"\",\n\t\t\"fiveMinutes\": \"\",\n\t\t\"tenMinutes\": \"\",\n\t\t\"twentyMinutes\": \"\",\n\t\t\"oneHour\": \"\",\n\t\t\"oneDay\": \"\",\n\t\t\"oneWeek\": \"\",\n\t\t\"fourMinutes\": \"\",\n\t\t\"oneMinute\": \"\",\n\t\t\"twoMinutes\": \"\",\n\t\t\"fifteenSeconds\": \"\",\n\t\t\"thirtySeconds\": \"\"\n\t},\n\t\"general\": {\n\t\t\"noOptionsFound\": \"\"\n\t},\n\t\"infrastructureMonitor\": {\n\t\t\"fallback\": {\n\t\t\t\"checks\": [\"\"],\n\t\t\t\"title\": \"\",\n\t\t\t\"actionButton\": \"\"\n\t\t}\n\t},\n\t\"maintenanceWindow\": {\n\t\t\"fallback\": {\n\t\t\t\"checks\": [\"\"],\n\t\t\t\"title\": \"\",\n\t\t\t\"actionButton\": \"\"\n\t\t}\n\t},\n\t\"pageSpeed\": {\n\t\t\"fallback\": {\n\t\t\t\"checks\": [\"\"],\n\t\t\t\"title\": \"\",\n\t\t\t\"actionButton\": \"\"\n\t\t}\n\t},\n\t\"uptimeMonitor\": {\n\t\t\"fallback\": {\n\t\t\t\"checks\": [\"\"],\n\t\t\t\"title\": \"\",\n\t\t\t\"actionButton\": \"\"\n\t\t}\n\t},\n\t\"editUserPage\": {\n\t\t\"form\": {\n\t\t\t\"email\": \"\",\n\t\t\t\"firstName\": \"\",\n\t\t\t\"lastName\": \"\",\n\t\t\t\"role\": \"\",\n\t\t\t\"save\": \"\"\n\t\t},\n\t\t\"table\": {\n\t\t\t\"actionHeader\": \"\",\n\t\t\t\"roleHeader\": \"\"\n\t\t},\n\t\t\"title\": \"\",\n\t\t\"toast\": {\n\t\t\t\"successUserUpdate\": \"\",\n\t\t\t\"validationErrors\": \"\"\n\t\t}\n\t},\n\t\"incidentsPageActionResolveMonitor\": \"\",\n\t\"incidentsPageActionResolveAll\": \"\",\n\t\"matchMethodOptions\": {\n\t\t\"equal\": \"\",\n\t\t\"equalPlaceholder\": \"\",\n\t\t\"include\": \"\",\n\t\t\"includePlaceholder\": \"\",\n\t\t\"regex\": \"\",\n\t\t\"regexPlaceholder\": \"\",\n\t\t\"text\": \"\"\n\t},\n\t\"monitorType\": {\n\t\t\"docker\": {\n\t\t\t\"label\": \"\",\n\t\t\t\"namePlaceholder\": \"\",\n\t\t\t\"placeholder\": \"\"\n\t\t},\n\t\t\"http\": {\n\t\t\t\"label\": \"\",\n\t\t\t\"namePlaceholder\": \"\",\n\t\t\t\"placeholder\": \"\"\n\t\t},\n\t\t\"ping\": {\n\t\t\t\"label\": \"\",\n\t\t\t\"namePlaceholder\": \"\",\n\t\t\t\"placeholder\": \"\"\n\t\t},\n\t\t\"port\": {\n\t\t\t\"label\": \"\",\n\t\t\t\"namePlaceholder\": \"\",\n\t\t\t\"placeholder\": \"\"\n\t\t},\n\t\t\"game\": {\n\t\t\t\"label\": \"\",\n\t\t\t\"namePlaceholder\": \"\",\n\t\t\t\"placeholder\": \"\"\n\t\t}\n\t},\n\t\"uptimeAdvancedMatching\": {\n\t\t\"jsonPath\": \"\"\n\t},\n\t\"bytesPerSecond\": \"\",\n\t\"bytesReceived\": \"\",\n\t\"bytesSent\": \"\",\n\t\"chooseGame\": \"\",\n\t\"createMonitorPage\": {\n\t\t\"incidentConfigDescription\": \"\",\n\t\t\"incidentConfigStatusWindowLabel\": \"\",\n\t\t\"incidentConfigStatusWindowThresholdLabel\": \"\",\n\t\t\"incidentConfigTitle\": \"\",\n\t\t\"incidentConfigDescriptionV2\": \"\",\n\t\t\"incidentConfigStatusCheckNumber\": \"\",\n\t\t\"intervalTitle\": \"\",\n\t\t\"intervalDescription\": \"\"\n\t},\n\t\"dataRate\": \"\",\n\t\"dataReceived\": \"\",\n\t\"dataSent\": \"\",\n\t\"details\": \"\",\n\t\"drops\": \"\",\n\t\"errors\": \"\",\n\t\"errorsIn\": \"\",\n\t\"errorsOut\": \"\",\n\t\"gameServerMonitoring\": \"\",\n\t\"gameServerMonitoringDescription\": \"\",\n\t\"network\": \"\",\n\t\"networkDrops\": \"\",\n\t\"networkErrors\": \"\",\n\t\"networkInterface\": \"\",\n\t\"noNetworkStatsAvailable\": \"\",\n\t\"packetsPerSecond\": \"\",\n\t\"packetsReceived\": \"\",\n\t\"packetsReceivedRate\": \"\",\n\t\"packetsSent\": \"\",\n\t\"rate\": \"\",\n\t\"selectInterface\": \"\"\n}\n"
  },
  {
    "path": "client/src/locales/de.json",
    "content": "{\n\t\"submit\": \"Absenden\",\n\t\"title\": \"Titel\",\n\t\"distributedStatusHeaderText\": \"Echtzeit Abdeckung\",\n\t\"distributedStatusSubHeaderText\": \"Genutzt von Millionen von Geräten weltweit, siehst Du die Systemleistung nach globaler Region, Land oder Stadt\",\n\t\"settingsDisabled\": \"Inaktiv\",\n\t\"settingsSuccessSaved\": \"Einstellungen erfolgreich gespeichert\",\n\t\"settingsFailedToSave\": \"Fehler beim Speichern der Einstellungen\",\n\t\"settingsStatsCleared\": \"Statistiken gelöscht\",\n\t\"settingsFailedToClearStats\": \"Fehler beim löschen der Statistiken\",\n\t\"settingsMonitorsDeleted\": \"Alle Monitore erfolgreich gelöscht.\",\n\t\"settingsFailedToDeleteMonitors\": \"Fehler beim Löschen aller Monitore\",\n\t\"starPromptTitle\": \"Stern vergeben\",\n\t\"starPromptDescription\": \"Sieh dir die neuesten Veröffentlichungen an und hilf der Community auf GitHub\",\n\t\"https\": \"HTTPS\",\n\t\"http\": \"HTTP\",\n\t\"monitor\": \"monitor\",\n\t\"aboutus\": \"Über uns\",\n\t\"now\": \"Jetzt\",\n\t\"delete\": \"Löschen\",\n\t\"configure\": \"Einstellungen\",\n\t\"responseTime\": \"Antwortzeit\",\n\t\"ms\": \"ms\",\n\t\"bar\": \"Bar\",\n\t\"area\": \"Bereich\",\n\t\"country\": \"Land\",\n\t\"city\": \"Stadt\",\n\t\"response\": \"Antwort\",\n\t\"monitorStatusUp\": \"Monitor {name} ({url}) ist jetzt ONLINE und antwortet\",\n\t\"monitorStatusDown\": \"Monitor {name} ({url}) ist jetzt OFFLINE und antwortet nicht\",\n\t\"webhookSendSuccess\": \"Webhook-Benachrichtigung erfolgreich gesendet\",\n\t\"webhookSendError\": \"Fehler beim Senden der Webhook-Benachrichtigung an {platform}\",\n\t\"webhookUnsupportedPlatform\": \"Nicht unterstützte Plattform: {platform}\",\n\t\"distributedRightCategoryTitle\": \"Monitor\",\n\t\"distributedStatusServerMonitors\": \"Server Monitore\",\n\t\"distributedStatusServerMonitorsDescription\": \"Überwache den Status der zugehörigen Server\",\n\t\"distributedUptimeCreateSelectURL\": \"Hier kannst Du die URL und Typ des Hosts auswählen\",\n\t\"distributedUptimeCreateChecks\": \"Durchzuführende Prüfungen\",\n\t\"distributedUptimeCreateChecksDescription\": \"Du kannst jederzeit Überprüfungen hinzufügen oder entfernen, nachdem Du Deine Seite hinzugefügt hast.\\n\",\n\t\"distributedUptimeCreateIncidentNotification\": \"Ereignisbenachrichtigungen\",\n\t\"distributedUptimeCreateIncidentDescription\": \"Wenn es ein Ereignis gibt, benachrichtige die Benutzer.\",\n\t\"distributedUptimeCreateAdvancedSettings\": \"Erweiterte Einstellungen\",\n\t\"distributedUptimeDetailsNoMonitorHistory\": \"Es gibt noch keine Überprüfungshistorie für diesen Monitor.\",\n\t\"distributedUptimeDetailsStatusHeaderUptime\": \"Uptime:\",\n\t\"distributedUptimeDetailsStatusHeaderLastUpdate\": \"Zuletzt aktualisiert\",\n\t\"notifications\": {\n\t\t\"enableNotifications\": \"Aktiviere {{platform}} Benachrichtigungen\\n\",\n\t\t\"testNotification\": \"Test Benachrichtigung\",\n\t\t\"addOrEditNotifications\": \"Benachrichtigungen hinzufügen oder bearbeiten\",\n\t\t\"slack\": {\n\t\t\t\"label\": \"Slack\",\n\t\t\t\"description\": \"Um Slack-Benachrichtigungen zu aktivieren, erstelle eine Slack-App und aktiviere eingehende Webhooks. Danach gib einfach die Webhook-URL hier ein.\",\n\t\t\t\"webhookLabel\": \"Webhook URL\",\n\t\t\t\"webhookPlaceholder\": \"https://hooks.slack.com/services/...\",\n\t\t\t\"webhookRequired\": \"Slack webhook URL wird benötigt\"\n\t\t},\n\t\t\"discord\": {\n\t\t\t\"label\": \"Discord\",\n\t\t\t\"description\": \"Um Daten von Checkmate an einen Discord-Kanal über Discord-Benachrichtigungen mithilfe von Webhooks zu senden, kannst Du die eingehenden Webhooks von Discord verwenden.\",\n\t\t\t\"webhookLabel\": \"Discord Webhook URL\",\n\t\t\t\"webhookPlaceholder\": \"https://discord.com/api/webhooks/...\",\n\t\t\t\"webhookRequired\": \"Discord webhook URL wird benötigt\"\n\t\t},\n\t\t\"telegram\": {\n\t\t\t\"label\": \"Telegram\",\n\t\t\t\"description\": \"Um Telegram-Benachrichtigungen zu aktivieren, erstelle einen Telegram-Bot mit BotFather, einem offiziellen Bot zum Erstellen und Verwalten von Telegram-Bots. Dann hole dir das API-Token und die Chat-ID und notiere sie hier.\",\n\t\t\t\"tokenLabel\": \"Dein bot token\",\n\t\t\t\"tokenPlaceholder\": \"123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11\",\n\t\t\t\"chatIdLabel\": \"Deine Chat ID\",\n\t\t\t\"chatIdPlaceholder\": \"-1001234567890\",\n\t\t\t\"fieldsRequired\": \"Telegram token und Chat-ID werden benötigt\"\n\t\t},\n\t\t\"webhook\": {\n\t\t\t\"label\": \"Webhooks\",\n\t\t\t\"description\": \"Du kannst einen benutzerdefinierten Webhook einrichten, um Benachrichtigungen zu erhalten, wenn Ereignisse auftreten.\",\n\t\t\t\"urlLabel\": \"Webhook URL\",\n\t\t\t\"urlPlaceholder\": \"https://your-server.com/webhook\",\n\t\t\t\"urlRequired\": \"Webhook URL wird benötigt\"\n\t\t},\n\t\t\"testNotificationDevelop\": \"Testbenachrichtigung 2\",\n\t\t\"integrationButton\": \"Benachrichtigungsintegration\",\n\t\t\"testSuccess\": \"Testbenachrichtigung erfolgreich gesendet!\",\n\t\t\"testFailed\": \"Senden der Testbenachrichtigung fehlgeschlagen\",\n\t\t\"unsupportedType\": \"Nicht unterstützter Benachrichtigungstyp\",\n\t\t\"networkError\": \"Netzwerkfehler aufgetreten\",\n\t\t\"fallback\": {\n\t\t\t\"title\": \"Ein Benachrichtigungskanal wird verwendet, um:\",\n\t\t\t\"checks\": [\n\t\t\t\t\"Teams über Ausfallzeiten oder Leistungsprobleme informieren\",\n\t\t\t\t\"Informieren Sie Techniker über Vorfälle\",\n\t\t\t\t\"Informieren Sie Administratoren über Systemänderungen\"\n\t\t\t],\n\t\t\t\"actionButton\": \"Lassen Sie uns Ihren ersten Benachrichtigungskanal erstellen!\"\n\t\t},\n\t\t\"createButton\": \"Benachrichtigungskanal erstellen\",\n\t\t\"createTitle\": \"Benachrichtigungskanal\",\n\t\t\"create\": {\n\t\t\t\"success\": \"Benachrichtigung erfolgreich erstellt\",\n\t\t\t\"failed\": \"Benachrichtigung konnte nicht erstellt werden\"\n\t\t},\n\t\t\"fetch\": {\n\t\t\t\"success\": \"Benachrichtigungen erfolgreich abgerufen\",\n\t\t\t\"failed\": \"Abrufen der Benachrichtigungen fehlgeschlagen\"\n\t\t},\n\t\t\"delete\": {\n\t\t\t\"success\": \"Benachrichtigung erfolgreich gelöscht\",\n\t\t\t\"failed\": \"Benachrichtigung konnte nicht gelöscht werden\"\n\t\t},\n\t\t\"edit\": {\n\t\t\t\"success\": \"Benachrichtigung erfolgreich aktualisiert\",\n\t\t\t\"failed\": \"Benachrichtigung konnte nicht aktualisiert werden\"\n\t\t},\n\t\t\"test\": {\n\t\t\t\"success\": \"Test Benachrichtigung erfolgreich gesendet\",\n\t\t\t\"failed\": \"Fehler beim senden der Test Benachrichtigung\"\n\t\t}\n\t},\n\t\"testLocale\": \"testLocale\",\n\t\"add\": \"Hinzufügen\",\n\t\"monitors\": \"Monitore\",\n\t\"distributedUptimeStatusCreateStatusPage\": \"Statusseite\",\n\t\"distributedUptimeStatusCreateStatusPageAccess\": \"Zugriff\",\n\t\"distributedUptimeStatusCreateStatusPageReady\": \"Wenn deine Statusseite bereit ist, kannst du sie als veröffentlicht markieren.\",\n\t\"distributedUptimeStatusBasicInfoHeader\": \"Grundlegende Informationen\",\n\t\"distributedUptimeStatusBasicInfoDescription\": \"Definiere den Firmennamen und die Subdomain, auf die deine Statusseite verweist.\",\n\t\"distributedUptimeStatusLogoHeader\": \"Logo\",\n\t\"distributedUptimeStatusLogoDescription\": \"Lade ein Logo für deine Statusseite hoch\",\n\t\"distributedUptimeStatusLogoUploadButton\": \"Logo hochladen\",\n\t\"distributedUptimeStatusStandardMonitorsHeader\": \"Standardmonitore\",\n\t\"distributedUptimeStatusStandardMonitorsDescription\": \"Füge Standardmonitore zu deiner Statusseite hinzu.\",\n\t\"distributedUptimeStatusCreateYour\": \"Erstelle Dein\",\n\t\"distributedUptimeStatusEditYour\": \"Ändere Dein\",\n\t\"distributedUptimeStatusPublishedLabel\": \"Veröffentlicht und für die Öffentlichkeit sichtbar\",\n\t\"distributedUptimeStatusCompanyNameLabel\": \"Firmenname\",\n\t\"distributedUptimeStatusPageAddressLabel\": \"Die Adresse deiner Statusseite\",\n\t\"distributedUptimeStatus30Days\": \"30 Tage\",\n\t\"distributedUptimeStatus60Days\": \"60 Tage\",\n\t\"distributedUptimeStatus90Days\": \"90 Tage\",\n\t\"distributedUptimeStatusPageNotSetUp\": \"Eine Statusseite ist nicht eingerichtet.\",\n\t\"distributedUptimeStatusContactAdmin\": \"Bitte kontaktiere deinen Administrator\",\n\t\"distributedUptimeStatusPageNotPublic\": \"Diese Statusseite ist nicht öffentlich.\",\n\t\"distributedUptimeStatusPageDeleteDialog\": \"Möchtest du diese Statusseite löschen?\",\n\t\"distributedUptimeStatusPageDeleteConfirm\": \"Ja, Statusseite löschen\",\n\t\"distributedUptimeStatusPageDeleteDescription\": \"Sobald sie gelöscht ist, kann deine Statusseite nicht wiederhergestellt werden.\",\n\t\"distributedUptimeStatusDevices\": \"Geräte\",\n\t\"distributedUptimeStatusUpt\": \"UPT\",\n\t\"distributedUptimeStatusUptBurned\": \"UPT Burned\",\n\t\"distributedUptimeStatusUptLogo\": \"Upt Logo\",\n\t\"incidentsTableNoIncidents\": \"Keine Ereignisse aufgezeichnet\",\n\t\"incidentsTablePaginationLabel\": \"Ereignisse\",\n\t\"incidentsTableMonitorName\": \"Monitor Name\",\n\t\"incidentsTableStatus\": \"Status\",\n\t\"incidentsTableDateTime\": \"Datum & Zeit\",\n\t\"incidentsTableStatusCode\": \"Status Code\",\n\t\"incidentsTableMessage\": \"Nachricht\",\n\t\"incidentsOptionsHeader\": \"Ereignisse für\",\n\t\"incidentsOptionsHeaderFilterBy\": \"Gefiltert nach:\",\n\t\"incidentsOptionsHeaderFilterAll\": \"Alle\",\n\t\"incidentsOptionsHeaderFilterDown\": \"offline\",\n\t\"incidentsOptionsHeaderFilterCannotResolve\": \"Kann nicht aufgelöst werden\",\n\t\"incidentsOptionsHeaderShow\": \"Anzeigen:\",\n\t\"incidentsOptionsHeaderLastHour\": \"Letzte Stunde\",\n\t\"incidentsOptionsHeaderLastDay\": \"Letzter Tag\",\n\t\"incidentsOptionsHeaderLastWeek\": \"Letzte Woche\",\n\t\"incidentsOptionsPlaceholderAllServers\": \"Alle Server\",\n\t\"infrastructureCreateYour\": \"Erstelle dein\",\n\t\"infrastructureCreateGeneralSettingsDescription\": \"Hier kannst du die URL des Hosts auswählen, zusammen mit dem Namen und dem Autorisierungs-token, um eine Verbindung zum Server-Agenten herzustellen.\",\n\t\"infrastructureServerRequirement\": \"Der Server, den du überwachst, muss die folgende Software ausführen:\",\n\t\"infrastructureCustomizeAlerts\": \"Benachrichtigungen anpassen\",\n\t\"infrastructureAlertNotificationDescription\": \"Sende eine Benachrichtigung an Benutzer, wenn Schwellenwerte einen bestimmten Prozentsatz überschreiten.\",\n\t\"infrastructureCreateMonitor\": \"Erstelle Infrastrukturmonitor\",\n\t\"infrastructureProtocol\": \"Protokoll\",\n\t\"infrastructureServerUrlLabel\": \"Server URL\",\n\t\"infrastructureDisplayNameLabel\": \"Anzeigename\",\n\t\"infrastructureAuthorizationSecretLabel\": \"Autorisierungs-token\",\n\t\"gb\": \"GB\",\n\t\"mb\": \"MB\",\n\t\"mem\": \"Speicher\",\n\t\"memoryUsage\": \"Speicher Nutzung\",\n\t\"cpu\": \"CPU\",\n\t\"cpuUsage\": \"CPU Nutzung\",\n\t\"cpuTemperature\": \"CPU Temperatur\",\n\t\"diskUsage\": \"Disk benutzt\",\n\t\"used\": \"benutzt\",\n\t\"total\": \"Total\",\n\t\"cores\": \"Kerne\",\n\t\"frequency\": \"Frequenz\",\n\t\"status\": \"Status\",\n\t\"cpuPhysical\": \"CPU (Physical)\",\n\t\"cpuLogical\": \"CPU (Logical)\",\n\t\"cpuFrequency\": \"CPU Frequenz\",\n\t\"avgCpuTemperature\": \"Durchschn. CPU Termperatur\",\n\t\"memory\": \"Speicher\",\n\t\"disk\": \"Disk\",\n\t\"uptime\": \"Uptime\",\n\t\"os\": \"OS\",\n\t\"host\": \"Host\",\n\t\"actions\": \"Aktionen\",\n\t\"integrations\": \"Integrationen\",\n\t\"integrationsPrism\": \"Verbinde Prism mit deinem favorisierten Gerät\",\n\t\"integrationsSlack\": \"Slack\",\n\t\"integrationsSlackInfo\": \"Verbinde dich mit Slack und sieh Ereignisse in einem Kanal\",\n\t\"integrationsDiscord\": \"Discord\",\n\t\"integrationsDiscordInfo\": \"Verbinde dich mit Discord und sieh Ereignisse direkt in einem Kanal\",\n\t\"integrationsZapier\": \"Zapier\",\n\t\"integrationsZapierInfo\": \"Sende alle Ereignisse an Zapier und sieh sie dann überall\",\n\t\"commonSave\": \"Speichern\",\n\t\"createYour\": \"Erstelle Deinen\",\n\t\"createMonitor\": \"Erstelle Monitor\",\n\t\"pause\": \"Pausieren\",\n\t\"resume\": \"Weiter\",\n\t\"editing\": \"Bearbeiten...\",\n\t\"url\": \"URL\",\n\t\"access\": \"Zugriff\",\n\t\"timezone\": \"Zeitzone\",\n\t\"features\": \"Funktionen\",\n\t\"administrator\": \"Administrator?\",\n\t\"loginHere\": \"Hier anmelden\",\n\t\"displayName\": \"Anzeigename\",\n\t\"urlMonitor\": \"zu überwachende URL\",\n\t\"portToMonitor\": \"zu überwachender Port\",\n\t\"websiteMonitoring\": \"Websiten-Überwachung\",\n\t\"websiteMonitoringDescription\": \"Verwende HTTP(s), um deine Website oder API-Endpunkt zu überwachen.\",\n\t\"pingMonitoring\": \"Ping-Überwachung\",\n\t\"pingMonitoringDescription\": \"Überprüfe, ob dein Server verfügbar ist oder nicht.\",\n\t\"dockerContainerMonitoring\": \"Docker-Container-Überwachung\",\n\t\"dockerContainerMonitoringDescription\": \"Überprüfe, ob dein Docker-Container läuft oder nicht.\",\n\t\"portMonitoring\": \"Port-Überwachung\",\n\t\"portMonitoringDescription\": \"Überprüfe, ob dein Port offen ist oder nicht.\",\n\t\"createMaintenanceWindow\": \"Erstelle Wartungsfenster\",\n\t\"createMaintenance\": \"Erstelle Wartungsfenster\",\n\t\"editMaintenance\": \"Ändere Wartungsfenster\",\n\t\"maintenanceWindowName\": \"Name des Wartungsfensters\",\n\t\"friendlyNameInput\": \"Freundlicher Name\",\n\t\"friendlyNamePlaceholder\": \"Wartung um __ : __ für ___ Minuten\",\n\t\"maintenanceRepeat\": \"Wartungsfenster wiederholen\",\n\t\"maintenance\": \"Wartungsfenster\",\n\t\"duration\": \"Dauer\",\n\t\"addMonitors\": \"Monitor hinzufügen\",\n\t\"window\": \"Fenster\",\n\t\"cancel\": \"Abbrechen\",\n\t\"message\": \"Nachricht\",\n\t\"low\": \"niedrig\",\n\t\"high\": \"hoch\",\n\t\"statusCode\": \"Status Code\",\n\t\"date&Time\": \"Datum & Zeit\",\n\t\"type\": \"Art\",\n\t\"statusPageName\": \"Name der Statusseite\",\n\t\"publicURL\": \"Öffentliche URL\",\n\t\"repeat\": \"Wiederholen\",\n\t\"edit\": \"Ändern\",\n\t\"createA\": \"Erstelle ein\",\n\t\"remove\": \"Löschen\",\n\t\"maintenanceWindowDescription\": \"Pings werden während dieses Zeitraums nicht gesendet\",\n\t\"startTime\": \"Anfangszeit\",\n\t\"timeZoneInfo\": \"Alle Daten und Zeiten sind in der Zeitzone GMT+0.\",\n\t\"monitorsToApply\": \"Monitore, auf die das Wartungsfenster angewendet werden soll\",\n\t\"nextWindow\": \"Nächstes Fenster\",\n\t\"notFoundButton\": \"Gehe zum Haupt-Dashboard\",\n\t\"pageSpeedConfigureSettingsDescription\": \"Hier kannst du die URL des Hosts auswählen, zusammen mit der Art des Monitors.\",\n\t\"monitorDisplayName\": \"Anzeigename des Monitors\",\n\t\"whenNewIncident\": \"Wenn es ein neues Ereignis gibt,\",\n\t\"notifySMS\": \"Benachrichtige per SMS (kommt bald)\",\n\t\"notifyEmails\": \"Benachrichtige auch per E-Mail an mehrere Adressen (kommt bald)\",\n\t\"seperateEmails\": \"Du kannst mehrere E-Mails mit einem Komma trennen\",\n\t\"checkFrequency\": \"Überprüfungsfrequenz\",\n\t\"matchMethod\": \"Übereinstimmungsmethode\",\n\t\"expectedValue\": \"Erwarteter Wert\",\n\t\"deleteDialogTitle\": \"Möchtest du diesen Monitor wirklich löschen?\",\n\t\"deleteDialogDescription\": \"Sobald dieser Monitor gelöscht ist, kann er nicht wiederhergestellt werden.\",\n\t\"pageSpeedMonitor\": \"PageSpeed-Monitor\",\n\t\"shown\": \"Gezeigt\",\n\t\"ago\": \"vor\",\n\t\"companyName\": \"Name der Firma\",\n\t\"pageSpeedDetailsPerformanceReport\": \"Die Werte sind geschätzt und können variieren.\",\n\t\"pageSpeedDetailsPerformanceReportCalculator\": \"Rechner öffnen\",\n\t\"checkingEvery\": \"Überprüfen alle\",\n\t\"statusPageCreateSettings\": \"Wenn Ihre Statusseite fertig ist, können Sie sie als veröffentlicht markieren.\",\n\t\"basicInformation\": \"Grundlegende Informationen\",\n\t\"statusPageCreateBasicInfoDescription\": \"Definieren Sie den Firmennamen und die Subdomäne, auf die Ihre Statusseite verweist.\",\n\t\"statusPageCreateSelectTimeZoneDescription\": \"Wählen Sie die Zeitzone aus, in der Ihre Statusseite angezeigt wird.\",\n\t\"statusPageCreateAppearanceDescription\": \"Definieren Sie das Standard-Erscheinungsbild Ihrer öffentlichen Statusseite.\",\n\t\"statusPageCreateSettingsCheckboxLabel\": \"Veröffentlicht und für die Öffentlichkeit sichtbar\",\n\t\"statusPageCreateBasicInfoStatusPageAddress\": \"Ihre Statusseitenadresse\",\n\t\"statusPageCreateTabsContent\": \"Statusseitenserver\",\n\t\"statusPageCreateTabsContentDescription\": \"Sie können Ihrer Statusseite beliebig viele Server hinzufügen, die Sie überwachen. Sie die Reihenfolge der Server ändern.\",\n\t\"statusPageCreateTabsContentFeaturesDescription\": \"Mehr Details auf der Statusseite anzeigen\",\n\t\"showCharts\": \"Diagramme anzeigen\",\n\t\"showUptimePercentage\": \"Verfügbarkeitsprozentsatz anzeigen\",\n\t\"removeLogo\": \"Entferne Logo\",\n\t\"statusPageStatus\": \"Eine öffentliche Statusseite ist nicht eingerichtet.\",\n\t\"statusPageStatusContactAdmin\": \"Bitte wenden Sie sich an Ihren Administrator\",\n\t\"statusPageStatusNotPublic\": \"Diese Statusseite ist nicht öffentlich.\",\n\t\"statusPageStatusNoPage\": \"Hier gibt es keine Statusseite.\",\n\t\"statusPageStatusServiceStatus\": \"Dienststatus\",\n\t\"deleteStatusPage\": \"Möchten Sie diese Statusseite löschen?\",\n\t\"deleteStatusPageConfirm\": \"Ja, Statusseite löschen\",\n\t\"deleteStatusPageDescription\": \"Nach dem Löschen kann Ihre Statusseite nicht mehr abgerufen werden.\",\n\t\"uptimeCreate\": \"Der erwartete Wert wird zum Abgleich mit dem Antwortergebnis verwendet und die Übereinstimmung bestimmt den Status.\",\n\t\"uptimeCreateJsonPath\": \"Dieser Ausdruck wird anhand der JSON-Antwortdaten ausgewertet und das Ergebnis wird zum Abgleich mit dem erwarteten Wert verwendet. Siehe\",\n\t\"uptimeCreateJsonPathQuery\": \"für die Dokumentation der Abfragesprache.\",\n\t\"maintenanceTableActionMenuDialogTitle\": \"Möchten Sie dieses Wartungsfenster wirklich entfernen?\",\n\t\"infrastructureEditYour\": \"Bearbeiten Sie Ihre\",\n\t\"infrastructureEditMonitor\": \"Infrastrukturmonitor speichern\",\n\t\"infrastructureMonitorCreated\": \"Infrastrukturmonitor erfolgreich erstellt!\",\n\t\"infrastructureMonitorUpdated\": \"Infrastrukturmonitor erfolgreich aktualisiert!\",\n\t\"errorInvalidTypeId\": \"Ungültiger Benachrichtigungstyp angegeben\",\n\t\"errorInvalidFieldId\": \"Ungültige Feld-ID angegeben\",\n\t\"inviteNoTokenFound\": \"Kein Einladungstoken gefunden\",\n\t\"pageSpeedWarning\": \"Warnung: Sie haben noch keinen Google PageSpeed API-Schlüssel hinzugefügt. Ohne diesen funktioniert der PageSpeed-Monitor nicht.\",\n\t\"pageSpeedLearnMoreLink\": \"Hier klicken\",\n\t\"pageSpeedAddApiKey\": \"um einen API key einzutragen\",\n\t\"update\": \"Update\",\n\t\"invalidFileFormat\": \"Nicht unterstützes Dateiformat\",\n\t\"invalidFileSize\": \"Dateigröße zu groß!\",\n\t\"ClickUpload\": \"Zum Hochladen klicken\",\n\t\"DragandDrop\": \"drag and drop\",\n\t\"MaxSize\": \"Maximalgröße\",\n\t\"SupportedFormats\": \"Unterstützte Formate\",\n\t\"FirstName\": \"Vorname\",\n\t\"LastName\": \"Zuname\",\n\t\"EmailDescriptionText\": \"Dies ist Ihre aktuelle E-Mail-Adresse – sie kann nicht geändert werden.\",\n\t\"YourPhoto\": \"Profilphoto\",\n\t\"PhotoDescriptionText\": \"Dieses Foto wird auf Ihrer Profilseite angezeigt.\",\n\t\"save\": \"Speichern\",\n\t\"DeleteDescriptionText\": \"Dadurch werden das Konto und alle zugehörigen Daten vom Server entfernt. Dieser Vorgang kann nicht rückgängig gemacht werden.\",\n\t\"DeleteAccountWarning\": \"Wenn Sie Ihr Konto löschen, können Sie sich nicht mehr anmelden und alle Ihre Daten werden gelöscht. Dieser Vorgang kann nicht rückgängig gemacht werden.\",\n\t\"DeleteWarningTitle\": \"Account wirklich löschen?\",\n\t\"bulkImport\": {\n\t\t\"title\": \"Massenimport\",\n\t\t\"selectFileTips\": \"Wählen Sie die CSV-Datei zum Hochladen aus\",\n\t\t\"selectFileDescription\": \"Sie können unsere <template>Vorlage</template> oder <sample>Beispiel</sample> herunterladen.\",\n\t\t\"selectFile\": \"Datei auswählen\",\n\t\t\"parsingFailed\": \"Parsen fehlgeschlagen\",\n\t\t\"uploadSuccess\": \"Monitore erfolgreich erstellt!\",\n\t\t\"validationFailed\": \"Prüfung fehlgeschlagen\",\n\t\t\"noFileSelected\": \"Keine Datei ausgewählt\",\n\t\t\"fallbackPage\": \"Importieren Sie eine Datei, um eine Liste von Servern gleichzeitig hochzuladen\",\n\t\t\"invalidFileType\": \"Ungültiger Dateityp\",\n\t\t\"uploadFailed\": \"Upload fehlgeschlagen\"\n\t},\n\t\"DeleteAccountTitle\": \"Account löschen\",\n\t\"DeleteAccountButton\": \"Account löschen\",\n\t\"publicLink\": \"Öffentlicher Link\",\n\t\"maskedPageSpeedKeyPlaceholder\": \"*************************************\",\n\t\"reset\": \"Reset\",\n\t\"ignoreTLSError\": \"TLS/SSL Fehler ignorieren\",\n\t\"tlsErrorIgnored\": \"TLS/SSL Fehler ignoriert\",\n\t\"ignoreTLSErrorDescription\": \"TLS/SSL Fehler ignorieren und Verfügbarkeit weiter prüfen\",\n\t\"createNew\": \"Neu anlegen\",\n\t\"greeting\": {\n\t\t\"prepend\": \"Hallo\",\n\t\t\"append\": \"Der Nachmittag gehört Ihnen – machen wir ihn episch!\",\n\t\t\"overview\": \"Hier ist eine Übersicht Ihrer {{type}}-Monitore.\"\n\t},\n\t\"roles\": {\n\t\t\"superAdmin\": \"Super admin\",\n\t\t\"admin\": \"Admin\",\n\t\t\"teamMember\": \"Team Mitglied\",\n\t\t\"demoUser\": \"Demo user\"\n\t},\n\t\"teamPanel\": {\n\t\t\"teamMembers\": \"Team Mitglied\",\n\t\t\"filter\": {\n\t\t\t\"all\": \"Alle\",\n\t\t\t\"member\": \"Mitglied\"\n\t\t},\n\t\t\"inviteTeamMember\": \"Team Mirglied einladen\",\n\t\t\"inviteNewTeamMember\": \"Neues Team Mirglied einladen\",\n\t\t\"inviteDescription\": \"Wenn Sie ein neues Teammitglied hinzufügen, erhält dieses Zugriff auf alle Monitore.\",\n\t\t\"email\": \"Email\",\n\t\t\"selectRole\": \"Rolle auswählen\",\n\t\t\"inviteLink\": \"Einladungslink\",\n\t\t\"cancel\": \"Abbrechen\",\n\t\t\"noMembers\": \"Es gibt keine Team Mitglieder mit dieser Rolle\",\n\t\t\"getToken\": \"Token holen\",\n\t\t\"emailToken\": \"E-mail token\",\n\t\t\"table\": {\n\t\t\t\"name\": \"Name\",\n\t\t\t\"email\": \"Email\",\n\t\t\t\"role\": \"Rolle\",\n\t\t\t\"created\": \"Angelegt\"\n\t\t},\n\t\t\"addTeamMember\": {\n\t\t\t\"addMemberMenu\": \"Teammitglied hinzufügen\",\n\t\t\t\"title\": \"Neues Teammitglied registrieren\",\n\t\t\t\"description\": \"Einen neuen Benutzer anlegen und Zugangsdaten mit ihm teilen. Diese Methode gibt dem Mitglied direkt Zugriff auf alle Überwachungen.\",\n\t\t\t\"addButton\": \"Mitglied hinzufügen\"\n\t\t},\n\t\t\"register\": \"Teammitglied registrieren\",\n\t\t\"registerToast\": {\n\t\t\t\"success\": \"Benutzer erstellt, Zugangsdaten auf sichere Weise weitergeben.\",\n\t\t\t\"dbUserExists\": \"Der Benutzer existiert bereits.\",\n\t\t\t\"unknownError\": \"Unbekannter Fehler aufgetreten.\"\n\t\t},\n\t\t\"registerTeamMember\": {\n\t\t\t\"title\": \"Teammitglied registrieren\",\n\t\t\t\"auth\": {\n\t\t\t\t\"common\": {\n\t\t\t\t\t\"inputs\": {\n\t\t\t\t\t\t\"firstName\": {\n\t\t\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\t\t\"empty\": \"Bitte einen Namen eingeben\",\n\t\t\t\t\t\t\t\t\"pattern\": \"Der Name darf nur Buchstaben, Leerzeichen, Apostrophe oder Bindestriche enthalten\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"lastName\": {\n\t\t\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\t\t\"empty\": \"Bitte einen Vornamen eingeben\",\n\t\t\t\t\t\t\t\t\"pattern\": \"Der Vorname darf nur Buchstaben, Leerzeichen, Apostrophe oder Bindestriche enthalten\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"email\": {\n\t\t\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\t\t\"empty\": \"Zum Fortsetzen bitte eine E-Mail-Adresse eingeben\",\n\t\t\t\t\t\t\t\t\"invalid\": \"Bitte die Gültigkeit der E-Mail-Adresse erneut prüfen\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"role\": {\n\t\t\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\t\t\"empty\": \"Eine Rolle wird benötigt\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"role\": \"Rolle\",\n\t\t\"changeTeamPassword\": {\n\t\t\t\"changePasswordMenu\": \"Passwort zurücksetzen\",\n\t\t\t\"title\": \"Passwort des Teammitgliedes zurücksetzen\",\n\t\t\t\"description\": \"Neues Passwort für dieses Teammitglied erstellen. Es muss auf einem Sicheren weg zur Verfügung gestellt werden.\",\n\t\t\t\"success\": \"Passwort erfolgreich zurückgesetzt. Bitte sicherstellen, dass die Zugangsdaten auf sichere Weise weitergegeben werden.\"\n\t\t}\n\t},\n\t\"monitorState\": {\n\t\t\"paused\": \"Pausiert\",\n\t\t\"resumed\": \"Wiederaufgenommen\",\n\t\t\"active\": \"Aktiv\"\n\t},\n\t\"menu\": {\n\t\t\"uptime\": \"Uptime\",\n\t\t\"pagespeed\": \"Pagespeed\",\n\t\t\"infrastructure\": \"Infrastruktur\",\n\t\t\"incidents\": \"Vorfälle\",\n\t\t\"statusPages\": \"Statusseite\",\n\t\t\"maintenance\": \"Wartung\",\n\t\t\"integrations\": \"Integrationen\",\n\t\t\"settings\": \"Einstellungen\",\n\t\t\"support\": \"Support\",\n\t\t\"discussions\": \"Diskussionen\",\n\t\t\"docs\": \"Anleitungen\",\n\t\t\"changelog\": \"Änderungen\",\n\t\t\"profile\": \"Profil\",\n\t\t\"password\": \"Passwort\",\n\t\t\"team\": \"Team\",\n\t\t\"logOut\": \"Abmelden\",\n\t\t\"notifications\": \"Benachrichtigungen\",\n\t\t\"logs\": \"Logs\"\n\t},\n\t\"settingsEmailUser\": \"E-Mail-Benutzer – Benutzername zur Authentifizierung, überschreibt die E-Mail-Adresse, falls angegeben\",\n\t\"state\": \"Zustand\",\n\t\"statusBreadCrumbsStatusPages\": \"Statusseite\",\n\t\"statusBreadCrumbsDetails\": \"Details\",\n\t\"commonSaving\": \"Speichere...\",\n\t\"navControls\": \"Steuerungen\",\n\t\"incidentsPageTitle\": \"Ereignisse\",\n\t\"passwordPanel\": {\n\t\t\"passwordChangedSuccess\": \"Dein Passwort wurde erfolgreich geändert.\",\n\t\t\"passwordInputIncorrect\": \"Die Passworteingabe war nicht korrekt.\",\n\t\t\"currentPassword\": \"Aktuelles Passwort\",\n\t\t\"enterCurrentPassword\": \"Aktuelles Passwort eingeben\",\n\t\t\"newPassword\": \"Neues Passwort\",\n\t\t\"enterNewPassword\": \"Neues Passwort eingeben\",\n\t\t\"confirmNewPassword\": \"Neues Passwort  wiederholen\",\n\t\t\"passwordRequirements\": \"Das Passwort muss mindestens 8 Zeichen, einen Großbuchstaben, eine Zahl und ein Sonderzeichen enthalten.\",\n\t\t\"saving\": \"Speichere...\"\n\t},\n\t\"emailSent\": \"Email erfolgreich gesendet\",\n\t\"failedToSendEmail\": \"Email konnte nicht gesendet werden\",\n\t\"settingsTestEmailSuccess\": \"Test-Email erfolgreich gesendet\",\n\t\"settingsTestEmailFailed\": \"Test-Email konnte nicht gesendet werden\",\n\t\"settingsTestEmailFailedWithReason\": \"Email konnte nicht gesendet werden: {{reason}}\",\n\t\"settingsTestEmailUnknownError\": \"Unbekannter Fehler\",\n\t\"statusMsg\": {\n\t\t\"paused\": \"Monitoring pausiert\",\n\t\t\"up\": \"Ihre Site ist online.\",\n\t\t\"down\": \"Ihre Site ist nicht erreichbar.\",\n\t\t\"pending\": \"Ausstehend...\"\n\t},\n\t\"uptimeGeneralInstructions\": {\n\t\t\"http\": \"Geben Sie die zu überwachende URL oder IP ein (z. B. https://example.com/ oder 192.168.1.100) und fügen Sie einen eindeutigen Anzeigenamen hinzu, der auf dem Dashboard angezeigt wird.\",\n\t\t\"ping\": \"Geben Sie die IP-Adresse oder den Hostnamen ein, der angepingt werden soll (z. B. 192.168.1.100 oder example.com), und fügen Sie einen eindeutigen Anzeigenamen hinzu, der auf dem Dashboard angezeigt wird.\",\n\t\t\"docker\": \"Geben Sie die Docker-ID Ihres Containers ein. Docker-IDs müssen die vollständige 64-Zeichen-ID sein. Sie können docker inspect <short_id> ausführen, um die vollständige Container-ID abzurufen.\",\n\t\t\"port\": \"Geben Sie die URL oder IP des Servers, die Portnummer und einen eindeutigen Anzeigenamen ein, der auf dem Dashboard angezeigt wird.\",\n\t\t\"game\": \"IP Adresse oder Hostnamen und Port für Ping eingeben (z.B. 192.168.1.100 oder beispiel.de) und Spieletyp auswählen.\",\n\t\t\"https\": \"Zu überwachende Adresse oder IP (z.B. https://beispiel.de/ oder 192.168.1.100) eingeben und einen klaren Anzeigenamen, der im Dashboard erscheint.\"\n\t},\n\t\"common\": {\n\t\t\"appName\": \"Checkmate\",\n\t\t\"monitoringAgentName\": \"Capture\",\n\t\t\"buttons\": {\n\t\t\t\"toggleTheme\": \"Schaltet hell und dunkel um\"\n\t\t},\n\t\t\"toasts\": {\n\t\t\t\"networkError\": \"Netzwerkfehler\",\n\t\t\t\"checkConnection\": \"Bitte Verbindung prüfen\",\n\t\t\t\"unknownError\": \"Unbekannter Fehler\"\n\t\t}\n\t},\n\t\"auth\": {\n\t\t\"common\": {\n\t\t\t\"navigation\": {\n\t\t\t\t\"continue\": \"Weiter\",\n\t\t\t\t\"back\": \"Zurück\"\n\t\t\t},\n\t\t\t\"inputs\": {\n\t\t\t\t\"email\": {\n\t\t\t\t\t\"label\": \"Email\",\n\t\t\t\t\t\"placeholder\": \"jordan.ellis@domain.com\",\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"Email adresse eingeben um fortzufahren\",\n\t\t\t\t\t\t\"invalid\": \"Bitte überprüfen Sie die Gültigkeit der eingegebenen E-Mail-Adresse erneut\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"password\": {\n\t\t\t\t\t\"label\": \"Passwort\",\n\t\t\t\t\t\"rules\": {\n\t\t\t\t\t\t\"length\": {\n\t\t\t\t\t\t\t\"beginning\": \"Muß mindestens\",\n\t\t\t\t\t\t\t\"highlighted\": \"8 Zeichen lang\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"special\": {\n\t\t\t\t\t\t\t\"beginning\": \"Muß mindestens\",\n\t\t\t\t\t\t\t\"highlighted\": \"ein Sonderzeichen enthalten\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"number\": {\n\t\t\t\t\t\t\t\"beginning\": \"Muß mindestens\",\n\t\t\t\t\t\t\t\"highlighted\": \"eine Zahl enthalten\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"uppercase\": {\n\t\t\t\t\t\t\t\"beginning\": \"Muß mindestens\",\n\t\t\t\t\t\t\t\"highlighted\": \"einen Großbuchstaben enthalten\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"lowercase\": {\n\t\t\t\t\t\t\t\"beginning\": \"Muß mindestens\",\n\t\t\t\t\t\t\t\"highlighted\": \"einen Kleinbuchstaben enthalten\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"match\": {\n\t\t\t\t\t\t\t\"beginning\": \"Passwort und Kennwort bestätigen\",\n\t\t\t\t\t\t\t\"highlighted\": \"muß übereinstimmen\"\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"Bitte Passwort eingeben\",\n\t\t\t\t\t\t\"length\": \"Passwort muss mindestens 8 Zeichen lang sein\",\n\t\t\t\t\t\t\"uppercase\": \"Passwort muss mindestens einen Großbuchstaben enthalten\",\n\t\t\t\t\t\t\"lowercase\": \"Passwort muss mindestens einen Kleinbuchstaben enthalten\",\n\t\t\t\t\t\t\"number\": \"Passwort muss mindestens eine Zahl enthalten\",\n\t\t\t\t\t\t\"special\": \"Passwort muss mindestens ein Sonderzeichen enthalten\",\n\t\t\t\t\t\t\"incorrect\": \"Das Passwort stimmt nicht mit dem gespeicherten überein\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"passwordConfirm\": {\n\t\t\t\t\t\"label\": \"Passwort bestätigen\",\n\t\t\t\t\t\"placeholder\": \"Passwort nochmal eingeben\",\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"Passwort nochmal eingeben\",\n\t\t\t\t\t\t\"different\": \"Die Passwörter stimmen nicht überein\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"firstName\": {\n\t\t\t\t\t\"label\": \"Name\",\n\t\t\t\t\t\"placeholder\": \"Jordan\",\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"Bitte Name eingeben\",\n\t\t\t\t\t\t\"length\": \"Name darf nicht mehr als 50 Zeichen lang sein\",\n\t\t\t\t\t\t\"pattern\": \"Name darf nur aus Buchstaben, Leerstellen, Apostroph und Bindestrichen bestehen\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"lastName\": {\n\t\t\t\t\t\"label\": \"Zuname\",\n\t\t\t\t\t\"placeholder\": \"Ellis\",\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"Bitte Zuname eingeben\",\n\t\t\t\t\t\t\"length\": \"Zuname darf nicht länger als 50 Zeichen sein\",\n\t\t\t\t\t\t\"pattern\": \"Zuname darf nur aus Buchstaben, Leerstellen, Apostroph und Bindestrichen bestehen\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"errors\": {\n\t\t\t\t\"validation\": \"Fehler bei der prüfung der Daten\"\n\t\t\t},\n\t\t\t\"fields\": {\n\t\t\t\t\"password\": {\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"incorrect\": \"Das Passwort stimmt nicht mit dem gespeicherten überein\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"role\": {\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"min\": \"Mindestens eine Rolle ist erforderlich\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"login\": {\n\t\t\t\"heading\": \"Anmelden\",\n\t\t\t\"subheadings\": {\n\t\t\t\t\"stepOne\": \"Email eingeben\",\n\t\t\t\t\"stepTwo\": \"Passwort eingeben\"\n\t\t\t},\n\t\t\t\"links\": {\n\t\t\t\t\"forgotPassword\": \"Passwort vergessen?\",\n\t\t\t\t\"register\": \"Noch keinen Account?\",\n\t\t\t\t\"forgotPasswordLink\": \"Passwort zurücksetzen\",\n\t\t\t\t\"registerLink\": \"Hier registrieren\"\n\t\t\t},\n\t\t\t\"toasts\": {\n\t\t\t\t\"success\": \"Willkommen zurück. Erfolgreich angemeldet.\",\n\t\t\t\t\"incorrectPassword\": \"Falsches Passwort\"\n\t\t\t},\n\t\t\t\"errors\": {\n\t\t\t\t\"password\": {\n\t\t\t\t\t\"incorrect\": \"Das Passwort stimmt nicht mit dem gespeicherten überein\"\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"welcome\": \"Willkommen zurück bei Checkmate!\"\n\t\t},\n\t\t\"registration\": {\n\t\t\t\"heading\": {\n\t\t\t\t\"superAdmin\": \"Super Admin anlegen\",\n\t\t\t\t\"user\": \"Anmelden\"\n\t\t\t},\n\t\t\t\"subheadings\": {\n\t\t\t\t\"stepOne\": \"Geben Sie Ihre persönlichen Daten ein\",\n\t\t\t\t\"stepTwo\": \"Email eingeben\",\n\t\t\t\t\"stepThree\": \"Passwort eingeben\"\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\t\"superAdmin\": \"Super admin account anlegen um zu beginnen\",\n\t\t\t\t\"user\": \"Melden Sie sich als Benutzer an und bitten Sie den Superadministrator um Zugriff auf Ihre Monitore\"\n\t\t\t},\n\t\t\t\"gettingStartedButton\": {\n\t\t\t\t\"superAdmin\": \"Super admin account anlegen\",\n\t\t\t\t\"user\": \"Normalen Benutzer anlegen\"\n\t\t\t},\n\t\t\t\"termsAndPolicies\": \"Indem Sie ein Konto erstellen, stimmen Sie unseren <a1>Servicebedingungen</a1> und <a2>Datenschutzrichtlinien</a2> zu.\",\n\t\t\t\"links\": {\n\t\t\t\t\"login\": \"Du hast bereits einen Benutzer? <a>Anmelden</a>\"\n\t\t\t},\n\t\t\t\"toasts\": {\n\t\t\t\t\"success\": \"Willkommen! Benutzer erfolgreich angelegt\"\n\t\t\t},\n\t\t\t\"welcome\": \"Willkommen bei Checkmate!\"\n\t\t},\n\t\t\"forgotPassword\": {\n\t\t\t\"heading\": \"Passwort vergessen?\",\n\t\t\t\"subheadings\": {\n\t\t\t\t\"stepOne\": \"Kein Problem. Wir schicken Dir Infos zum zurücksetzen.\",\n\t\t\t\t\"stepTwo\": \"Link zum Password zurücksetzen an <email/> geschickt. \",\n\t\t\t\t\"stepThree\": \"Das neue Passwort darf nicht gleich wie frühere Passwörter sein.\",\n\t\t\t\t\"stepFour\": \"Das Passwort wurde zurückgesetzt. Unten klicken zum Anmelden.\"\n\t\t\t},\n\t\t\t\"buttons\": {\n\t\t\t\t\"openEmail\": \"Email app öffnen\",\n\t\t\t\t\"resetPassword\": \"Passwort zurücksetzen\"\n\t\t\t},\n\t\t\t\"imageAlts\": {\n\t\t\t\t\"passwordKey\": \"Password key icon\",\n\t\t\t\t\"email\": \"Email icon\",\n\t\t\t\t\"lock\": \"Lock icon\",\n\t\t\t\t\"passwordConfirm\": \"Password confirm icon\"\n\t\t\t},\n\t\t\t\"links\": {\n\t\t\t\t\"login\": \"Zurück zum  <a>Anmelden</a>\",\n\t\t\t\t\"resend\": \"Keine Email bekommen? <a>Klicken um nochmal zu senden</a>\"\n\t\t\t},\n\t\t\t\"toasts\": {\n\t\t\t\t\"sent\": \"Anleitung an <email/> gesendet.\",\n\t\t\t\t\"emailNotFound\": \"Email nicht gefunden.\",\n\t\t\t\t\"redirect\": \"Umleitung in <seconds/>...\",\n\t\t\t\t\"success\": \"Passwort erfolgreich zurückgesetzt.\",\n\t\t\t\t\"error\": \"Kennwort konnte nicht zurückgesetzt werden. Bitte versuchen Sie es später erneut oder wenden Sie sich an den Support.\"\n\t\t\t}\n\t\t}\n\t},\n\t\"errorPages\": {\n\t\t\"serverUnreachable\": {\n\t\t\t\"toasts\": {\n\t\t\t\t\"reconnected\": \"Verbindung zum Server wiederhergestellt.\",\n\t\t\t\t\"stillUnreachable\": \"Server immer noch nicht erreichbar. Bitte später erneut versuchen.\"\n\t\t\t},\n\t\t\t\"alertBox\": \"Server Verbindungsfehler\",\n\t\t\t\"description\": \"Wir können keine Verbindung zum Server herstellen. Bitte überprüfen Sie Ihre Internetverbindung oder Ihre Bereitstellungskonfiguration, falls das Problem weiterhin besteht.\",\n\t\t\t\"retryButton\": {\n\t\t\t\t\"default\": \"Verbindung erneut versuchen\",\n\t\t\t\t\"processing\": \"Verbinde...\"\n\t\t\t}\n\t\t}\n\t},\n\t\"createNotifications\": {\n\t\t\"title\": \"Benachrichtigungskanal erstellen\",\n\t\t\"nameSettings\": {\n\t\t\t\"title\": \"Name\",\n\t\t\t\"description\": \"Ein beschreibender Name für Ihre Integration.\",\n\t\t\t\"nameLabel\": \"Name\",\n\t\t\t\"namePlaceholder\": \"z.B. Slack Benachrichtigung\"\n\t\t},\n\t\t\"typeSettings\": {\n\t\t\t\"title\": \"Typ\",\n\t\t\t\"description\": \"Wählen Sie den Typ des Benachrichtigungskanals aus, den Sie erstellen möchten.\",\n\t\t\t\"typeLabel\": \"Typ\"\n\t\t},\n\t\t\"emailSettings\": {\n\t\t\t\"title\": \"Email\",\n\t\t\t\"description\": \"Empfänger Email adresse\",\n\t\t\t\"emailLabel\": \"Email addresse\",\n\t\t\t\"emailPlaceholder\": \"z.B. john@example.com\"\n\t\t},\n\t\t\"slackSettings\": {\n\t\t\t\"title\": \"Slack\",\n\t\t\t\"description\": \"Slack webhook hier konfigurieren\",\n\t\t\t\"webhookLabel\": \"Slack webhook URL\",\n\t\t\t\"webhookPlaceholder\": \"https://hooks.slack.com/services/...\"\n\t\t},\n\t\t\"pagerdutySettings\": {\n\t\t\t\"title\": \"PagerDuty\",\n\t\t\t\"description\": \"PagerDuty hier konfigurieren\",\n\t\t\t\"integrationKeyLabel\": \"Integration key\",\n\t\t\t\"integrationKeyPlaceholder\": \"1234567890\"\n\t\t},\n\t\t\"discordSettings\": {\n\t\t\t\"title\": \"Discord\",\n\t\t\t\"description\": \"Discord webhook hier konfigurieren\",\n\t\t\t\"webhookLabel\": \"Discord Webhook URL\",\n\t\t\t\"webhookPlaceholder\": \"https://your-server.com/webhook\"\n\t\t},\n\t\t\"webhookSettings\": {\n\t\t\t\"title\": \"Webhook\",\n\t\t\t\"description\": \"Webhook hier konfigurieren\",\n\t\t\t\"webhookLabel\": \"Webhook URL\",\n\t\t\t\"webhookPlaceholder\": \"https://your-server.com/webhook\"\n\t\t},\n\t\t\"testNotification\": \"Testbenachrichtigung\",\n\t\t\"dialogDeleteTitle\": \"Möchten Sie diese Benachrichtigung wirklich löschen?\",\n\t\t\"dialogDeleteConfirm\": \"Löschen\"\n\t},\n\t\"notificationConfig\": {\n\t\t\"title\": \"Benachrichtigungen\",\n\t\t\"description\": \"Wählen Sie die Benachrichtigungskanäle aus, die Sie verwenden möchten\"\n\t},\n\t\"monitorStatus\": {\n\t\t\"checkingEvery\": \"Überprüfung alle {{interval}}\",\n\t\t\"withCaptureAgent\": \"mit Capture-Agent {{version}}\",\n\t\t\"up\": \"Online\",\n\t\t\"down\": \"Offline\",\n\t\t\"paused\": \"pausiert\"\n\t},\n\t\"advancedMatching\": \"Erweiterter Abgleich\",\n\t\"sendTestNotifications\": \"Test Benachrichtigung senden\",\n\t\"selectAll\": \"Alle auswählen\",\n\t\"showAdminLoginLink\": \"Link „Administrator? Hier anmelden“ auf der Statusseite anzeigen\",\n\t\"logsPage\": {\n\t\t\"title\": \"Logs\",\n\t\t\"description\": \"Systemprotokolle – letzte 1000 Zeilen\",\n\t\t\"tabs\": {\n\t\t\t\"queue\": \"Warteschlange\",\n\t\t\t\"logs\": \"Server logs\",\n\t\t\t\"diagnostics\": \"Diagnose\"\n\t\t},\n\t\t\"toast\": {\n\t\t\t\"fetchLogsSuccess\": \"Protokolle erfolgreich abgerufen\"\n\t\t},\n\t\t\"logLevelSelect\": {\n\t\t\t\"title\": \"Protokollebene\",\n\t\t\t\"values\": {\n\t\t\t\t\"all\": \"Alle\",\n\t\t\t\t\"info\": \"Info\",\n\t\t\t\t\"warn\": \"Warnung\",\n\t\t\t\t\"error\": \"Fehler\",\n\t\t\t\t\"debug\": \"Debug\"\n\t\t\t}\n\t\t}\n\t},\n\t\"queuePage\": {\n\t\t\"title\": \"Warteschlange\",\n\t\t\"refreshButton\": \"Auffrischen\",\n\t\t\"flushButton\": \"Warteschlange leeren\",\n\t\t\"jobTable\": {\n\t\t\t\"title\": \"Aufgaben in der Warteschlange\",\n\t\t\t\"idHeader\": \"Monitor ID\",\n\t\t\t\"urlHeader\": \"URL\",\n\t\t\t\"typeHeader\": \"Typ\",\n\t\t\t\"activeHeader\": \"Aktiv\",\n\t\t\t\"lockedAtHeader\": \"Gesperrt bei\",\n\t\t\t\"runCountHeader\": \"Anzahl Läufe\",\n\t\t\t\"failCountHeader\": \"Anzahl Fehler\",\n\t\t\t\"lastRunHeader\": \"Letzter Lauf um\",\n\t\t\t\"lastFinishedAtHeader\": \"Zuletzt abgeschlossen um\",\n\t\t\t\"lastRunTookHeader\": \"Letzter Lauf dauerte\",\n\t\t\t\"intervalHeader\": \"Invervall\"\n\t\t},\n\t\t\"metricsTable\": {\n\t\t\t\"title\": \"Warteschlangenmetriken\",\n\t\t\t\"metricHeader\": \"Metrisch\",\n\t\t\t\"valueHeader\": \"Wert\"\n\t\t},\n\t\t\"failedJobTable\": {\n\t\t\t\"title\": \"Anzahl Fehler\",\n\t\t\t\"monitorIdHeader\": \"Monitor ID\",\n\t\t\t\"monitorUrlHeader\": \"Monitor URL\",\n\t\t\t\"failCountHeader\": \"Anzahl Fehler\",\n\t\t\t\"failedAtHeader\": \"Zuletzt fehlgeschlagen um\",\n\t\t\t\"failReasonHeader\": \"Fehlergrund\"\n\t\t}\n\t},\n\t\"export\": {\n\t\t\"title\": \"Monitore exportieren\",\n\t\t\"success\": \"Monitore erfolgreich exportiert\",\n\t\t\"failed\": \"Fehler beim exportieren der Monitore\"\n\t},\n\t\"monitorActions\": {\n\t\t\"title\": \"Export/Import\",\n\t\t\"import\": \"Monitore importieren\",\n\t\t\"export\": \"Monitore exportieren\",\n\t\t\"deleteSuccess\": \"Monitor erfolgreich gelöscht\",\n\t\t\"deleteFailed\": \"Monitor konnte nicht gelöscht werden\",\n\t\t\"details\": \"Details\"\n\t},\n\t\"settingsPage\": {\n\t\t\"aboutSettings\": {\n\t\t\t\"labelDevelopedBy\": \"Entwickelt von Bluewave Labs\",\n\t\t\t\"labelVersion\": \"Version\",\n\t\t\t\"title\": \"Über\"\n\t\t},\n\t\t\"demoMonitorsSettings\": {\n\t\t\t\"buttonAddMonitors\": \"Demo Monitor hinzufügen\",\n\t\t\t\"description\": \"Beispiel Monitor zur Demonstration hinzufügen.\",\n\t\t\t\"title\": \"Demo Monitore\"\n\t\t},\n\t\t\"emailSettings\": {\n\t\t\t\"buttonSendTestEmail\": \"Test-Email senden\",\n\t\t\t\"description\": \"Konfigurieren Sie die E-Mail-Einstellungen für Ihr System. Diese werden zum Senden von Benachrichtigungen und Warnungen verwendet.\",\n\t\t\t\"descriptionTransport\": \"Dies erstellt einen SMTP-Transport für NodeMailer\",\n\t\t\t\"labelAddress\": \"E-Mail-Adresse - Wird zur Authentifizierung verwendet\",\n\t\t\t\"labelConnectionHost\": \"E-Mail-Verbindungshost – Hostname zur Verwendung in der HELO/EHLO-Begrüßung\",\n\t\t\t\"labelHost\": \"E-Mail-Host – Hostname oder IP-Adresse, mit der eine Verbindung hergestellt werden soll\",\n\t\t\t\"labelIgnoreTLS\": \"STARTTLS abschalten: TLS nicht nutzen, selbst wenn der Server es unterstützt\",\n\t\t\t\"labelPassword\": \"Email password - Password für Anmeldung\",\n\t\t\t\"labelPasswordSet\": \"Passwort erstellt. Reset drücken um es zu ändern.\",\n\t\t\t\"labelPool\": \"Verbindungspooling aktivieren: Vorhandene Verbindungen wiederverwenden, um die Leistung zu verbessern\",\n\t\t\t\"labelPort\": \"Email port - Port zum verbinden\",\n\t\t\t\"labelRejectUnauthorized\": \"Ungültige Zertifikate ablehnen. Verbindungen mit self-signed oder nicht vertrauenswürdigen Zertifikaten ablehnen.\",\n\t\t\t\"labelRequireTLS\": \"STARTTLS erzwingen: TLS-Upgrade erforderlich, schlägt fehl, wenn nicht unterstützt\",\n\t\t\t\"labelSecure\": \"SSL verwenden (empfohlen): Verbindung mit SSL/TLS verschlüsseln\",\n\t\t\t\"labelTLSServername\": \"TLS-Servername – Optionaler Hostname für die TLS-Validierung, wenn der Host eine IP ist\",\n\t\t\t\"labelUser\": \"E-Mail-Benutzer – Benutzername zur Authentifizierung, überschreibt die E-Mail-Adresse, falls angegeben\",\n\t\t\t\"linkTransport\": \"Spezifikationen finden Sie hier\",\n\t\t\t\"placeholderUser\": \"Leer lassen, wenn nicht benötigt\",\n\t\t\t\"title\": \"Email\",\n\t\t\t\"toastEmailRequiredFieldsError\": \"E-Mail-Adresse, Host, Port und Passwort sind erforderlich\"\n\t\t},\n\t\t\"pageSpeedSettings\": {\n\t\t\t\"description\": \"Geben Sie Ihren Google PageSpeed API-Schlüssel ein, um die Google PageSpeed-Überwachung zu aktivieren. Klicken Sie auf „Zurücksetzen“, um den Schlüssel zu aktualisieren.\",\n\t\t\t\"labelApiKeySet\": \"API key erstellt. Reset drücken um ihn zu ändern.\",\n\t\t\t\"labelApiKey\": \"PageSpeed API key\",\n\t\t\t\"title\": \"Google PageSpeed API key\"\n\t\t},\n\t\t\"saveButtonLabel\": \"Speichern\",\n\t\t\"statsSettings\": {\n\t\t\t\"clearAllStatsButton\": \"Alle Statistiken löschen\",\n\t\t\t\"clearAllStatsDescription\": \"Alle Statistiken löschen. Dies ist irreversibel.\",\n\t\t\t\"clearAllStatsDialogConfirm\": \"Ja, alle Statistiken löschen\",\n\t\t\t\"clearAllStatsDialogDescription\": \"Nach dem Entfernen können der Überwachungsverlauf und die Statistiken nicht mehr abgerufen werden.\",\n\t\t\t\"clearAllStatsDialogTitle\": \"Möchten Sie alle Statistiken löschen?\",\n\t\t\t\"description\": \"Legen Sie fest, wie lange Sie historische Daten aufbewahren möchten. Sie können auch alle vorhandenen Daten löschen.\",\n\t\t\t\"labelTTL\": \"Die Tage, an denen Sie den Überwachungsverlauf beibehalten möchten.\",\n\t\t\t\"labelTTLOptional\": \"0 für unendlich\",\n\t\t\t\"title\": \"Monitorverlauf\"\n\t\t},\n\t\t\"systemResetSettings\": {\n\t\t\t\"buttonRemoveAllMonitors\": \"Alle Monitore löschen\",\n\t\t\t\"description\": \"Alle Monitore löschen\",\n\t\t\t\"dialogConfirm\": \"Ja, alle Monitore löschen\",\n\t\t\t\"dialogDescription\": \"Gelöschte Monitore können nicht wiederhergestellt werden.\",\n\t\t\t\"dialogTitle\": \"Wirklich alle Monitore löschen?\",\n\t\t\t\"title\": \"System zurücksetzen\"\n\t\t},\n\t\t\"timezoneSettings\": {\n\t\t\t\"description\": \"Wählen Sie die Zeitzone aus, die zum Anzeigen von Datum und Uhrzeit in der gesamten Anwendung verwendet wird.\",\n\t\t\t\"label\": \"Zeitzone\",\n\t\t\t\"title\": \"Zeitzone\"\n\t\t},\n\t\t\"title\": \"Einstellungen\",\n\t\t\"uiSettings\": {\n\t\t\t\"description\": \"Wechseln Sie zwischen hellem und dunklem Modus oder ändern Sie die Sprache der Benutzeroberfläche.\",\n\t\t\t\"labelLanguage\": \"Sprache\",\n\t\t\t\"labelTheme\": \"Themenmodus\",\n\t\t\t\"title\": \"Aussehen\"\n\t\t},\n\t\t\"urlSettings\": {\n\t\t\t\"description\": \"Zeigt die IP-Adresse oder URL des Monitors auf der öffentlichen Statusseite an. Wenn diese Option deaktiviert ist, wird zum Schutz vertraulicher Informationen nur der Monitorname angezeigt.\",\n\t\t\t\"label\": \"IP/URL auf der Statusseite anzeigen\",\n\t\t\t\"selectDisabled\": \"Inaktiv\",\n\t\t\t\"selectEnabled\": \"Aktiv\",\n\t\t\t\"title\": \"Überwachen Sie IP/URL auf der Statusseite\"\n\t\t},\n\t\t\"globalThresholds\": {\n\t\t\t\"title\": \"Globale Schwellenwerte\",\n\t\t\t\"description\": \"Globale CPU-, Speicher-, Festplatten- und Temperaturschwellenwerte festlegen. Wenn ein Wert angegeben ist, wird er automatisch für die Überwachung genutzt.\"\n\t\t}\n\t},\n\t\"statusPageCreate\": {\n\t\t\"buttonSave\": \"Speichern\"\n\t},\n\t\"incidentsOptionsHeaderFilterResolved\": \"Gelöst\",\n\t\"settingsSave\": \"Speichern\",\n\t\"statusPageCreateAppearanceTitle\": \"Aussehen\",\n\t\"confirmPassword\": \"Passwort bestätigen\",\n\t\"monitorHooks\": {\n\t\t\"failureAddDemoMonitors\": \"Demo Monitor konnte nicht hinzugefügt werden\",\n\t\t\"successAddDemoMonitors\": \"Demo Monitor erfolgreich hinzugefügt\"\n\t},\n\t\"settingsAppearance\": \"Aussehen\",\n\t\"settingsDisplayTimezone\": \"Zeitzone anzeigen\",\n\t\"settingsGeneralSettings\": \"Allgemeine Einstellungen\",\n\t\"incidentsOptionsHeaderTotalIncidents\": \"Gesamtanzahl der Vorfälle\",\n\t\"statusPage\": {\n\t\t\"deleteSuccess\": \"Statusseite erfolgreich gelöscht\",\n\t\t\"deleteFailed\": \"Löschen der Statusseite fehlgeschlagen\",\n\t\t\"createSuccess\": \"Statusseite erfolgreich erstellt\",\n\t\t\"updateSuccess\": \"Statusseite erfolgreich aktualisiert\",\n\t\t\"generalSettings\": \"Allgemeine Einstellungen\",\n\t\t\"contents\": \"Inhalt\",\n\t\t\"fallback\": {\n\t\t\t\"checks\": [\n\t\t\t\t\"Überwachen und zeigen Sie den Zustand Ihrer Dienste in Echtzeit an.\",\n\t\t\t\t\"Verfolgen Sie mehrere Dienste und teilen Sie deren Status.\",\n\t\t\t\t\"Informieren Sie Nutzer über Ausfälle und Leistung.\"\n\t\t\t],\n\t\t\t\"title\": \"Eine Statusseite wird verwendet, um:\",\n\t\t\t\"actionButton\": \"Lassen Sie uns Ihre erste Statusseite erstellen!\"\n\t\t}\n\t},\n\t\"testNotificationsDisabled\": \"Für diesen Monitor sind keine Benachrichtigungen eingerichtet. Sie müssen eine hinzufügen, indem Sie auf die Schaltfläche „Konfigurieren“ klicken.\",\n\t\"incidentsTableResolvedAt\": \"Gelöst am\",\n\t\"incidentsTableActionResolve\": \"Lösen\",\n\t\"checkHooks\": {\n\t\t\"failureResolveOne\": \"Der Vorfall konnte nicht gelöst werden.\",\n\t\t\"failureResolveAll\": \"Es konnten nicht alle Vorfälle gelöst werden.\",\n\t\t\"failureResolveMonitor\": \"Monitorvorfälle konnten nicht behoben werden.\"\n\t},\n\t\"checkFormError\": \"Bitte überprüfen Sie das Formular auf Fehler.\",\n\t\"diagnosticsPage\": {\n\t\t\"diagnosticDescription\": \"Systemdiagnose\",\n\t\t\"statsDescription\": \"Systemstatistiken\",\n\t\t\"gauges\": {\n\t\t\t\"heapAllocationTitle\": \"Heap-Zuweisung\",\n\t\t\t\"heapAllocationSubtitle\": \"% des verfügbaren Speichers\",\n\t\t\t\"heapUsageTitle\": \"Heap-Nutzung\",\n\t\t\t\"heapUsageSubtitle\": \"% des verfügbaren Speichers\",\n\t\t\t\"heapUtilizationTitle\": \"Heap-Auslastung\",\n\t\t\t\"heapUtilizationSubtitle\": \"% der zugewiesenen\",\n\t\t\t\"instantCpuUsageTitle\": \"Sofortige CPU-Auslastung\",\n\t\t\t\"instantCpuUsageSubtitle\": \"% der von der CPU genutzten 1s\"\n\t\t},\n\t\t\"stats\": {\n\t\t\t\"eventLoopDelayTitle\": \"Ereignisschleifenverzögerung\",\n\t\t\t\"uptimeTitle\": \"Betriebszeit\",\n\t\t\t\"usedHeapSizeTitle\": \"Verwendete Heap-Größe\",\n\t\t\t\"totalHeapSizeTitle\": \"Gesamtgröße des Heapspeichers\",\n\t\t\t\"osMemoryLimitTitle\": \"Betriebssystem-Speicherlimit\"\n\t\t}\n\t},\n\t\"pageSpeedLighthouseAPI\": \"Verwenden Sie die Lighthouse PageSpeed API, um Ihre Website zu überwachen\",\n\t\"time\": {\n\t\t\"threeMinutes\": \"3 Minuten\",\n\t\t\"fiveMinutes\": \"5 Minuten\",\n\t\t\"tenMinutes\": \"10 Minuten\",\n\t\t\"twentyMinutes\": \"20 Minuten\",\n\t\t\"oneHour\": \"1 Stunde\",\n\t\t\"oneDay\": \"1 Tag\",\n\t\t\"oneWeek\": \"1 Woche\",\n\t\t\"fourMinutes\": \"4 Minuten\",\n\t\t\"oneMinute\": \"Eine Minute\",\n\t\t\"twoMinutes\": \"Zwei Minuten\",\n\t\t\"fifteenSeconds\": \"15 Sekunden\",\n\t\t\"thirtySeconds\": \"30 Sekunden\"\n\t},\n\t\"general\": {\n\t\t\"noOptionsFound\": \"Keine {{unit}} gefunden\"\n\t},\n\t\"infrastructureMonitor\": {\n\t\t\"fallback\": {\n\t\t\t\"checks\": [\n\t\t\t\t\"Verfolgen Sie die Leistung Ihrer Server\",\n\t\t\t\t\"Identifizieren Sie Engpässe und optimieren Sie die Nutzung\",\n\t\t\t\t\"Sorgen Sie für Zuverlässigkeit durch Echtzeitüberwachung\"\n\t\t\t],\n\t\t\t\"title\": \"Ein Infrastrukturmonitor wird verwendet, um:\",\n\t\t\t\"actionButton\": \"Lassen Sie uns Ihren ersten Infrastrukturmonitor erstellen!\"\n\t\t}\n\t},\n\t\"maintenanceWindow\": {\n\t\t\"fallback\": {\n\t\t\t\"checks\": [\n\t\t\t\t\"Markieren Sie Ihre Wartungszeiträume.\",\n\t\t\t\t\"Beseitigen Sie Missverständnisse.\",\n\t\t\t\t\"Beenden Sie das Senden von Warnmeldungen in Wartungsfenstern.\"\n\t\t\t],\n\t\t\t\"title\": \"Ein Wartungsfenster wird verwendet, um:\",\n\t\t\t\"actionButton\": \"Lassen Sie uns Ihr erstes Wartungsfenster erstellen!\"\n\t\t}\n\t},\n\t\"pageSpeed\": {\n\t\t\"fallback\": {\n\t\t\t\"checks\": [\n\t\t\t\t\"Berichten Sie über die Benutzerfreundlichkeit einer Seite.\",\n\t\t\t\t\"Helfen Sie bei der Analyse der Webseitengeschwindigkeit.\",\n\t\t\t\t\"Geben Sie Verbesserungsvorschläge für die Seite.\"\n\t\t\t],\n\t\t\t\"title\": \"Ein PageSpeed-Monitor wird verwendet, um:\",\n\t\t\t\"actionButton\": \"Lassen Sie uns Ihren ersten PageSpeed-Monitor erstellen!\"\n\t\t}\n\t},\n\t\"uptimeMonitor\": {\n\t\t\"fallback\": {\n\t\t\t\"checks\": [\n\t\t\t\t\"Prüfen Sie, ob Websites oder Server online und reaktionsfähig sind.\",\n\t\t\t\t\"Benachrichtigen Sie Ihre Teams über Ausfallzeiten oder Leistungsprobleme.\",\n\t\t\t\t\"Überwachen Sie HTTP-Endpunkte, Pings, Container und Ports.\",\n\t\t\t\t\"Verfolgen Sie historische Verfügbarkeits- und Zuverlässigkeitstrends.\"\n\t\t\t],\n\t\t\t\"title\": \"Ein Uptime-Monitor wird verwendet, um:\",\n\t\t\t\"actionButton\": \"Lassen Sie uns Ihren ersten Uptime-Monitor erstellen!\"\n\t\t}\n\t},\n\t\"editUserPage\": {\n\t\t\"form\": {\n\t\t\t\"email\": \"E-Mail\",\n\t\t\t\"firstName\": \"Vorname\",\n\t\t\t\"lastName\": \"Nachname\",\n\t\t\t\"role\": \"Rollen\",\n\t\t\t\"save\": \"Speichern\"\n\t\t},\n\t\t\"table\": {\n\t\t\t\"actionHeader\": \"Aktion\",\n\t\t\t\"roleHeader\": \"Rolle\"\n\t\t},\n\t\t\"title\": \"Benutzer bearbeiten\",\n\t\t\"toast\": {\n\t\t\t\"successUserUpdate\": \"Benutzer erfolgreich aktualisiert\",\n\t\t\t\"validationErrors\": \"Validierungsfehler\"\n\t\t}\n\t},\n\t\"incidentsPageActionResolveMonitor\": \"Monitor-Vorfälle beheben\",\n\t\"incidentsPageActionResolveAll\": \"Alle Vorfälle lösen\",\n\t\"matchMethodOptions\": {\n\t\t\"equal\": \"Gleich\",\n\t\t\"equalPlaceholder\": \"Erfolg\",\n\t\t\"include\": \"Enthält\",\n\t\t\"includePlaceholder\": \"OK\",\n\t\t\"regex\": \"Regex\",\n\t\t\"regexPlaceholder\": \"^(success|ok)$\",\n\t\t\"text\": \"Übereinstummungsmethode\"\n\t},\n\t\"monitorType\": {\n\t\t\"docker\": {\n\t\t\t\"label\": \"Container Name/ID\",\n\t\t\t\"namePlaceholder\": \"Mein Container\",\n\t\t\t\"placeholder\": \"Meine-App\"\n\t\t},\n\t\t\"http\": {\n\t\t\t\"label\": \"Zu überwachende URL\",\n\t\t\t\"namePlaceholder\": \"Google\",\n\t\t\t\"placeholder\": \"google.de\"\n\t\t},\n\t\t\"ping\": {\n\t\t\t\"label\": \"Zu überwachende IP-Adresse\",\n\t\t\t\"namePlaceholder\": \"Google\",\n\t\t\t\"placeholder\": \"1.1.1.1\"\n\t\t},\n\t\t\"port\": {\n\t\t\t\"label\": \"Zu überwachende URL\",\n\t\t\t\"namePlaceholder\": \"localhost:5173\",\n\t\t\t\"placeholder\": \"localhost\"\n\t\t},\n\t\t\"game\": {\n\t\t\t\"label\": \"Zu überwachende URL\",\n\t\t\t\"namePlaceholder\": \"localhost:5173\",\n\t\t\t\"placeholder\": \"localhost\"\n\t\t}\n\t},\n\t\"uptimeAdvancedMatching\": {\n\t\t\"jsonPath\": \"JSON Pfad\"\n\t},\n\t\"bytesPerSecond\": \"Bytes pro Sekunde\",\n\t\"bytesReceived\": \"Empfangene Bytes\",\n\t\"bytesSent\": \"Gesendete Bytes\",\n\t\"chooseGame\": \"Spiel auswählen\",\n\t\"createMonitorPage\": {\n\t\t\"incidentConfigDescription\": \"Mithilfe eines gleitenden Fensters wird ermittelt, wann ein Monitor ausfällt. Der Status eines Monitors ändert sich nur, wenn der Prozentsatz der Prüfungen im gleitenden Fenster den angegebenen Wert erreicht.\",\n\t\t\"incidentConfigStatusWindowLabel\": \"Wie viele Prüfungen sollen im gleitenden Fenster ausgeführt werden?\",\n\t\t\"incidentConfigStatusWindowThresholdLabel\": \"Wie viel Prozent der Prüfungen im gleitenden Fenster sollen fehlschlagen/erfolgreich sein, bevor sich der Status ändert?\",\n\t\t\"incidentConfigTitle\": \"Vorfälle\",\n\t\t\"incidentConfigDescriptionV2\": \"Anzahl der aufeinanderfolgenden Prüfungen, die zum Ändern des Monitorstatus erforderlich sind. Maximal 25\",\n\t\t\"incidentConfigStatusCheckNumber\": \"Anzahl der Prüfungen bevor sich er Status ändert\",\n\t\t\"intervalTitle\": \"Prüfintervall\",\n\t\t\"intervalDescription\": \"Wie oft soll die Überwachung geprüft werden.\"\n\t},\n\t\"dataRate\": \"Datenrate\",\n\t\"dataReceived\": \"Empfangene Daten\",\n\t\"dataSent\": \"Gesendete Daten\",\n\t\"details\": \"Details\",\n\t\"drops\": \"verloren\",\n\t\"errors\": \"Fehler\",\n\t\"errorsIn\": \"Fehler eingehend\",\n\t\"errorsOut\": \"Fehler ausgehend\",\n\t\"gameServerMonitoring\": \"Spiele Server Überwachung\",\n\t\"gameServerMonitoringDescription\": \"Prüfen ob der Spiele-Server läuft oder nicht\",\n\t\"network\": \"Netzwerk\",\n\t\"networkDrops\": \"Netzwerkabbrüche\",\n\t\"networkErrors\": \"Netzwerkfehler\",\n\t\"networkInterface\": \"Netzwerkschnittstelle\",\n\t\"noNetworkStatsAvailable\": \"Keine Netzwerkstatistiken verfügbar.\",\n\t\"packetsPerSecond\": \"Pakete pro Sekunde\",\n\t\"packetsReceived\": \"Empfangene Pakete\",\n\t\"packetsReceivedRate\": \"Rate empfangener Pakete\",\n\t\"packetsSent\": \"Gesendete Pakete\",\n\t\"rate\": \"Rate\",\n\t\"selectInterface\": \"Schnittstelle auswählen\",\n\t\"v1\": {\n\t\t\"infrastructure\": {\n\t\t\t\"disk_selection_title\": \"Festplattenauswahl\",\n\t\t\t\"disk_selection_info\": \"Momentan wurde keine Festplatte erkannt.\",\n\t\t\t\"disk_selection_description\": \"Wählen Sie die spezifischen Festplatten aus, die Sie überwachen möchten.\"\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "client/src/locales/en.json",
    "content": "{\n\t\"common\": {\n\t\t\"auth\": {\n\t\t\t\"roles\": {\n\t\t\t\t\"admin\": \"Admin\",\n\t\t\t\t\"demo\": \"Demo\",\n\t\t\t\t\"superadmin\": \"Super admin\",\n\t\t\t\t\"user\": \"User\"\n\t\t\t}\n\t\t},\n\t\t\"alerts\": {\n\t\t\t\"pageSpeedApiKey\": {\n\t\t\t\t\"content\": \"Warning: You haven't added a Google PageSpeed API key yet. Visit <settingsLink>Settings</settingsLink> to add one. Without it, the PageSpeed monitor won't function.\"\n\t\t\t}\n\t\t},\n\t\t\"appName\": \"Checkmate\",\n\t\t\"breadcrumbs\": {\n\t\t\t\"details\": \"Details\",\n\t\t\t\"home\": \"Home\"\n\t\t},\n\t\t\"buttons\": {\n\t\t\t\"addMember\": \"Add member\",\n\t\t\t\"cancel\": \"Cancel\",\n\t\t\t\"close\": \"Close\",\n\t\t\t\"configure\": \"Configure\",\n\t\t\t\"confirm\": \"Confirm\",\n\t\t\t\"create\": \"Create\",\n\t\t\t\"delete\": \"Delete\",\n\t\t\t\"generateToken\": \"Generate token\",\n\t\t\t\"incidents\": \"Incidents\",\n\t\t\t\"inviteMember\": \"Invite member\",\n\t\t\t\"pause\": \"Pause\",\n\t\t\t\"resume\": \"Resume\",\n\t\t\t\"save\": \"Save\",\n\t\t\t\"sendInvite\": \"Send invite\",\n\t\t\t\"test\": \"Test\",\n\t\t\t\"testNotifications\": \"Test notifications\",\n\t\t\t\"toggleTheme\": \"Toggles light & dark\",\n\t\t\t\"flushQueue\": \"Flush queue\",\n\t\t\t\"notFound\": \"Go to the main dashboard\",\n\t\t\t\"resetPassword\": \"Reset password\",\n\t\t\t\"reset\": \"Reset\",\n\t\t\t\"clear\": \"Clear\",\n\t\t\t\"addDemo\": \"Add demo monitors\",\n\t\t\t\"removeMonitors\": \"Remove monitors\",\n\t\t\t\"sendTestEmail\": \"Send test email\",\n\t\t\t\"exportToJSON\": \"Export to JSON\",\n\t\t\t\"importFromJSON\": \"Import from JSON\",\n\t\t\t\"clearFilters\": \"Clear filters\",\n\t\t\t\"removeUser\": \"Remove user\"\n\t\t},\n\t\t\"charts\": {\n\t\t\t\"labels\": {\n\t\t\t\t\"averageResponseTime\": \"Average response time\",\n\t\t\t\t\"downtime\": \"Downtime\",\n\t\t\t\t\"high\": \"High\",\n\t\t\t\t\"low\": \"Low\",\n\t\t\t\t\"uptime\": \"Uptime\"\n\t\t\t},\n\t\t\t\"histogram\": {\n\t\t\t\t\"avg\": \"Avg: {{value}} ms\",\n\t\t\t\t\"max\": \"Max: {{value}} ms\"\n\t\t\t}\n\t\t},\n\t\t\"dialogs\": {\n\t\t\t\"delete\": {\n\t\t\t\t\"description\": \"This action cannot be undone.\",\n\t\t\t\t\"title\": \"Are you sure you want to delete this?\"\n\t\t\t}\n\t\t},\n\t\t\"labels\": {\n\t\t\t\"active\": \"Active\",\n\t\t\t\"paused\": \"paused\",\n\t\t\t\"na\": \"N/A\",\n\t\t\t\"resolved\": \"Resolved\",\n\t\t\t\"responseTime\": \"Response time\"\n\t\t},\n\t\t\"form\": {\n\t\t\t\"role\": {\n\t\t\t\t\"option\": {\n\t\t\t\t\t\"role\": {\n\t\t\t\t\t\t\"label\": \"Roles\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"name\": {\n\t\t\t\t\"option\": {\n\t\t\t\t\t\"firstName\": {\n\t\t\t\t\t\t\"label\": \"First name\",\n\t\t\t\t\t\t\"placeholder\": \"Enter your first name\"\n\t\t\t\t\t},\n\t\t\t\t\t\"lastName\": {\n\t\t\t\t\t\t\"label\": \"Last name\",\n\t\t\t\t\t\t\"placeholder\": \"Enter your last name\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"email\": {\n\t\t\t\t\"option\": {\n\t\t\t\t\t\"email\": {\n\t\t\t\t\t\t\"label\": \"Email\",\n\t\t\t\t\t\t\"placeholder\": \"you@example.com\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"table\": {\n\t\t\t\"empty\": \"Nothing here\",\n\t\t\t\"headers\": {\n\t\t\t\t\"actions\": \"Actions\",\n\t\t\t\t\"dateTime\": \"Date & time\",\n\t\t\t\t\"message\": \"Message\",\n\t\t\t\t\"monitor\": \"Monitor\",\n\t\t\t\t\"monitorId\": \"Monitor ID\",\n\t\t\t\t\"name\": \"Name\",\n\t\t\t\t\"status\": \"Status\",\n\t\t\t\t\"type\": \"Type\",\n\t\t\t\t\"url\": \"Url\",\n\t\t\t\t\"interval\": \"Interval\",\n\t\t\t\t\"active\": \"Active\",\n\t\t\t\t\"responseTime\": \"Response time\"\n\t\t\t}\n\t\t}\n\t},\n\t\"components\": {\n\t\t\"imageUpload\": {\n\t\t\t\"clickToUpload\": \"Click to upload\",\n\t\t\t\"dragAndDrop\": \"or drag and drop\",\n\t\t\t\"supportedFormats\": \"Supported formats\",\n\t\t\t\"maxSize\": \"Max size\",\n\t\t\t\"orDragAndDrop\": \"or drag and drop\",\n\t\t\t\"errors\": {\n\t\t\t\t\"invalidFileSize\": \"File size is too large!\",\n\t\t\t\t\"invalidFileFormat\": \"Unsupported file format!\"\n\t\t\t}\n\t\t},\n\t\t\"headerStatusPageControls\": {\n\t\t\t\"publicLink\": \"Public link\"\n\t\t},\n\t\t\"headerTimeRange\": {\n\t\t\t\"labels\": {\n\t\t\t\t\"day\": \"Day\",\n\t\t\t\t\"month\": \"Month\",\n\t\t\t\t\"recent\": \"Recent\",\n\t\t\t\t\"week\": \"Week\"\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\t\"recent\": \"Showing statistics for past 2 hours.\",\n\t\t\t\t\"day\": \"Showing statistics for past 24 hours.\",\n\t\t\t\t\"week\": \"Showing statistics for past 7 days.\",\n\t\t\t\t\"month\": \"Showing statistics for past 30 days.\"\n\t\t\t}\n\t\t},\n\t\t\"offlineBanner\": {\n\t\t\t\"serverUnreachable\": \"Unable to reach server\",\n\t\t\t\"retry\": \"Retry\",\n\t\t\t\"retrying\": \"Retrying...\",\n\t\t\t\"reconnected\": \"Connection restored\"\n\t\t},\n\t\t\"sidebar\": {\n\t\t\t\"menu\": {\n\t\t\t\t\"uptime\": \"Uptime\",\n\t\t\t\t\"pagespeed\": \"Pagespeed\",\n\t\t\t\t\"infrastructure\": \"Infrastructure\",\n\t\t\t\t\"notifications\": \"Notifications\",\n\t\t\t\t\"checks\": \"Checks\",\n\t\t\t\t\"incidents\": \"Incidents\",\n\t\t\t\t\"statusPages\": \"Status pages\",\n\t\t\t\t\"maintenance\": \"Maintenance\",\n\t\t\t\t\"logs\": \"Logs\",\n\t\t\t\t\"settings\": \"Settings\"\n\t\t\t},\n\t\t\t\"bottomMenu\": {\n\t\t\t\t\"support\": \"Support\",\n\t\t\t\t\"discussions\": \"Discussions\",\n\t\t\t\t\"docs\": \"Docs\",\n\t\t\t\t\"changelog\": \"Changelog\"\n\t\t\t},\n\t\t\t\"accountMenu\": {\n\t\t\t\t\"profile\": \"Profile\",\n\t\t\t\t\"password\": \"Password\",\n\t\t\t\t\"team\": \"Team\"\n\t\t\t},\n\t\t\t\"starPrompt\": {\n\t\t\t\t\"title\": \"Star Checkmate\",\n\t\t\t\t\"description\": \"See the latest releases and help grow the community on GitHub\"\n\t\t\t},\n\t\t\t\"authFooter\": {\n\t\t\t\t\"navControls\": \"Controls\",\n\t\t\t\t\"logOut\": \"Log out\",\n\t\t\t\t\"roles\": {\n\t\t\t\t\t\"superAdmin\": \"Super admin\",\n\t\t\t\t\t\"admin\": \"Admin\",\n\t\t\t\t\t\"user\": \"User\",\n\t\t\t\t\t\"demoUser\": \"Demo user\"\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"starPrompt\": {\n\t\t\t\"title\": \"Star Checkmate\",\n\t\t\t\"description\": \"See the latest releases and help grow the community on GitHub\"\n\t\t}\n\t},\n\t\"pages\": {\n\t\t\"notFound\": {\n\t\t\t\"title\": \"Oh no!  You dropped your sushi!\",\n\t\t\t\"subtitle\": \"Either the URL doesn’t exist, or you don’t have access to it.\"\n\t\t},\n\t\t\"account\": {\n\t\t\t\"tabs\": {\n\t\t\t\t\"profile\": \"Profile\",\n\t\t\t\t\"password\": \"Password\",\n\t\t\t\t\"team\": \"Team\"\n\t\t\t},\n\t\t\t\"form\": {\n\t\t\t\t\"name\": {\n\t\t\t\t\t\"title\": \"Name\",\n\t\t\t\t\t\"description\": \"Update your personal information\"\n\t\t\t\t},\n\t\t\t\t\"photo\": {\n\t\t\t\t\t\"title\": \"Profile photo\",\n\t\t\t\t\t\"description\": \"Upload a profile picture\"\n\t\t\t\t},\n\t\t\t\t\"currentPassword\": {\n\t\t\t\t\t\"title\": \"Current password\",\n\t\t\t\t\t\"description\": \"Enter your current password to verify your identity\",\n\t\t\t\t\t\"option\": {\n\t\t\t\t\t\t\"label\": \"Current password\",\n\t\t\t\t\t\t\"placeholder\": \"Enter current password\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"newPassword\": {\n\t\t\t\t\t\"title\": \"New password\",\n\t\t\t\t\t\"description\": \"Choose a strong password with at least 8 characters\",\n\t\t\t\t\t\"option\": {\n\t\t\t\t\t\t\"newPassword\": {\n\t\t\t\t\t\t\t\"label\": \"New password\",\n\t\t\t\t\t\t\t\"placeholder\": \"Enter new password\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"confirm\": {\n\t\t\t\t\t\t\t\"label\": \"Confirm password\",\n\t\t\t\t\t\t\t\"placeholder\": \"Confirm new password\"\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"deleteAccount\": {\n\t\t\t\t\t\"title\": \"Delete account\",\n\t\t\t\t\t\"description\": \"This action is permanent and cannot be undone\"\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"team\": {\n\t\t\t\t\"filter\": {\n\t\t\t\t\t\"placeholder\": \"Filter by role\",\n\t\t\t\t\t\"all\": \"All roles\",\n\t\t\t\t\t\"admin\": \"Admin\",\n\t\t\t\t\t\"member\": \"Member\"\n\t\t\t\t},\n\t\t\t\t\"table\": {\n\t\t\t\t\t\"headers\": {\n\t\t\t\t\t\t\"email\": \"Email\",\n\t\t\t\t\t\t\"role\": \"Role\",\n\t\t\t\t\t\t\"created\": \"Created at\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"addMember\": {\n\t\t\t\t\t\"title\": \"Register new team member\",\n\t\t\t\t\t\"description\": \"Create a new user account. Share credentials securely after creation.\"\n\t\t\t\t},\n\t\t\t\t\"invite\": {\n\t\t\t\t\t\"title\": \"Invite team member\",\n\t\t\t\t\t\"description\": \"Send an invitation to join your team\",\n\t\t\t\t\t\"email\": {\n\t\t\t\t\t\t\"label\": \"Email address\",\n\t\t\t\t\t\t\"placeholder\": \"Enter email address\"\n\t\t\t\t\t},\n\t\t\t\t\t\"role\": {\n\t\t\t\t\t\t\"label\": \"Role\",\n\t\t\t\t\t\t\"placeholder\": \"Select a role\"\n\t\t\t\t\t},\n\t\t\t\t\t\"linkLabel\": \"Invite link\"\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"auth\": {\n\t\t\t\"common\": {\n\t\t\t\t\"passwordRules\": {\n\t\t\t\t\t\"length\": {\n\t\t\t\t\t\t\"beginning\": \"Must be at least\",\n\t\t\t\t\t\t\"highlighted\": \"8 characters long\"\n\t\t\t\t\t},\n\t\t\t\t\t\"lowercase\": {\n\t\t\t\t\t\t\"beginning\": \"Must contain at least\",\n\t\t\t\t\t\t\"highlighted\": \"one lower character\"\n\t\t\t\t\t},\n\t\t\t\t\t\"match\": {\n\t\t\t\t\t\t\"beginning\": \"Passwords\",\n\t\t\t\t\t\t\"highlighted\": \"must match\"\n\t\t\t\t\t},\n\t\t\t\t\t\"number\": {\n\t\t\t\t\t\t\"beginning\": \"Must contain at least\",\n\t\t\t\t\t\t\"highlighted\": \"one number\"\n\t\t\t\t\t},\n\t\t\t\t\t\"special\": {\n\t\t\t\t\t\t\"beginning\": \"Must contain at least\",\n\t\t\t\t\t\t\"highlighted\": \"one special character (!?@#$%^&*()-_=+[]{}|;:'\\\",./\\\\~`)\"\n\t\t\t\t\t},\n\t\t\t\t\t\"uppercase\": {\n\t\t\t\t\t\t\"beginning\": \"Must contain at least\",\n\t\t\t\t\t\t\"highlighted\": \"one upper character\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"form\": {\n\t\t\t\t\t\"option\": {\n\t\t\t\t\t\t\"email\": {\n\t\t\t\t\t\t\t\"label\": \"Email\",\n\t\t\t\t\t\t\t\"placeholder\": \"me@example.com\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"password\": {\n\t\t\t\t\t\t\t\"label\": \"Password\",\n\t\t\t\t\t\t\t\"placeholder\": \"********\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"confirmPassword\": {\n\t\t\t\t\t\t\t\"label\": \"Confirm password\"\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"login\": {\n\t\t\t\t\"title\": \"Welcome back to Checkmate!\",\n\t\t\t\t\"subtitle\": \"Log in to continue\",\n\t\t\t\t\"submit\": \"Login\",\n\t\t\t\t\"links\": {\n\t\t\t\t\t\"forgotPassword\": {\n\t\t\t\t\t\t\"text\": \"Forgot password?\",\n\t\t\t\t\t\t\"linkText\": \"Reset password\"\n\t\t\t\t\t},\n\t\t\t\t\t\"register\": {\n\t\t\t\t\t\t\"text\": \"Don't have an account?\",\n\t\t\t\t\t\t\"linkText\": \"Register here\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"register\": {\n\t\t\t\t\"title\": \"Welcome back to Checkmate!\",\n\t\t\t\t\"subtitle\": \"Sign up to get started\",\n\t\t\t\t\"submit\": \"Register\"\n\t\t\t},\n\t\t\t\"forgotPassword\": {\n\t\t\t\t\"title\": \"Forgot your password?\",\n\t\t\t\t\"subtitle\": \"No worries, we'll send you reset instructions.\",\n\t\t\t\t\"submit\": \"Request recovery\",\n\t\t\t\t\"links\": {\n\t\t\t\t\t\"login\": {\n\t\t\t\t\t\t\"text\": \"Go back to\",\n\t\t\t\t\t\t\"linkText\": \"login\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"setNewPassword\": {\n\t\t\t\t\"title\": \"Reset your password\",\n\t\t\t\t\"subtitle\": \"Your new password must be different from previously used passwords.\"\n\t\t\t}\n\t\t},\n\t\t\"checks\": {\n\t\t\t\"selects\": {\n\t\t\t\t\"monitor\": {\n\t\t\t\t\t\"all\": \"All monitors\"\n\t\t\t\t},\n\t\t\t\t\"status\": {\n\t\t\t\t\t\"all\": \"All\",\n\t\t\t\t\t\"down\": \"Down\",\n\t\t\t\t\t\"up\": \"Up\"\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"table\": {\n\t\t\t\t\"empty\": \"No down checks in this time range\",\n\t\t\t\t\"headers\": {\n\t\t\t\t\t\"statusCode\": \"Status code\",\n\t\t\t\t\t\"location\": \"Location\"\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"common\": {\n\t\t\t\"monitors\": {\n\t\t\t\t\"actions\": {\n\t\t\t\t\t\"configure\": \"Configure\",\n\t\t\t\t\t\"delete\": \"Delete\",\n\t\t\t\t\t\"generateToken\": \"Generate token\",\n\t\t\t\t\t\"details\": \"Details\",\n\t\t\t\t\t\"incidents\": \"Incidents\",\n\t\t\t\t\t\"inviteMember\": \"Invite member\",\n\t\t\t\t\t\"openSite\": \"Open site\",\n\t\t\t\t\t\"pause\": \"Pause\",\n\t\t\t\t\t\"resume\": \"Resume\"\n\t\t\t\t},\n\t\t\t\t\"statBoxes\": {\n\t\t\t\t\t\"activeFor\": \"Active for\",\n\t\t\t\t\t\"certificateExpiry\": \"Certificate expiry\",\n\t\t\t\t\t\"lastCheck\": \"Last check\",\n\t\t\t\t\t\"lastResponseTime\": \"Last response time\"\n\t\t\t\t},\n\t\t\t\t\"status\": {\n\t\t\t\t\t\"down\": \"down\",\n\t\t\t\t\t\"breached\": \"threshold exceeded\",\n\t\t\t\t\t\"initializing\": \"initializing\",\n\t\t\t\t\t\"maintenance\": \"maintenance\",\n\t\t\t\t\t\"paused\": \"paused\",\n\t\t\t\t\t\"total\": \"total\",\n\t\t\t\t\t\"up\": \"up\"\n\t\t\t\t},\n\t\t\t\t\"monitorTypes\": {\n\t\t\t\t\t\"optionDocker\": \"Docker\",\n\t\t\t\t\t\"optionGame\": \"Game\",\n\t\t\t\t\t\"optionHttp\": \"HTTP(S)\",\n\t\t\t\t\t\"optionPing\": \"Ping\",\n\t\t\t\t\t\"optionPort\": \"Port\",\n\t\t\t\t\t\"optionPagespeed\": \"PageSpeed\",\n\t\t\t\t\t\"optionHardware\": \"Infrastructure\",\n\t\t\t\t\t\"optionGrpc\": \"gRPC\",\n\t\t\t\t\t\"optionWebSocket\": \"WebSocket\"\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"createMonitor\": {\n\t\t\t\"form\": {\n\t\t\t\t\"advanced\": {\n\t\t\t\t\t\"description\": \"Optional settings for advanced use cases\",\n\t\t\t\t\t\"option\": {\n\t\t\t\t\t\t\"advancedMatching\": {\n\t\t\t\t\t\t\t\"label\": \"Use advanced matching\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"expectedValue\": {\n\t\t\t\t\t\t\t\"label\": \"Expected value\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"jsonPath\": {\n\t\t\t\t\t\t\t\"description\": \"This expression will be evaluated against the response JSON data and the result will be used to match against the expected value. See <jmesLink>jmespath.org</jmesLink> for query language documentation.\",\n\t\t\t\t\t\t\t\"label\": \"JSONPath expression\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"matchMethod\": {\n\t\t\t\t\t\t\t\"label\": \"Match method\",\n\t\t\t\t\t\t\t\"equal\": \"Equal\",\n\t\t\t\t\t\t\t\"include\": \"Include\",\n\t\t\t\t\t\t\t\"regex\": \"Regex\"\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"title\": \"Advanced settings\"\n\t\t\t\t},\n\t\t\t\t\"frequency\": {\n\t\t\t\t\t\"description\": \"How often do you want to check the status of this monitor?\",\n\t\t\t\t\t\"option\": {\n\t\t\t\t\t\t\"frequency\": {\n\t\t\t\t\t\t\t\"label\": \"Check frequency\",\n\t\t\t\t\t\t\t\"value\": {\n\t\t\t\t\t\t\t\t\"fifteenMinutes\": \"15 minutes\",\n\t\t\t\t\t\t\t\t\"fifteenSeconds\": \"15 seconds\",\n\t\t\t\t\t\t\t\t\"fiveMinutes\": \"5 minutes\",\n\t\t\t\t\t\t\t\t\"fourMinutes\": \"4 minutes\",\n\t\t\t\t\t\t\t\t\"oneMinute\": \"1 minute\",\n\t\t\t\t\t\t\t\t\"tenMinutes\": \"10 minutes\",\n\t\t\t\t\t\t\t\t\"thirtyMinutes\": \"30 minutes\",\n\t\t\t\t\t\t\t\t\"thirtySeconds\": \"30 seconds\",\n\t\t\t\t\t\t\t\t\"threeMinutes\": \"3 minutes\",\n\t\t\t\t\t\t\t\t\"twoMinutes\": \"2 minutes\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"title\": \"Check frequency\"\n\t\t\t\t},\n\t\t\t\t\"general\": {\n\t\t\t\t\t\"option\": {\n\t\t\t\t\t\t\"container\": {\n\t\t\t\t\t\t\t\"label\": \"Container name/ID\",\n\t\t\t\t\t\t\t\"placeholder\": \"my-app or abcd1234\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"host\": {\n\t\t\t\t\t\t\t\"label\": \"Host\",\n\t\t\t\t\t\t\t\"placeholder\": \"192.168.1.100 or example.com\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"name\": {\n\t\t\t\t\t\t\t\"label\": \"Display name\",\n\t\t\t\t\t\t\t\"placeholder\": \"e.g. My Website\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"secret\": {\n\t\t\t\t\t\t\t\"label\": \"Authorization secret\",\n\t\t\t\t\t\t\t\"placeholder\": \"Enter your secret key\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"url\": {\n\t\t\t\t\t\t\t\"label\": \"URL\",\n\t\t\t\t\t\t\t\"placeholder\": \"https://www.google.com\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"game\": {\n\t\t\t\t\t\t\t\"label\": \"Choose game\",\n\t\t\t\t\t\t\t\"placeholder\": \"Select a game\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"port\": {\n\t\t\t\t\t\t\t\"label\": \"Port to monitor\",\n\t\t\t\t\t\t\t\"placeholder\": 80\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"grpcServiceName\": {\n\t\t\t\t\t\t\t\"label\": \"Service name\",\n\t\t\t\t\t\t\t\"placeholder\": \"e.g. my.service.v1 (leave empty for overall health)\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"wsUrl\": {\n\t\t\t\t\t\t\t\"label\": \"WebSocket URL\",\n\t\t\t\t\t\t\t\"placeholder\": \"wss://example.com/socket\"\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"title\": \"General settings\",\n\t\t\t\t\t\"description\": {\n\t\t\t\t\t\t\"http\": \"Enter the URL or IP to monitor (e.g., https://example.com/ or 192.168.1.100) and add a clear display name that appears on the dashboard.\",\n\t\t\t\t\t\t\"ping\": \"Enter the IP address or hostname to ping (e.g., 192.168.1.100 or example.com) and add a clear display name that appears on the dashboard.\",\n\t\t\t\t\t\t\"port\": \"Enter the URL or IP of the server, the port number and a clear display name that appears on the dashboard.\",\n\t\t\t\t\t\t\"docker\": \"Enter the Docker container name or ID. You can use either the container name (e.g., my-app) or the container ID (full 64-char ID or short ID).\",\n\t\t\t\t\t\t\"game\": \"Enter the IP address or hostname and the port number to ping (e.g., 192.168.1.100 or example.com) and choose game type.\",\n\t\t\t\t\t\t\"pagespeed\": \"Track page load performance, Core Web Vitals, and optimization scores for your website.\",\n\t\t\t\t\t\t\"grpc\": \"Enter the hostname and port of the gRPC server, optionally specify a service name for the health check, and add a display name.\",\n\t\t\t\t\t\t\"websocket\": \"Enter the WebSocket URL to monitor (e.g., wss://example.com/socket) and add a display name.\",\n\t\t\t\t\t\t\"hardware\": \"Monitor CPU, memory, disk usage, and temperature for your infrastructure.\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"ignoreTls\": {\n\t\t\t\t\t\"description\": \"Configure TLS/SSL certificate validation for HTTPS connections.\",\n\t\t\t\t\t\"option\": {\n\t\t\t\t\t\t\"tls\": {\n\t\t\t\t\t\t\t\"label\": \"Ignore TLS/SSL errors\"\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"title\": \"TLS/SSL settings\"\n\t\t\t\t},\n\t\t\t\t\"incidents\": {\n\t\t\t\t\t\"description\": \"A sliding window is used to determine when a monitor goes down. The status of a monitor will only change when the percentage of checks in the sliding window meet the specified value.\",\n\t\t\t\t\t\"option\": {\n\t\t\t\t\t\t\"checks\": {\n\t\t\t\t\t\t\t\"label\": \"Number of checks in sliding window\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"percentage\": {\n\t\t\t\t\t\t\t\"label\": \"What percentage of checks in the sliding window fail/succeed before monitor status changes?\"\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"title\": \"Incidents\"\n\t\t\t\t},\n\t\t\t\t\"notifications\": {\n\t\t\t\t\t\"description\": \"Select the notification channels you want to use\",\n\t\t\t\t\t\"title\": \"Notifications\"\n\t\t\t\t},\n\t\t\t\t\"type\": {\n\t\t\t\t\t\"description\": \"Select the type of check to perform\",\n\t\t\t\t\t\"optionDockerDescription\": \"Use Docker to monitor if a container is running.\",\n\t\t\t\t\t\"optionGameDescription\": \"Monitor if a specific game server is online.\",\n\t\t\t\t\t\"optionGrpcDescription\": \"Monitor gRPC services using the standard Health Checking Protocol.\",\n\t\t\t\t\t\"optionWebSocketDescription\": \"Monitor WebSocket endpoints for connection health and response time.\",\n\t\t\t\t\t\"optionHttpDescription\": \"Use HTTP(S) to monitor your website or API endpoint.\",\n\t\t\t\t\t\"optionPingDescription\": \"Use ICMP Ping to monitor if a server is online.\",\n\t\t\t\t\t\"optionPortDescription\": \"Monitor if a specific port on a server is open.\",\n\t\t\t\t\t\"title\": \"Type\"\n\t\t\t\t},\n\t\t\t\t\"thresholds\": {\n\t\t\t\t\t\"title\": \"Alert thresholds\",\n\t\t\t\t\t\"description\": \"Define the thresholds at which alerts should be triggered for this hardware monitor.\",\n\t\t\t\t\t\"option\": {\n\t\t\t\t\t\t\"cpuThreshold\": {\n\t\t\t\t\t\t\t\"label\": \"CPU alert threshold (%)\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"memoryThreshold\": {\n\t\t\t\t\t\t\t\"label\": \"Memory alert threshold (%)\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"diskThreshold\": {\n\t\t\t\t\t\t\t\"label\": \"Disk alert threshold (%)\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"tempThreshold\": {\n\t\t\t\t\t\t\t\"label\": \"Temperature alert threshold (°C)\"\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"geoChecks\": {\n\t\t\t\t\t\"title\": \"Geo-Distributed Checks\",\n\t\t\t\t\t\"description\": \"Run checks from multiple geographic locations to monitor global availability and performance.\",\n\t\t\t\t\t\"option\": {\n\t\t\t\t\t\t\"enabled\": {\n\t\t\t\t\t\t\t\"label\": \"Enable geo-distributed checks\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"locations\": {\n\t\t\t\t\t\t\t\"label\": \"Locations\",\n\t\t\t\t\t\t\t\"placeholder\": \"Select locations\",\n\t\t\t\t\t\t\t\"options\": {\n\t\t\t\t\t\t\t\t\"EU\": \"Europe\",\n\t\t\t\t\t\t\t\t\"NA\": \"North America\",\n\t\t\t\t\t\t\t\t\"AS\": \"Asia\",\n\t\t\t\t\t\t\t\t\"SA\": \"South America\",\n\t\t\t\t\t\t\t\t\"AF\": \"Africa\",\n\t\t\t\t\t\t\t\t\"OC\": \"Oceania\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"interval\": {\n\t\t\t\t\t\t\t\"label\": \"Check interval\",\n\t\t\t\t\t\t\t\"value\": {\n\t\t\t\t\t\t\t\t\"fiveMinutes\": \"5 minutes\",\n\t\t\t\t\t\t\t\t\"tenMinutes\": \"10 minutes\",\n\t\t\t\t\t\t\t\t\"fifteenMinutes\": \"15 minutes\",\n\t\t\t\t\t\t\t\t\"thirtyMinutes\": \"30 minutes\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"url\": {\n\t\t\t\t\t\"title\": \"Monitor IP/URL on Status Page\",\n\t\t\t\t\t\"description\": \"Display the IP address or URL of monitor on the public Status page. If it's disabled, only the monitor name will be shown to protect sensitive information.\",\n\t\t\t\t\t\"option\": {\n\t\t\t\t\t\t\"showURL\": {\n\t\t\t\t\t\t\t\"label\": \"Display IP/URL on status page\",\n\t\t\t\t\t\t\t\"enabled\": \"Enabled\",\n\t\t\t\t\t\t\t\"disabled\": \"Disabled\"\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"stats\": {\n\t\t\t\t\t\"title\": \"Monitor history\",\n\t\t\t\t\t\"description\": \"Clear all monitoring history and statistics for your team. This action is irreversible.\",\n\t\t\t\t\t\"buttonText\": \"Clear all stats\",\n\t\t\t\t\t\"dialog\": {\n\t\t\t\t\t\t\"title\": \"Clear all monitoring history?\",\n\t\t\t\t\t\t\"description\": \"This will permanently delete all monitoring history, statistics, and check data for your team. This action cannot be undone.\",\n\t\t\t\t\t\t\"confirm\": \"Yes, clear all stats\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"editUser\": {\n\t\t\t\"form\": {\n\t\t\t\t\"roles\": {\n\t\t\t\t\t\"title\": \"Roles\",\n\t\t\t\t\t\"description\": \"Assign roles to the user. Multiple roles can be selected.\"\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"dialog\": {\n\t\t\t\t\"removeUser\": {\n\t\t\t\t\t\"title\": \"Remove user\",\n\t\t\t\t\t\"content\": \"Are you sure you want to remove {{name}} from your team? This action cannot be undone.\"\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"incidents\": {\n\t\t\t\"dialog\": {\n\t\t\t\t\"resolveIncident\": {\n\t\t\t\t\t\"title\": \"Resolve incident\",\n\t\t\t\t\t\"option\": {\n\t\t\t\t\t\t\"comment\": {\n\t\t\t\t\t\t\t\"label\": \"Comment (optional)\",\n\t\t\t\t\t\t\t\"placeholder\": \"Add a comment about the resolution...\"\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"details\": {\n\t\t\t\t\t\"analysis\": \"Incident analysis\",\n\t\t\t\t\t\"comment\": \"Comment:\",\n\t\t\t\t\t\"detailsLabel\": \"Details\",\n\t\t\t\t\t\"downtime\": \"Downtime:\",\n\t\t\t\t\t\"message\": \"Message:\",\n\t\t\t\t\t\"monitor\": \"Monitor:\",\n\t\t\t\t\t\"overview\": \"Overview\",\n\t\t\t\t\t\"resolutionDetails\": \"Resolution details\",\n\t\t\t\t\t\"resolutionType\": \"Type:\",\n\t\t\t\t\t\"resolutionTypes\": {\n\t\t\t\t\t\t\"automatic\": \"Automatic\",\n\t\t\t\t\t\t\"manual\": \"Manual\"\n\t\t\t\t\t},\n\t\t\t\t\t\"resolve\": \"Resolve Incident\",\n\t\t\t\t\t\"resolvedAt\": \"Resolved at:\",\n\t\t\t\t\t\"resolvedBy\": \"Resolved by:\",\n\t\t\t\t\t\"startedAt\": \"Started at:\",\n\t\t\t\t\t\"status\": \"Status:\",\n\t\t\t\t\t\"statusCode\": \"Status code:\",\n\t\t\t\t\t\"timeline\": \"Timeline\",\n\t\t\t\t\t\"title\": \"Incident details\",\n\t\t\t\t\t\"url\": \"URL:\"\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"filters\": {\n\t\t\t\t\"allMonitors\": \"All monitors\",\n\t\t\t\t\"monitor\": \"Monitor\",\n\t\t\t\t\"resolutionType\": \"Resolution type\",\n\t\t\t\t\"resolutionTypes\": {\n\t\t\t\t\t\"manual\": \"Manual\",\n\t\t\t\t\t\"automatic\": \"Automatic\",\n\t\t\t\t\t\"all\": \"All\"\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"summaryCard\": {\n\t\t\t\t\"activeIncidents\": {\n\t\t\t\t\t\"title\": \"Active Incidents\",\n\t\t\t\t\t\"active_zero\": \"No active incidents\",\n\t\t\t\t\t\"active_one\": \"{{count}} active incident\",\n\t\t\t\t\t\"active_other\": \"{{count}} active incidents\"\n\t\t\t\t},\n\t\t\t\t\"incidentStats\": {\n\t\t\t\t\t\"avgResolutionTime\": \"Avg Resolution Time\",\n\t\t\t\t\t\"mostAffectedMonitor\": \"Most Affected Monitor\",\n\t\t\t\t\t\"title\": \"Incident Statistics\",\n\t\t\t\t\t\"totalIncidents\": \"Total Incidents\"\n\t\t\t\t},\n\t\t\t\t\"latestIncidents\": {\n\t\t\t\t\t\"title\": \"Latest Incidents\"\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"table\": {\n\t\t\t\t\"actions\": {\n\t\t\t\t\t\"details\": \"Details\",\n\t\t\t\t\t\"goToMonitor\": \"Go to monitor\",\n\t\t\t\t\t\"resolveManually\": \"Resolve Manually\"\n\t\t\t\t},\n\t\t\t\t\"activeIncidents\": \"Active Incidents\",\n\t\t\t\t\"headers\": {\n\t\t\t\t\t\"endTime\": \"End Time\",\n\t\t\t\t\t\"resolutionType\": \"Resolution Type\",\n\t\t\t\t\t\"startTime\": \"Start Time\",\n\t\t\t\t\t\"statusCode\": \"Status Code\"\n\t\t\t\t},\n\t\t\t\t\"resolvedIncidents\": \"Resolved Incidents\",\n\t\t\t\t\"status\": {\n\t\t\t\t\t\"active\": \"Active\",\n\t\t\t\t\t\"resolved\": \"Resolved\"\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"infrastructure\": {\n\t\t\t\"charts\": {\n\t\t\t\t\"labels\": {\n\t\t\t\t\t\"cpu\": \"CPU usage\",\n\t\t\t\t\t\"disk\": \"Disk usage\",\n\t\t\t\t\t\"memory\": \"Memory usage\",\n\t\t\t\t\t\"netBytesRecv\": \"{{name}} - Bytes Received\",\n\t\t\t\t\t\"netBytesSent\": \"{{name}} - Bytes Sent\",\n\t\t\t\t\t\"temp\": \"Temp\"\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"gauges\": {\n\t\t\t\t\"cpu\": {\n\t\t\t\t\t\"lowerLabel\": \"Max frequency\",\n\t\t\t\t\t\"title\": \"CPU usage\",\n\t\t\t\t\t\"upperLabel\": \"Current frequency\"\n\t\t\t\t},\n\t\t\t\t\"disk\": {\n\t\t\t\t\t\"lowerLabel\": \"Free\",\n\t\t\t\t\t\"title\": \"Disk {{idx}} usage\",\n\t\t\t\t\t\"upperLabel\": \"Used\"\n\t\t\t\t},\n\t\t\t\t\"memory\": {\n\t\t\t\t\t\"lowerLabel\": \"Free\",\n\t\t\t\t\t\"title\": \"Memory usage\",\n\t\t\t\t\t\"upperLabel\": \"Used\"\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"statBoxes\": {\n\t\t\t\t\"avgCpuTemperature\": \"Average CPU Temperature\",\n\t\t\t\t\"cpuFrequency\": \"CPU Frequency\",\n\t\t\t\t\"cpuLogical\": \"CPU (Logical)\",\n\t\t\t\t\"cpuPhysical\": \"CPU (Physical)\",\n\t\t\t\t\"disk\": \"Disk\",\n\t\t\t\t\"memory\": \"Memory\",\n\t\t\t\t\"os\": \"OS\"\n\t\t\t},\n\t\t\t\"table\": {\n\t\t\t\t\"headers\": {\n\t\t\t\t\t\"cpu\": \"CPU\",\n\t\t\t\t\t\"disk\": \"Disk\",\n\t\t\t\t\t\"memory\": \"Memory\"\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"tabs\": {\n\t\t\t\t\"labels\": {\n\t\t\t\t\t\"network\": \"Network\",\n\t\t\t\t\t\"overview\": \"Overview\"\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"fallback\": {\n\t\t\t\t\"actionButton\": \"Create a monitor!\",\n\t\t\t\t\"checks\": [\n\t\t\t\t\t\"Track the performance of your servers\",\n\t\t\t\t\t\"Identify bottlenecks and optimize usage\",\n\t\t\t\t\t\"Ensure reliability with real-time monitoring\"\n\t\t\t\t],\n\t\t\t\t\"title\": \"An infrastructure monitor is used to:\"\n\t\t\t}\n\t\t},\n\t\t\"logs\": {\n\t\t\t\"tabs\": {\n\t\t\t\t\"diagnostics\": \"Diagnostics\",\n\t\t\t\t\"logs\": \"Logs\",\n\t\t\t\t\"queue\": \"Job queue\"\n\t\t\t},\n\t\t\t\"logLevelSelect\": {\n\t\t\t\t\"label\": \"Log level\"\n\t\t\t},\n\t\t\t\"jobQueue\": \"Job queue\",\n\t\t\t\"failedJobs\": \"Failed jobs\",\n\t\t\t\"noLogs\": \"No logs found\",\n\t\t\t\"metrics\": {\n\t\t\t\t\"jobs\": \"Jobs\",\n\t\t\t\t\"activeJobs\": \"Active jobs\",\n\t\t\t\t\"failingJobs\": \"Failing jobs\",\n\t\t\t\t\"totalRuns\": \"Total runs\",\n\t\t\t\t\"totalFailures\": \"Total failures\"\n\t\t\t},\n\t\t\t\"diagnostics\": {\n\t\t\t\t\"stats\": {\n\t\t\t\t\t\"eventLoopDelay\": \"Event loop delay\",\n\t\t\t\t\t\"uptime\": \"Uptime\",\n\t\t\t\t\t\"usedHeapSize\": \"Used heap size\",\n\t\t\t\t\t\"totalHeapSize\": \"Total heap size\",\n\t\t\t\t\t\"osMemoryLimit\": \"OS memory limit\"\n\t\t\t\t},\n\t\t\t\t\"gauges\": {\n\t\t\t\t\t\"heapAllocation\": \"Heap allocaton\",\n\t\t\t\t\t\"heapUsage\": \"Heap usage\",\n\t\t\t\t\t\"heapUtilization\": \"Heap utilization\",\n\t\t\t\t\t\"instantCpuUsage\": \"Instant CPU usage\",\n\t\t\t\t\t\"availableMemoryPercentage\": \"% of available memory\",\n\t\t\t\t\t\"allocatedPercentage\": \"% allocated\",\n\t\t\t\t\t\"usedSPercentage\": \"% of 1s used by CPU\",\n\t\t\t\t\t\"total\": \"Total\",\n\t\t\t\t\t\"used\": \"Used\"\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"table\": {\n\t\t\t\t\"headers\": {\n\t\t\t\t\t\"timestamp\": \"Timestamp\",\n\t\t\t\t\t\"level\": \"Level\",\n\t\t\t\t\t\"service\": \"Service\",\n\t\t\t\t\t\"method\": \"Method\",\n\t\t\t\t\t\"monitorId\": \"Monitor ID\",\n\t\t\t\t\t\"runCount\": \"Run count\",\n\t\t\t\t\t\"failCount\": \"Fail count\",\n\t\t\t\t\t\"lastRunAt\": \"Last run at\",\n\t\t\t\t\t\"lockedAt\": \"Locked at\",\n\t\t\t\t\t\"lastFinishedAt\": \"Last finished at\",\n\t\t\t\t\t\"lastRunTook\": \"Last run took\",\n\t\t\t\t\t\"lastFailedAt\": \"Last failed at\",\n\t\t\t\t\t\"failReason\": \"Fail reason\"\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"maintenanceWindow\": {\n\t\t\t\"fallback\": {\n\t\t\t\t\"actionButton\": \"Create a maintenance window!\",\n\t\t\t\t\"checks\": [\n\t\t\t\t\t\"Mark your maintenance periods\",\n\t\t\t\t\t\"Eliminate any misunderstandings\",\n\t\t\t\t\t\"Stop sending alerts in maintenance windows\"\n\t\t\t\t],\n\t\t\t\t\"title\": \"A maintenance window is used to:\"\n\t\t\t},\n\t\t\t\"table\": {\n\t\t\t\t\"headers\": {\n\t\t\t\t\t\"nextWindow\": \"Next window\",\n\t\t\t\t\t\"repeat\": \"Repeat\"\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"form\": {\n\t\t\t\t\"general\": {\n\t\t\t\t\t\"title\": \"General settings\",\n\t\t\t\t\t\"description\": \"Set a name and repeat option for your maintenance window.\",\n\t\t\t\t\t\"option\": {\n\t\t\t\t\t\t\"name\": {\n\t\t\t\t\t\t\t\"label\": \"Name\",\n\t\t\t\t\t\t\t\"placeholder\": \"e.g. Weekly Maintenance\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"repeat\": {\n\t\t\t\t\t\t\t\"label\": \"Repeat\"\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"startDate\": {\n\t\t\t\t\t\"title\": \"Start date\",\n\t\t\t\t\t\"description\": \"Select the start date for your maintenance window.\",\n\t\t\t\t\t\"option\": {\n\t\t\t\t\t\t\"startDate\": {\n\t\t\t\t\t\t\t\"label\": \"Start date\"\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"startTime\": {\n\t\t\t\t\t\"title\": \"Start time\",\n\t\t\t\t\t\"description\": \"Set the start time and duration for your maintenance window. All values are in UTC\",\n\t\t\t\t\t\"option\": {\n\t\t\t\t\t\t\"duration\": {\n\t\t\t\t\t\t\t\"label\": \"Duration\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"startTime\": {\n\t\t\t\t\t\t\t\"label\": \"Start time\"\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"monitors\": {\n\t\t\t\t\t\t\"title\": \"Monitors\",\n\t\t\t\t\t\t\"description\": \"Monitors that the maintenance window should apply to\",\n\t\t\t\t\t\t\"option\": {\n\t\t\t\t\t\t\t\"addMonitors\": {\n\t\t\t\t\t\t\t\t\"label\": \"Add monitors\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"notifications\": {\n\t\t\t\"fallback\": {\n\t\t\t\t\"actionButton\": \"Create a channel\",\n\t\t\t\t\"checks\": [\n\t\t\t\t\t\"Alert teams about downtime or performance issues\",\n\t\t\t\t\t\"Let engineers know when incidents happen\",\n\t\t\t\t\t\"Keep administrators informed of system changes\"\n\t\t\t\t],\n\t\t\t\t\"title\": \"Notification channles are used to:\"\n\t\t\t},\n\t\t\t\"form\": {\n\t\t\t\t\"accessToken\": {\n\t\t\t\t\t\"optionAccessToken\": \"Access token\",\n\t\t\t\t\t\"placeholder\": \"syt_YWxleF9ob2xsaWRheQ_VmtScmV0U2VjcmV0S2V5_abc123\"\n\t\t\t\t},\n\t\t\t\t\"address\": {\n\t\t\t\t\t\"description\": \"The address where notifications will be sent.\",\n\t\t\t\t\t\"optionAddress\": \"Address\",\n\t\t\t\t\t\"placeholderEmail\": \"example@example.com\",\n\t\t\t\t\t\"placeholderWebhook\": \"https://your-server.com/webhook\",\n\t\t\t\t\t\"title\": \"Address\"\n\t\t\t\t},\n\t\t\t\t\"homeServer\": {\n\t\t\t\t\t\"optionHomeServer\": \"Home server\",\n\t\t\t\t\t\"placeholder\": \"example.com\"\n\t\t\t\t},\n\t\t\t\t\"matrix\": {\n\t\t\t\t\t\"description\": \"Configure your Matrix homeserver connection for notifications.\",\n\t\t\t\t\t\"title\": \"Matrix configuration\"\n\t\t\t\t},\n\t\t\t\t\"notificationName\": {\n\t\t\t\t\t\"description\": \"A descriptive name for the notification channel\",\n\t\t\t\t\t\"optionName\": \"Channel name\",\n\t\t\t\t\t\"placeholder\": \"e.g. Production Alerts\",\n\t\t\t\t\t\"title\": \"Channel name\"\n\t\t\t\t},\n\t\t\t\t\"pagerDuty\": {\n\t\t\t\t\t\"description\": \"Your PagerDuty integration key for receiving alerts.\",\n\t\t\t\t\t\"optionIntegrationKey\": \"Integration key\",\n\t\t\t\t\t\"placeholder\": \"a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6\",\n\t\t\t\t\t\"title\": \"Integration key\"\n\t\t\t\t},\n\t\t\t\t\"roomId\": {\n\t\t\t\t\t\"optionRoomId\": \"Room ID\",\n\t\t\t\t\t\"placeholder\": \"!abcdefg:matrix.org\"\n\t\t\t\t},\n\t\t\t\t\"type\": {\n\t\t\t\t\t\"description\": \"Select the type of notification channel to create.\",\n\t\t\t\t\t\"optionType\": \"Type\",\n\t\t\t\t\t\"title\": \"Channel type\"\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"table\": {\n\t\t\t\t\"headers\": {\n\t\t\t\t\t\"destination\": \"Destination\"\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"pageSpeed\": {\n\t\t\t\"charts\": {\n\t\t\t\t\"common\": {\n\t\t\t\t\t\"cls\": \"Cumulative Layout Shift (CLS)\",\n\t\t\t\t\t\"fcp\": \"First Contentful Paint (FCP)\",\n\t\t\t\t\t\"lcp\": \"Largest Contentful Paint (LCP)\",\n\t\t\t\t\t\"si\": \"Speed Index (SI)\",\n\t\t\t\t\t\"tbt\": \"Total Blocking Time (TBT)\"\n\t\t\t\t},\n\t\t\t\t\"legend\": {\n\t\t\t\t\t\"title\": \"PageSpeed report\",\n\t\t\t\t\t\"weight\": \"Weight\"\n\t\t\t\t},\n\t\t\t\t\"pie\": {\n\t\t\t\t\t\"title\": \"Performance report\"\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"table\": {\n\t\t\t\t\"headers\": {\n\t\t\t\t\t\"pageSpeedScore\": \"PageSpeed score\"\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"fallback\": {\n\t\t\t\t\"actionButton\": \"Create a monitor!\",\n\t\t\t\t\"checks\": [\n\t\t\t\t\t\"Report on the user experience of a page\",\n\t\t\t\t\t\"Help analyze webpage speed\",\n\t\t\t\t\t\"Give suggestions on how the page can be improved\"\n\t\t\t\t],\n\t\t\t\t\"title\": \"A PageSpeed monitor is used to:\"\n\t\t\t}\n\t\t},\n\t\t\"settings\": {\n\t\t\t\"form\": {\n\t\t\t\t\"timezone\": {\n\t\t\t\t\t\"title\": \"Display timezone\",\n\t\t\t\t\t\"description\": \"Select the timezone used to display dates and times throughout the application.\",\n\t\t\t\t\t\"option\": {\n\t\t\t\t\t\t\"timezone\": {\n\t\t\t\t\t\t\t\"label\": \"Display timezone\"\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"ui\": {\n\t\t\t\t\t\"title\": \"Appearance\",\n\t\t\t\t\t\"description\": \"Switch between light and dark mode, change language, or customize chart display type.\",\n\t\t\t\t\t\"option\": {\n\t\t\t\t\t\t\"theme\": {\n\t\t\t\t\t\t\t\"label\": \"Theme mode\",\n\t\t\t\t\t\t\t\"light\": \"Light\",\n\t\t\t\t\t\t\t\"dark\": \"Dark\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"language\": {\n\t\t\t\t\t\t\t\"label\": \"Language\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"chartType\": {\n\t\t\t\t\t\t\t\"label\": \"Chart type\",\n\t\t\t\t\t\t\t\"histogram\": \"Histogram\",\n\t\t\t\t\t\t\t\"heatmap\": \"Heatmap\"\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"pagespeed\": {\n\t\t\t\t\t\"title\": \"Google PageSpeed API key\",\n\t\t\t\t\t\"description\": \"Enter your Google PageSpeed API key to enable Google PageSpeed monitoring. Click Reset to update the key.\",\n\t\t\t\t\t\"option\": {\n\t\t\t\t\t\t\"apiKey\": {\n\t\t\t\t\t\t\t\"label\": \"PageSpeed API key\",\n\t\t\t\t\t\t\t\"labelSet\": \"API key is set. Click Reset to change it.\",\n\t\t\t\t\t\t\t\"placeholder\": \"Enter your Google PageSpeed API key\"\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"url\": {\n\t\t\t\t\t\"title\": \"Monitor IP/URL on Status Page\",\n\t\t\t\t\t\"description\": \"Display the IP address or URL of monitor on the public Status page. If it's disabled, only the monitor name will be shown to protect sensitive information.\",\n\t\t\t\t\t\"option\": {\n\t\t\t\t\t\t\"showURL\": {\n\t\t\t\t\t\t\t\"label\": \"Display IP/URL on status page\",\n\t\t\t\t\t\t\t\"enabled\": \"Enabled\",\n\t\t\t\t\t\t\t\"disabled\": \"Disabled\"\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"stats\": {\n\t\t\t\t\t\"title\": \"Monitor history\",\n\t\t\t\t\t\"description\": \"Clear all monitoring history and statistics for your team. This action is irreversible.\",\n\t\t\t\t\t\"option\": {\n\t\t\t\t\t\t\"clear\": {\n\t\t\t\t\t\t\t\"label\": \"Clear all stats. This is irreversible.\"\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"dialog\": {\n\t\t\t\t\t\t\"title\": \"Clear all monitoring history?\",\n\t\t\t\t\t\t\"description\": \"This cannot be undone\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"retention\": {\n\t\t\t\t\t\"title\": \"Check retention\",\n\t\t\t\t\t\"description\": \"Set how long check data is retained before being automatically cleaned up.\",\n\t\t\t\t\t\"option\": {\n\t\t\t\t\t\t\"days\": {\n\t\t\t\t\t\t\t\"label\": \"Retention period (days)\",\n\t\t\t\t\t\t\t\"unlimited\": \"Unlimited\"\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"thresholds\": {\n\t\t\t\t\t\"title\": \"Global Thresholds\",\n\t\t\t\t\t\"description\": \"Set global CPU, Memory, Disk, and Temperature thresholds for infrastructure monitoring. These apply to all hardware monitors unless overridden.\",\n\t\t\t\t\t\"option\": {\n\t\t\t\t\t\t\"cpu\": {\n\t\t\t\t\t\t\t\"label\": \"CPU Threshold (%)\",\n\t\t\t\t\t\t\t\"placeholder\": \"1 - 100\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"memory\": {\n\t\t\t\t\t\t\t\"label\": \"Memory Threshold (%)\",\n\t\t\t\t\t\t\t\"placeholder\": \"1 - 100\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"disk\": {\n\t\t\t\t\t\t\t\"label\": \"Disk Threshold (%)\",\n\t\t\t\t\t\t\t\"placeholder\": \"1 - 100\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"temperature\": {\n\t\t\t\t\t\t\t\"label\": \"Temperature Threshold (°C)\",\n\t\t\t\t\t\t\t\"placeholder\": \"1 - 150\"\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"email\": {\n\t\t\t\t\t\"title\": \"Email settings\",\n\t\t\t\t\t\"description\": \"Configure the email settings for your system. This is used to send notifications and alerts.\",\n\t\t\t\t\t\"descriptionTransport\": \"This builds an SMTP transport for NodeMailer\",\n\t\t\t\t\t\"descriptionTransportLink\": \"See specifications here\",\n\t\t\t\t\t\"option\": {\n\t\t\t\t\t\t\"host\": {\n\t\t\t\t\t\t\t\"label\": \"Email host - Hostname or IP address to connect to\",\n\t\t\t\t\t\t\t\"placeholder\": \"smtp.gmail.com\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"port\": {\n\t\t\t\t\t\t\t\"label\": \"Email port - Port to connect to\",\n\t\t\t\t\t\t\t\"placeholder\": \"587\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"address\": {\n\t\t\t\t\t\t\t\"label\": \"Email address - Used for authentication\",\n\t\t\t\t\t\t\t\"placeholder\": \"you@example.com\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"user\": {\n\t\t\t\t\t\t\t\"label\": \"Email user - Username for authentication, overrides email address if specified\",\n\t\t\t\t\t\t\t\"placeholder\": \"Leave empty if not required\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"password\": {\n\t\t\t\t\t\t\t\"label\": \"Email password - Password for authentication\",\n\t\t\t\t\t\t\t\"labelSet\": \"Password is set. Click Reset to change it.\",\n\t\t\t\t\t\t\t\"placeholder\": \"Enter your password\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"tlsServername\": {\n\t\t\t\t\t\t\t\"label\": \"TLS Servername - Optional Hostname for TLS Validation when host is an IP\",\n\t\t\t\t\t\t\t\"placeholder\": \"example.com\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"connectionHost\": {\n\t\t\t\t\t\t\t\"label\": \"Email connection host - Hostname to use in the HELO/EHLO greeting\",\n\t\t\t\t\t\t\t\"placeholder\": \"localhost\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"secure\": {\n\t\t\t\t\t\t\t\"label\": \"Use SSL (recommended): Encrypt the connection using SSL/TLS\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"pool\": {\n\t\t\t\t\t\t\t\"label\": \"Enable connection pooling: Reuse existing connections to improve performance\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"ignoreTLS\": {\n\t\t\t\t\t\t\t\"label\": \"Disable STARTTLS: Don't use TLS even if the server supports it\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"requireTLS\": {\n\t\t\t\t\t\t\t\"label\": \"Force STARTTLS: Require TLS upgrade, fail if not supported\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"rejectUnauthorized\": {\n\t\t\t\t\t\t\t\"label\": \"Reject invalid certificates: Reject connections with self-signed or untrusted certificates\"\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"demoMonitors\": {\n\t\t\t\t\t\"title\": \"Demo monitors\",\n\t\t\t\t\t\"description\": \"Add sample monitors for demonstration purposes.\"\n\t\t\t\t},\n\t\t\t\t\"removeMonitors\": {\n\t\t\t\t\t\"title\": \"System reset\",\n\t\t\t\t\t\"description\": \"Remove all monitors from your system.\",\n\t\t\t\t\t\"dialog\": {\n\t\t\t\t\t\t\"title\": \"Remove all monitors?\",\n\t\t\t\t\t\t\"description\": \"This cannot be undone.\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"exportMonitors\": {\n\t\t\t\t\t\"title\": \"Export monitors\"\n\t\t\t\t},\n\t\t\t\t\"importExportMonitors\": {\n\t\t\t\t\t\"title\": \"Import / Export monitors\",\n\t\t\t\t\t\"description\": \"Import or export your monitors data as a JSON file for backup or transfer.\"\n\t\t\t\t},\n\t\t\t\t\"about\": {\n\t\t\t\t\t\"title\": \"About\",\n\t\t\t\t\t\"developedBy\": \"Developed by Bluewave Labs\"\n\t\t\t\t},\n\t\t\t\t\"validation\": {\n\t\t\t\t\t\"errorMessage\": \"Please fix the following validation errors:\"\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"statusPages\": {\n\t\t\t\"deleteSuccess\": \"Status page deleted successfully\",\n\t\t\t\"fallback\": {\n\t\t\t\t\"title\": \"A status page is used to:\",\n\t\t\t\t\"checks\": [\n\t\t\t\t\t\"Communicate system status to users and stakeholders\",\n\t\t\t\t\t\"Display real-time uptime information publicly\",\n\t\t\t\t\t\"Build trust with transparent service monitoring\",\n\t\t\t\t\t\"Reduce support requests during incidents\"\n\t\t\t\t],\n\t\t\t\t\"actionButton\": \"Create a status page!\"\n\t\t\t},\n\t\t\t\"monitorsList\": {\n\t\t\t\t\"chartTypeHeatmap\": \"Heatmap\",\n\t\t\t\t\"chartTypeHistogram\": \"Histogram\",\n\t\t\t\t\"noData\": \"No data available\",\n\t\t\t\t\"infrastructure\": {\n\t\t\t\t\t\"title\": \"Infrastructure\",\n\t\t\t\t\t\"cpu\": \"CPU\",\n\t\t\t\t\t\"memory\": \"RAM\",\n\t\t\t\t\t\"memoryText\": \"Memory\",\n\t\t\t\t\t\"disk\": \"Disk\",\n\t\t\t\t\t\"usage\": \"Usage\",\n\t\t\t\t\t\"used\": \"Used\",\n\t\t\t\t\t\"total\": \"Total\"\n\t\t\t\t},\n\t\t\t\t\"uptime\": {\n\t\t\t\t\t\"title\": \"Uptime\",\n\t\t\t\t\t\"responseTime\": \"Response time\"\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"statusBar\": {\n\t\t\t\t\"allDown\": \"All systems are down\",\n\t\t\t\t\"allUp\": \"All systems operational\",\n\t\t\t\t\"degraded\": \"Some systems are experiencing issues\",\n\t\t\t\t\"unknown\": \"Unable to determine system status\"\n\t\t\t},\n\t\t\t\"table\": {\n\t\t\t\t\"headers\": {\n\t\t\t\t\t\"name\": \"Status page name\",\n\t\t\t\t\t\"url\": \"Public URL\"\n\t\t\t\t},\n\t\t\t\t\"published\": \"Published\",\n\t\t\t\t\"unpublished\": \"Unpublished\"\n\t\t\t},\n\t\t\t\"title\": \"Status pages\",\n\t\t\t\"details\": {\n\t\t\t\t\"empty\": {\n\t\t\t\t\t\"title\": \"There's nothing here yet\",\n\t\t\t\t\t\"addMonitor\": \"Add a monitor to get started\"\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"form\": {\n\t\t\t\t\"access\": {\n\t\t\t\t\t\"title\": \"Access\",\n\t\t\t\t\t\"description\": \"If your status page is ready, you can mark it as published.\",\n\t\t\t\t\t\"option\": {\n\t\t\t\t\t\t\"published\": {\n\t\t\t\t\t\t\t\"name\": \"Published and visible to the public\"\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"basicInfo\": {\n\t\t\t\t\t\"title\": \"Basic information\",\n\t\t\t\t\t\"description\": \"Define company name and the subdomain that your status page points to.\",\n\t\t\t\t\t\"option\": {\n\t\t\t\t\t\t\"name\": {\n\t\t\t\t\t\t\t\"label\": \"Company name\",\n\t\t\t\t\t\t\t\"placeholder\": \"Acme Inc.\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"url\": {\n\t\t\t\t\t\t\t\"label\": \"Your status page address\",\n\t\t\t\t\t\t\t\"placeholder\": \"my-status-page\"\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"monitors\": {\n\t\t\t\t\t\"title\": \"Monitors\",\n\t\t\t\t\t\"description\": \"Select the monitors to display on your status page.\",\n\t\t\t\t\t\"noMonitors\": \"No monitors selected\",\n\t\t\t\t\t\"option\": {\n\t\t\t\t\t\t\"monitors\": {\n\t\t\t\t\t\t\t\"label\": \"Select monitors\",\n\t\t\t\t\t\t\t\"placeholder\": \"Search and select monitors...\"\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"timezone\": {\n\t\t\t\t\t\"title\": \"Timezone\",\n\t\t\t\t\t\"description\": \"Select the timezone that your status page will be displayed in.\",\n\t\t\t\t\t\"option\": {\n\t\t\t\t\t\t\"timezone\": {\n\t\t\t\t\t\t\t\"label\": \"Timezone\",\n\t\t\t\t\t\t\t\"placeholder\": \"Select timezone...\"\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"appearance\": {\n\t\t\t\t\t\"title\": \"Appearance\",\n\t\t\t\t\t\"description\": \"Define the default look and feel of your public status page.\",\n\t\t\t\t\t\"option\": {\n\t\t\t\t\t\t\"logo\": {\n\t\t\t\t\t\t\t\"label\": \"Logo\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"color\": {\n\t\t\t\t\t\t\t\"label\": \"Brand color\"\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"features\": {\n\t\t\t\t\t\"title\": \"Features\",\n\t\t\t\t\t\"description\": \"Configure what information is displayed on your status page.\",\n\t\t\t\t\t\"option\": {\n\t\t\t\t\t\t\"showCharts\": {\n\t\t\t\t\t\t\t\"label\": \"Show response time charts\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"showUptimePercentage\": {\n\t\t\t\t\t\t\t\"label\": \"Show uptime percentage\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"showAdminLoginLink\": {\n\t\t\t\t\t\t\t\"label\": \"Show admin login link\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"showInfrastructure\": {\n\t\t\t\t\t\t\t\"label\": \"Show infrastructure metrics\"\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"uptime\": {\n\t\t\t\"filters\": {\n\t\t\t\t\"search\": {\n\t\t\t\t\t\"placeholder\": \"Search monitors...\"\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"table\": {\n\t\t\t\t\"headers\": {\n\t\t\t\t\t\"responseTime\": \"Response time\"\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"fallback\": {\n\t\t\t\t\"actionButton\": \"Create a monitor!\",\n\t\t\t\t\"checks\": [\n\t\t\t\t\t\"Check if websites or servers are online & responsive\",\n\t\t\t\t\t\"Alert teams about downtime or performance issues\",\n\t\t\t\t\t\"Monitor HTTP endpoints, pings, containers & ports\",\n\t\t\t\t\t\"Track historical uptime and reliability trends\"\n\t\t\t\t],\n\t\t\t\t\"title\": \"An uptime monitor is used to:\"\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "client/src/locales/es.json",
    "content": "{\n\t\"submit\": \"Enviar\",\n\t\"title\": \"Titulo\",\n\t\"distributedStatusHeaderText\": \"Cobertura en tiempo real, para dispositivos reales\",\n\t\"distributedStatusSubHeaderText\": \"Potenciado por millones de dispositivos alrededor del mundo, vea el rendimiento del sistema por región global, país o ciudad\",\n\t\"settingsDisabled\": \"Deshabilitado\",\n\t\"settingsSuccessSaved\": \"Ajustes guardados correctamente\",\n\t\"settingsFailedToSave\": \"Fallo al guardar los ajustes\",\n\t\"settingsStatsCleared\": \"Estadísticas eliminadas correctamente\",\n\t\"settingsFailedToClearStats\": \"Fallo al eliminar las estadísticas\",\n\t\"settingsMonitorsDeleted\": \"Todos los monitores eliminados correctamente\",\n\t\"settingsFailedToDeleteMonitors\": \"Fallo al eliminar todos los monitores\",\n\t\"starPromptTitle\": \"\",\n\t\"starPromptDescription\": \"Vea las últimas versiones y ayude a incrementar la comunidad en Github\",\n\t\"https\": \"HTTPS\",\n\t\"http\": \"HTTP\",\n\t\"monitor\": \"monitor\",\n\t\"aboutus\": \"Acerca de\",\n\t\"now\": \"Ahora\",\n\t\"delete\": \"Eliminar\",\n\t\"configure\": \"Configurar\",\n\t\"responseTime\": \"Tiempo de Respuesta\",\n\t\"ms\": \"ms\",\n\t\"bar\": \"Barra\",\n\t\"area\": \"Área\",\n\t\"country\": \"PAIS\",\n\t\"city\": \"CIUDAD\",\n\t\"response\": \"RESPUESTA\",\n\t\"monitorStatusUp\": \"El monitor {name} ({url}) está ahora activo y respondiendo\",\n\t\"monitorStatusDown\": \"El monitor {name} ({url}) está inactivo y no está respondiendo\",\n\t\"webhookSendSuccess\": \"Notificación webhook enviada correctamente\",\n\t\"webhookSendError\": \"Error al enviar notificación webhook a {platform}\",\n\t\"webhookUnsupportedPlatform\": \"Plataforma no soportada: {platform}\",\n\t\"distributedRightCategoryTitle\": \"Monitor\",\n\t\"distributedStatusServerMonitors\": \"Monitores de Servidores\",\n\t\"distributedStatusServerMonitorsDescription\": \"Monitoree el estado de los servidores relacionados\",\n\t\"distributedUptimeCreateSelectURL\": \"Aquí puede seleccionar la URL del anfitrión, junto con el tipo de monitor.\",\n\t\"distributedUptimeCreateChecks\": \"Verificaciones a realizar\",\n\t\"distributedUptimeCreateChecksDescription\": \"Usted siempre puede agregar o eliminar verificaciones luego de añadir su sitio.\",\n\t\"distributedUptimeCreateIncidentNotification\": \"Notificaciones de incidentes\",\n\t\"distributedUptimeCreateIncidentDescription\": \"Cuando ocurra un incidente, notificar a usuarios.\",\n\t\"distributedUptimeCreateAdvancedSettings\": \"Ajustes avanzados\",\n\t\"distributedUptimeDetailsNoMonitorHistory\": \"No hay historial de verificaciones para este monitor aún.\",\n\t\"distributedUptimeDetailsStatusHeaderUptime\": \"Tiempo de funcionamiento:\",\n\t\"distributedUptimeDetailsStatusHeaderLastUpdate\": \"Actualizado por última vez\",\n\t\"notifications\": {\n\t\t\"enableNotifications\": \"Habilitar notificaciones para {{platform}}\",\n\t\t\"testNotification\": \"Notificación de prueba\",\n\t\t\"addOrEditNotifications\": \"Agregar o eliminar notificaciones\",\n\t\t\"slack\": {\n\t\t\t\"label\": \"Slack\",\n\t\t\t\"description\": \"Para habilitar notificaciones de Slack, cree una aplicación de Slack y habilite los webhooks entrantes. Luego de eso, simplemente introduzca la URL del webhook aquí.\",\n\t\t\t\"webhookLabel\": \"URL del webhook\",\n\t\t\t\"webhookPlaceholder\": \"\",\n\t\t\t\"webhookRequired\": \"\"\n\t\t},\n\t\t\"discord\": {\n\t\t\t\"label\": \"Discord\",\n\t\t\t\"description\": \"Para enviar datos a un canal de Discord desde Checkmate a través de notificaciones de Discord utilizando webhooks, puede utilizar la característica de webhooks entrantes de Discord.\",\n\t\t\t\"webhookLabel\": \"URL de Webhooks de Discord\",\n\t\t\t\"webhookPlaceholder\": \"\",\n\t\t\t\"webhookRequired\": \"\"\n\t\t},\n\t\t\"telegram\": {\n\t\t\t\"label\": \"Telegram\",\n\t\t\t\"description\": \"Para habilitar las notificaciones de Telegram, cree un bot de Telegram utilizando BotFather, un bot oficial para crear y administrar bots de Telegram. Entonces, obtenga una clave API y un ID de chat y escríbalos aquí.\",\n\t\t\t\"tokenLabel\": \"La clave de su bot\",\n\t\t\t\"tokenPlaceholder\": \"123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11\",\n\t\t\t\"chatIdLabel\": \"El ID de su Chat\",\n\t\t\t\"chatIdPlaceholder\": \"-1001234567890\",\n\t\t\t\"fieldsRequired\": \"\"\n\t\t},\n\t\t\"webhook\": {\n\t\t\t\"label\": \"Webhooks\",\n\t\t\t\"description\": \"Puede establecer un webhook personalizado para recibir notificaciones cuando ocurra un incidente.\",\n\t\t\t\"urlLabel\": \"URL del webhook\",\n\t\t\t\"urlPlaceholder\": \"https://your-server.com/webhook\",\n\t\t\t\"urlRequired\": \"\"\n\t\t},\n\t\t\"testNotificationDevelop\": \"Notificación de prueba 2\",\n\t\t\"integrationButton\": \"\",\n\t\t\"testSuccess\": \"\",\n\t\t\"testFailed\": \"\",\n\t\t\"unsupportedType\": \"\",\n\t\t\"networkError\": \"\",\n\t\t\"fallback\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"checks\": [\"\"],\n\t\t\t\"actionButton\": \"\"\n\t\t},\n\t\t\"createButton\": \"\",\n\t\t\"createTitle\": \"\",\n\t\t\"create\": {\n\t\t\t\"success\": \"\",\n\t\t\t\"failed\": \"\"\n\t\t},\n\t\t\"fetch\": {\n\t\t\t\"success\": \"\",\n\t\t\t\"failed\": \"\"\n\t\t},\n\t\t\"delete\": {\n\t\t\t\"success\": \"\",\n\t\t\t\"failed\": \"\"\n\t\t},\n\t\t\"edit\": {\n\t\t\t\"success\": \"\",\n\t\t\t\"failed\": \"\"\n\t\t},\n\t\t\"test\": {\n\t\t\t\"success\": \"\",\n\t\t\t\"failed\": \"\"\n\t\t}\n\t},\n\t\"testLocale\": \"testLocale\",\n\t\"add\": \"Agregar\",\n\t\"monitors\": \"monitores\",\n\t\"distributedUptimeStatusCreateStatusPage\": \"página de estado\",\n\t\"distributedUptimeStatusCreateStatusPageAccess\": \"\",\n\t\"distributedUptimeStatusCreateStatusPageReady\": \"\",\n\t\"distributedUptimeStatusBasicInfoHeader\": \"\",\n\t\"distributedUptimeStatusBasicInfoDescription\": \"\",\n\t\"distributedUptimeStatusLogoHeader\": \"\",\n\t\"distributedUptimeStatusLogoDescription\": \"\",\n\t\"distributedUptimeStatusLogoUploadButton\": \"\",\n\t\"distributedUptimeStatusStandardMonitorsHeader\": \"\",\n\t\"distributedUptimeStatusStandardMonitorsDescription\": \"\",\n\t\"distributedUptimeStatusCreateYour\": \"\",\n\t\"distributedUptimeStatusEditYour\": \"\",\n\t\"distributedUptimeStatusPublishedLabel\": \"\",\n\t\"distributedUptimeStatusCompanyNameLabel\": \"\",\n\t\"distributedUptimeStatusPageAddressLabel\": \"\",\n\t\"distributedUptimeStatus30Days\": \"30 dias\",\n\t\"distributedUptimeStatus60Days\": \"60 días\",\n\t\"distributedUptimeStatus90Days\": \"90 dias\",\n\t\"distributedUptimeStatusPageNotSetUp\": \"\",\n\t\"distributedUptimeStatusContactAdmin\": \"\",\n\t\"distributedUptimeStatusPageNotPublic\": \"\",\n\t\"distributedUptimeStatusPageDeleteDialog\": \"\",\n\t\"distributedUptimeStatusPageDeleteConfirm\": \"\",\n\t\"distributedUptimeStatusPageDeleteDescription\": \"\",\n\t\"distributedUptimeStatusDevices\": \"Dispositivos\",\n\t\"distributedUptimeStatusUpt\": \"\",\n\t\"distributedUptimeStatusUptBurned\": \"\",\n\t\"distributedUptimeStatusUptLogo\": \"\",\n\t\"incidentsTableNoIncidents\": \"\",\n\t\"incidentsTablePaginationLabel\": \"Incidentes\",\n\t\"incidentsTableMonitorName\": \"\",\n\t\"incidentsTableStatus\": \"Estado\",\n\t\"incidentsTableDateTime\": \"\",\n\t\"incidentsTableStatusCode\": \"\",\n\t\"incidentsTableMessage\": \"Mensaje\",\n\t\"incidentsOptionsHeader\": \"\",\n\t\"incidentsOptionsHeaderFilterBy\": \"\",\n\t\"incidentsOptionsHeaderFilterAll\": \"Todo\",\n\t\"incidentsOptionsHeaderFilterDown\": \"\",\n\t\"incidentsOptionsHeaderFilterCannotResolve\": \"\",\n\t\"incidentsOptionsHeaderShow\": \"Mostrar:\",\n\t\"incidentsOptionsHeaderLastHour\": \"\",\n\t\"incidentsOptionsHeaderLastDay\": \"\",\n\t\"incidentsOptionsHeaderLastWeek\": \"\",\n\t\"incidentsOptionsPlaceholderAllServers\": \"\",\n\t\"infrastructureCreateYour\": \"\",\n\t\"infrastructureCreateGeneralSettingsDescription\": \"\",\n\t\"infrastructureServerRequirement\": \"\",\n\t\"infrastructureCustomizeAlerts\": \"\",\n\t\"infrastructureAlertNotificationDescription\": \"\",\n\t\"infrastructureCreateMonitor\": \"\",\n\t\"infrastructureProtocol\": \"Protocolo\",\n\t\"infrastructureServerUrlLabel\": \"\",\n\t\"infrastructureDisplayNameLabel\": \"\",\n\t\"infrastructureAuthorizationSecretLabel\": \"\",\n\t\"gb\": \"GB\",\n\t\"mb\": \"MB\",\n\t\"mem\": \"Mem\",\n\t\"memoryUsage\": \"\",\n\t\"cpu\": \"CPU\",\n\t\"cpuUsage\": \"\",\n\t\"cpuTemperature\": \"\",\n\t\"diskUsage\": \"\",\n\t\"used\": \"\",\n\t\"total\": \"Total\",\n\t\"cores\": \"Nucleos\",\n\t\"frequency\": \"Frecuencia\",\n\t\"status\": \"\",\n\t\"cpuPhysical\": \"\",\n\t\"cpuLogical\": \"\",\n\t\"cpuFrequency\": \"\",\n\t\"avgCpuTemperature\": \"\",\n\t\"memory\": \"\",\n\t\"disk\": \"\",\n\t\"uptime\": \"\",\n\t\"os\": \"SO\",\n\t\"host\": \"\",\n\t\"actions\": \"\",\n\t\"integrations\": \"\",\n\t\"integrationsPrism\": \"\",\n\t\"integrationsSlack\": \"Slack\",\n\t\"integrationsSlackInfo\": \"\",\n\t\"integrationsDiscord\": \"Discord\",\n\t\"integrationsDiscordInfo\": \"\",\n\t\"integrationsZapier\": \"Zapier\",\n\t\"integrationsZapierInfo\": \"\",\n\t\"commonSave\": \"Guardar\",\n\t\"createYour\": \"\",\n\t\"createMonitor\": \"\",\n\t\"pause\": \"Pausar\",\n\t\"resume\": \"Resumir\",\n\t\"editing\": \"Editando...\",\n\t\"url\": \"URL\",\n\t\"access\": \"Acceso\",\n\t\"timezone\": \"\",\n\t\"features\": \"\",\n\t\"administrator\": \"\",\n\t\"loginHere\": \"\",\n\t\"displayName\": \"\",\n\t\"urlMonitor\": \"\",\n\t\"portToMonitor\": \"\",\n\t\"websiteMonitoring\": \"\",\n\t\"websiteMonitoringDescription\": \"\",\n\t\"pingMonitoring\": \"\",\n\t\"pingMonitoringDescription\": \"\",\n\t\"dockerContainerMonitoring\": \"\",\n\t\"dockerContainerMonitoringDescription\": \"\",\n\t\"portMonitoring\": \"\",\n\t\"portMonitoringDescription\": \"\",\n\t\"createMaintenanceWindow\": \"\",\n\t\"createMaintenance\": \"\",\n\t\"editMaintenance\": \"\",\n\t\"maintenanceWindowName\": \"\",\n\t\"friendlyNameInput\": \"\",\n\t\"friendlyNamePlaceholder\": \"\",\n\t\"maintenanceRepeat\": \"\",\n\t\"maintenance\": \"\",\n\t\"duration\": \"Duración\",\n\t\"addMonitors\": \"\",\n\t\"window\": \"ventana\",\n\t\"cancel\": \"Cancelar\",\n\t\"message\": \"Mensaje\",\n\t\"low\": \"bajo\",\n\t\"high\": \"alto\",\n\t\"statusCode\": \"\",\n\t\"date&Time\": \"\",\n\t\"type\": \"\",\n\t\"statusPageName\": \"\",\n\t\"publicURL\": \"\",\n\t\"repeat\": \"\",\n\t\"edit\": \"\",\n\t\"createA\": \"\",\n\t\"remove\": \"\",\n\t\"maintenanceWindowDescription\": \"\",\n\t\"startTime\": \"\",\n\t\"timeZoneInfo\": \"\",\n\t\"monitorsToApply\": \"\",\n\t\"nextWindow\": \"\",\n\t\"notFoundButton\": \"\",\n\t\"pageSpeedConfigureSettingsDescription\": \"\",\n\t\"monitorDisplayName\": \"\",\n\t\"whenNewIncident\": \"\",\n\t\"notifySMS\": \"\",\n\t\"notifyEmails\": \"\",\n\t\"seperateEmails\": \"\",\n\t\"checkFrequency\": \"\",\n\t\"matchMethod\": \"\",\n\t\"expectedValue\": \"\",\n\t\"deleteDialogTitle\": \"\",\n\t\"deleteDialogDescription\": \"\",\n\t\"pageSpeedMonitor\": \"\",\n\t\"shown\": \"\",\n\t\"ago\": \"\",\n\t\"companyName\": \"\",\n\t\"pageSpeedDetailsPerformanceReport\": \"\",\n\t\"pageSpeedDetailsPerformanceReportCalculator\": \"\",\n\t\"checkingEvery\": \"\",\n\t\"statusPageCreateSettings\": \"\",\n\t\"basicInformation\": \"\",\n\t\"statusPageCreateBasicInfoDescription\": \"\",\n\t\"statusPageCreateSelectTimeZoneDescription\": \"\",\n\t\"statusPageCreateAppearanceDescription\": \"\",\n\t\"statusPageCreateSettingsCheckboxLabel\": \"\",\n\t\"statusPageCreateBasicInfoStatusPageAddress\": \"\",\n\t\"statusPageCreateTabsContent\": \"\",\n\t\"statusPageCreateTabsContentDescription\": \"\",\n\t\"statusPageCreateTabsContentFeaturesDescription\": \"\",\n\t\"showCharts\": \"\",\n\t\"showUptimePercentage\": \"\",\n\t\"removeLogo\": \"\",\n\t\"statusPageStatus\": \"\",\n\t\"statusPageStatusContactAdmin\": \"\",\n\t\"statusPageStatusNotPublic\": \"\",\n\t\"statusPageStatusNoPage\": \"\",\n\t\"statusPageStatusServiceStatus\": \"\",\n\t\"deleteStatusPage\": \"\",\n\t\"deleteStatusPageConfirm\": \"\",\n\t\"deleteStatusPageDescription\": \"\",\n\t\"uptimeCreate\": \"\",\n\t\"uptimeCreateJsonPath\": \"\",\n\t\"uptimeCreateJsonPathQuery\": \"\",\n\t\"maintenanceTableActionMenuDialogTitle\": \"\",\n\t\"infrastructureEditYour\": \"\",\n\t\"infrastructureEditMonitor\": \"\",\n\t\"infrastructureMonitorCreated\": \"\",\n\t\"infrastructureMonitorUpdated\": \"\",\n\t\"errorInvalidTypeId\": \"\",\n\t\"errorInvalidFieldId\": \"\",\n\t\"inviteNoTokenFound\": \"\",\n\t\"pageSpeedWarning\": \"\",\n\t\"pageSpeedLearnMoreLink\": \"\",\n\t\"pageSpeedAddApiKey\": \"\",\n\t\"update\": \"\",\n\t\"invalidFileFormat\": \"\",\n\t\"invalidFileSize\": \"\",\n\t\"ClickUpload\": \"\",\n\t\"DragandDrop\": \"\",\n\t\"MaxSize\": \"\",\n\t\"SupportedFormats\": \"\",\n\t\"FirstName\": \"\",\n\t\"LastName\": \"\",\n\t\"EmailDescriptionText\": \"\",\n\t\"YourPhoto\": \"\",\n\t\"PhotoDescriptionText\": \"\",\n\t\"save\": \"\",\n\t\"DeleteDescriptionText\": \"\",\n\t\"DeleteAccountWarning\": \"\",\n\t\"DeleteWarningTitle\": \"\",\n\t\"bulkImport\": {\n\t\t\"title\": \"\",\n\t\t\"selectFileTips\": \"\",\n\t\t\"selectFileDescription\": \"\",\n\t\t\"selectFile\": \"\",\n\t\t\"parsingFailed\": \"\",\n\t\t\"uploadSuccess\": \"\",\n\t\t\"validationFailed\": \"\",\n\t\t\"noFileSelected\": \"\",\n\t\t\"fallbackPage\": \"\",\n\t\t\"invalidFileType\": \"\",\n\t\t\"uploadFailed\": \"\"\n\t},\n\t\"DeleteAccountTitle\": \"\",\n\t\"DeleteAccountButton\": \"\",\n\t\"publicLink\": \"\",\n\t\"maskedPageSpeedKeyPlaceholder\": \"\",\n\t\"reset\": \"\",\n\t\"ignoreTLSError\": \"\",\n\t\"tlsErrorIgnored\": \"\",\n\t\"ignoreTLSErrorDescription\": \"\",\n\t\"createNew\": \"\",\n\t\"greeting\": {\n\t\t\"prepend\": \"\",\n\t\t\"append\": \"\",\n\t\t\"overview\": \"\"\n\t},\n\t\"roles\": {\n\t\t\"superAdmin\": \"\",\n\t\t\"admin\": \"\",\n\t\t\"teamMember\": \"\",\n\t\t\"demoUser\": \"\"\n\t},\n\t\"teamPanel\": {\n\t\t\"teamMembers\": \"\",\n\t\t\"filter\": {\n\t\t\t\"all\": \"\",\n\t\t\t\"member\": \"\"\n\t\t},\n\t\t\"inviteTeamMember\": \"\",\n\t\t\"inviteNewTeamMember\": \"\",\n\t\t\"inviteDescription\": \"\",\n\t\t\"email\": \"\",\n\t\t\"selectRole\": \"\",\n\t\t\"inviteLink\": \"\",\n\t\t\"cancel\": \"\",\n\t\t\"noMembers\": \"\",\n\t\t\"getToken\": \"\",\n\t\t\"emailToken\": \"\",\n\t\t\"table\": {\n\t\t\t\"name\": \"\",\n\t\t\t\"email\": \"\",\n\t\t\t\"role\": \"\",\n\t\t\t\"created\": \"\"\n\t\t},\n\t\t\"addTeamMember\": {\n\t\t\t\"addMemberMenu\": \"\",\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"addButton\": \"\"\n\t\t},\n\t\t\"register\": \"\",\n\t\t\"registerToast\": {\n\t\t\t\"success\": \"\",\n\t\t\t\"dbUserExists\": \"\",\n\t\t\t\"unknownError\": \"\"\n\t\t},\n\t\t\"registerTeamMember\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"auth\": {\n\t\t\t\t\"common\": {\n\t\t\t\t\t\"inputs\": {\n\t\t\t\t\t\t\"firstName\": {\n\t\t\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\t\t\"empty\": \"\",\n\t\t\t\t\t\t\t\t\"pattern\": \"\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"lastName\": {\n\t\t\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\t\t\"empty\": \"\",\n\t\t\t\t\t\t\t\t\"pattern\": \"\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"email\": {\n\t\t\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\t\t\"empty\": \"\",\n\t\t\t\t\t\t\t\t\"invalid\": \"\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"role\": {\n\t\t\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\t\t\"empty\": \"\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"role\": \"\",\n\t\t\"changeTeamPassword\": {\n\t\t\t\"changePasswordMenu\": \"\",\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"success\": \"\"\n\t\t}\n\t},\n\t\"monitorState\": {\n\t\t\"paused\": \"\",\n\t\t\"resumed\": \"\",\n\t\t\"active\": \"\"\n\t},\n\t\"menu\": {\n\t\t\"uptime\": \"\",\n\t\t\"pagespeed\": \"\",\n\t\t\"infrastructure\": \"\",\n\t\t\"incidents\": \"\",\n\t\t\"statusPages\": \"\",\n\t\t\"maintenance\": \"\",\n\t\t\"integrations\": \"\",\n\t\t\"settings\": \"\",\n\t\t\"support\": \"\",\n\t\t\"discussions\": \"\",\n\t\t\"docs\": \"\",\n\t\t\"changelog\": \"\",\n\t\t\"profile\": \"\",\n\t\t\"password\": \"\",\n\t\t\"team\": \"\",\n\t\t\"logOut\": \"\",\n\t\t\"notifications\": \"\",\n\t\t\"logs\": \"\"\n\t},\n\t\"settingsEmailUser\": \"\",\n\t\"state\": \"\",\n\t\"statusBreadCrumbsStatusPages\": \"\",\n\t\"statusBreadCrumbsDetails\": \"\",\n\t\"commonSaving\": \"\",\n\t\"navControls\": \"\",\n\t\"incidentsPageTitle\": \"\",\n\t\"passwordPanel\": {\n\t\t\"passwordChangedSuccess\": \"\",\n\t\t\"passwordInputIncorrect\": \"\",\n\t\t\"currentPassword\": \"\",\n\t\t\"enterCurrentPassword\": \"\",\n\t\t\"newPassword\": \"\",\n\t\t\"enterNewPassword\": \"\",\n\t\t\"confirmNewPassword\": \"\",\n\t\t\"passwordRequirements\": \"\",\n\t\t\"saving\": \"\"\n\t},\n\t\"emailSent\": \"\",\n\t\"failedToSendEmail\": \"\",\n\t\"settingsTestEmailSuccess\": \"\",\n\t\"settingsTestEmailFailed\": \"\",\n\t\"settingsTestEmailFailedWithReason\": \"\",\n\t\"settingsTestEmailUnknownError\": \"\",\n\t\"statusMsg\": {\n\t\t\"paused\": \"\",\n\t\t\"up\": \"\",\n\t\t\"down\": \"\",\n\t\t\"pending\": \"\"\n\t},\n\t\"uptimeGeneralInstructions\": {\n\t\t\"http\": \"\",\n\t\t\"ping\": \"\",\n\t\t\"docker\": \"\",\n\t\t\"port\": \"\",\n\t\t\"game\": \"\",\n\t\t\"https\": \"\"\n\t},\n\t\"common\": {\n\t\t\"appName\": \"\",\n\t\t\"monitoringAgentName\": \"\",\n\t\t\"buttons\": {\n\t\t\t\"toggleTheme\": \"\"\n\t\t},\n\t\t\"toasts\": {\n\t\t\t\"networkError\": \"\",\n\t\t\t\"checkConnection\": \"\",\n\t\t\t\"unknownError\": \"\"\n\t\t}\n\t},\n\t\"auth\": {\n\t\t\"common\": {\n\t\t\t\"navigation\": {\n\t\t\t\t\"continue\": \"\",\n\t\t\t\t\"back\": \"\"\n\t\t\t},\n\t\t\t\"inputs\": {\n\t\t\t\t\"email\": {\n\t\t\t\t\t\"label\": \"\",\n\t\t\t\t\t\"placeholder\": \"\",\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"\",\n\t\t\t\t\t\t\"invalid\": \"\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"password\": {\n\t\t\t\t\t\"label\": \"\",\n\t\t\t\t\t\"rules\": {\n\t\t\t\t\t\t\"length\": {\n\t\t\t\t\t\t\t\"beginning\": \"\",\n\t\t\t\t\t\t\t\"highlighted\": \"\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"special\": {\n\t\t\t\t\t\t\t\"beginning\": \"\",\n\t\t\t\t\t\t\t\"highlighted\": \"\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"number\": {\n\t\t\t\t\t\t\t\"beginning\": \"\",\n\t\t\t\t\t\t\t\"highlighted\": \"\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"uppercase\": {\n\t\t\t\t\t\t\t\"beginning\": \"\",\n\t\t\t\t\t\t\t\"highlighted\": \"\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"lowercase\": {\n\t\t\t\t\t\t\t\"beginning\": \"\",\n\t\t\t\t\t\t\t\"highlighted\": \"\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"match\": {\n\t\t\t\t\t\t\t\"beginning\": \"\",\n\t\t\t\t\t\t\t\"highlighted\": \"\"\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"\",\n\t\t\t\t\t\t\"length\": \"\",\n\t\t\t\t\t\t\"uppercase\": \"\",\n\t\t\t\t\t\t\"lowercase\": \"\",\n\t\t\t\t\t\t\"number\": \"\",\n\t\t\t\t\t\t\"special\": \"\",\n\t\t\t\t\t\t\"incorrect\": \"\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"passwordConfirm\": {\n\t\t\t\t\t\"label\": \"\",\n\t\t\t\t\t\"placeholder\": \"\",\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"\",\n\t\t\t\t\t\t\"different\": \"\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"firstName\": {\n\t\t\t\t\t\"label\": \"\",\n\t\t\t\t\t\"placeholder\": \"\",\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"\",\n\t\t\t\t\t\t\"length\": \"\",\n\t\t\t\t\t\t\"pattern\": \"\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"lastName\": {\n\t\t\t\t\t\"label\": \"\",\n\t\t\t\t\t\"placeholder\": \"\",\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"\",\n\t\t\t\t\t\t\"length\": \"\",\n\t\t\t\t\t\t\"pattern\": \"\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"errors\": {\n\t\t\t\t\"validation\": \"\"\n\t\t\t},\n\t\t\t\"fields\": {\n\t\t\t\t\"password\": {\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"incorrect\": \"\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"role\": {\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"min\": \"\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"login\": {\n\t\t\t\"heading\": \"\",\n\t\t\t\"subheadings\": {\n\t\t\t\t\"stepOne\": \"\",\n\t\t\t\t\"stepTwo\": \"\"\n\t\t\t},\n\t\t\t\"links\": {\n\t\t\t\t\"forgotPassword\": \"\",\n\t\t\t\t\"register\": \"\",\n\t\t\t\t\"forgotPasswordLink\": \"\",\n\t\t\t\t\"registerLink\": \"\"\n\t\t\t},\n\t\t\t\"toasts\": {\n\t\t\t\t\"success\": \"\",\n\t\t\t\t\"incorrectPassword\": \"\"\n\t\t\t},\n\t\t\t\"errors\": {\n\t\t\t\t\"password\": {\n\t\t\t\t\t\"incorrect\": \"\"\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"welcome\": \"\"\n\t\t},\n\t\t\"registration\": {\n\t\t\t\"heading\": {\n\t\t\t\t\"superAdmin\": \"\",\n\t\t\t\t\"user\": \"\"\n\t\t\t},\n\t\t\t\"subheadings\": {\n\t\t\t\t\"stepOne\": \"\",\n\t\t\t\t\"stepTwo\": \"\",\n\t\t\t\t\"stepThree\": \"\"\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\t\"superAdmin\": \"\",\n\t\t\t\t\"user\": \"\"\n\t\t\t},\n\t\t\t\"gettingStartedButton\": {\n\t\t\t\t\"superAdmin\": \"\",\n\t\t\t\t\"user\": \"\"\n\t\t\t},\n\t\t\t\"termsAndPolicies\": \"\",\n\t\t\t\"links\": {\n\t\t\t\t\"login\": \"\"\n\t\t\t},\n\t\t\t\"toasts\": {\n\t\t\t\t\"success\": \"\"\n\t\t\t},\n\t\t\t\"welcome\": \"\"\n\t\t},\n\t\t\"forgotPassword\": {\n\t\t\t\"heading\": \"\",\n\t\t\t\"subheadings\": {\n\t\t\t\t\"stepOne\": \"\",\n\t\t\t\t\"stepTwo\": \"\",\n\t\t\t\t\"stepThree\": \"\",\n\t\t\t\t\"stepFour\": \"\"\n\t\t\t},\n\t\t\t\"buttons\": {\n\t\t\t\t\"openEmail\": \"\",\n\t\t\t\t\"resetPassword\": \"\"\n\t\t\t},\n\t\t\t\"imageAlts\": {\n\t\t\t\t\"passwordKey\": \"\",\n\t\t\t\t\"email\": \"\",\n\t\t\t\t\"lock\": \"\",\n\t\t\t\t\"passwordConfirm\": \"\"\n\t\t\t},\n\t\t\t\"links\": {\n\t\t\t\t\"login\": \"\",\n\t\t\t\t\"resend\": \"\"\n\t\t\t},\n\t\t\t\"toasts\": {\n\t\t\t\t\"sent\": \"\",\n\t\t\t\t\"emailNotFound\": \"\",\n\t\t\t\t\"redirect\": \"\",\n\t\t\t\t\"success\": \"\",\n\t\t\t\t\"error\": \"\"\n\t\t\t}\n\t\t}\n\t},\n\t\"errorPages\": {\n\t\t\"serverUnreachable\": {\n\t\t\t\"toasts\": {\n\t\t\t\t\"reconnected\": \"\",\n\t\t\t\t\"stillUnreachable\": \"\"\n\t\t\t},\n\t\t\t\"alertBox\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"retryButton\": {\n\t\t\t\t\"default\": \"\",\n\t\t\t\t\"processing\": \"\"\n\t\t\t}\n\t\t}\n\t},\n\t\"createNotifications\": {\n\t\t\"title\": \"\",\n\t\t\"nameSettings\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"nameLabel\": \"\",\n\t\t\t\"namePlaceholder\": \"\"\n\t\t},\n\t\t\"typeSettings\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"typeLabel\": \"\"\n\t\t},\n\t\t\"emailSettings\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"emailLabel\": \"\",\n\t\t\t\"emailPlaceholder\": \"\"\n\t\t},\n\t\t\"slackSettings\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"webhookLabel\": \"\",\n\t\t\t\"webhookPlaceholder\": \"\"\n\t\t},\n\t\t\"pagerdutySettings\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"integrationKeyLabel\": \"\",\n\t\t\t\"integrationKeyPlaceholder\": \"\"\n\t\t},\n\t\t\"discordSettings\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"webhookLabel\": \"\",\n\t\t\t\"webhookPlaceholder\": \"\"\n\t\t},\n\t\t\"webhookSettings\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"webhookLabel\": \"\",\n\t\t\t\"webhookPlaceholder\": \"\"\n\t\t},\n\t\t\"testNotification\": \"\",\n\t\t\"dialogDeleteTitle\": \"\",\n\t\t\"dialogDeleteConfirm\": \"\"\n\t},\n\t\"notificationConfig\": {\n\t\t\"title\": \"\",\n\t\t\"description\": \"\"\n\t},\n\t\"monitorStatus\": {\n\t\t\"checkingEvery\": \"\",\n\t\t\"withCaptureAgent\": \"\",\n\t\t\"up\": \"\",\n\t\t\"down\": \"\",\n\t\t\"paused\": \"\"\n\t},\n\t\"advancedMatching\": \"\",\n\t\"sendTestNotifications\": \"\",\n\t\"selectAll\": \"\",\n\t\"showAdminLoginLink\": \"\",\n\t\"logsPage\": {\n\t\t\"title\": \"\",\n\t\t\"description\": \"\",\n\t\t\"tabs\": {\n\t\t\t\"queue\": \"\",\n\t\t\t\"logs\": \"\",\n\t\t\t\"diagnostics\": \"\"\n\t\t},\n\t\t\"toast\": {\n\t\t\t\"fetchLogsSuccess\": \"\"\n\t\t},\n\t\t\"logLevelSelect\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"values\": {\n\t\t\t\t\"all\": \"\",\n\t\t\t\t\"info\": \"\",\n\t\t\t\t\"warn\": \"\",\n\t\t\t\t\"error\": \"\",\n\t\t\t\t\"debug\": \"\"\n\t\t\t}\n\t\t}\n\t},\n\t\"queuePage\": {\n\t\t\"title\": \"\",\n\t\t\"refreshButton\": \"\",\n\t\t\"flushButton\": \"\",\n\t\t\"jobTable\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"idHeader\": \"\",\n\t\t\t\"urlHeader\": \"\",\n\t\t\t\"typeHeader\": \"\",\n\t\t\t\"activeHeader\": \"\",\n\t\t\t\"lockedAtHeader\": \"\",\n\t\t\t\"runCountHeader\": \"\",\n\t\t\t\"failCountHeader\": \"\",\n\t\t\t\"lastRunHeader\": \"\",\n\t\t\t\"lastFinishedAtHeader\": \"\",\n\t\t\t\"lastRunTookHeader\": \"\",\n\t\t\t\"intervalHeader\": \"\"\n\t\t},\n\t\t\"metricsTable\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"metricHeader\": \"\",\n\t\t\t\"valueHeader\": \"\"\n\t\t},\n\t\t\"failedJobTable\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"monitorIdHeader\": \"\",\n\t\t\t\"monitorUrlHeader\": \"\",\n\t\t\t\"failCountHeader\": \"\",\n\t\t\t\"failedAtHeader\": \"\",\n\t\t\t\"failReasonHeader\": \"\"\n\t\t}\n\t},\n\t\"export\": {\n\t\t\"title\": \"\",\n\t\t\"success\": \"\",\n\t\t\"failed\": \"\"\n\t},\n\t\"monitorActions\": {\n\t\t\"title\": \"\",\n\t\t\"import\": \"\",\n\t\t\"export\": \"\",\n\t\t\"deleteSuccess\": \"\",\n\t\t\"deleteFailed\": \"\",\n\t\t\"details\": \"\"\n\t},\n\t\"settingsPage\": {\n\t\t\"aboutSettings\": {\n\t\t\t\"labelDevelopedBy\": \"\",\n\t\t\t\"labelVersion\": \"\",\n\t\t\t\"title\": \"\"\n\t\t},\n\t\t\"demoMonitorsSettings\": {\n\t\t\t\"buttonAddMonitors\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"title\": \"\"\n\t\t},\n\t\t\"emailSettings\": {\n\t\t\t\"buttonSendTestEmail\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"descriptionTransport\": \"\",\n\t\t\t\"labelAddress\": \"\",\n\t\t\t\"labelConnectionHost\": \"\",\n\t\t\t\"labelHost\": \"\",\n\t\t\t\"labelIgnoreTLS\": \"\",\n\t\t\t\"labelPassword\": \"\",\n\t\t\t\"labelPasswordSet\": \"\",\n\t\t\t\"labelPool\": \"\",\n\t\t\t\"labelPort\": \"\",\n\t\t\t\"labelRejectUnauthorized\": \"\",\n\t\t\t\"labelRequireTLS\": \"\",\n\t\t\t\"labelSecure\": \"\",\n\t\t\t\"labelTLSServername\": \"\",\n\t\t\t\"labelUser\": \"\",\n\t\t\t\"linkTransport\": \"\",\n\t\t\t\"placeholderUser\": \"\",\n\t\t\t\"title\": \"\",\n\t\t\t\"toastEmailRequiredFieldsError\": \"\"\n\t\t},\n\t\t\"pageSpeedSettings\": {\n\t\t\t\"description\": \"\",\n\t\t\t\"labelApiKeySet\": \"\",\n\t\t\t\"labelApiKey\": \"\",\n\t\t\t\"title\": \"\"\n\t\t},\n\t\t\"saveButtonLabel\": \"\",\n\t\t\"statsSettings\": {\n\t\t\t\"clearAllStatsButton\": \"\",\n\t\t\t\"clearAllStatsDescription\": \"\",\n\t\t\t\"clearAllStatsDialogConfirm\": \"\",\n\t\t\t\"clearAllStatsDialogDescription\": \"\",\n\t\t\t\"clearAllStatsDialogTitle\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"labelTTL\": \"\",\n\t\t\t\"labelTTLOptional\": \"\",\n\t\t\t\"title\": \"\"\n\t\t},\n\t\t\"systemResetSettings\": {\n\t\t\t\"buttonRemoveAllMonitors\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"dialogConfirm\": \"\",\n\t\t\t\"dialogDescription\": \"\",\n\t\t\t\"dialogTitle\": \"\",\n\t\t\t\"title\": \"\"\n\t\t},\n\t\t\"timezoneSettings\": {\n\t\t\t\"description\": \"\",\n\t\t\t\"label\": \"\",\n\t\t\t\"title\": \"\"\n\t\t},\n\t\t\"title\": \"\",\n\t\t\"uiSettings\": {\n\t\t\t\"description\": \"\",\n\t\t\t\"labelLanguage\": \"\",\n\t\t\t\"labelTheme\": \"\",\n\t\t\t\"title\": \"\"\n\t\t},\n\t\t\"urlSettings\": {\n\t\t\t\"description\": \"\",\n\t\t\t\"label\": \"\",\n\t\t\t\"selectDisabled\": \"\",\n\t\t\t\"selectEnabled\": \"\",\n\t\t\t\"title\": \"\"\n\t\t},\n\t\t\"globalThresholds\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\"\n\t\t}\n\t},\n\t\"statusPageCreate\": {\n\t\t\"buttonSave\": \"\"\n\t},\n\t\"incidentsOptionsHeaderFilterResolved\": \"\",\n\t\"settingsSave\": \"\",\n\t\"statusPageCreateAppearanceTitle\": \"\",\n\t\"confirmPassword\": \"\",\n\t\"monitorHooks\": {\n\t\t\"failureAddDemoMonitors\": \"\",\n\t\t\"successAddDemoMonitors\": \"\"\n\t},\n\t\"settingsAppearance\": \"\",\n\t\"settingsDisplayTimezone\": \"\",\n\t\"settingsGeneralSettings\": \"\",\n\t\"incidentsOptionsHeaderTotalIncidents\": \"\",\n\t\"statusPage\": {\n\t\t\"deleteSuccess\": \"\",\n\t\t\"deleteFailed\": \"\",\n\t\t\"createSuccess\": \"\",\n\t\t\"updateSuccess\": \"\",\n\t\t\"generalSettings\": \"\",\n\t\t\"contents\": \"\",\n\t\t\"fallback\": {\n\t\t\t\"checks\": [\"\"],\n\t\t\t\"title\": \"\",\n\t\t\t\"actionButton\": \"\"\n\t\t}\n\t},\n\t\"testNotificationsDisabled\": \"\",\n\t\"incidentsTableResolvedAt\": \"\",\n\t\"incidentsTableActionResolve\": \"\",\n\t\"checkHooks\": {\n\t\t\"failureResolveOne\": \"\",\n\t\t\"failureResolveAll\": \"\",\n\t\t\"failureResolveMonitor\": \"\"\n\t},\n\t\"checkFormError\": \"\",\n\t\"diagnosticsPage\": {\n\t\t\"diagnosticDescription\": \"\",\n\t\t\"statsDescription\": \"\",\n\t\t\"gauges\": {\n\t\t\t\"heapAllocationTitle\": \"\",\n\t\t\t\"heapAllocationSubtitle\": \"\",\n\t\t\t\"heapUsageTitle\": \"\",\n\t\t\t\"heapUsageSubtitle\": \"\",\n\t\t\t\"heapUtilizationTitle\": \"\",\n\t\t\t\"heapUtilizationSubtitle\": \"\",\n\t\t\t\"instantCpuUsageTitle\": \"\",\n\t\t\t\"instantCpuUsageSubtitle\": \"\"\n\t\t},\n\t\t\"stats\": {\n\t\t\t\"eventLoopDelayTitle\": \"\",\n\t\t\t\"uptimeTitle\": \"\",\n\t\t\t\"usedHeapSizeTitle\": \"\",\n\t\t\t\"totalHeapSizeTitle\": \"\",\n\t\t\t\"osMemoryLimitTitle\": \"\"\n\t\t}\n\t},\n\t\"pageSpeedLighthouseAPI\": \"\",\n\t\"time\": {\n\t\t\"threeMinutes\": \"\",\n\t\t\"fiveMinutes\": \"\",\n\t\t\"tenMinutes\": \"\",\n\t\t\"twentyMinutes\": \"\",\n\t\t\"oneHour\": \"\",\n\t\t\"oneDay\": \"\",\n\t\t\"oneWeek\": \"\",\n\t\t\"fourMinutes\": \"\",\n\t\t\"oneMinute\": \"\",\n\t\t\"twoMinutes\": \"\",\n\t\t\"fifteenSeconds\": \"\",\n\t\t\"thirtySeconds\": \"\"\n\t},\n\t\"general\": {\n\t\t\"noOptionsFound\": \"\"\n\t},\n\t\"infrastructureMonitor\": {\n\t\t\"fallback\": {\n\t\t\t\"checks\": [\"\"],\n\t\t\t\"title\": \"\",\n\t\t\t\"actionButton\": \"\"\n\t\t}\n\t},\n\t\"maintenanceWindow\": {\n\t\t\"fallback\": {\n\t\t\t\"checks\": [\"\"],\n\t\t\t\"title\": \"\",\n\t\t\t\"actionButton\": \"\"\n\t\t}\n\t},\n\t\"pageSpeed\": {\n\t\t\"fallback\": {\n\t\t\t\"checks\": [\"\"],\n\t\t\t\"title\": \"\",\n\t\t\t\"actionButton\": \"\"\n\t\t}\n\t},\n\t\"uptimeMonitor\": {\n\t\t\"fallback\": {\n\t\t\t\"checks\": [\"\"],\n\t\t\t\"title\": \"\",\n\t\t\t\"actionButton\": \"\"\n\t\t}\n\t},\n\t\"editUserPage\": {\n\t\t\"form\": {\n\t\t\t\"email\": \"\",\n\t\t\t\"firstName\": \"\",\n\t\t\t\"lastName\": \"\",\n\t\t\t\"role\": \"\",\n\t\t\t\"save\": \"\"\n\t\t},\n\t\t\"table\": {\n\t\t\t\"actionHeader\": \"\",\n\t\t\t\"roleHeader\": \"\"\n\t\t},\n\t\t\"title\": \"\",\n\t\t\"toast\": {\n\t\t\t\"successUserUpdate\": \"\",\n\t\t\t\"validationErrors\": \"\"\n\t\t}\n\t},\n\t\"incidentsPageActionResolveMonitor\": \"\",\n\t\"incidentsPageActionResolveAll\": \"\",\n\t\"matchMethodOptions\": {\n\t\t\"equal\": \"\",\n\t\t\"equalPlaceholder\": \"\",\n\t\t\"include\": \"\",\n\t\t\"includePlaceholder\": \"\",\n\t\t\"regex\": \"\",\n\t\t\"regexPlaceholder\": \"\",\n\t\t\"text\": \"\"\n\t},\n\t\"monitorType\": {\n\t\t\"docker\": {\n\t\t\t\"label\": \"\",\n\t\t\t\"namePlaceholder\": \"\",\n\t\t\t\"placeholder\": \"\"\n\t\t},\n\t\t\"http\": {\n\t\t\t\"label\": \"\",\n\t\t\t\"namePlaceholder\": \"\",\n\t\t\t\"placeholder\": \"\"\n\t\t},\n\t\t\"ping\": {\n\t\t\t\"label\": \"\",\n\t\t\t\"namePlaceholder\": \"\",\n\t\t\t\"placeholder\": \"\"\n\t\t},\n\t\t\"port\": {\n\t\t\t\"label\": \"\",\n\t\t\t\"namePlaceholder\": \"\",\n\t\t\t\"placeholder\": \"\"\n\t\t},\n\t\t\"game\": {\n\t\t\t\"label\": \"\",\n\t\t\t\"namePlaceholder\": \"\",\n\t\t\t\"placeholder\": \"\"\n\t\t}\n\t},\n\t\"uptimeAdvancedMatching\": {\n\t\t\"jsonPath\": \"\"\n\t},\n\t\"bytesPerSecond\": \"\",\n\t\"bytesReceived\": \"\",\n\t\"bytesSent\": \"\",\n\t\"chooseGame\": \"\",\n\t\"createMonitorPage\": {\n\t\t\"incidentConfigDescription\": \"\",\n\t\t\"incidentConfigStatusWindowLabel\": \"\",\n\t\t\"incidentConfigStatusWindowThresholdLabel\": \"\",\n\t\t\"incidentConfigTitle\": \"\",\n\t\t\"incidentConfigDescriptionV2\": \"\",\n\t\t\"incidentConfigStatusCheckNumber\": \"\",\n\t\t\"intervalTitle\": \"\",\n\t\t\"intervalDescription\": \"\"\n\t},\n\t\"dataRate\": \"\",\n\t\"dataReceived\": \"\",\n\t\"dataSent\": \"\",\n\t\"details\": \"\",\n\t\"drops\": \"\",\n\t\"errors\": \"\",\n\t\"errorsIn\": \"\",\n\t\"errorsOut\": \"\",\n\t\"gameServerMonitoring\": \"\",\n\t\"gameServerMonitoringDescription\": \"\",\n\t\"network\": \"\",\n\t\"networkDrops\": \"\",\n\t\"networkErrors\": \"\",\n\t\"networkInterface\": \"\",\n\t\"noNetworkStatsAvailable\": \"\",\n\t\"packetsPerSecond\": \"\",\n\t\"packetsReceived\": \"\",\n\t\"packetsReceivedRate\": \"\",\n\t\"packetsSent\": \"\",\n\t\"rate\": \"\",\n\t\"selectInterface\": \"\"\n}\n"
  },
  {
    "path": "client/src/locales/fi.json",
    "content": "{\n\t\"submit\": \"Lähetä\",\n\t\"title\": \"Otsikko\",\n\t\"distributedStatusHeaderText\": \"Reaaliaikainen kattavuus oikeilla laitteilla\",\n\t\"distributedStatusSubHeaderText\": \"Miljoonien laitteiden voimin ympäri maailman näet järjestelmän suorituskyvyn maailman alueittain, maittain tai kaupungeittain\",\n\t\"settingsDisabled\": \"Poistettu käytöstä\",\n\t\"settingsSuccessSaved\": \"\",\n\t\"settingsFailedToSave\": \"\",\n\t\"settingsStatsCleared\": \"\",\n\t\"settingsFailedToClearStats\": \"\",\n\t\"settingsMonitorsDeleted\": \"\",\n\t\"settingsFailedToDeleteMonitors\": \"\",\n\t\"starPromptTitle\": \"\",\n\t\"starPromptDescription\": \"\",\n\t\"https\": \"HTTPS\",\n\t\"http\": \"HTTP\",\n\t\"monitor\": \"Seurain\",\n\t\"aboutus\": \"Tietoja meistä\",\n\t\"now\": \"Nyt\",\n\t\"delete\": \"Poista\",\n\t\"configure\": \"Määritä\",\n\t\"responseTime\": \"Vasteaika\",\n\t\"ms\": \"ms\",\n\t\"bar\": \"Palkki\",\n\t\"area\": \"Alue\",\n\t\"country\": \"MAA\",\n\t\"city\": \"KAUPUNKI\",\n\t\"response\": \"Vastaus\",\n\t\"monitorStatusUp\": \"Valvontakohde {name} ({url}) on nyt toiminnassa ja vastaa\",\n\t\"monitorStatusDown\": \"Valvontakohde {name} ({url}) ei ole toiminnassa, eikä vastaa\",\n\t\"webhookSendSuccess\": \"Webhook-ilmoitus lähetettiin onnistuneesti\",\n\t\"webhookSendError\": \"Virhe lähetettäessä webhook-ilmoitusta palveluun {platform}\",\n\t\"webhookUnsupportedPlatform\": \"Ei tuettu palvelu: {platform}\",\n\t\"distributedRightCategoryTitle\": \"Valvonta\",\n\t\"distributedStatusServerMonitors\": \"Palvelin valvonta\",\n\t\"distributedStatusServerMonitorsDescription\": \"Valvo palvelimien tilaa\",\n\t\"distributedUptimeCreateSelectURL\": \"Tässä voit valita isäntäkohteen URL-osoitteen ja valvontatyypin.\",\n\t\"distributedUptimeCreateChecks\": \"Suoritettavat tarkistukset\",\n\t\"distributedUptimeCreateChecksDescription\": \"Voit aina lisätä tai poistaa tarkistuksia sivuston lisäämisen jälkeen.\",\n\t\"distributedUptimeCreateIncidentNotification\": \"Häiriöilmoitukset\",\n\t\"distributedUptimeCreateIncidentDescription\": \"Jos ilmenee häiriö, ilmoita käyttäjille.\",\n\t\"distributedUptimeCreateAdvancedSettings\": \"Lisäasetukset\",\n\t\"distributedUptimeDetailsNoMonitorHistory\": \"Tälle valvontakohteelle ei ole vielä tarkistushistoriaa.\",\n\t\"distributedUptimeDetailsStatusHeaderUptime\": \"\",\n\t\"distributedUptimeDetailsStatusHeaderLastUpdate\": \"Viimeksi päivitetty\",\n\t\"notifications\": {\n\t\t\"enableNotifications\": \"\",\n\t\t\"testNotification\": \"Testi-ilmoitus\",\n\t\t\"addOrEditNotifications\": \"Lisää tai muokkaa ilmoituksia\",\n\t\t\"slack\": {\n\t\t\t\"label\": \"Slack\",\n\t\t\t\"description\": \"\",\n\t\t\t\"webhookLabel\": \"Webhookin URL\",\n\t\t\t\"webhookPlaceholder\": \"\",\n\t\t\t\"webhookRequired\": \"\"\n\t\t},\n\t\t\"discord\": {\n\t\t\t\"label\": \"Discord\",\n\t\t\t\"description\": \"\",\n\t\t\t\"webhookLabel\": \"Discord Webhookin URL-osoite\",\n\t\t\t\"webhookPlaceholder\": \"https://discord.com/api/webhooks/...\",\n\t\t\t\"webhookRequired\": \"\"\n\t\t},\n\t\t\"telegram\": {\n\t\t\t\"label\": \"Telegram\",\n\t\t\t\"description\": \"\",\n\t\t\t\"tokenLabel\": \"\",\n\t\t\t\"tokenPlaceholder\": \"123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11\",\n\t\t\t\"chatIdLabel\": \"\",\n\t\t\t\"chatIdPlaceholder\": \"-1001234567890\",\n\t\t\t\"fieldsRequired\": \"\"\n\t\t},\n\t\t\"webhook\": {\n\t\t\t\"label\": \"Webhookit\",\n\t\t\t\"description\": \"\",\n\t\t\t\"urlLabel\": \"Webhookin URL\",\n\t\t\t\"urlPlaceholder\": \"https://your-server.com/webhook\",\n\t\t\t\"urlRequired\": \"\"\n\t\t},\n\t\t\"testNotificationDevelop\": \"Testi-ilmoitus 2\",\n\t\t\"integrationButton\": \"\",\n\t\t\"testSuccess\": \"Testi ilmoituksen lähetys onnistui!\",\n\t\t\"testFailed\": \"Testi ilmoituksen lähetys epäonnistui\",\n\t\t\"unsupportedType\": \"\",\n\t\t\"networkError\": \"\",\n\t\t\"fallback\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"checks\": [\"\"],\n\t\t\t\"actionButton\": \"\"\n\t\t},\n\t\t\"createButton\": \"\",\n\t\t\"createTitle\": \"\",\n\t\t\"create\": {\n\t\t\t\"success\": \"\",\n\t\t\t\"failed\": \"\"\n\t\t},\n\t\t\"fetch\": {\n\t\t\t\"success\": \"\",\n\t\t\t\"failed\": \"\"\n\t\t},\n\t\t\"delete\": {\n\t\t\t\"success\": \"\",\n\t\t\t\"failed\": \"\"\n\t\t},\n\t\t\"edit\": {\n\t\t\t\"success\": \"\",\n\t\t\t\"failed\": \"\"\n\t\t},\n\t\t\"test\": {\n\t\t\t\"success\": \"\",\n\t\t\t\"failed\": \"\"\n\t\t}\n\t},\n\t\"testLocale\": \"\",\n\t\"add\": \"Lisää\",\n\t\"monitors\": \"Seuraimet\",\n\t\"distributedUptimeStatusCreateStatusPage\": \"\",\n\t\"distributedUptimeStatusCreateStatusPageAccess\": \"\",\n\t\"distributedUptimeStatusCreateStatusPageReady\": \"\",\n\t\"distributedUptimeStatusBasicInfoHeader\": \"\",\n\t\"distributedUptimeStatusBasicInfoDescription\": \"\",\n\t\"distributedUptimeStatusLogoHeader\": \"Logo\",\n\t\"distributedUptimeStatusLogoDescription\": \"\",\n\t\"distributedUptimeStatusLogoUploadButton\": \"\",\n\t\"distributedUptimeStatusStandardMonitorsHeader\": \"\",\n\t\"distributedUptimeStatusStandardMonitorsDescription\": \"\",\n\t\"distributedUptimeStatusCreateYour\": \"\",\n\t\"distributedUptimeStatusEditYour\": \"\",\n\t\"distributedUptimeStatusPublishedLabel\": \"\",\n\t\"distributedUptimeStatusCompanyNameLabel\": \"Yrityksen nimi\",\n\t\"distributedUptimeStatusPageAddressLabel\": \"\",\n\t\"distributedUptimeStatus30Days\": \"30 päivää\",\n\t\"distributedUptimeStatus60Days\": \"60 päivää\",\n\t\"distributedUptimeStatus90Days\": \"90 päivää\",\n\t\"distributedUptimeStatusPageNotSetUp\": \"\",\n\t\"distributedUptimeStatusContactAdmin\": \"Ota yhteys järjestelmävalvojaasi\",\n\t\"distributedUptimeStatusPageNotPublic\": \"\",\n\t\"distributedUptimeStatusPageDeleteDialog\": \"\",\n\t\"distributedUptimeStatusPageDeleteConfirm\": \"\",\n\t\"distributedUptimeStatusPageDeleteDescription\": \"\",\n\t\"distributedUptimeStatusDevices\": \"\",\n\t\"distributedUptimeStatusUpt\": \"\",\n\t\"distributedUptimeStatusUptBurned\": \"\",\n\t\"distributedUptimeStatusUptLogo\": \"UPT logo\",\n\t\"incidentsTableNoIncidents\": \"\",\n\t\"incidentsTablePaginationLabel\": \"\",\n\t\"incidentsTableMonitorName\": \"\",\n\t\"incidentsTableStatus\": \"Tila\",\n\t\"incidentsTableDateTime\": \"Päivämäärä ja aika\",\n\t\"incidentsTableStatusCode\": \"\",\n\t\"incidentsTableMessage\": \"Viesti\",\n\t\"incidentsOptionsHeader\": \"\",\n\t\"incidentsOptionsHeaderFilterBy\": \"\",\n\t\"incidentsOptionsHeaderFilterAll\": \"Kaikki\",\n\t\"incidentsOptionsHeaderFilterDown\": \"Alhaalla\",\n\t\"incidentsOptionsHeaderFilterCannotResolve\": \"\",\n\t\"incidentsOptionsHeaderShow\": \"Näytä:\",\n\t\"incidentsOptionsHeaderLastHour\": \"Viime tunti\",\n\t\"incidentsOptionsHeaderLastDay\": \"Viime päivä\",\n\t\"incidentsOptionsHeaderLastWeek\": \"Viime viikko\",\n\t\"incidentsOptionsPlaceholderAllServers\": \"Kaikki palvelimet\",\n\t\"infrastructureCreateYour\": \"\",\n\t\"infrastructureCreateGeneralSettingsDescription\": \"\",\n\t\"infrastructureServerRequirement\": \"\",\n\t\"infrastructureCustomizeAlerts\": \"\",\n\t\"infrastructureAlertNotificationDescription\": \"\",\n\t\"infrastructureCreateMonitor\": \"\",\n\t\"infrastructureProtocol\": \"Protokolla\",\n\t\"infrastructureServerUrlLabel\": \"Palvelimen URL-osoite\",\n\t\"infrastructureDisplayNameLabel\": \"\",\n\t\"infrastructureAuthorizationSecretLabel\": \"\",\n\t\"gb\": \"\",\n\t\"mb\": \"\",\n\t\"mem\": \"\",\n\t\"memoryUsage\": \"Muistinkäyttö\",\n\t\"cpu\": \"\",\n\t\"cpuUsage\": \"\",\n\t\"cpuTemperature\": \"\",\n\t\"diskUsage\": \"\",\n\t\"used\": \"\",\n\t\"total\": \"\",\n\t\"cores\": \"\",\n\t\"frequency\": \"\",\n\t\"status\": \"Tila\",\n\t\"cpuPhysical\": \"\",\n\t\"cpuLogical\": \"\",\n\t\"cpuFrequency\": \"\",\n\t\"avgCpuTemperature\": \"\",\n\t\"memory\": \"Muisti\",\n\t\"disk\": \"\",\n\t\"uptime\": \"\",\n\t\"os\": \"\",\n\t\"host\": \"\",\n\t\"actions\": \"\",\n\t\"integrations\": \"\",\n\t\"integrationsPrism\": \"\",\n\t\"integrationsSlack\": \"Slack\",\n\t\"integrationsSlackInfo\": \"\",\n\t\"integrationsDiscord\": \"\",\n\t\"integrationsDiscordInfo\": \"\",\n\t\"integrationsZapier\": \"Zapier\",\n\t\"integrationsZapierInfo\": \"\",\n\t\"commonSave\": \"Tallenna\",\n\t\"createYour\": \"\",\n\t\"createMonitor\": \"\",\n\t\"pause\": \"\",\n\t\"resume\": \"\",\n\t\"editing\": \"\",\n\t\"url\": \"\",\n\t\"access\": \"\",\n\t\"timezone\": \"Aikavyöhyke\",\n\t\"features\": \"\",\n\t\"administrator\": \"\",\n\t\"loginHere\": \"\",\n\t\"displayName\": \"\",\n\t\"urlMonitor\": \"\",\n\t\"portToMonitor\": \"\",\n\t\"websiteMonitoring\": \"\",\n\t\"websiteMonitoringDescription\": \"\",\n\t\"pingMonitoring\": \"\",\n\t\"pingMonitoringDescription\": \"\",\n\t\"dockerContainerMonitoring\": \"\",\n\t\"dockerContainerMonitoringDescription\": \"\",\n\t\"portMonitoring\": \"\",\n\t\"portMonitoringDescription\": \"\",\n\t\"createMaintenanceWindow\": \"\",\n\t\"createMaintenance\": \"\",\n\t\"editMaintenance\": \"\",\n\t\"maintenanceWindowName\": \"\",\n\t\"friendlyNameInput\": \"\",\n\t\"friendlyNamePlaceholder\": \"\",\n\t\"maintenanceRepeat\": \"\",\n\t\"maintenance\": \"\",\n\t\"duration\": \"\",\n\t\"addMonitors\": \"\",\n\t\"window\": \"\",\n\t\"cancel\": \"Peruuttaa\",\n\t\"message\": \"Viesti\",\n\t\"low\": \"\",\n\t\"high\": \"\",\n\t\"statusCode\": \"Tilakoodi\",\n\t\"date&Time\": \"Päivämäärä ja aika\",\n\t\"type\": \"\",\n\t\"statusPageName\": \"\",\n\t\"publicURL\": \"Julkinen URL-osoite\",\n\t\"repeat\": \"\",\n\t\"edit\": \"Muokkaa\",\n\t\"createA\": \"\",\n\t\"remove\": \"\",\n\t\"maintenanceWindowDescription\": \"\",\n\t\"startTime\": \"\",\n\t\"timeZoneInfo\": \"\",\n\t\"monitorsToApply\": \"\",\n\t\"nextWindow\": \"\",\n\t\"notFoundButton\": \"\",\n\t\"pageSpeedConfigureSettingsDescription\": \"\",\n\t\"monitorDisplayName\": \"\",\n\t\"whenNewIncident\": \"\",\n\t\"notifySMS\": \"Ilmoita tekstiviestillä (tulossa pian)\",\n\t\"notifyEmails\": \"\",\n\t\"seperateEmails\": \"\",\n\t\"checkFrequency\": \"\",\n\t\"matchMethod\": \"\",\n\t\"expectedValue\": \"\",\n\t\"deleteDialogTitle\": \"\",\n\t\"deleteDialogDescription\": \"\",\n\t\"pageSpeedMonitor\": \"\",\n\t\"shown\": \"\",\n\t\"ago\": \"sitten\",\n\t\"companyName\": \"Yrityksen nimi\",\n\t\"pageSpeedDetailsPerformanceReport\": \"\",\n\t\"pageSpeedDetailsPerformanceReportCalculator\": \"\",\n\t\"checkingEvery\": \"\",\n\t\"statusPageCreateSettings\": \"\",\n\t\"basicInformation\": \"\",\n\t\"statusPageCreateBasicInfoDescription\": \"\",\n\t\"statusPageCreateSelectTimeZoneDescription\": \"\",\n\t\"statusPageCreateAppearanceDescription\": \"\",\n\t\"statusPageCreateSettingsCheckboxLabel\": \"\",\n\t\"statusPageCreateBasicInfoStatusPageAddress\": \"\",\n\t\"statusPageCreateTabsContent\": \"\",\n\t\"statusPageCreateTabsContentDescription\": \"\",\n\t\"statusPageCreateTabsContentFeaturesDescription\": \"\",\n\t\"showCharts\": \"Näytä kaaviot\",\n\t\"showUptimePercentage\": \"\",\n\t\"removeLogo\": \"Poista logo\",\n\t\"statusPageStatus\": \"\",\n\t\"statusPageStatusContactAdmin\": \"Ota yhteyttä järjestelmänvalvojaan\",\n\t\"statusPageStatusNotPublic\": \"\",\n\t\"statusPageStatusNoPage\": \"\",\n\t\"statusPageStatusServiceStatus\": \"\",\n\t\"deleteStatusPage\": \"\",\n\t\"deleteStatusPageConfirm\": \"\",\n\t\"deleteStatusPageDescription\": \"\",\n\t\"uptimeCreate\": \"\",\n\t\"uptimeCreateJsonPath\": \"\",\n\t\"uptimeCreateJsonPathQuery\": \"\",\n\t\"maintenanceTableActionMenuDialogTitle\": \"\",\n\t\"infrastructureEditYour\": \"Muokkaa omaa\",\n\t\"infrastructureEditMonitor\": \"\",\n\t\"infrastructureMonitorCreated\": \"\",\n\t\"infrastructureMonitorUpdated\": \"\",\n\t\"errorInvalidTypeId\": \"\",\n\t\"errorInvalidFieldId\": \"\",\n\t\"inviteNoTokenFound\": \"\",\n\t\"pageSpeedWarning\": \"\",\n\t\"pageSpeedLearnMoreLink\": \"\",\n\t\"pageSpeedAddApiKey\": \"\",\n\t\"update\": \"Päivitä\",\n\t\"invalidFileFormat\": \"\",\n\t\"invalidFileSize\": \"Tiedoston koko on liian suuri!\",\n\t\"ClickUpload\": \"\",\n\t\"DragandDrop\": \"raahaa ja pudota\",\n\t\"MaxSize\": \"Enimmäiskoko\",\n\t\"SupportedFormats\": \"Tuetut muodot\",\n\t\"FirstName\": \"Etunimi\",\n\t\"LastName\": \"Sukunimi\",\n\t\"EmailDescriptionText\": \"Tämä on nykyinen sähköpostiosoitteesi — sitä ei voi vaihtaa.\",\n\t\"YourPhoto\": \"Profiilikuva\",\n\t\"PhotoDescriptionText\": \"\",\n\t\"save\": \"Tallenna\",\n\t\"DeleteDescriptionText\": \"\",\n\t\"DeleteAccountWarning\": \"\",\n\t\"DeleteWarningTitle\": \"Haluatko todella poistaa tämän tilin?\",\n\t\"bulkImport\": {\n\t\t\"title\": \"\",\n\t\t\"selectFileTips\": \"\",\n\t\t\"selectFileDescription\": \"\",\n\t\t\"selectFile\": \"Valitse tiedosto\",\n\t\t\"parsingFailed\": \"\",\n\t\t\"uploadSuccess\": \"\",\n\t\t\"validationFailed\": \"\",\n\t\t\"noFileSelected\": \"Ei valittua tiedostoa\",\n\t\t\"fallbackPage\": \"\",\n\t\t\"invalidFileType\": \"\",\n\t\t\"uploadFailed\": \"\"\n\t},\n\t\"DeleteAccountTitle\": \"Poista tili\",\n\t\"DeleteAccountButton\": \"Poista tili\",\n\t\"publicLink\": \"Julkinen linkki\",\n\t\"maskedPageSpeedKeyPlaceholder\": \"*************************************\",\n\t\"reset\": \"Palauta\",\n\t\"ignoreTLSError\": \"\",\n\t\"tlsErrorIgnored\": \"\",\n\t\"ignoreTLSErrorDescription\": \"\",\n\t\"createNew\": \"Luo uusi\",\n\t\"greeting\": {\n\t\t\"prepend\": \"Hei\",\n\t\t\"append\": \"\",\n\t\t\"overview\": \"\"\n\t},\n\t\"roles\": {\n\t\t\"superAdmin\": \"Pääylläpitäjä\",\n\t\t\"admin\": \"Ylläpitäjä\",\n\t\t\"teamMember\": \"Tiimin jäsen\",\n\t\t\"demoUser\": \"Demokäyttäjä\"\n\t},\n\t\"teamPanel\": {\n\t\t\"teamMembers\": \"Tiimin jäsenet\",\n\t\t\"filter\": {\n\t\t\t\"all\": \"Kaikki\",\n\t\t\t\"member\": \"Jäsen\"\n\t\t},\n\t\t\"inviteTeamMember\": \"\",\n\t\t\"inviteNewTeamMember\": \"\",\n\t\t\"inviteDescription\": \"\",\n\t\t\"email\": \"Sähköposti\",\n\t\t\"selectRole\": \"Valitse rooli\",\n\t\t\"inviteLink\": \"Kutsulinkki\",\n\t\t\"cancel\": \"Peruuttaa\",\n\t\t\"noMembers\": \"\",\n\t\t\"getToken\": \"Hae tunniste\",\n\t\t\"emailToken\": \"Sähköpostitunnus\",\n\t\t\"table\": {\n\t\t\t\"name\": \"Nimi\",\n\t\t\t\"email\": \"Sähköposti\",\n\t\t\t\"role\": \"Rooli\",\n\t\t\t\"created\": \"Luotu\"\n\t\t},\n\t\t\"addTeamMember\": {\n\t\t\t\"addMemberMenu\": \"\",\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"addButton\": \"\"\n\t\t},\n\t\t\"register\": \"\",\n\t\t\"registerToast\": {\n\t\t\t\"success\": \"\",\n\t\t\t\"dbUserExists\": \"\",\n\t\t\t\"unknownError\": \"\"\n\t\t},\n\t\t\"registerTeamMember\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"auth\": {\n\t\t\t\t\"common\": {\n\t\t\t\t\t\"inputs\": {\n\t\t\t\t\t\t\"firstName\": {\n\t\t\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\t\t\"empty\": \"\",\n\t\t\t\t\t\t\t\t\"pattern\": \"\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"lastName\": {\n\t\t\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\t\t\"empty\": \"\",\n\t\t\t\t\t\t\t\t\"pattern\": \"\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"email\": {\n\t\t\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\t\t\"empty\": \"\",\n\t\t\t\t\t\t\t\t\"invalid\": \"\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"role\": {\n\t\t\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\t\t\"empty\": \"\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"role\": \"\",\n\t\t\"changeTeamPassword\": {\n\t\t\t\"changePasswordMenu\": \"\",\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"success\": \"\"\n\t\t}\n\t},\n\t\"monitorState\": {\n\t\t\"paused\": \"Tauota\",\n\t\t\"resumed\": \"Jatka\",\n\t\t\"active\": \"\"\n\t},\n\t\"menu\": {\n\t\t\"uptime\": \"\",\n\t\t\"pagespeed\": \"\",\n\t\t\"infrastructure\": \"Infrastruktuuri\",\n\t\t\"incidents\": \"\",\n\t\t\"statusPages\": \"Tilasivut\",\n\t\t\"maintenance\": \"Huolto\",\n\t\t\"integrations\": \"\",\n\t\t\"settings\": \"Asetukset\",\n\t\t\"support\": \"Tuki\",\n\t\t\"discussions\": \"Keskustelut\",\n\t\t\"docs\": \"Dokumentit\",\n\t\t\"changelog\": \"Muutosloki\",\n\t\t\"profile\": \"Profiili\",\n\t\t\"password\": \"Salasana\",\n\t\t\"team\": \"Tiimi\",\n\t\t\"logOut\": \"Kirjaudu ulos\",\n\t\t\"notifications\": \"\",\n\t\t\"logs\": \"\"\n\t},\n\t\"settingsEmailUser\": \"\",\n\t\"state\": \"Tila\",\n\t\"statusBreadCrumbsStatusPages\": \"Tilasivut\",\n\t\"statusBreadCrumbsDetails\": \"Tiedot\",\n\t\"commonSaving\": \"Tallennetaan...\",\n\t\"navControls\": \"Ohjaimet\",\n\t\"incidentsPageTitle\": \"Häiriöt\",\n\t\"passwordPanel\": {\n\t\t\"passwordChangedSuccess\": \"Salasanasi vaihdettiin onnistuneesti.\",\n\t\t\"passwordInputIncorrect\": \"\",\n\t\t\"currentPassword\": \"Nykyinen salasana\",\n\t\t\"enterCurrentPassword\": \"Kirjoita nykyinen salasanasi\",\n\t\t\"newPassword\": \"Uusi salasana\",\n\t\t\"enterNewPassword\": \"Kirjoita uusi salasana\",\n\t\t\"confirmNewPassword\": \"Vahvista uusi salasana\",\n\t\t\"passwordRequirements\": \"Uuden salasanan on oltava vähintään 8 merkkiä pitkä ja sen on sisältävä vähintään yksi iso kirjain, yksi pieni kirjain, yksi numero sekä yksi erikoismerkki.\",\n\t\t\"saving\": \"Tallennetaan...\"\n\t},\n\t\"emailSent\": \"Sähköpostin lähetys onnistui\",\n\t\"failedToSendEmail\": \"Sähköpostin lähetys epäonnistui\",\n\t\"settingsTestEmailSuccess\": \"Testisähköpostin lähetys onnistui\",\n\t\"settingsTestEmailFailed\": \"Testisähköpostin lähetys epäonnistui\",\n\t\"settingsTestEmailFailedWithReason\": \"Testisähköpostin lähetys epäonnistui: {{reason}}\",\n\t\"settingsTestEmailUnknownError\": \"Tuntematon virhe\",\n\t\"statusMsg\": {\n\t\t\"paused\": \"Valvonta on keskeytetty.\",\n\t\t\"up\": \"Sivusi on ylhäällä.\",\n\t\t\"down\": \"Sivusi on alhaalla.\",\n\t\t\"pending\": \"Odottaa...\"\n\t},\n\t\"uptimeGeneralInstructions\": {\n\t\t\"http\": \"\",\n\t\t\"ping\": \"\",\n\t\t\"docker\": \"\",\n\t\t\"port\": \"\",\n\t\t\"game\": \"\",\n\t\t\"https\": \"\"\n\t},\n\t\"common\": {\n\t\t\"appName\": \"\",\n\t\t\"monitoringAgentName\": \"\",\n\t\t\"buttons\": {\n\t\t\t\"toggleTheme\": \"\"\n\t\t},\n\t\t\"toasts\": {\n\t\t\t\"networkError\": \"\",\n\t\t\t\"checkConnection\": \"\",\n\t\t\t\"unknownError\": \"\"\n\t\t}\n\t},\n\t\"auth\": {\n\t\t\"common\": {\n\t\t\t\"navigation\": {\n\t\t\t\t\"continue\": \"\",\n\t\t\t\t\"back\": \"\"\n\t\t\t},\n\t\t\t\"inputs\": {\n\t\t\t\t\"email\": {\n\t\t\t\t\t\"label\": \"\",\n\t\t\t\t\t\"placeholder\": \"\",\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"\",\n\t\t\t\t\t\t\"invalid\": \"\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"password\": {\n\t\t\t\t\t\"label\": \"\",\n\t\t\t\t\t\"rules\": {\n\t\t\t\t\t\t\"length\": {\n\t\t\t\t\t\t\t\"beginning\": \"\",\n\t\t\t\t\t\t\t\"highlighted\": \"\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"special\": {\n\t\t\t\t\t\t\t\"beginning\": \"\",\n\t\t\t\t\t\t\t\"highlighted\": \"\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"number\": {\n\t\t\t\t\t\t\t\"beginning\": \"\",\n\t\t\t\t\t\t\t\"highlighted\": \"\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"uppercase\": {\n\t\t\t\t\t\t\t\"beginning\": \"\",\n\t\t\t\t\t\t\t\"highlighted\": \"\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"lowercase\": {\n\t\t\t\t\t\t\t\"beginning\": \"\",\n\t\t\t\t\t\t\t\"highlighted\": \"\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"match\": {\n\t\t\t\t\t\t\t\"beginning\": \"\",\n\t\t\t\t\t\t\t\"highlighted\": \"\"\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"\",\n\t\t\t\t\t\t\"length\": \"\",\n\t\t\t\t\t\t\"uppercase\": \"\",\n\t\t\t\t\t\t\"lowercase\": \"\",\n\t\t\t\t\t\t\"number\": \"\",\n\t\t\t\t\t\t\"special\": \"\",\n\t\t\t\t\t\t\"incorrect\": \"\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"passwordConfirm\": {\n\t\t\t\t\t\"label\": \"\",\n\t\t\t\t\t\"placeholder\": \"\",\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"\",\n\t\t\t\t\t\t\"different\": \"\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"firstName\": {\n\t\t\t\t\t\"label\": \"\",\n\t\t\t\t\t\"placeholder\": \"\",\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"\",\n\t\t\t\t\t\t\"length\": \"\",\n\t\t\t\t\t\t\"pattern\": \"\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"lastName\": {\n\t\t\t\t\t\"label\": \"\",\n\t\t\t\t\t\"placeholder\": \"\",\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"\",\n\t\t\t\t\t\t\"length\": \"\",\n\t\t\t\t\t\t\"pattern\": \"\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"errors\": {\n\t\t\t\t\"validation\": \"\"\n\t\t\t},\n\t\t\t\"fields\": {\n\t\t\t\t\"password\": {\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"incorrect\": \"\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"role\": {\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"min\": \"\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"login\": {\n\t\t\t\"heading\": \"\",\n\t\t\t\"subheadings\": {\n\t\t\t\t\"stepOne\": \"\",\n\t\t\t\t\"stepTwo\": \"\"\n\t\t\t},\n\t\t\t\"links\": {\n\t\t\t\t\"forgotPassword\": \"\",\n\t\t\t\t\"register\": \"\",\n\t\t\t\t\"forgotPasswordLink\": \"\",\n\t\t\t\t\"registerLink\": \"\"\n\t\t\t},\n\t\t\t\"toasts\": {\n\t\t\t\t\"success\": \"\",\n\t\t\t\t\"incorrectPassword\": \"\"\n\t\t\t},\n\t\t\t\"errors\": {\n\t\t\t\t\"password\": {\n\t\t\t\t\t\"incorrect\": \"\"\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"welcome\": \"\"\n\t\t},\n\t\t\"registration\": {\n\t\t\t\"heading\": {\n\t\t\t\t\"superAdmin\": \"\",\n\t\t\t\t\"user\": \"\"\n\t\t\t},\n\t\t\t\"subheadings\": {\n\t\t\t\t\"stepOne\": \"\",\n\t\t\t\t\"stepTwo\": \"\",\n\t\t\t\t\"stepThree\": \"\"\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\t\"superAdmin\": \"\",\n\t\t\t\t\"user\": \"\"\n\t\t\t},\n\t\t\t\"gettingStartedButton\": {\n\t\t\t\t\"superAdmin\": \"\",\n\t\t\t\t\"user\": \"\"\n\t\t\t},\n\t\t\t\"termsAndPolicies\": \"\",\n\t\t\t\"links\": {\n\t\t\t\t\"login\": \"\"\n\t\t\t},\n\t\t\t\"toasts\": {\n\t\t\t\t\"success\": \"\"\n\t\t\t},\n\t\t\t\"welcome\": \"\"\n\t\t},\n\t\t\"forgotPassword\": {\n\t\t\t\"heading\": \"\",\n\t\t\t\"subheadings\": {\n\t\t\t\t\"stepOne\": \"\",\n\t\t\t\t\"stepTwo\": \"\",\n\t\t\t\t\"stepThree\": \"\",\n\t\t\t\t\"stepFour\": \"\"\n\t\t\t},\n\t\t\t\"buttons\": {\n\t\t\t\t\"openEmail\": \"\",\n\t\t\t\t\"resetPassword\": \"\"\n\t\t\t},\n\t\t\t\"imageAlts\": {\n\t\t\t\t\"passwordKey\": \"\",\n\t\t\t\t\"email\": \"\",\n\t\t\t\t\"lock\": \"\",\n\t\t\t\t\"passwordConfirm\": \"\"\n\t\t\t},\n\t\t\t\"links\": {\n\t\t\t\t\"login\": \"\",\n\t\t\t\t\"resend\": \"\"\n\t\t\t},\n\t\t\t\"toasts\": {\n\t\t\t\t\"sent\": \"\",\n\t\t\t\t\"emailNotFound\": \"\",\n\t\t\t\t\"redirect\": \"\",\n\t\t\t\t\"success\": \"\",\n\t\t\t\t\"error\": \"\"\n\t\t\t}\n\t\t}\n\t},\n\t\"errorPages\": {\n\t\t\"serverUnreachable\": {\n\t\t\t\"toasts\": {\n\t\t\t\t\"reconnected\": \"\",\n\t\t\t\t\"stillUnreachable\": \"\"\n\t\t\t},\n\t\t\t\"alertBox\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"retryButton\": {\n\t\t\t\t\"default\": \"\",\n\t\t\t\t\"processing\": \"\"\n\t\t\t}\n\t\t}\n\t},\n\t\"createNotifications\": {\n\t\t\"title\": \"\",\n\t\t\"nameSettings\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"nameLabel\": \"\",\n\t\t\t\"namePlaceholder\": \"\"\n\t\t},\n\t\t\"typeSettings\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"typeLabel\": \"\"\n\t\t},\n\t\t\"emailSettings\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"emailLabel\": \"\",\n\t\t\t\"emailPlaceholder\": \"\"\n\t\t},\n\t\t\"slackSettings\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"webhookLabel\": \"\",\n\t\t\t\"webhookPlaceholder\": \"\"\n\t\t},\n\t\t\"pagerdutySettings\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"integrationKeyLabel\": \"\",\n\t\t\t\"integrationKeyPlaceholder\": \"\"\n\t\t},\n\t\t\"discordSettings\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"webhookLabel\": \"\",\n\t\t\t\"webhookPlaceholder\": \"\"\n\t\t},\n\t\t\"webhookSettings\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"webhookLabel\": \"\",\n\t\t\t\"webhookPlaceholder\": \"\"\n\t\t},\n\t\t\"testNotification\": \"\",\n\t\t\"dialogDeleteTitle\": \"\",\n\t\t\"dialogDeleteConfirm\": \"\"\n\t},\n\t\"notificationConfig\": {\n\t\t\"title\": \"\",\n\t\t\"description\": \"\"\n\t},\n\t\"monitorStatus\": {\n\t\t\"checkingEvery\": \"\",\n\t\t\"withCaptureAgent\": \"\",\n\t\t\"up\": \"\",\n\t\t\"down\": \"\",\n\t\t\"paused\": \"\"\n\t},\n\t\"advancedMatching\": \"\",\n\t\"sendTestNotifications\": \"\",\n\t\"selectAll\": \"\",\n\t\"showAdminLoginLink\": \"\",\n\t\"logsPage\": {\n\t\t\"title\": \"\",\n\t\t\"description\": \"\",\n\t\t\"tabs\": {\n\t\t\t\"queue\": \"\",\n\t\t\t\"logs\": \"\",\n\t\t\t\"diagnostics\": \"\"\n\t\t},\n\t\t\"toast\": {\n\t\t\t\"fetchLogsSuccess\": \"\"\n\t\t},\n\t\t\"logLevelSelect\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"values\": {\n\t\t\t\t\"all\": \"\",\n\t\t\t\t\"info\": \"\",\n\t\t\t\t\"warn\": \"\",\n\t\t\t\t\"error\": \"\",\n\t\t\t\t\"debug\": \"\"\n\t\t\t}\n\t\t}\n\t},\n\t\"queuePage\": {\n\t\t\"title\": \"\",\n\t\t\"refreshButton\": \"\",\n\t\t\"flushButton\": \"\",\n\t\t\"jobTable\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"idHeader\": \"\",\n\t\t\t\"urlHeader\": \"\",\n\t\t\t\"typeHeader\": \"\",\n\t\t\t\"activeHeader\": \"\",\n\t\t\t\"lockedAtHeader\": \"\",\n\t\t\t\"runCountHeader\": \"\",\n\t\t\t\"failCountHeader\": \"\",\n\t\t\t\"lastRunHeader\": \"\",\n\t\t\t\"lastFinishedAtHeader\": \"\",\n\t\t\t\"lastRunTookHeader\": \"\",\n\t\t\t\"intervalHeader\": \"\"\n\t\t},\n\t\t\"metricsTable\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"metricHeader\": \"\",\n\t\t\t\"valueHeader\": \"\"\n\t\t},\n\t\t\"failedJobTable\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"monitorIdHeader\": \"\",\n\t\t\t\"monitorUrlHeader\": \"\",\n\t\t\t\"failCountHeader\": \"\",\n\t\t\t\"failedAtHeader\": \"\",\n\t\t\t\"failReasonHeader\": \"\"\n\t\t}\n\t},\n\t\"export\": {\n\t\t\"title\": \"\",\n\t\t\"success\": \"\",\n\t\t\"failed\": \"\"\n\t},\n\t\"monitorActions\": {\n\t\t\"title\": \"\",\n\t\t\"import\": \"\",\n\t\t\"export\": \"\",\n\t\t\"deleteSuccess\": \"\",\n\t\t\"deleteFailed\": \"\",\n\t\t\"details\": \"\"\n\t},\n\t\"settingsPage\": {\n\t\t\"aboutSettings\": {\n\t\t\t\"labelDevelopedBy\": \"\",\n\t\t\t\"labelVersion\": \"\",\n\t\t\t\"title\": \"\"\n\t\t},\n\t\t\"demoMonitorsSettings\": {\n\t\t\t\"buttonAddMonitors\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"title\": \"\"\n\t\t},\n\t\t\"emailSettings\": {\n\t\t\t\"buttonSendTestEmail\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"descriptionTransport\": \"\",\n\t\t\t\"labelAddress\": \"\",\n\t\t\t\"labelConnectionHost\": \"\",\n\t\t\t\"labelHost\": \"\",\n\t\t\t\"labelIgnoreTLS\": \"\",\n\t\t\t\"labelPassword\": \"\",\n\t\t\t\"labelPasswordSet\": \"\",\n\t\t\t\"labelPool\": \"\",\n\t\t\t\"labelPort\": \"\",\n\t\t\t\"labelRejectUnauthorized\": \"\",\n\t\t\t\"labelRequireTLS\": \"\",\n\t\t\t\"labelSecure\": \"\",\n\t\t\t\"labelTLSServername\": \"\",\n\t\t\t\"labelUser\": \"\",\n\t\t\t\"linkTransport\": \"\",\n\t\t\t\"placeholderUser\": \"\",\n\t\t\t\"title\": \"\",\n\t\t\t\"toastEmailRequiredFieldsError\": \"\"\n\t\t},\n\t\t\"pageSpeedSettings\": {\n\t\t\t\"description\": \"\",\n\t\t\t\"labelApiKeySet\": \"\",\n\t\t\t\"labelApiKey\": \"\",\n\t\t\t\"title\": \"\"\n\t\t},\n\t\t\"saveButtonLabel\": \"\",\n\t\t\"statsSettings\": {\n\t\t\t\"clearAllStatsButton\": \"\",\n\t\t\t\"clearAllStatsDescription\": \"\",\n\t\t\t\"clearAllStatsDialogConfirm\": \"\",\n\t\t\t\"clearAllStatsDialogDescription\": \"\",\n\t\t\t\"clearAllStatsDialogTitle\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"labelTTL\": \"\",\n\t\t\t\"labelTTLOptional\": \"\",\n\t\t\t\"title\": \"\"\n\t\t},\n\t\t\"systemResetSettings\": {\n\t\t\t\"buttonRemoveAllMonitors\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"dialogConfirm\": \"\",\n\t\t\t\"dialogDescription\": \"\",\n\t\t\t\"dialogTitle\": \"\",\n\t\t\t\"title\": \"\"\n\t\t},\n\t\t\"timezoneSettings\": {\n\t\t\t\"description\": \"\",\n\t\t\t\"label\": \"\",\n\t\t\t\"title\": \"\"\n\t\t},\n\t\t\"title\": \"\",\n\t\t\"uiSettings\": {\n\t\t\t\"description\": \"\",\n\t\t\t\"labelLanguage\": \"\",\n\t\t\t\"labelTheme\": \"\",\n\t\t\t\"title\": \"\"\n\t\t},\n\t\t\"urlSettings\": {\n\t\t\t\"description\": \"\",\n\t\t\t\"label\": \"\",\n\t\t\t\"selectDisabled\": \"\",\n\t\t\t\"selectEnabled\": \"\",\n\t\t\t\"title\": \"\"\n\t\t},\n\t\t\"globalThresholds\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\"\n\t\t}\n\t},\n\t\"statusPageCreate\": {\n\t\t\"buttonSave\": \"\"\n\t},\n\t\"incidentsOptionsHeaderFilterResolved\": \"\",\n\t\"settingsSave\": \"\",\n\t\"statusPageCreateAppearanceTitle\": \"\",\n\t\"confirmPassword\": \"\",\n\t\"monitorHooks\": {\n\t\t\"failureAddDemoMonitors\": \"\",\n\t\t\"successAddDemoMonitors\": \"\"\n\t},\n\t\"settingsAppearance\": \"\",\n\t\"settingsDisplayTimezone\": \"\",\n\t\"settingsGeneralSettings\": \"\",\n\t\"incidentsOptionsHeaderTotalIncidents\": \"\",\n\t\"statusPage\": {\n\t\t\"deleteSuccess\": \"\",\n\t\t\"deleteFailed\": \"\",\n\t\t\"createSuccess\": \"\",\n\t\t\"updateSuccess\": \"\",\n\t\t\"generalSettings\": \"\",\n\t\t\"contents\": \"\",\n\t\t\"fallback\": {\n\t\t\t\"checks\": [\"\"],\n\t\t\t\"title\": \"\",\n\t\t\t\"actionButton\": \"\"\n\t\t}\n\t},\n\t\"testNotificationsDisabled\": \"\",\n\t\"incidentsTableResolvedAt\": \"\",\n\t\"incidentsTableActionResolve\": \"\",\n\t\"checkHooks\": {\n\t\t\"failureResolveOne\": \"\",\n\t\t\"failureResolveAll\": \"\",\n\t\t\"failureResolveMonitor\": \"\"\n\t},\n\t\"checkFormError\": \"\",\n\t\"diagnosticsPage\": {\n\t\t\"diagnosticDescription\": \"\",\n\t\t\"statsDescription\": \"\",\n\t\t\"gauges\": {\n\t\t\t\"heapAllocationTitle\": \"\",\n\t\t\t\"heapAllocationSubtitle\": \"\",\n\t\t\t\"heapUsageTitle\": \"\",\n\t\t\t\"heapUsageSubtitle\": \"\",\n\t\t\t\"heapUtilizationTitle\": \"\",\n\t\t\t\"heapUtilizationSubtitle\": \"\",\n\t\t\t\"instantCpuUsageTitle\": \"\",\n\t\t\t\"instantCpuUsageSubtitle\": \"\"\n\t\t},\n\t\t\"stats\": {\n\t\t\t\"eventLoopDelayTitle\": \"\",\n\t\t\t\"uptimeTitle\": \"\",\n\t\t\t\"usedHeapSizeTitle\": \"\",\n\t\t\t\"totalHeapSizeTitle\": \"\",\n\t\t\t\"osMemoryLimitTitle\": \"\"\n\t\t}\n\t},\n\t\"pageSpeedLighthouseAPI\": \"\",\n\t\"time\": {\n\t\t\"threeMinutes\": \"\",\n\t\t\"fiveMinutes\": \"\",\n\t\t\"tenMinutes\": \"\",\n\t\t\"twentyMinutes\": \"\",\n\t\t\"oneHour\": \"\",\n\t\t\"oneDay\": \"\",\n\t\t\"oneWeek\": \"\",\n\t\t\"fourMinutes\": \"\",\n\t\t\"oneMinute\": \"\",\n\t\t\"twoMinutes\": \"\",\n\t\t\"fifteenSeconds\": \"\",\n\t\t\"thirtySeconds\": \"\"\n\t},\n\t\"general\": {\n\t\t\"noOptionsFound\": \"\"\n\t},\n\t\"infrastructureMonitor\": {\n\t\t\"fallback\": {\n\t\t\t\"checks\": [\"\"],\n\t\t\t\"title\": \"\",\n\t\t\t\"actionButton\": \"\"\n\t\t}\n\t},\n\t\"maintenanceWindow\": {\n\t\t\"fallback\": {\n\t\t\t\"checks\": [\"\"],\n\t\t\t\"title\": \"\",\n\t\t\t\"actionButton\": \"\"\n\t\t}\n\t},\n\t\"pageSpeed\": {\n\t\t\"fallback\": {\n\t\t\t\"checks\": [\"\"],\n\t\t\t\"title\": \"\",\n\t\t\t\"actionButton\": \"\"\n\t\t}\n\t},\n\t\"uptimeMonitor\": {\n\t\t\"fallback\": {\n\t\t\t\"checks\": [\"\"],\n\t\t\t\"title\": \"\",\n\t\t\t\"actionButton\": \"\"\n\t\t}\n\t},\n\t\"editUserPage\": {\n\t\t\"form\": {\n\t\t\t\"email\": \"\",\n\t\t\t\"firstName\": \"\",\n\t\t\t\"lastName\": \"\",\n\t\t\t\"role\": \"\",\n\t\t\t\"save\": \"\"\n\t\t},\n\t\t\"table\": {\n\t\t\t\"actionHeader\": \"\",\n\t\t\t\"roleHeader\": \"\"\n\t\t},\n\t\t\"title\": \"\",\n\t\t\"toast\": {\n\t\t\t\"successUserUpdate\": \"\",\n\t\t\t\"validationErrors\": \"\"\n\t\t}\n\t},\n\t\"incidentsPageActionResolveMonitor\": \"\",\n\t\"incidentsPageActionResolveAll\": \"\",\n\t\"matchMethodOptions\": {\n\t\t\"equal\": \"\",\n\t\t\"equalPlaceholder\": \"\",\n\t\t\"include\": \"\",\n\t\t\"includePlaceholder\": \"\",\n\t\t\"regex\": \"\",\n\t\t\"regexPlaceholder\": \"\",\n\t\t\"text\": \"\"\n\t},\n\t\"monitorType\": {\n\t\t\"docker\": {\n\t\t\t\"label\": \"\",\n\t\t\t\"namePlaceholder\": \"\",\n\t\t\t\"placeholder\": \"\"\n\t\t},\n\t\t\"http\": {\n\t\t\t\"label\": \"\",\n\t\t\t\"namePlaceholder\": \"\",\n\t\t\t\"placeholder\": \"\"\n\t\t},\n\t\t\"ping\": {\n\t\t\t\"label\": \"\",\n\t\t\t\"namePlaceholder\": \"\",\n\t\t\t\"placeholder\": \"\"\n\t\t},\n\t\t\"port\": {\n\t\t\t\"label\": \"\",\n\t\t\t\"namePlaceholder\": \"\",\n\t\t\t\"placeholder\": \"\"\n\t\t},\n\t\t\"game\": {\n\t\t\t\"label\": \"\",\n\t\t\t\"namePlaceholder\": \"\",\n\t\t\t\"placeholder\": \"\"\n\t\t}\n\t},\n\t\"uptimeAdvancedMatching\": {\n\t\t\"jsonPath\": \"\"\n\t},\n\t\"bytesPerSecond\": \"\",\n\t\"bytesReceived\": \"\",\n\t\"bytesSent\": \"\",\n\t\"chooseGame\": \"\",\n\t\"createMonitorPage\": {\n\t\t\"incidentConfigDescription\": \"\",\n\t\t\"incidentConfigStatusWindowLabel\": \"\",\n\t\t\"incidentConfigStatusWindowThresholdLabel\": \"\",\n\t\t\"incidentConfigTitle\": \"\",\n\t\t\"incidentConfigDescriptionV2\": \"\",\n\t\t\"incidentConfigStatusCheckNumber\": \"\",\n\t\t\"intervalTitle\": \"\",\n\t\t\"intervalDescription\": \"\"\n\t},\n\t\"dataRate\": \"\",\n\t\"dataReceived\": \"\",\n\t\"dataSent\": \"\",\n\t\"details\": \"\",\n\t\"drops\": \"\",\n\t\"errors\": \"\",\n\t\"errorsIn\": \"\",\n\t\"errorsOut\": \"\",\n\t\"gameServerMonitoring\": \"\",\n\t\"gameServerMonitoringDescription\": \"\",\n\t\"network\": \"\",\n\t\"networkDrops\": \"\",\n\t\"networkErrors\": \"\",\n\t\"networkInterface\": \"\",\n\t\"noNetworkStatsAvailable\": \"\",\n\t\"packetsPerSecond\": \"\",\n\t\"packetsReceived\": \"\",\n\t\"packetsReceivedRate\": \"\",\n\t\"packetsSent\": \"\",\n\t\"rate\": \"\",\n\t\"selectInterface\": \"\"\n}\n"
  },
  {
    "path": "client/src/locales/fr.json",
    "content": "{\n\t\"submit\": \"Envoyer\",\n\t\"title\": \"Titre\",\n\t\"distributedStatusHeaderText\": \"Couverture en temps réel, sur des appareils en temps réel\",\n\t\"distributedStatusSubHeaderText\": \"Alimenté par des millions d'appareils à travers le monde, consultez les performances du système par région, pays ou ville\",\n\t\"settingsDisabled\": \"Désactivé\",\n\t\"settingsSuccessSaved\": \"Les paramètres ont bien été sauvegardés\",\n\t\"settingsFailedToSave\": \"Les paramètres n'ont pas pu être sauvegardés\",\n\t\"settingsStatsCleared\": \"Les statistiques ont été réinitialisées avec succès\",\n\t\"settingsFailedToClearStats\": \"Les statistiques n'ont pas pu être réinitialisées\",\n\t\"settingsMonitorsDeleted\": \"Tous les moniteurs ont bien été supprimés\",\n\t\"settingsFailedToDeleteMonitors\": \"La suppression de tous les moniteurs a échoué\",\n\t\"starPromptTitle\": \"Ajouter Checkmate aux favoris\",\n\t\"starPromptDescription\": \"Voir les dernières versions et aider la communauté à grandir sur Github\",\n\t\"https\": \"HTTPS\",\n\t\"http\": \"HTTP\",\n\t\"monitor\": \"Moniteur\",\n\t\"aboutus\": \"A propos de nous\",\n\t\"now\": \"Maintenant\",\n\t\"delete\": \"Supprimer\",\n\t\"configure\": \"Configurer\",\n\t\"responseTime\": \"Temps de réponse\",\n\t\"ms\": \"ms\",\n\t\"bar\": \"Graphique\",\n\t\"area\": \"Zone\",\n\t\"country\": \"PAYS\",\n\t\"city\": \"VILLE\",\n\t\"response\": \"Réponse\",\n\t\"monitorStatusUp\": \"Moniteur {name} ({url}) est désormais EN LIGNE et répond aux requêtes\",\n\t\"monitorStatusDown\": \"Moniteur {name} ({url}) est désormais HORS LIGNE et ne répond plus\",\n\t\"webhookSendSuccess\": \"La notification webhook a bien été envoyée\",\n\t\"webhookSendError\": \"Une erreur s'est produite lors de l'envoi de la notification webhook sur {platform}\",\n\t\"webhookUnsupportedPlatform\": \"La plateforme {platform} n'est pas supportée actuellement\",\n\t\"distributedRightCategoryTitle\": \"Moniteur\",\n\t\"distributedStatusServerMonitors\": \"Monitoring des serveurs\",\n\t\"distributedStatusServerMonitorsDescription\": \"Statut des moniteurs relatifs aux serveurs\",\n\t\"distributedUptimeCreateSelectURL\": \"Ici vous pouvez sélectionner l'URL de l'hôte et le type de moniteur\",\n\t\"distributedUptimeCreateChecks\": \"Vérifications à effectuer\",\n\t\"distributedUptimeCreateChecksDescription\": \"Vous pourrez ajouter ou supprimer des vérifications après l'ajout de votre site\",\n\t\"distributedUptimeCreateIncidentNotification\": \"Notifications d'incidents\",\n\t\"distributedUptimeCreateIncidentDescription\": \"Quand il y a un incident, notifier les utilisateurs\",\n\t\"distributedUptimeCreateAdvancedSettings\": \"Paramètres avancés\",\n\t\"distributedUptimeDetailsNoMonitorHistory\": \"Il n'y a pas encore d'historique de vérification pour ce moniteur\",\n\t\"distributedUptimeDetailsStatusHeaderUptime\": \"Temps en ligne :\",\n\t\"distributedUptimeDetailsStatusHeaderLastUpdate\": \"Dernière mise à jour\",\n\t\"notifications\": {\n\t\t\"enableNotifications\": \"Activer les notifications sur {{platform}}\",\n\t\t\"testNotification\": \"Notification de test\",\n\t\t\"addOrEditNotifications\": \"Ajouter ou éditer des notifications\",\n\t\t\"slack\": {\n\t\t\t\"label\": \"Slack\",\n\t\t\t\"description\": \"Pour activer les notifications Slack, créez une application Slack et activez les webhooks entrants. Ensuite, indiquer l'URL du webhook ici.\",\n\t\t\t\"webhookLabel\": \"URL du webhook\",\n\t\t\t\"webhookPlaceholder\": \"https://hooks.slack.com/services/...\",\n\t\t\t\"webhookRequired\": \"L'URL du webhook Slack est requise\"\n\t\t},\n\t\t\"discord\": {\n\t\t\t\"label\": \"Discord\",\n\t\t\t\"description\": \"Pour envoyer des données sur un canal Discord depuis Checkmate, utilisez l'intégration Webhook Discord.\",\n\t\t\t\"webhookLabel\": \"URL du webhook Discord\",\n\t\t\t\"webhookPlaceholder\": \"https://discord.com/api/webhooks/...\",\n\t\t\t\"webhookRequired\": \"L'URL du webhook Discord est requise\"\n\t\t},\n\t\t\"telegram\": {\n\t\t\t\"label\": \"Telegram\",\n\t\t\t\"description\": \"Pour activer les notifications Telegram, créez un bot Telegram en utilisant BotFather, le robot officiel pour créer et gérer ses propres robots. Indiquez ensuite votre clé API et l'ID du chat ici.\",\n\t\t\t\"tokenLabel\": \"Token du robot\",\n\t\t\t\"tokenPlaceholder\": \"123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11\",\n\t\t\t\"chatIdLabel\": \"Votre Chat ID\",\n\t\t\t\"chatIdPlaceholder\": \"-1001234567890\",\n\t\t\t\"fieldsRequired\": \"Le token Telegram et l'ID du chat sont requis.\"\n\t\t},\n\t\t\"webhook\": {\n\t\t\t\"label\": \"Webhooks\",\n\t\t\t\"description\": \"Vous pouvez indiquer un webhook personnalisé pour recevoir des notifications lorsqu'un incident se produit.\",\n\t\t\t\"urlLabel\": \"URL du webhook\",\n\t\t\t\"urlPlaceholder\": \"https://votre-serveur.fr/webhook\",\n\t\t\t\"urlRequired\": \"L'URL du webhook est nécessaire\"\n\t\t},\n\t\t\"testNotificationDevelop\": \"Notification de test 2\",\n\t\t\"integrationButton\": \"Intégration de notification\",\n\t\t\"testSuccess\": \"La notification de test a été envoyée avec succès !\",\n\t\t\"testFailed\": \"Échec de l'envoi de la notification de test\",\n\t\t\"unsupportedType\": \"Type de notification non supporté\",\n\t\t\"networkError\": \"Une erreur réseau s'est produite\",\n\t\t\"fallback\": {\n\t\t\t\"title\": \"canal de notification\",\n\t\t\t\"checks\": [\n\t\t\t\t\"Alertez les équipes en cas de temps d'arrêt ou de problèmes de performances\",\n\t\t\t\t\"Informez les ingénieurs lorsque des incidents se produisent\",\n\t\t\t\t\"Tenez les administrateurs informés des changements apportés au système\"\n\t\t\t],\n\t\t\t\"actionButton\": \"Créez votre premier canal de notification !\"\n\t\t},\n\t\t\"createButton\": \"Créer un canal de notification\",\n\t\t\"createTitle\": \"Canal de notification\",\n\t\t\"create\": {\n\t\t\t\"success\": \"La notification a été créée avec succès\",\n\t\t\t\"failed\": \"Une erreur s'est produite lors de la création de la notification\"\n\t\t},\n\t\t\"fetch\": {\n\t\t\t\"success\": \"Les notifications ont été récupérées avec succès\",\n\t\t\t\"failed\": \"Une erreur s'est produite lors de la récupération des notifications\"\n\t\t},\n\t\t\"delete\": {\n\t\t\t\"success\": \"Notification supprimée avec succès\",\n\t\t\t\"failed\": \"Une erreur s'est produite lors de la suppression de la notification\"\n\t\t},\n\t\t\"edit\": {\n\t\t\t\"success\": \"Notification modifiée avec succès\",\n\t\t\t\"failed\": \"Une erreur s'est produite lors de la modification de la notification\"\n\t\t},\n\t\t\"test\": {\n\t\t\t\"success\": \"Notification de test envoyée avec succès\",\n\t\t\t\"failed\": \"Une erreur s'est produite lors de l'envoi de la notification de test\"\n\t\t}\n\t},\n\t\"testLocale\": \"testLocale\",\n\t\"add\": \"Ajouter\",\n\t\"monitors\": \"moniteurs\",\n\t\"distributedUptimeStatusCreateStatusPage\": \"page de statut\",\n\t\"distributedUptimeStatusCreateStatusPageAccess\": \"Accès\",\n\t\"distributedUptimeStatusCreateStatusPageReady\": \"Si votre page de statut est prête, vous pouvez l'indiquer en \\\"Publiée\\\".\",\n\t\"distributedUptimeStatusBasicInfoHeader\": \"Informations de base\",\n\t\"distributedUptimeStatusBasicInfoDescription\": \"Définir le nom de la société et le sous domaine sur lequel votre page de statut pointe.\",\n\t\"distributedUptimeStatusLogoHeader\": \"Logo\",\n\t\"distributedUptimeStatusLogoDescription\": \"Ajoutez un logo pour votre page de statut\",\n\t\"distributedUptimeStatusLogoUploadButton\": \"Téléverser un logo\",\n\t\"distributedUptimeStatusStandardMonitorsHeader\": \"Moniteurs standards\",\n\t\"distributedUptimeStatusStandardMonitorsDescription\": \"Ajouter un moniteur standard à votre page de statut\",\n\t\"distributedUptimeStatusCreateYour\": \"Créer votre\",\n\t\"distributedUptimeStatusEditYour\": \"Editer votre\",\n\t\"distributedUptimeStatusPublishedLabel\": \"Publiée et visible publiquement\",\n\t\"distributedUptimeStatusCompanyNameLabel\": \"Nom de l'entreprise\",\n\t\"distributedUptimeStatusPageAddressLabel\": \"Adresse de votre page de statut\",\n\t\"distributedUptimeStatus30Days\": \"30 jours\",\n\t\"distributedUptimeStatus60Days\": \"60 jours\",\n\t\"distributedUptimeStatus90Days\": \"90 jours\",\n\t\"distributedUptimeStatusPageNotSetUp\": \"Aucune page de statut n'est mise en place.\",\n\t\"distributedUptimeStatusContactAdmin\": \"Veuillez contacter votre administrateur\",\n\t\"distributedUptimeStatusPageNotPublic\": \"Cette page de statut n'est pas publique.\",\n\t\"distributedUptimeStatusPageDeleteDialog\": \"Voulez-vous supprimer cette page de statut ?\",\n\t\"distributedUptimeStatusPageDeleteConfirm\": \"Oui, supprimer la page de statut\",\n\t\"distributedUptimeStatusPageDeleteDescription\": \"Supprimer votre page de statut est irréversible.\",\n\t\"distributedUptimeStatusDevices\": \"Équipements\",\n\t\"distributedUptimeStatusUpt\": \"UPT\",\n\t\"distributedUptimeStatusUptBurned\": \"\",\n\t\"distributedUptimeStatusUptLogo\": \"Logo Upt\",\n\t\"incidentsTableNoIncidents\": \"Aucun incident enregistrée\",\n\t\"incidentsTablePaginationLabel\": \"incidents\",\n\t\"incidentsTableMonitorName\": \"Nom du moniteur\",\n\t\"incidentsTableStatus\": \"Statut\",\n\t\"incidentsTableDateTime\": \"Date et heure\",\n\t\"incidentsTableStatusCode\": \"Code de statut\",\n\t\"incidentsTableMessage\": \"Message\",\n\t\"incidentsOptionsHeader\": \"Incidents pour :\",\n\t\"incidentsOptionsHeaderFilterBy\": \"Filtrer par :\",\n\t\"incidentsOptionsHeaderFilterAll\": \"Tout\",\n\t\"incidentsOptionsHeaderFilterDown\": \"Hors ligne\",\n\t\"incidentsOptionsHeaderFilterCannotResolve\": \"Impossible de résoudre\",\n\t\"incidentsOptionsHeaderShow\": \"Voir:\",\n\t\"incidentsOptionsHeaderLastHour\": \"Dernière heure\",\n\t\"incidentsOptionsHeaderLastDay\": \"Dernier jour\",\n\t\"incidentsOptionsHeaderLastWeek\": \"Dernière semaine\",\n\t\"incidentsOptionsPlaceholderAllServers\": \"Tous les serveurs\",\n\t\"infrastructureCreateYour\": \"Créer votre\",\n\t\"infrastructureCreateGeneralSettingsDescription\": \"Ici, vous pouvez sélectionner l'URL de l'hôte, ainsi que le nom familier et le secret d'autorisation pour vous connecter à l'agent sur le serveur.\",\n\t\"infrastructureServerRequirement\": \"Le serveur que vous surveillez doit exécuter le\",\n\t\"infrastructureCustomizeAlerts\": \"Personnaliser les alertes\",\n\t\"infrastructureAlertNotificationDescription\": \"Envoyer une notification aux utilisateurs lorsque le seuil dépasse un pourcentage spécifié.\",\n\t\"infrastructureCreateMonitor\": \"Créer un moniteur d'infrastructure\",\n\t\"infrastructureProtocol\": \"Protocole\",\n\t\"infrastructureServerUrlLabel\": \"URL du serveur\",\n\t\"infrastructureDisplayNameLabel\": \"Nom d'affichage\",\n\t\"infrastructureAuthorizationSecretLabel\": \"Secret d'autorisation\",\n\t\"gb\": \"GB\",\n\t\"mb\": \"MB\",\n\t\"mem\": \"Mém\",\n\t\"memoryUsage\": \"Utilisation de la mémoire\",\n\t\"cpu\": \"CPU\",\n\t\"cpuUsage\": \"Utilisation CPU\",\n\t\"cpuTemperature\": \"Température CPU\",\n\t\"diskUsage\": \"Utilisation du disque\",\n\t\"used\": \"Utilisé\",\n\t\"total\": \"Total\",\n\t\"cores\": \"Coeurs\",\n\t\"frequency\": \"Fréquence\",\n\t\"status\": \"Statut\",\n\t\"cpuPhysical\": \"CPU (Physique)\",\n\t\"cpuLogical\": \"CPU (Logique)\",\n\t\"cpuFrequency\": \"Fréquence CPU\",\n\t\"avgCpuTemperature\": \"Température moyenne du CPU\",\n\t\"memory\": \"Mémoire\",\n\t\"disk\": \"Disque\",\n\t\"uptime\": \"Temps en ligne\",\n\t\"os\": \"OS\",\n\t\"host\": \"Hôte\",\n\t\"actions\": \"Actions\",\n\t\"integrations\": \"Intégrations\",\n\t\"integrationsPrism\": \"Connecter Prism à votre service préféré.\",\n\t\"integrationsSlack\": \"Slack\",\n\t\"integrationsSlackInfo\": \"Connecter à Slack et voir les incidents dans un canal\",\n\t\"integrationsDiscord\": \"Discord\",\n\t\"integrationsDiscordInfo\": \"Connecter à Discord et voir les incidents dans un canal\",\n\t\"integrationsZapier\": \"Zapier\",\n\t\"integrationsZapierInfo\": \"Envoyer tous les incidents à Zapier\",\n\t\"commonSave\": \"Sauvegarder\",\n\t\"createYour\": \"Créez votre\",\n\t\"createMonitor\": \"Ajouter un moniteur\",\n\t\"pause\": \"Mettre en pause\",\n\t\"resume\": \"Reprendre\",\n\t\"editing\": \"Edition...\",\n\t\"url\": \"URL\",\n\t\"access\": \"Accès\",\n\t\"timezone\": \"Fuseau horaire\",\n\t\"features\": \"Fonctionnalités\",\n\t\"administrator\": \"Administrateur ?\",\n\t\"loginHere\": \"Connexion\",\n\t\"displayName\": \"Nom d'affichage\",\n\t\"urlMonitor\": \"URL à suivre\",\n\t\"portToMonitor\": \"Port du moniteur\",\n\t\"websiteMonitoring\": \"Monitoring d'un site internet\",\n\t\"websiteMonitoringDescription\": \"Utiliser HTTP(s) pour vérifier votre site ou votre API.\",\n\t\"pingMonitoring\": \"Monitoring par ping\",\n\t\"pingMonitoringDescription\": \"Vérifier si le serveur est disponible ou pas\",\n\t\"dockerContainerMonitoring\": \"Monitoring d'un container Docker\",\n\t\"dockerContainerMonitoringDescription\": \"Vérifier si votre container Docker fonctionne ou pas.\",\n\t\"portMonitoring\": \"Monitoring d'un port\",\n\t\"portMonitoringDescription\": \"Vérifier si votre port est ouvert ou non.\",\n\t\"createMaintenanceWindow\": \"Créer une fenêtre de maintenance\",\n\t\"createMaintenance\": \"Créer une maintenance\",\n\t\"editMaintenance\": \"Modifier la maintenance\",\n\t\"maintenanceWindowName\": \"Nom de la fenêtre de maintenance\",\n\t\"friendlyNameInput\": \"Nom\",\n\t\"friendlyNamePlaceholder\": \"Maintenance à __ : __ pendant ___ minutes\",\n\t\"maintenanceRepeat\": \"Répéter la maintenance\",\n\t\"maintenance\": \"maintenance\",\n\t\"duration\": \"Durée\",\n\t\"addMonitors\": \"Ajouter des moniteurs\",\n\t\"window\": \"fenêtre\",\n\t\"cancel\": \"Annuler\",\n\t\"message\": \"Message\",\n\t\"low\": \"bas\",\n\t\"high\": \"haut\",\n\t\"statusCode\": \"Code de statut\",\n\t\"date&Time\": \"Date et heure\",\n\t\"type\": \"Type\",\n\t\"statusPageName\": \"Nom de la page de statut\",\n\t\"publicURL\": \"URL publique\",\n\t\"repeat\": \"Répéter\",\n\t\"edit\": \"Modifier\",\n\t\"createA\": \"Créer un\",\n\t\"remove\": \"Supprimer\",\n\t\"maintenanceWindowDescription\": \"Vos pings ne seront pas envoyés pendant cette fenêtre de temps.\",\n\t\"startTime\": \"Date de démarrage\",\n\t\"timeZoneInfo\": \"Toutes les dates et heures sont dans le fuseau GMT+0\",\n\t\"monitorsToApply\": \"Moniteurs sur lesquels appliquer la fenêtre de maintenance\",\n\t\"nextWindow\": \"Prochaine fenêtre de maintenance\",\n\t\"notFoundButton\": \"Aller au tableau de bord principal\",\n\t\"pageSpeedConfigureSettingsDescription\": \"Vous pouvez sélectionner l'URL de hôte et le type de moniteur.\",\n\t\"monitorDisplayName\": \"Nom du moniteur\",\n\t\"whenNewIncident\": \"Lors d'un nouvel incident,\",\n\t\"notifySMS\": \"Notification par SMS (bientôt)\",\n\t\"notifyEmails\": \"Envoyer également une notification par email à plusieurs adresses (bientôt).\",\n\t\"seperateEmails\": \"Vous pouvez ajouter plusieurs adresses emails en les séparant par une virgule\",\n\t\"checkFrequency\": \"Vérifier la fréquence\",\n\t\"matchMethod\": \"Méthode de rapprochement\",\n\t\"expectedValue\": \"Valeur attendue\",\n\t\"deleteDialogTitle\": \"Voulez-vous vraiment supprimer ce moniteur ?\",\n\t\"deleteDialogDescription\": \"Une fois supprimé, le moniteur ne peut pas être récupéré.\",\n\t\"pageSpeedMonitor\": \"Moniteur PageSpeed\",\n\t\"shown\": \"Visibles\",\n\t\"ago\": \"depuis\",\n\t\"companyName\": \"Nom de la société\",\n\t\"pageSpeedDetailsPerformanceReport\": \"Les valeurs sont estimatives et peuvent varier.\",\n\t\"pageSpeedDetailsPerformanceReportCalculator\": \"Voir le calculateur\",\n\t\"checkingEvery\": \"Vérification tous les\",\n\t\"statusPageCreateSettings\": \"Si votre page de statut est prête, vous pouvez la rendre publique.\",\n\t\"basicInformation\": \"Informations de base\",\n\t\"statusPageCreateBasicInfoDescription\": \"Définir le nom de la société et le sous-domaine vers lequel pointe votre page de statut.\",\n\t\"statusPageCreateSelectTimeZoneDescription\": \"Sélectionnez le fuseau horaire qui sera utilisé pour votre page de statut\",\n\t\"statusPageCreateAppearanceDescription\": \"Définir le style par défaut de votre page de statut.\",\n\t\"statusPageCreateSettingsCheckboxLabel\": \"Publiée et visible au public\",\n\t\"statusPageCreateBasicInfoStatusPageAddress\": \"L'adresse de votre page de statut\",\n\t\"statusPageCreateTabsContent\": \"Serveurs de votre page de statut\",\n\t\"statusPageCreateTabsContentDescription\": \"Vous pouvez ajouter autant de moniteurs à votre page de statut que vous le souhaitez. Vous pouvez également les réordonner pour améliorer l'expérience utilisateur.\",\n\t\"statusPageCreateTabsContentFeaturesDescription\": \"Voir plus de détails sur la page de statut\",\n\t\"showCharts\": \"Voir les graphiques\",\n\t\"showUptimePercentage\": \"Voir le pourcentage de temps en ligne\",\n\t\"removeLogo\": \"Supprimer le logo\",\n\t\"statusPageStatus\": \"Aucune page de statut publique n'est déployée\",\n\t\"statusPageStatusContactAdmin\": \"Merci de contacter votre administrateur\",\n\t\"statusPageStatusNotPublic\": \"Cette page de statut n'est pas piblique\",\n\t\"statusPageStatusNoPage\": \"Il n'y a aucune page de statut ici\",\n\t\"statusPageStatusServiceStatus\": \"Statut des services\",\n\t\"deleteStatusPage\": \"Voulez-vous supprimer cette page de statut ?\",\n\t\"deleteStatusPageConfirm\": \"Oui, supprimer la page de statut\",\n\t\"deleteStatusPageDescription\": \"Une fois supprimée, votre page de statut ne pourra plus être récupérée.\",\n\t\"uptimeCreate\": \"La valeur attendue est utilisée pour comparer le résultat de la réponse et la correspondance détermine le statut du moniteur.\",\n\t\"uptimeCreateJsonPath\": \"Cette expression sera évaluée par rapport aux données JSON de la réponse et le résultat sera utilisé pour la comparaison avec la valeur attendue. Voir\",\n\t\"uptimeCreateJsonPathQuery\": \"pour la documentation sur le langage de requête.\",\n\t\"maintenanceTableActionMenuDialogTitle\": \"Voulez-vous vraiment supprimer cette fenêtre de maintenance ?\",\n\t\"infrastructureEditYour\": \"Modifier votre\",\n\t\"infrastructureEditMonitor\": \"Sauvegarder le moniteur d'infrastructure\",\n\t\"infrastructureMonitorCreated\": \"Le moniteur d'infrastructure a été créé avec succès !\",\n\t\"infrastructureMonitorUpdated\": \"Le moniteur d'infrastructure a été modifié avec succès !\",\n\t\"errorInvalidTypeId\": \"Le type de notification fourni est invalide\",\n\t\"errorInvalidFieldId\": \"Le champ ID fourni est invalide\",\n\t\"inviteNoTokenFound\": \"Aucun jeton d'invitation fourni\",\n\t\"pageSpeedWarning\": \"Attention : vous n'avez pas encore ajouté de clé API Google PageSpeed. Sans celle-ci, le moniteur PageSpeed ne fonctionnera pas.\",\n\t\"pageSpeedLearnMoreLink\": \"Cliquer ici\",\n\t\"pageSpeedAddApiKey\": \"pour ajouter votre clé API.\",\n\t\"update\": \"Mettre à jour\",\n\t\"invalidFileFormat\": \"Format de fichier non supporté !\",\n\t\"invalidFileSize\": \"Le fichier est trop volumineux !\",\n\t\"ClickUpload\": \"Cliquez pour téléverser\",\n\t\"DragandDrop\": \"glisser et déposer\",\n\t\"MaxSize\": \"Taille maximum\",\n\t\"SupportedFormats\": \"Formats supportés\",\n\t\"FirstName\": \"Prénom\",\n\t\"LastName\": \"Nom\",\n\t\"EmailDescriptionText\": \"Il s'agit de votre adresse email actuelle : elle ne peut pas être changée.\",\n\t\"YourPhoto\": \"Photo de profil\",\n\t\"PhotoDescriptionText\": \"La photo sera affichée sur votre page de profil.\",\n\t\"save\": \"Enregistrer\",\n\t\"DeleteDescriptionText\": \"Cela supprimera le compte et toutes les données associées du serveur. Cette opération est irréversible.\",\n\t\"DeleteAccountWarning\": \"Supprimer votre compte signifie que vous ne pourrez pas vous reconnecter et que toutes vos données seront supprimés. Ceci est irréversible.\",\n\t\"DeleteWarningTitle\": \"Vous supprimez vraiment ce compte ?\",\n\t\"bulkImport\": {\n\t\t\"title\": \"Import en masse\",\n\t\t\"selectFileTips\": \"Sélectionnez un fichier CSV pour l'upload\",\n\t\t\"selectFileDescription\": \"Vous pouvez télécharger notre <template>modèle</template> ou <sample>exemple</sample>.\",\n\t\t\"selectFile\": \"Sélectionner un fichier\",\n\t\t\"parsingFailed\": \"L'analyse du fichier a rencontré un problème\",\n\t\t\"uploadSuccess\": \"Moniteurs créés avec succès !\",\n\t\t\"validationFailed\": \"Echec de la validation\",\n\t\t\"noFileSelected\": \"Aucun fichier sélectionné\",\n\t\t\"fallbackPage\": \"Importer un fichier pour ajouter une liste de serveurs en masse\",\n\t\t\"invalidFileType\": \"Type de fichier invalide\",\n\t\t\"uploadFailed\": \"Le téléchargement a échoué\"\n\t},\n\t\"DeleteAccountTitle\": \"Supprimer le compte\",\n\t\"DeleteAccountButton\": \"Supprimer le compte\",\n\t\"publicLink\": \"Lien public\",\n\t\"maskedPageSpeedKeyPlaceholder\": \"*************************************\",\n\t\"reset\": \"Réinitialiser\",\n\t\"ignoreTLSError\": \"Ignorer les erreurs TLS/SSL\",\n\t\"tlsErrorIgnored\": \"Erreurs TLS/SSL ignorées\",\n\t\"ignoreTLSErrorDescription\": \"Ignorer les erreurs TLS/SSL et continuer à vérifier l'accessibilité du site web\",\n\t\"createNew\": \"Créer un nouveau\",\n\t\"greeting\": {\n\t\t\"prepend\": \"Salut !\",\n\t\t\"append\": \"L'après-midi est votre libre, rendons-le épique !\",\n\t\t\"overview\": \"Voici un aperçu de vos moniteurs {{type}}.\"\n\t},\n\t\"roles\": {\n\t\t\"superAdmin\": \"Super admin\",\n\t\t\"admin\": \"Admin\",\n\t\t\"teamMember\": \"Membre de l'équipe\",\n\t\t\"demoUser\": \"Utilisateur de démonstration\"\n\t},\n\t\"teamPanel\": {\n\t\t\"teamMembers\": \"Membres de l'équipe\",\n\t\t\"filter\": {\n\t\t\t\"all\": \"Tous\",\n\t\t\t\"member\": \"Membre\"\n\t\t},\n\t\t\"inviteTeamMember\": \"Inviter un membre de l'équipe\",\n\t\t\"inviteNewTeamMember\": \"Inviter un nouveau membre d'équipe\",\n\t\t\"inviteDescription\": \"Lorsque vous ajoutez un nouveau membre à l'équipe, il aura accès à tous les moniteurs.\",\n\t\t\"email\": \"Email\",\n\t\t\"selectRole\": \"Sélectionnez un rôle\",\n\t\t\"inviteLink\": \"Lien d'invitation\",\n\t\t\"cancel\": \"Annuler\",\n\t\t\"noMembers\": \"Il n'y a aucun membre d'équipe avec ce rôle\",\n\t\t\"getToken\": \"Récupérer un token\",\n\t\t\"emailToken\": \"Token de l'email\",\n\t\t\"table\": {\n\t\t\t\"name\": \"Nom\",\n\t\t\t\"email\": \"Email\",\n\t\t\t\"role\": \"Rôle\",\n\t\t\t\"created\": \"Créée\"\n\t\t},\n\t\t\"addTeamMember\": {\n\t\t\t\"addMemberMenu\": \"\",\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"addButton\": \"\"\n\t\t},\n\t\t\"register\": \"\",\n\t\t\"registerToast\": {\n\t\t\t\"success\": \"\",\n\t\t\t\"dbUserExists\": \"\",\n\t\t\t\"unknownError\": \"\"\n\t\t},\n\t\t\"registerTeamMember\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"auth\": {\n\t\t\t\t\"common\": {\n\t\t\t\t\t\"inputs\": {\n\t\t\t\t\t\t\"firstName\": {\n\t\t\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\t\t\"empty\": \"\",\n\t\t\t\t\t\t\t\t\"pattern\": \"\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"lastName\": {\n\t\t\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\t\t\"empty\": \"\",\n\t\t\t\t\t\t\t\t\"pattern\": \"\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"email\": {\n\t\t\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\t\t\"empty\": \"\",\n\t\t\t\t\t\t\t\t\"invalid\": \"\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"role\": {\n\t\t\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\t\t\"empty\": \"\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"role\": \"\",\n\t\t\"changeTeamPassword\": {\n\t\t\t\"changePasswordMenu\": \"\",\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"success\": \"\"\n\t\t}\n\t},\n\t\"monitorState\": {\n\t\t\"paused\": \"Pause\",\n\t\t\"resumed\": \"Reprendre\",\n\t\t\"active\": \"Actif\"\n\t},\n\t\"menu\": {\n\t\t\"uptime\": \"Temps en ligne\",\n\t\t\"pagespeed\": \"Vitesse\",\n\t\t\"infrastructure\": \"Infrastructure\",\n\t\t\"incidents\": \"Incidents\",\n\t\t\"statusPages\": \"Pages de statut\",\n\t\t\"maintenance\": \"Maintenance\",\n\t\t\"integrations\": \"Intégrations\",\n\t\t\"settings\": \"Paramètres\",\n\t\t\"support\": \"Support\",\n\t\t\"discussions\": \"Discussions\",\n\t\t\"docs\": \"Documentation\",\n\t\t\"changelog\": \"Changelog\",\n\t\t\"profile\": \"Profil\",\n\t\t\"password\": \"Mot de passe\",\n\t\t\"team\": \"Équipe\",\n\t\t\"logOut\": \"Déconnexion\",\n\t\t\"notifications\": \"Notifications\",\n\t\t\"logs\": \"Journaux\"\n\t},\n\t\"settingsEmailUser\": \"Utilisateur SMTP - Utilisateur pour l'authentification, écrase l'adresse email si spécifiée\",\n\t\"state\": \"État\",\n\t\"statusBreadCrumbsStatusPages\": \"Pages de statut\",\n\t\"statusBreadCrumbsDetails\": \"Détails\",\n\t\"commonSaving\": \"Sauvegarde...\",\n\t\"navControls\": \"Contrôle\",\n\t\"incidentsPageTitle\": \"Incidents\",\n\t\"passwordPanel\": {\n\t\t\"passwordChangedSuccess\": \"Votre mot de passe a été modifié avec succès.\",\n\t\t\"passwordInputIncorrect\": \"La saisie de votre mot de passe est incorrecte.\",\n\t\t\"currentPassword\": \"Mot de passe actuel\",\n\t\t\"enterCurrentPassword\": \"Entrez votre mot de passe actuel\",\n\t\t\"newPassword\": \"Nouveau mot de passe\",\n\t\t\"enterNewPassword\": \"Entrez votre nouveau mot de passe\",\n\t\t\"confirmNewPassword\": \"Confirmer le nouveau mot de passe\",\n\t\t\"passwordRequirements\": \"Le nouveau mot de passe doit contenir au moins 8 caractères et au moins une lettre majuscule, une lettre minuscule, un chiffre et un caractère spécial.\",\n\t\t\"saving\": \"Sauvegarde...\"\n\t},\n\t\"emailSent\": \"Email envoyé avec succès\",\n\t\"failedToSendEmail\": \"Une erreur s'est produite lors de l'envoi de l'email\",\n\t\"settingsTestEmailSuccess\": \"Email de test envoyé avec succès\",\n\t\"settingsTestEmailFailed\": \"Une erreur s'est produite lors de l'envoi de l'email de test\",\n\t\"settingsTestEmailFailedWithReason\": \"Une erreur s'est produite lors de l'envoi de l'email de test : {{reason}}\",\n\t\"settingsTestEmailUnknownError\": \"Erreur inconnue\",\n\t\"statusMsg\": {\n\t\t\"paused\": \"Le moniteur est en pause.\",\n\t\t\"up\": \"Votre site est en ligne.\",\n\t\t\"down\": \"Votre site est hors-ligne.\",\n\t\t\"pending\": \"En attente...\"\n\t},\n\t\"uptimeGeneralInstructions\": {\n\t\t\"http\": \"Entrez l'URL ou l'IP du moniteur (par exemple https://exemple.fr ou 192.168.1.100) et ajoutez un nom familier qui apparaîtra sur le tableau de bord.\",\n\t\t\"ping\": \"Entrez l'adresse IP ou le nom d'hôte à tester (par exemple, 192.168.1.100 ou exemple.fr) et ajoutez un nom familier qui apparaîtra sur le tableau de bord.\",\n\t\t\"docker\": \"Entrer l'ID Docker du container. Les identifiants Docker doivent être les 64 caractères de l'ID Docker. Vous pouvez utiliser la commande docker inspect <short_id> pour avoir l'ID complet.\",\n\t\t\"port\": \"Entrez l'URL ou l'adresse IP du serveur, le numéro de port et un nom d'affichage familier qui apparaîtra sur le tableau de bord.\",\n\t\t\"game\": \"\",\n\t\t\"https\": \"\"\n\t},\n\t\"common\": {\n\t\t\"appName\": \"Checkmate\",\n\t\t\"monitoringAgentName\": \"Capture\",\n\t\t\"buttons\": {\n\t\t\t\"toggleTheme\": \"Afficher le mode clair & sombre\"\n\t\t},\n\t\t\"toasts\": {\n\t\t\t\"networkError\": \"Erreur de réseau\",\n\t\t\t\"checkConnection\": \"Merci de vérifier votre connexion\",\n\t\t\t\"unknownError\": \"Erreur inconnue\"\n\t\t}\n\t},\n\t\"auth\": {\n\t\t\"common\": {\n\t\t\t\"navigation\": {\n\t\t\t\t\"continue\": \"Continuer\",\n\t\t\t\t\"back\": \"Retour\"\n\t\t\t},\n\t\t\t\"inputs\": {\n\t\t\t\t\"email\": {\n\t\t\t\t\t\"label\": \"Email\",\n\t\t\t\t\t\"placeholder\": \"jean.dupont@domaine.fr\",\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"Pour continuer, merci d'indiquer votre adresse email\",\n\t\t\t\t\t\t\"invalid\": \"Merci de vérifier la validité de l'adresse email saisie\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"password\": {\n\t\t\t\t\t\"label\": \"Mot de passe\",\n\t\t\t\t\t\"rules\": {\n\t\t\t\t\t\t\"length\": {\n\t\t\t\t\t\t\t\"beginning\": \"Doit contenir au moins\",\n\t\t\t\t\t\t\t\"highlighted\": \"Longueur de 8 caractères\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"special\": {\n\t\t\t\t\t\t\t\"beginning\": \"Doit contenir au moins\",\n\t\t\t\t\t\t\t\"highlighted\": \"un caractère spécial\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"number\": {\n\t\t\t\t\t\t\t\"beginning\": \"Doit contenir au moins\",\n\t\t\t\t\t\t\t\"highlighted\": \"un nombre\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"uppercase\": {\n\t\t\t\t\t\t\t\"beginning\": \"Doit contenir au moins\",\n\t\t\t\t\t\t\t\"highlighted\": \"un caractère majuscule\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"lowercase\": {\n\t\t\t\t\t\t\t\"beginning\": \"Doit contenir au moins\",\n\t\t\t\t\t\t\t\"highlighted\": \"un caractère miniscule\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"match\": {\n\t\t\t\t\t\t\t\"beginning\": \"Confirmer le mot de passe et le mot de passe\",\n\t\t\t\t\t\t\t\"highlighted\": \"doit valoir\"\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"Merci d'entrer votre mot de passe\",\n\t\t\t\t\t\t\"length\": \"Le mot de passe doit faire 8 caractères minimum\",\n\t\t\t\t\t\t\"uppercase\": \"Le mot de passe doit contenir au minimum une lettre majuscule\",\n\t\t\t\t\t\t\"lowercase\": \"Le mot de passe doit contenir au minimum une lettre minuscule\",\n\t\t\t\t\t\t\"number\": \"Le mot de passe doit contenir au minimum un chiffre\",\n\t\t\t\t\t\t\"special\": \"Le mot de passe doit contenir au minimum un caractère spécial\",\n\t\t\t\t\t\t\"incorrect\": \"Le mot de passe fourni est erroné\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"passwordConfirm\": {\n\t\t\t\t\t\"label\": \"Confirmer le mot de passe\",\n\t\t\t\t\t\"placeholder\": \"Entrez à nouveau le mot de passe pour confirmer\",\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"Merci d'entrer votre mot de passe à nouveau pour le confirmer (aide avec la typo)\",\n\t\t\t\t\t\t\"different\": \"Les mots de passe indiqués ne sont pas identiques, l'un d'entre eux est probablement mal écrit\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"firstName\": {\n\t\t\t\t\t\"label\": \"Prénom\",\n\t\t\t\t\t\"placeholder\": \"Jean\",\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"Merci d'entrer votre prénom\",\n\t\t\t\t\t\t\"length\": \"Le prénom doit être inférieur à 50 caractères\",\n\t\t\t\t\t\t\"pattern\": \"Le prénom ne peut contenir que des lettres, des espaces, des apostrophes ou des tirets\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"lastName\": {\n\t\t\t\t\t\"label\": \"Nom\",\n\t\t\t\t\t\"placeholder\": \"Dupont\",\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"Merci d'entrer votre nom\",\n\t\t\t\t\t\t\"length\": \"Le nom doit être inférieur à 50 caractères\",\n\t\t\t\t\t\t\"pattern\": \"Le nom ne peut contenir que des lettres, des espaces, des apostrophes ou des tirets\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"errors\": {\n\t\t\t\t\"validation\": \"Une erreur s'est produite lors de la validation des données.\"\n\t\t\t},\n\t\t\t\"fields\": {\n\t\t\t\t\"password\": {\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"incorrect\": \"Le mot de passe fourni est erroné\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"role\": {\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"min\": \"Au moins un rôle est requis\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"login\": {\n\t\t\t\"heading\": \"Connexion\",\n\t\t\t\"subheadings\": {\n\t\t\t\t\"stepOne\": \"Entrez votre adresse email\",\n\t\t\t\t\"stepTwo\": \"Entrez votre mot de passe\"\n\t\t\t},\n\t\t\t\"links\": {\n\t\t\t\t\"forgotPassword\": \"Mot de passe oublié ?\",\n\t\t\t\t\"register\": \"Pas encore de compte ?\",\n\t\t\t\t\"forgotPasswordLink\": \"Réinitialiser le mot de passe\",\n\t\t\t\t\"registerLink\": \"Inscrivez vous ici\"\n\t\t\t},\n\t\t\t\"toasts\": {\n\t\t\t\t\"success\": \"Bon retour ! Vous êtes connecté avec succès.\",\n\t\t\t\t\"incorrectPassword\": \"Mot de passe incorrect\"\n\t\t\t},\n\t\t\t\"errors\": {\n\t\t\t\t\"password\": {\n\t\t\t\t\t\"incorrect\": \"Le mot de passe fourni est erroné\"\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"welcome\": \"Bon retour sur Checkmate !\"\n\t\t},\n\t\t\"registration\": {\n\t\t\t\"heading\": {\n\t\t\t\t\"superAdmin\": \"Créer un super admin\",\n\t\t\t\t\"user\": \"Inscription\"\n\t\t\t},\n\t\t\t\"subheadings\": {\n\t\t\t\t\"stepOne\": \"Entrez votre informations personnelles\",\n\t\t\t\t\"stepTwo\": \"Entrez votre adresse email\",\n\t\t\t\t\"stepThree\": \"Créez votre mot de passe\"\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\t\"superAdmin\": \"Créer le compte \\\"SuperAdmin\\\" pour commencer\",\n\t\t\t\t\"user\": \"inscription comme utilisateur et demander à l'administrateur principal l'accès aux moniteurs\"\n\t\t\t},\n\t\t\t\"gettingStartedButton\": {\n\t\t\t\t\"superAdmin\": \"Créer un compte super admin\",\n\t\t\t\t\"user\": \"Inscription comme utilisateur normal\"\n\t\t\t},\n\t\t\t\"termsAndPolicies\": \"En créant un compte, vous comprenez et acceptez les <a1>Conditions d'Utilisation</a1> et la <a2>Politique de Confidentialité</a2>.\",\n\t\t\t\"links\": {\n\t\t\t\t\"login\": \"Déjà inscrit ? <a>Connexion</a>\"\n\t\t\t},\n\t\t\t\"toasts\": {\n\t\t\t\t\"success\": \"Bienvenue ! Votre compte a été créé avec succès.\"\n\t\t\t},\n\t\t\t\"welcome\": \"Bienvenue sur Checkmate !\"\n\t\t},\n\t\t\"forgotPassword\": {\n\t\t\t\"heading\": \"Mot de passe oublié ?\",\n\t\t\t\"subheadings\": {\n\t\t\t\t\"stepOne\": \"Pas d'inquiétude, nous allons vous envoyer des informations pour réinitialiser votre mot de passe.\",\n\t\t\t\t\"stepTwo\": \"Nous avons envoyer un lien de réinitialisation du mot de passe à l'email <email/>\",\n\t\t\t\t\"stepThree\": \"Votre nouveau mot de passe doit être différent des précédents.\",\n\t\t\t\t\"stepFour\": \"Votre mot de passe a été réinitialisé avec succès. Cliquez ci-dessous pour vous connecter.\"\n\t\t\t},\n\t\t\t\"buttons\": {\n\t\t\t\t\"openEmail\": \"Ouvrir votre application email\",\n\t\t\t\t\"resetPassword\": \"Réinitialiser le mot de passe\"\n\t\t\t},\n\t\t\t\"imageAlts\": {\n\t\t\t\t\"passwordKey\": \"Icône du mot de passe\",\n\t\t\t\t\"email\": \"Icône de l'email\",\n\t\t\t\t\"lock\": \"Icône de verrouillage\",\n\t\t\t\t\"passwordConfirm\": \"Icône de confirmation du mot de passe\"\n\t\t\t},\n\t\t\t\"links\": {\n\t\t\t\t\"login\": \"Retourner à la page de <a>connexion</a>\",\n\t\t\t\t\"resend\": \"Vous n'avez pas reçu l'email ? <a>Cliquez ici pour le renvoyer</a>\"\n\t\t\t},\n\t\t\t\"toasts\": {\n\t\t\t\t\"sent\": \"Instructions envoyées sur l'adresse email <email/>.\",\n\t\t\t\t\"emailNotFound\": \"L'email n'a pas été trouvé.\",\n\t\t\t\t\"redirect\": \"Redirection dans <seconds/>...\",\n\t\t\t\t\"success\": \"Votre mot de passe\",\n\t\t\t\t\"error\": \"Une erreur s'est produite lors de la réinitialisation du mot de passe. Réessayez ultérieurement ou contactez le support.\"\n\t\t\t}\n\t\t}\n\t},\n\t\"errorPages\": {\n\t\t\"serverUnreachable\": {\n\t\t\t\"toasts\": {\n\t\t\t\t\"reconnected\": \"Connexion rétablie avec le serveur.\",\n\t\t\t\t\"stillUnreachable\": \"Le serveur est toujours inaccessible. Réessayez ultérieurement.\"\n\t\t\t},\n\t\t\t\"alertBox\": \"Erreur de connexion au serveur\",\n\t\t\t\"description\": \"Nous ne parvenons pas à nous connecter au serveur. Veuillez vérifier votre connexion Internet ou vérifier votre configuration de déploiement si le problème persiste.\",\n\t\t\t\"retryButton\": {\n\t\t\t\t\"default\": \"Réessayer la connexion\",\n\t\t\t\t\"processing\": \"Connexion...\"\n\t\t\t}\n\t\t}\n\t},\n\t\"createNotifications\": {\n\t\t\"title\": \"Créer un canal de notification\",\n\t\t\"nameSettings\": {\n\t\t\t\"title\": \"Nom\",\n\t\t\t\"description\": \"Une description pour votre intégration.\",\n\t\t\t\"nameLabel\": \"Nom\",\n\t\t\t\"namePlaceholder\": \"e.g. notifications Slack\"\n\t\t},\n\t\t\"typeSettings\": {\n\t\t\t\"title\": \"Type\",\n\t\t\t\"description\": \"Sélectionnez le type de canal de notification que vous souhaitez créer.\",\n\t\t\t\"typeLabel\": \"Type\"\n\t\t},\n\t\t\"emailSettings\": {\n\t\t\t\"title\": \"Email\",\n\t\t\t\"description\": \"Adresse email du destinataire\",\n\t\t\t\"emailLabel\": \"Adresse email\",\n\t\t\t\"emailPlaceholder\": \"e.g. jean@exemple.fr\"\n\t\t},\n\t\t\"slackSettings\": {\n\t\t\t\"title\": \"Slack\",\n\t\t\t\"description\": \"Configurez votre webhook Slack ici\",\n\t\t\t\"webhookLabel\": \"URL du webhook Slack\",\n\t\t\t\"webhookPlaceholder\": \"https://hooks.slack.com/services/...\"\n\t\t},\n\t\t\"pagerdutySettings\": {\n\t\t\t\"title\": \"PagerDuty\",\n\t\t\t\"description\": \"Configurez l'intégration PagerDuty ici\",\n\t\t\t\"integrationKeyLabel\": \"Clé d'intégration\",\n\t\t\t\"integrationKeyPlaceholder\": \"1234567890\"\n\t\t},\n\t\t\"discordSettings\": {\n\t\t\t\"title\": \"Discord\",\n\t\t\t\"description\": \"Configurez votre webhook Discord ici\",\n\t\t\t\"webhookLabel\": \"URL du webhook Discord\",\n\t\t\t\"webhookPlaceholder\": \"https://your-server.com/webhook\"\n\t\t},\n\t\t\"webhookSettings\": {\n\t\t\t\"title\": \"Webhook\",\n\t\t\t\"description\": \"Configurez votre webhook ici\",\n\t\t\t\"webhookLabel\": \"URL du webhook\",\n\t\t\t\"webhookPlaceholder\": \"https://your-server.com/webhook\"\n\t\t},\n\t\t\"testNotification\": \"Notification de test\",\n\t\t\"dialogDeleteTitle\": \"Voulez-vous vraiment supprimer cette notification ?\",\n\t\t\"dialogDeleteConfirm\": \"Supprimer\"\n\t},\n\t\"notificationConfig\": {\n\t\t\"title\": \"Notifications\",\n\t\t\"description\": \"Sélectionnez les canaux de notification que vous souhaitez utiliser\"\n\t},\n\t\"monitorStatus\": {\n\t\t\"checkingEvery\": \"Vérifier toutes les {{interval}}\",\n\t\t\"withCaptureAgent\": \"avec l'agent Capture {{version}}\",\n\t\t\"up\": \"en ligne\",\n\t\t\"down\": \"hors ligne\",\n\t\t\"paused\": \"en pause\"\n\t},\n\t\"advancedMatching\": \"Filtrage avancé\",\n\t\"sendTestNotifications\": \"Envoyer une notification de test\",\n\t\"selectAll\": \"Sélectionner tout\",\n\t\"showAdminLoginLink\": \"Voir le lien \\\"Administrateur ? Connectez-vous ici\\\" sur la page de statut\",\n\t\"logsPage\": {\n\t\t\"title\": \"Journaux\",\n\t\t\"description\": \"Journaux systèmes - 1000 dernières lignes\",\n\t\t\"tabs\": {\n\t\t\t\"queue\": \"File d'attente des tâches\",\n\t\t\t\"logs\": \"Journaux des serveurs\",\n\t\t\t\"diagnostics\": \"Diagnostic\"\n\t\t},\n\t\t\"toast\": {\n\t\t\t\"fetchLogsSuccess\": \"Journaux récupérés avec succès\"\n\t\t},\n\t\t\"logLevelSelect\": {\n\t\t\t\"title\": \"Niveau de journalisation\",\n\t\t\t\"values\": {\n\t\t\t\t\"all\": \"Tout\",\n\t\t\t\t\"info\": \"Info\",\n\t\t\t\t\"warn\": \"Attention\",\n\t\t\t\t\"error\": \"Erreur\",\n\t\t\t\t\"debug\": \"Debug\"\n\t\t\t}\n\t\t}\n\t},\n\t\"queuePage\": {\n\t\t\"title\": \"File d'attente\",\n\t\t\"refreshButton\": \"Rafraîchir\",\n\t\t\"flushButton\": \"Vider la file d'attente\",\n\t\t\"jobTable\": {\n\t\t\t\"title\": \"Tâches actuellement dans la file d'attente\",\n\t\t\t\"idHeader\": \"ID du moniteur\",\n\t\t\t\"urlHeader\": \"URL\",\n\t\t\t\"typeHeader\": \"Type\",\n\t\t\t\"activeHeader\": \"Actif\",\n\t\t\t\"lockedAtHeader\": \"Verrouillé le\",\n\t\t\t\"runCountHeader\": \"Nombre de tentatives\",\n\t\t\t\"failCountHeader\": \"Nombre d'échecs\",\n\t\t\t\"lastRunHeader\": \"Dernière tentative le\",\n\t\t\t\"lastFinishedAtHeader\": \"Dernière finalisation à\",\n\t\t\t\"lastRunTookHeader\": \"Dernière exécution effectuée\",\n\t\t\t\"intervalHeader\": \"\"\n\t\t},\n\t\t\"metricsTable\": {\n\t\t\t\"title\": \"Métriques des files\",\n\t\t\t\"metricHeader\": \"Métrique\",\n\t\t\t\"valueHeader\": \"Valeur\"\n\t\t},\n\t\t\"failedJobTable\": {\n\t\t\t\"title\": \"Tâches en échec\",\n\t\t\t\"monitorIdHeader\": \"ID du moniteur\",\n\t\t\t\"monitorUrlHeader\": \"URL du moniteur\",\n\t\t\t\"failCountHeader\": \"Nombre de tentatives échouées\",\n\t\t\t\"failedAtHeader\": \"Dernier échec à\",\n\t\t\t\"failReasonHeader\": \"Raison de l'échec\"\n\t\t}\n\t},\n\t\"export\": {\n\t\t\"title\": \"Export des moniteurs\",\n\t\t\"success\": \"Les moniteurs ont été exportés avec succès !\",\n\t\t\"failed\": \"Une erreur s'est produite lors de l'export des moniteurs\"\n\t},\n\t\"monitorActions\": {\n\t\t\"title\": \"Export/Import\",\n\t\t\"import\": \"Importer des moniteurs\",\n\t\t\"export\": \"Exporter des moniteurs\",\n\t\t\"deleteSuccess\": \"Le moniteur a été supprimé avec succès\",\n\t\t\"deleteFailed\": \"Une erreur s'est produite lors de la suppression du moniteur\",\n\t\t\"details\": \"Détails\"\n\t},\n\t\"settingsPage\": {\n\t\t\"aboutSettings\": {\n\t\t\t\"labelDevelopedBy\": \"Développé par Bluewave Labs\",\n\t\t\t\"labelVersion\": \"Version\",\n\t\t\t\"title\": \"A propos\"\n\t\t},\n\t\t\"demoMonitorsSettings\": {\n\t\t\t\"buttonAddMonitors\": \"Ajouter un moniteur de démonstration\",\n\t\t\t\"description\": \"Ajouter un moniteur à des fins de démonstration.\",\n\t\t\t\"title\": \"Moniteurs de démonstration\"\n\t\t},\n\t\t\"emailSettings\": {\n\t\t\t\"buttonSendTestEmail\": \"Envoyer un mail de test\",\n\t\t\t\"description\": \"Configurez les paramètres emails pour le système. Il s'agit du système utilisé pour les notifications & alertes.\",\n\t\t\t\"descriptionTransport\": \"Ceci créé un transport SMTP pour NodeMailer\",\n\t\t\t\"labelAddress\": \"Adresse email - utilisée pour la connexion\",\n\t\t\t\"labelConnectionHost\": \"Hôte SMTP - Nom d'hôte à utiliser dans l'introduction HELO/EHLO\",\n\t\t\t\"labelHost\": \"Hôte SMTP - Nom d'hôte ou IP sur lequel se connecter\",\n\t\t\t\"labelIgnoreTLS\": \"Désactiver STARTTLS : ne pas utiliser TLS même si le serveur le supporte\",\n\t\t\t\"labelPassword\": \"Mot de passe SMTP - Mot de passe requis pour l'authentification\",\n\t\t\t\"labelPasswordSet\": \"Le mot de passe est renseigné. Réinitialisez le pour le changer.\",\n\t\t\t\"labelPool\": \"Activer le pool de connexion SMTP afin de réutiliser les connexions existantes pour améliorer la performance\",\n\t\t\t\"labelPort\": \"Port SMTP - Port auquel se connecter\",\n\t\t\t\"labelRejectUnauthorized\": \"Rejeter les certificats non valides : rejeter les connexions avec des certificats auto-signés ou non fiables\",\n\t\t\t\"labelRequireTLS\": \"Forcer STARTTLS : nécessite la mise à niveau TLS, échouer si ce n'est pas supporté\",\n\t\t\t\"labelSecure\": \"Utiliser le SSL (recommandé) : chiffrer la connexion SSL/TLS\",\n\t\t\t\"labelTLSServername\": \"Nom du serveur TLS - Nom d'hôte facultatif pour la validation TLS lorsque l'hôte est une adresse IP\",\n\t\t\t\"labelUser\": \"Utilisateur SMTP - Nom d'utilisateur pour l'authentification, remplace l'adresse email si spécifié\",\n\t\t\t\"linkTransport\": \"Voir les spécifications ici\",\n\t\t\t\"placeholderUser\": \"Laisser vide si non requis\",\n\t\t\t\"title\": \"Email\",\n\t\t\t\"toastEmailRequiredFieldsError\": \"L'adresse email, l'hôte, le port et le mot de passe sont obligatoires.\"\n\t\t},\n\t\t\"pageSpeedSettings\": {\n\t\t\t\"description\": \"Entrez votre clé API Google PageSpeed pour activer la surveillance Google PageSpeed. Cliquez sur Réinitialiser pour mettre à jour la clé.\",\n\t\t\t\"labelApiKeySet\": \"La clé API est générée. Cliquez sur \\\"Réinitialiser\\\" pour la modifier.\",\n\t\t\t\"labelApiKey\": \"Clé API PageSpeed\",\n\t\t\t\"title\": \"Clé API Google PageSpeed\"\n\t\t},\n\t\t\"saveButtonLabel\": \"Sauvegarder\",\n\t\t\"statsSettings\": {\n\t\t\t\"clearAllStatsButton\": \"Supprimer toutes les statistiques\",\n\t\t\t\"clearAllStatsDescription\": \"Supprimer toutes les statistiques. Cette action est irréversible.\",\n\t\t\t\"clearAllStatsDialogConfirm\": \"Oui, supprimer toutes les statistiques\",\n\t\t\t\"clearAllStatsDialogDescription\": \"Une fois supprimés, l'historique et les statistiques du moniteur ne peuvent plus être récupérés.\",\n\t\t\t\"clearAllStatsDialogTitle\": \"Voulez-vous supprimer toutes les statistiques ?\",\n\t\t\t\"description\": \"Définissez la durée pendant laquelle vous souhaitez conserver les données historiques. Vous pouvez également effacer toutes les données existantes.\",\n\t\t\t\"labelTTL\": \"Le nombre de jours dont vous souhaitez garder l'historique.\",\n\t\t\t\"labelTTLOptional\": \"0 pour une durée infinie\",\n\t\t\t\"title\": \"Historique du moniteur\"\n\t\t},\n\t\t\"systemResetSettings\": {\n\t\t\t\"buttonRemoveAllMonitors\": \"Supprimer tous les moniteurs\",\n\t\t\t\"description\": \"Supprimer toutes les moniteurs du système.\",\n\t\t\t\"dialogConfirm\": \"Oui, supprimer tous les moniteurs\",\n\t\t\t\"dialogDescription\": \"Une fois supprimés, les moniteurs ne peuvent plus être récupérés.\",\n\t\t\t\"dialogTitle\": \"Voulez-vous supprimer tous les moniteurs ?\",\n\t\t\t\"title\": \"Réinitialisation du système\"\n\t\t},\n\t\t\"timezoneSettings\": {\n\t\t\t\"description\": \"Sélectionnez le fuseau horaire utilisé pour afficher les dates et les heures dans l'application.\",\n\t\t\t\"label\": \"Fuseau horaire d'affichage\",\n\t\t\t\"title\": \"Fuseau horaire d'affichage\"\n\t\t},\n\t\t\"title\": \"Paramètres\",\n\t\t\"uiSettings\": {\n\t\t\t\"description\": \"Changer entre le mode clair et sombre, ou changer le langage de l'interface utilisateur.\",\n\t\t\t\"labelLanguage\": \"Langage\",\n\t\t\t\"labelTheme\": \"Thème\",\n\t\t\t\"title\": \"Apparence\"\n\t\t},\n\t\t\"urlSettings\": {\n\t\t\t\"description\": \"Affichez l'adresse IP ou l'URL du moniteur sur la page de statut publique. Si cette option est désactivée, seul le nom du moniteur sera affiché afin de protéger les informations sensibles.\",\n\t\t\t\"label\": \"Afficher l'IP/URL sur la page de statut\",\n\t\t\t\"selectDisabled\": \"Désactivé\",\n\t\t\t\"selectEnabled\": \"Activé\",\n\t\t\t\"title\": \"IP/URL du moniteur sur la page de statut\"\n\t\t},\n\t\t\"globalThresholds\": {\n\t\t\t\"title\": \"Seuils globaux\",\n\t\t\t\"description\": \"Configurez des seuils globaux pour le CPU, la mémoire, le disque et la température. Si une valeur est fournie, elle sera automatiquement activée pour la surveillance.\"\n\t\t}\n\t},\n\t\"statusPageCreate\": {\n\t\t\"buttonSave\": \"Sauvegarder\"\n\t},\n\t\"incidentsOptionsHeaderFilterResolved\": \"Résolu\",\n\t\"settingsSave\": \"Sauvegarder\",\n\t\"statusPageCreateAppearanceTitle\": \"Apparence\",\n\t\"confirmPassword\": \"Confirmer le mot de passe\",\n\t\"monitorHooks\": {\n\t\t\"failureAddDemoMonitors\": \"Une erreur s'est produite lors de l'ajout des moniteurs de démonstration\",\n\t\t\"successAddDemoMonitors\": \"Les moniteurs de démonstration ont bien été ajoutés\"\n\t},\n\t\"settingsAppearance\": \"Apparance\",\n\t\"settingsDisplayTimezone\": \"Fuseau horaire d'affichage\",\n\t\"settingsGeneralSettings\": \"Paramètres généraux\",\n\t\"incidentsOptionsHeaderTotalIncidents\": \"Nombre d'incidents\",\n\t\"statusPage\": {\n\t\t\"deleteSuccess\": \"La page de statut a été supprimée avec succès\",\n\t\t\"deleteFailed\": \"Une erreur s'est produite lors de l'ajout de la page de statut\",\n\t\t\"createSuccess\": \"La page de statut a été ajoutée avec succès\",\n\t\t\"updateSuccess\": \"La page de statut a été modifiée avec succès\",\n\t\t\"generalSettings\": \"Paramètres généraux\",\n\t\t\"contents\": \"Contenus\",\n\t\t\"fallback\": {\n\t\t\t\"checks\": [\n\t\t\t\t\"Surveillez et affichez l’état de santé de vos services en temps réel\",\n\t\t\t\t\"Suivez plusieurs services et partagez leur statut\",\n\t\t\t\t\"Tenez les utilisateurs informés des pannes et des performances\"\n\t\t\t],\n\t\t\t\"title\": \"Une page de status est utilisée pour :\",\n\t\t\t\"actionButton\": \"Créer votre première page de status !\"\n\t\t}\n\t},\n\t\"testNotificationsDisabled\": \"Il n'y aucune notification paramétrée pour ce moniteur. Vous pouvez en ajouter une en cliquant sur le bouton 'Configurer'\",\n\t\"incidentsTableResolvedAt\": \"Résolu le\",\n\t\"incidentsTableActionResolve\": \"Résoudre\",\n\t\"checkHooks\": {\n\t\t\"failureResolveOne\": \"Une erreur s'est produite lors de la résolution de l'incident.\",\n\t\t\"failureResolveAll\": \"Une erreur s'est produite lors de la résolution des incidents.\",\n\t\t\"failureResolveMonitor\": \"\"\n\t},\n\t\"checkFormError\": \"Merci de vérifier les erreurs du formulaire\",\n\t\"diagnosticsPage\": {\n\t\t\"diagnosticDescription\": \"Diagnostic du système\",\n\t\t\"statsDescription\": \"Statistiques du système\",\n\t\t\"gauges\": {\n\t\t\t\"heapAllocationTitle\": \"Allocation du tas\",\n\t\t\t\"heapAllocationSubtitle\": \"% de mémoire disponible\",\n\t\t\t\"heapUsageTitle\": \"Utilisation du tas\",\n\t\t\t\"heapUsageSubtitle\": \"% de mémoire disponible\",\n\t\t\t\"heapUtilizationTitle\": \"Utilisation du tas\",\n\t\t\t\"heapUtilizationSubtitle\": \"% d'allocation\",\n\t\t\t\"instantCpuUsageTitle\": \"Utilisation instantanée du CPU\",\n\t\t\t\"instantCpuUsageSubtitle\": \"% de CPU utilisé\"\n\t\t},\n\t\t\"stats\": {\n\t\t\t\"eventLoopDelayTitle\": \"Délai de la boucle d'évènements\",\n\t\t\t\"uptimeTitle\": \"Temps en ligne\",\n\t\t\t\"usedHeapSizeTitle\": \"Taille du tas utilisé\",\n\t\t\t\"totalHeapSizeTitle\": \"Taille total du tas\",\n\t\t\t\"osMemoryLimitTitle\": \"Limite de mémoire de l'OS\"\n\t\t}\n\t},\n\t\"pageSpeedLighthouseAPI\": \"Utilisez l'API Lighthouse PageSpeed pour suivre votre site web\",\n\t\"time\": {\n\t\t\"threeMinutes\": \"3 minutes\",\n\t\t\"fiveMinutes\": \"5 minutes\",\n\t\t\"tenMinutes\": \"10 minutes\",\n\t\t\"twentyMinutes\": \"20 minutes\",\n\t\t\"oneHour\": \"1 heure\",\n\t\t\"oneDay\": \"1 jour\",\n\t\t\"oneWeek\": \"1 semaine\",\n\t\t\"fourMinutes\": \"4 minutes\",\n\t\t\"oneMinute\": \"1 minute\",\n\t\t\"twoMinutes\": \"2 minutes\",\n\t\t\"fifteenSeconds\": \"15 secondes\",\n\t\t\"thirtySeconds\": \"30 secondes\"\n\t},\n\t\"general\": {\n\t\t\"noOptionsFound\": \"Aucune {{unit}} trouvée\"\n\t},\n\t\"infrastructureMonitor\": {\n\t\t\"fallback\": {\n\t\t\t\"checks\": [\n\t\t\t\t\"Suivez les performances de vos serveurs\",\n\t\t\t\t\"Identifiez les points de blocage et optimisez l’utilisation\",\n\t\t\t\t\"Assurez la fiabilité grâce à la surveillance en temps réel\"\n\t\t\t],\n\t\t\t\"title\": \"Une surveillance d'infrastructure est utilisé pour :\",\n\t\t\t\"actionButton\": \"Créer votre premier moniteur d'infrastructure !\"\n\t\t}\n\t},\n\t\"maintenanceWindow\": {\n\t\t\"fallback\": {\n\t\t\t\"checks\": [\n\t\t\t\t\"Marquez vos périodes de maintenance\",\n\t\t\t\t\"Éliminez tout malentendu\",\n\t\t\t\t\"Arrêtez d’envoyer des alertes pendant les fenêtres de maintenance\"\n\t\t\t],\n\t\t\t\"title\": \"Une fenêtre de maintenance est utilisé pour :\",\n\t\t\t\"actionButton\": \"Créer votre première fenêtre de maintenance  !\"\n\t\t}\n\t},\n\t\"pageSpeed\": {\n\t\t\"fallback\": {\n\t\t\t\"checks\": [\n\t\t\t\t\"Rapport sur l’expérience utilisateur d’une page\",\n\t\t\t\t\"Aider à analyser la vitesse de la page web\",\n\t\t\t\t\"Donner des suggestions sur la façon dont la page peut être améliorée\"\n\t\t\t],\n\t\t\t\"title\": \"\",\n\t\t\t\"actionButton\": \"\"\n\t\t}\n\t},\n\t\"uptimeMonitor\": {\n\t\t\"fallback\": {\n\t\t\t\"checks\": [\n\t\t\t\t\"Vérifiez si les sites web ou serveurs sont en ligne et réactifs\",\n\t\t\t\t\"Alertez les équipes en cas de panne ou de problème de performance\",\n\t\t\t\t\"Surveillez les points de terminaison HTTP, les pings, les conteneurs et les ports\",\n\t\t\t\t\"Suivez l’historique de la disponibilité et les tendances de fiabilité\"\n\t\t\t],\n\t\t\t\"title\": \"\",\n\t\t\t\"actionButton\": \"\"\n\t\t}\n\t},\n\t\"editUserPage\": {\n\t\t\"form\": {\n\t\t\t\"email\": \"Email\",\n\t\t\t\"firstName\": \"Prénom\",\n\t\t\t\"lastName\": \"Nom\",\n\t\t\t\"role\": \"Rôles\",\n\t\t\t\"save\": \"Enregistrer\"\n\t\t},\n\t\t\"table\": {\n\t\t\t\"actionHeader\": \"Action\",\n\t\t\t\"roleHeader\": \"Rôle\"\n\t\t},\n\t\t\"title\": \"Modifier l'utilisateur\",\n\t\t\"toast\": {\n\t\t\t\"successUserUpdate\": \"L'utilisateur à bien été modifié\",\n\t\t\t\"validationErrors\": \"\"\n\t\t}\n\t},\n\t\"incidentsPageActionResolveMonitor\": \"Résoudres les incidents de surveillance\",\n\t\"incidentsPageActionResolveAll\": \"Résoudre tous les incidents\",\n\t\"matchMethodOptions\": {\n\t\t\"equal\": \"Égal\",\n\t\t\"equalPlaceholder\": \"\",\n\t\t\"include\": \"Inclure\",\n\t\t\"includePlaceholder\": \"ok\",\n\t\t\"regex\": \"Regex\",\n\t\t\"regexPlaceholder\": \"\",\n\t\t\"text\": \"\"\n\t},\n\t\"monitorType\": {\n\t\t\"docker\": {\n\t\t\t\"label\": \"ID du conteneur\",\n\t\t\t\"namePlaceholder\": \"Mon conteneur\",\n\t\t\t\"placeholder\": \"abcd1234\"\n\t\t},\n\t\t\"http\": {\n\t\t\t\"label\": \"URL à surveiller\",\n\t\t\t\"namePlaceholder\": \"Google\",\n\t\t\t\"placeholder\": \"google.com\"\n\t\t},\n\t\t\"ping\": {\n\t\t\t\"label\": \"Adresse IP à surveiller\",\n\t\t\t\"namePlaceholder\": \"Google\",\n\t\t\t\"placeholder\": \"1.1.1.1\"\n\t\t},\n\t\t\"port\": {\n\t\t\t\"label\": \"URL à surveiller\",\n\t\t\t\"namePlaceholder\": \"\",\n\t\t\t\"placeholder\": \"localhost\"\n\t\t},\n\t\t\"game\": {\n\t\t\t\"label\": \"\",\n\t\t\t\"namePlaceholder\": \"\",\n\t\t\t\"placeholder\": \"\"\n\t\t}\n\t},\n\t\"uptimeAdvancedMatching\": {\n\t\t\"jsonPath\": \"Chemin JSON\"\n\t},\n\t\"bytesPerSecond\": \"\",\n\t\"bytesReceived\": \"\",\n\t\"bytesSent\": \"\",\n\t\"chooseGame\": \"\",\n\t\"createMonitorPage\": {\n\t\t\"incidentConfigDescription\": \"\",\n\t\t\"incidentConfigStatusWindowLabel\": \"\",\n\t\t\"incidentConfigStatusWindowThresholdLabel\": \"\",\n\t\t\"incidentConfigTitle\": \"\",\n\t\t\"incidentConfigDescriptionV2\": \"\",\n\t\t\"incidentConfigStatusCheckNumber\": \"\",\n\t\t\"intervalTitle\": \"\",\n\t\t\"intervalDescription\": \"\"\n\t},\n\t\"dataRate\": \"\",\n\t\"dataReceived\": \"\",\n\t\"dataSent\": \"\",\n\t\"details\": \"\",\n\t\"drops\": \"\",\n\t\"errors\": \"\",\n\t\"errorsIn\": \"\",\n\t\"errorsOut\": \"\",\n\t\"gameServerMonitoring\": \"\",\n\t\"gameServerMonitoringDescription\": \"\",\n\t\"network\": \"\",\n\t\"networkDrops\": \"\",\n\t\"networkErrors\": \"\",\n\t\"networkInterface\": \"\",\n\t\"noNetworkStatsAvailable\": \"\",\n\t\"packetsPerSecond\": \"\",\n\t\"packetsReceived\": \"\",\n\t\"packetsReceivedRate\": \"\",\n\t\"packetsSent\": \"\",\n\t\"rate\": \"\",\n\t\"selectInterface\": \"\",\n\t\"v1\": {\n\t\t\"infrastructure\": {\n\t\t\t\"disk_selection_title\": \"Sélection des disques\",\n\t\t\t\"disk_selection_info\": \"Aucun disque détecté pour le moment.\",\n\t\t\t\"disk_selection_description\": \"Sélectionnez les disques spécifiques que vous souhaitez surveiller.\"\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "client/src/locales/ja.json",
    "content": "{\n\t\"submit\": \"送信\",\n\t\"title\": \"タイトル\",\n\t\"distributedStatusHeaderText\": \"リアルタイム、実デバイス対応\",\n\t\"distributedStatusSubHeaderText\": \"世界中の数百万台のデバイスを活用し、グローバル地域、国、都市別にシステムパフォーマンスを表示\",\n\t\"settingsDisabled\": \"無効\",\n\t\"settingsSuccessSaved\": \"設定が正常に保存されました\",\n\t\"settingsFailedToSave\": \"設定の保存に失敗しました\",\n\t\"settingsStatsCleared\": \"統計が正常にクリアされました\",\n\t\"settingsFailedToClearStats\": \"統計のクリアに失敗しました\",\n\t\"settingsMonitorsDeleted\": \"すべてのモニターが正常に削除されました\",\n\t\"settingsFailedToDeleteMonitors\": \"すべてのモニターの削除に失敗しました\",\n\t\"starPromptTitle\": \"Checkmateにスター\",\n\t\"starPromptDescription\": \"GitHubで最新リリースを確認し、コミュニティの成長を支援\",\n\t\"https\": \"HTTPS\",\n\t\"http\": \"HTTP\",\n\t\"monitor\": \"モニター\",\n\t\"aboutus\": \"私たちについて\",\n\t\"now\": \"今\",\n\t\"delete\": \"削除\",\n\t\"configure\": \"設定\",\n\t\"responseTime\": \"レスポンス時間\",\n\t\"ms\": \"ミリ秒\",\n\t\"bar\": \"バー\",\n\t\"area\": \"エリア\",\n\t\"country\": \"国\",\n\t\"city\": \"都市\",\n\t\"response\": \"レスポンス\",\n\t\"monitorStatusUp\": \"モニター {name} ({url}) がアップして応答中です\",\n\t\"monitorStatusDown\": \"モニター {name} ({url}) がダウンして応答していません\",\n\t\"webhookSendSuccess\": \"Webhook通知が正常に送信されました\",\n\t\"webhookSendError\": \"{platform}へのWebhook通知送信エラー\",\n\t\"webhookUnsupportedPlatform\": \"サポートされていないプラットフォーム: {platform}\",\n\t\"distributedRightCategoryTitle\": \"モニター\",\n\t\"distributedStatusServerMonitors\": \"サーバーモニター\",\n\t\"distributedStatusServerMonitorsDescription\": \"関連サーバーのステータスを監視\",\n\t\"distributedUptimeCreateSelectURL\": \"ここでホストのURL、モニタータイプを選択できます。\",\n\t\"distributedUptimeCreateChecks\": \"実行するチェック\",\n\t\"distributedUptimeCreateChecksDescription\": \"サイト追加後はいつでもチェックを追加・削除できます。\",\n\t\"distributedUptimeCreateIncidentNotification\": \"インシデント通知\",\n\t\"distributedUptimeCreateIncidentDescription\": \"インシデント発生時、ユーザーに通知。\",\n\t\"distributedUptimeCreateAdvancedSettings\": \"詳細設定\",\n\t\"distributedUptimeDetailsNoMonitorHistory\": \"このモニターのチェック履歴はまだありません。\",\n\t\"distributedUptimeDetailsStatusHeaderUptime\": \"稼働時間:\",\n\t\"distributedUptimeDetailsStatusHeaderLastUpdate\": \"最終更新\",\n\t\"notifications\": {\n\t\t\"enableNotifications\": \"{{platform}}通知を有効化\",\n\t\t\"testNotification\": \"テスト通知\",\n\t\t\"addOrEditNotifications\": \"通知を追加または編集\",\n\t\t\"slack\": {\n\t\t\t\"label\": \"Slack\",\n\t\t\t\"description\": \"Slack通知を有効にするには、Slackアプリを作成し、incoming webhookを有効にします。その後、ここでWebhook URLを提供するだけです。\",\n\t\t\t\"webhookLabel\": \"Webhook URL\",\n\t\t\t\"webhookPlaceholder\": \"https://hooks.slack.com/services/...\",\n\t\t\t\"webhookRequired\": \"Slack Webhook URLが必要です\"\n\t\t},\n\t\t\"discord\": {\n\t\t\t\"label\": \"Discord\",\n\t\t\t\"description\": \"Webhookを使用してDiscord通知経由でCheckmateからDiscordチャンネルにデータを送信するには、DiscordのIncoming Webhook機能を使用できます。\",\n\t\t\t\"webhookLabel\": \"Discord Webhook URL\",\n\t\t\t\"webhookPlaceholder\": \"https://discord.com/api/webhooks/...\",\n\t\t\t\"webhookRequired\": \"Discord Webhook URLが必要です\"\n\t\t},\n\t\t\"telegram\": {\n\t\t\t\"label\": \"Telegram\",\n\t\t\t\"description\": \"Telegram通知を有効にするには、Telegramボットを作成・管理するための公式ボットであるBotFatherを使用してTelegramボットを作成します。次に、APIトークンとチャットIDを取得してここに記入します。\",\n\t\t\t\"tokenLabel\": \"ボットトークン\",\n\t\t\t\"tokenPlaceholder\": \"123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11\",\n\t\t\t\"chatIdLabel\": \"チャットID\",\n\t\t\t\"chatIdPlaceholder\": \"-1001234567890\",\n\t\t\t\"fieldsRequired\": \"TelegramトークンとチャットIDが必要です\"\n\t\t},\n\t\t\"webhook\": {\n\t\t\t\"label\": \"Webhook\",\n\t\t\t\"description\": \"インシデント発生時に通知を受信するためのカスタムWebhookを設定できます。\",\n\t\t\t\"urlLabel\": \"Webhook URL\",\n\t\t\t\"urlPlaceholder\": \"https://your-server.com/webhook\",\n\t\t\t\"urlRequired\": \"Webhook URLが必要です\"\n\t\t},\n\t\t\"testNotificationDevelop\": \"テスト通知2\",\n\t\t\"integrationButton\": \"通知統合\",\n\t\t\"testSuccess\": \"テスト通知が正常に送信されました！\",\n\t\t\"testFailed\": \"テスト通知の送信に失敗しました\",\n\t\t\"unsupportedType\": \"サポートされていない通知タイプ\",\n\t\t\"networkError\": \"ネットワークエラーが発生しました\",\n\t\t\"fallback\": {\n\t\t\t\"title\": \"通知チャンネル\",\n\t\t\t\"checks\": [\n\t\t\t\t\"ダウンタイムやパフォーマンス問題についてチームにアラート\",\n\t\t\t\t\"インシデント発生時にエンジニアに通知\",\n\t\t\t\t\"システム変更について管理者に情報提供\"\n\t\t\t],\n\t\t\t\"actionButton\": \"\"\n\t\t},\n\t\t\"createButton\": \"通知チャンネルを作成\",\n\t\t\"createTitle\": \"通知チャンネル\",\n\t\t\"create\": {\n\t\t\t\"success\": \"通知が正常に作成されました\",\n\t\t\t\"failed\": \"通知の作成に失敗しました\"\n\t\t},\n\t\t\"fetch\": {\n\t\t\t\"success\": \"通知が正常に取得されました\",\n\t\t\t\"failed\": \"通知の取得に失敗しました\"\n\t\t},\n\t\t\"delete\": {\n\t\t\t\"success\": \"通知が正常に削除されました\",\n\t\t\t\"failed\": \"通知の削除に失敗しました\"\n\t\t},\n\t\t\"edit\": {\n\t\t\t\"success\": \"通知が正常に更新されました\",\n\t\t\t\"failed\": \"通知の更新に失敗しました\"\n\t\t},\n\t\t\"test\": {\n\t\t\t\"success\": \"テスト通知が正常に送信されました\",\n\t\t\t\"failed\": \"テスト通知の送信に失敗しました\"\n\t\t}\n\t},\n\t\"testLocale\": \"テストロケール\",\n\t\"add\": \"追加\",\n\t\"monitors\": \"モニター\",\n\t\"distributedUptimeStatusCreateStatusPage\": \"ステータスページ\",\n\t\"distributedUptimeStatusCreateStatusPageAccess\": \"アクセス\",\n\t\"distributedUptimeStatusCreateStatusPageReady\": \"ステータスページの準備ができたら、公開済みとしてマークできます。\",\n\t\"distributedUptimeStatusBasicInfoHeader\": \"基本情報\",\n\t\"distributedUptimeStatusBasicInfoDescription\": \"会社名とステータスページが指すサブドメインを定義。\",\n\t\"distributedUptimeStatusLogoHeader\": \"ロゴ\",\n\t\"distributedUptimeStatusLogoDescription\": \"ステータスページ用のロゴをアップロード\",\n\t\"distributedUptimeStatusLogoUploadButton\": \"ロゴをアップロード\",\n\t\"distributedUptimeStatusStandardMonitorsHeader\": \"標準モニター\",\n\t\"distributedUptimeStatusStandardMonitorsDescription\": \"標準モニターをステータスページに添付。\",\n\t\"distributedUptimeStatusCreateYour\": \"作成する\",\n\t\"distributedUptimeStatusEditYour\": \"編集する\",\n\t\"distributedUptimeStatusPublishedLabel\": \"公開済みで一般に表示\",\n\t\"distributedUptimeStatusCompanyNameLabel\": \"会社名\",\n\t\"distributedUptimeStatusPageAddressLabel\": \"ステータスページアドレス\",\n\t\"distributedUptimeStatus30Days\": \"30日\",\n\t\"distributedUptimeStatus60Days\": \"60日\",\n\t\"distributedUptimeStatus90Days\": \"90日\",\n\t\"distributedUptimeStatusPageNotSetUp\": \"ステータスページが設定されていません。\",\n\t\"distributedUptimeStatusContactAdmin\": \"管理者にお問い合わせください\",\n\t\"distributedUptimeStatusPageNotPublic\": \"このステータスページは非公開です。\",\n\t\"distributedUptimeStatusPageDeleteDialog\": \"このステータスページを削除しますか？\",\n\t\"distributedUptimeStatusPageDeleteConfirm\": \"はい、ステータスページを削除\",\n\t\"distributedUptimeStatusPageDeleteDescription\": \"削除されると、ステータスページは復元できません。\",\n\t\"distributedUptimeStatusDevices\": \"デバイス\",\n\t\"distributedUptimeStatusUpt\": \"UPT\",\n\t\"distributedUptimeStatusUptBurned\": \"UPT消費\",\n\t\"distributedUptimeStatusUptLogo\": \"Uptロゴ\",\n\t\"incidentsTableNoIncidents\": \"記録されたインシデントはありません\",\n\t\"incidentsTablePaginationLabel\": \"インシデント\",\n\t\"incidentsTableMonitorName\": \"モニター名\",\n\t\"incidentsTableStatus\": \"ステータス\",\n\t\"incidentsTableDateTime\": \"日付と時刻\",\n\t\"incidentsTableStatusCode\": \"ステータスコード\",\n\t\"incidentsTableMessage\": \"メッセージ\",\n\t\"incidentsOptionsHeader\": \"インシデント対象:\",\n\t\"incidentsOptionsHeaderFilterBy\": \"フィルター:\",\n\t\"incidentsOptionsHeaderFilterAll\": \"すべて\",\n\t\"incidentsOptionsHeaderFilterDown\": \"ダウン\",\n\t\"incidentsOptionsHeaderFilterCannotResolve\": \"解決不可\",\n\t\"incidentsOptionsHeaderShow\": \"表示:\",\n\t\"incidentsOptionsHeaderLastHour\": \"最終時間\",\n\t\"incidentsOptionsHeaderLastDay\": \"最終日\",\n\t\"incidentsOptionsHeaderLastWeek\": \"最終週\",\n\t\"incidentsOptionsPlaceholderAllServers\": \"すべてのサーバー\",\n\t\"infrastructureCreateYour\": \"作成する\",\n\t\"infrastructureCreateGeneralSettingsDescription\": \"ここでホストのURL、フレンドリーネーム、サーバーエージェントに接続するための認証シークレットを選択できます。\",\n\t\"infrastructureServerRequirement\": \"監視中のサーバーで実行されている必要があります\",\n\t\"infrastructureCustomizeAlerts\": \"アラートをカスタマイズ\",\n\t\"infrastructureAlertNotificationDescription\": \"しきい値が指定された割合を超えた場合にユーザーに通知を送信。\",\n\t\"infrastructureCreateMonitor\": \"インフラストラクチャモニターを作成\",\n\t\"infrastructureProtocol\": \"プロトコル\",\n\t\"infrastructureServerUrlLabel\": \"サーバーURL\",\n\t\"infrastructureDisplayNameLabel\": \"表示名\",\n\t\"infrastructureAuthorizationSecretLabel\": \"認証シークレット\",\n\t\"gb\": \"GB\",\n\t\"mb\": \"MB\",\n\t\"mem\": \"メモリ\",\n\t\"memoryUsage\": \"メモリ使用率\",\n\t\"cpu\": \"CPU\",\n\t\"cpuUsage\": \"CPU使用率\",\n\t\"cpuTemperature\": \"CPU温度\",\n\t\"diskUsage\": \"ディスク使用率\",\n\t\"used\": \"使用済み\",\n\t\"total\": \"合計\",\n\t\"cores\": \"コア\",\n\t\"frequency\": \"頻度\",\n\t\"status\": \"ステータス\",\n\t\"cpuPhysical\": \"CPU（物理）\",\n\t\"cpuLogical\": \"CPU（論理）\",\n\t\"cpuFrequency\": \"CPU周波数\",\n\t\"avgCpuTemperature\": \"平均CPU温度\",\n\t\"memory\": \"メモリ\",\n\t\"disk\": \"ディスク\",\n\t\"uptime\": \"稼働時間\",\n\t\"os\": \"OS\",\n\t\"host\": \"ホスト\",\n\t\"actions\": \"アクション\",\n\t\"integrations\": \"統合\",\n\t\"integrationsPrism\": \"Prismをお気に入りのサービスに接続。\",\n\t\"integrationsSlack\": \"Slack\",\n\t\"integrationsSlackInfo\": \"Slackと接続してチャンネルでインシデントを表示\",\n\t\"integrationsDiscord\": \"Discord\",\n\t\"integrationsDiscordInfo\": \"Discordと接続してチャンネルでインシデントを直接表示\",\n\t\"integrationsZapier\": \"Zapier\",\n\t\"integrationsZapierInfo\": \"すべてのインシデントをZapierに送信し、どこでも表示\",\n\t\"commonSave\": \"保存\",\n\t\"createYour\": \"作成する\",\n\t\"createMonitor\": \"モニターを作成\",\n\t\"pause\": \"一時停止\",\n\t\"resume\": \"再開\",\n\t\"editing\": \"編集中...\",\n\t\"url\": \"URL\",\n\t\"access\": \"アクセス\",\n\t\"timezone\": \"タイムゾーン\",\n\t\"features\": \"機能\",\n\t\"administrator\": \"管理者？\",\n\t\"loginHere\": \"こちらでログイン\",\n\t\"displayName\": \"表示名\",\n\t\"urlMonitor\": \"監視するURL\",\n\t\"portToMonitor\": \"監視するポート\",\n\t\"websiteMonitoring\": \"ウェブサイト監視\",\n\t\"websiteMonitoringDescription\": \"HTTP(s)を使用してウェブサイトやAPIエンドポイントを監視。\",\n\t\"pingMonitoring\": \"Ping監視\",\n\t\"pingMonitoringDescription\": \"サーバーが利用可能かどうかをチェック。\",\n\t\"dockerContainerMonitoring\": \"Dockerコンテナ監視\",\n\t\"dockerContainerMonitoringDescription\": \"Dockerコンテナが実行中かどうかをチェック。\",\n\t\"portMonitoring\": \"ポート監視\",\n\t\"portMonitoringDescription\": \"ポートが開いているかどうかをチェック。\",\n\t\"createMaintenanceWindow\": \"メンテナンスウィンドウを作成\",\n\t\"createMaintenance\": \"メンテナンスを作成\",\n\t\"editMaintenance\": \"メンテナンスを編集\",\n\t\"maintenanceWindowName\": \"メンテナンスウィンドウ名\",\n\t\"friendlyNameInput\": \"フレンドリーネーム\",\n\t\"friendlyNamePlaceholder\": \"__:__で___分間のメンテナンス\",\n\t\"maintenanceRepeat\": \"メンテナンス繰り返し\",\n\t\"maintenance\": \"メンテナンス\",\n\t\"duration\": \"期間\",\n\t\"addMonitors\": \"モニターを追加\",\n\t\"window\": \"ウィンドウ\",\n\t\"cancel\": \"キャンセル\",\n\t\"message\": \"メッセージ\",\n\t\"low\": \"低\",\n\t\"high\": \"高\",\n\t\"statusCode\": \"ステータスコード\",\n\t\"date&Time\": \"日付と時刻\",\n\t\"type\": \"タイプ\",\n\t\"statusPageName\": \"ステータスページ名\",\n\t\"publicURL\": \"公開URL\",\n\t\"repeat\": \"繰り返し\",\n\t\"edit\": \"編集\",\n\t\"createA\": \"作成する\",\n\t\"remove\": \"削除\",\n\t\"maintenanceWindowDescription\": \"この時間帯はpingが送信されません\",\n\t\"startTime\": \"開始時刻\",\n\t\"timeZoneInfo\": \"すべての日付と時刻はGMT+0タイムゾーンです。\",\n\t\"monitorsToApply\": \"メンテナンスウィンドウを適用するモニター\",\n\t\"nextWindow\": \"次のウィンドウ\",\n\t\"notFoundButton\": \"メインダッシュボードに移動\",\n\t\"pageSpeedConfigureSettingsDescription\": \"ここでホストのURL、モニタータイプを選択できます。\",\n\t\"monitorDisplayName\": \"モニター表示名\",\n\t\"whenNewIncident\": \"新しいインシデントが発生した場合、\",\n\t\"notifySMS\": \"SMS経由で通知（近日公開）\",\n\t\"notifyEmails\": \"複数のアドレスにメールでも通知（近日公開）\",\n\t\"seperateEmails\": \"複数のメールはカンマで区切ることができます\",\n\t\"checkFrequency\": \"チェック頻度\",\n\t\"matchMethod\": \"マッチ方法\",\n\t\"expectedValue\": \"期待値\",\n\t\"deleteDialogTitle\": \"本当にこのモニターを削除しますか？\",\n\t\"deleteDialogDescription\": \"削除されると、このモニターは復元できません。\",\n\t\"pageSpeedMonitor\": \"PageSpeedモニター\",\n\t\"shown\": \"表示\",\n\t\"ago\": \"前\",\n\t\"companyName\": \"会社名\",\n\t\"pageSpeedDetailsPerformanceReport\": \"値は推定値で変動する可能性があります。\",\n\t\"pageSpeedDetailsPerformanceReportCalculator\": \"計算機を見る\",\n\t\"checkingEvery\": \"チェック間隔\",\n\t\"statusPageCreateSettings\": \"ステータスページの準備ができたら、公開済みとしてマークできます。\",\n\t\"basicInformation\": \"基本情報\",\n\t\"statusPageCreateBasicInfoDescription\": \"会社名とステータスページが指すサブドメインを定義。\",\n\t\"statusPageCreateSelectTimeZoneDescription\": \"ステータスページが表示されるタイムゾーンを選択。\",\n\t\"statusPageCreateAppearanceDescription\": \"公開ステータスページのデフォルトの外観を定義。\",\n\t\"statusPageCreateSettingsCheckboxLabel\": \"公開済みで一般に表示\",\n\t\"statusPageCreateBasicInfoStatusPageAddress\": \"ステータスページアドレス\",\n\t\"statusPageCreateTabsContent\": \"ステータスページサーバー\",\n\t\"statusPageCreateTabsContentDescription\": \"監視している任意の数のサーバーをステータスページに追加できます。最適な表示体験のために並び替えることもできます。\",\n\t\"statusPageCreateTabsContentFeaturesDescription\": \"ステータスページでより多くの詳細を表示\",\n\t\"showCharts\": \"チャートを表示\",\n\t\"showUptimePercentage\": \"稼働率を表示\",\n\t\"removeLogo\": \"ロゴを削除\",\n\t\"statusPageStatus\": \"公開ステータスページが設定されていません。\",\n\t\"statusPageStatusContactAdmin\": \"管理者にお問い合わせください\",\n\t\"statusPageStatusNotPublic\": \"このステータスページは非公開です。\",\n\t\"statusPageStatusNoPage\": \"ここにはステータスページがありません。\",\n\t\"statusPageStatusServiceStatus\": \"サービスステータス\",\n\t\"deleteStatusPage\": \"このステータスページを削除しますか？\",\n\t\"deleteStatusPageConfirm\": \"はい、ステータスページを削除\",\n\t\"deleteStatusPageDescription\": \"削除されると、ステータスページは復元できません。\",\n\t\"uptimeCreate\": \"期待値はレスポンス結果と照合するために使用され、マッチがステータスを決定します。\",\n\t\"uptimeCreateJsonPath\": \"この式はレスポンスJSONデータに対して評価され、結果は期待値との照合に使用されます。参照\",\n\t\"uptimeCreateJsonPathQuery\": \"クエリ言語ドキュメント。\",\n\t\"maintenanceTableActionMenuDialogTitle\": \"本当にこのメンテナンスウィンドウを削除しますか？\",\n\t\"infrastructureEditYour\": \"編集する\",\n\t\"infrastructureEditMonitor\": \"インフラストラクチャモニターを保存\",\n\t\"infrastructureMonitorCreated\": \"インフラストラクチャモニターが正常に作成されました！\",\n\t\"infrastructureMonitorUpdated\": \"インフラストラクチャモニターが正常に更新されました！\",\n\t\"errorInvalidTypeId\": \"無効な通知タイプが提供されました\",\n\t\"errorInvalidFieldId\": \"無効なフィールドIDが提供されました\",\n\t\"inviteNoTokenFound\": \"招待トークンが見つかりません\",\n\t\"pageSpeedWarning\": \"警告: Google PageSpeed APIキーがまだ追加されていません。これがないとPageSpeedモニターは機能しません。\",\n\t\"pageSpeedLearnMoreLink\": \"こちらをクリック\",\n\t\"pageSpeedAddApiKey\": \"APIキーを追加する。\",\n\t\"update\": \"更新\",\n\t\"invalidFileFormat\": \"サポートされていないファイル形式！\",\n\t\"invalidFileSize\": \"ファイルサイズが大きすぎます！\",\n\t\"ClickUpload\": \"クリックしてアップロード\",\n\t\"DragandDrop\": \"ドラッグアンドドロップ\",\n\t\"MaxSize\": \"最大サイズ\",\n\t\"SupportedFormats\": \"対応フォーマット\",\n\t\"FirstName\": \"名\",\n\t\"LastName\": \"姓\",\n\t\"EmailDescriptionText\": \"こちらは現在ご使用のメールアドレスです — 変更することはできません。\",\n\t\"YourPhoto\": \"プロフィール写真\",\n\t\"PhotoDescriptionText\": \"この写真はプロフィールページに表示されます。\",\n\t\"save\": \"保存\",\n\t\"DeleteDescriptionText\": \"これにより、アカウントと関連するすべてのデータがサーバーから削除されます。この操作は元に戻せません。\",\n\t\"DeleteAccountWarning\": \"アカウントを削除すると、再度サインインできなくなり、すべてのデータが削除されます。この操作は元に戻せません。\",\n\t\"DeleteWarningTitle\": \"本当にこのアカウントを削除しますか？\",\n\t\"bulkImport\": {\n\t\t\"title\": \"一括インポート\",\n\t\t\"selectFileTips\": \"アップロードするCSVファイルを選択\",\n\t\t\"selectFileDescription\": \"<template>テンプレート</template>または<sample>サンプル</sample>をダウンロードできます\",\n\t\t\"selectFile\": \"ファイルを選択\",\n\t\t\"parsingFailed\": \"解析に失敗しました\",\n\t\t\"uploadSuccess\": \"モニターが正常に作成されました！\",\n\t\t\"validationFailed\": \"検証に失敗しました\",\n\t\t\"noFileSelected\": \"ファイルが選択されていません\",\n\t\t\"fallbackPage\": \"サーバーのリストを一括アップロードするためのファイルをインポート\",\n\t\t\"invalidFileType\": \"無効なファイルタイプ\",\n\t\t\"uploadFailed\": \"アップロードに失敗しました\"\n\t},\n\t\"DeleteAccountTitle\": \"アカウントを削除\",\n\t\"DeleteAccountButton\": \"アカウントを削除\",\n\t\"publicLink\": \"公開リンク\",\n\t\"maskedPageSpeedKeyPlaceholder\": \"*************************************\",\n\t\"reset\": \"リセット\",\n\t\"ignoreTLSError\": \"TLS/SSLエラーを無視\",\n\t\"tlsErrorIgnored\": \"TLS/SSLエラーが無視されました\",\n\t\"ignoreTLSErrorDescription\": \"TLS/SSLエラーを無視してウェブサイトの可用性をチェック続行\",\n\t\"createNew\": \"新規作成\",\n\t\"greeting\": {\n\t\t\"prepend\": \"こんにちは\",\n\t\t\"append\": \"午後はあなたの遊び場です—壮大なものにしましょう！\",\n\t\t\"overview\": \"{{type}}モニターの概要です。\"\n\t},\n\t\"roles\": {\n\t\t\"superAdmin\": \"スーパー管理者\",\n\t\t\"admin\": \"管理者\",\n\t\t\"teamMember\": \"チームメンバー\",\n\t\t\"demoUser\": \"デモユーザー\"\n\t},\n\t\"teamPanel\": {\n\t\t\"teamMembers\": \"チームメンバー\",\n\t\t\"filter\": {\n\t\t\t\"all\": \"すべて\",\n\t\t\t\"member\": \"メンバー\"\n\t\t},\n\t\t\"inviteTeamMember\": \"チームメンバーを招待\",\n\t\t\"inviteNewTeamMember\": \"新しいチームメンバーを招待\",\n\t\t\"inviteDescription\": \"新しいチームメンバーを追加すると、すべてのモニターへのアクセス権が付与されます。\",\n\t\t\"email\": \"メール\",\n\t\t\"selectRole\": \"役割を選択\",\n\t\t\"inviteLink\": \"招待リンク\",\n\t\t\"cancel\": \"キャンセル\",\n\t\t\"noMembers\": \"この役割のチームメンバーはいません\",\n\t\t\"getToken\": \"トークンを取得\",\n\t\t\"emailToken\": \"メールトークン\",\n\t\t\"table\": {\n\t\t\t\"name\": \"名前\",\n\t\t\t\"email\": \"メール\",\n\t\t\t\"role\": \"役割\",\n\t\t\t\"created\": \"作成日\"\n\t\t},\n\t\t\"addTeamMember\": {\n\t\t\t\"addMemberMenu\": \"\",\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"addButton\": \"\"\n\t\t},\n\t\t\"register\": \"\",\n\t\t\"registerToast\": {\n\t\t\t\"success\": \"\",\n\t\t\t\"dbUserExists\": \"\",\n\t\t\t\"unknownError\": \"\"\n\t\t},\n\t\t\"registerTeamMember\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"auth\": {\n\t\t\t\t\"common\": {\n\t\t\t\t\t\"inputs\": {\n\t\t\t\t\t\t\"firstName\": {\n\t\t\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\t\t\"empty\": \"\",\n\t\t\t\t\t\t\t\t\"pattern\": \"\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"lastName\": {\n\t\t\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\t\t\"empty\": \"\",\n\t\t\t\t\t\t\t\t\"pattern\": \"\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"email\": {\n\t\t\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\t\t\"empty\": \"\",\n\t\t\t\t\t\t\t\t\"invalid\": \"\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"role\": {\n\t\t\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\t\t\"empty\": \"\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"role\": \"\",\n\t\t\"changeTeamPassword\": {\n\t\t\t\"changePasswordMenu\": \"\",\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"success\": \"\"\n\t\t}\n\t},\n\t\"monitorState\": {\n\t\t\"paused\": \"一時停止\",\n\t\t\"resumed\": \"再開\",\n\t\t\"active\": \"アクティブ\"\n\t},\n\t\"menu\": {\n\t\t\"uptime\": \"稼働時間\",\n\t\t\"pagespeed\": \"ページ速度\",\n\t\t\"infrastructure\": \"インフラストラクチャ\",\n\t\t\"incidents\": \"インシデント\",\n\t\t\"statusPages\": \"ステータスページ\",\n\t\t\"maintenance\": \"メンテナンス\",\n\t\t\"integrations\": \"統合\",\n\t\t\"settings\": \"設定\",\n\t\t\"support\": \"サポート\",\n\t\t\"discussions\": \"ディスカッション\",\n\t\t\"docs\": \"ドキュメント\",\n\t\t\"changelog\": \"変更履歴\",\n\t\t\"profile\": \"プロフィール\",\n\t\t\"password\": \"パスワード\",\n\t\t\"team\": \"チーム\",\n\t\t\"logOut\": \"ログアウト\",\n\t\t\"notifications\": \"通知\",\n\t\t\"logs\": \"ログ\"\n\t},\n\t\"settingsEmailUser\": \"メールユーザー - 認証用ユーザー名、指定されている場合はメールアドレスを上書き\",\n\t\"state\": \"状態\",\n\t\"statusBreadCrumbsStatusPages\": \"ステータスページ\",\n\t\"statusBreadCrumbsDetails\": \"詳細\",\n\t\"commonSaving\": \"保存中...\",\n\t\"navControls\": \"コントロール\",\n\t\"incidentsPageTitle\": \"インシデント\",\n\t\"passwordPanel\": {\n\t\t\"passwordChangedSuccess\": \"パスワードが正常に変更されました。\",\n\t\t\"passwordInputIncorrect\": \"パスワード入力が間違っています。\",\n\t\t\"currentPassword\": \"現在のパスワード\",\n\t\t\"enterCurrentPassword\": \"現在のパスワードを入力\",\n\t\t\"newPassword\": \"新しいパスワード\",\n\t\t\"enterNewPassword\": \"新しいパスワードを入力\",\n\t\t\"confirmNewPassword\": \"新しいパスワードの確認\",\n\t\t\"passwordRequirements\": \"新しいパスワードは少なくとも8文字で、少なくとも1つの大文字、1つの小文字、1つの数字、1つの特殊文字を含む必要があります。\",\n\t\t\"saving\": \"保存中...\"\n\t},\n\t\"emailSent\": \"メールが正常に送信されました\",\n\t\"failedToSendEmail\": \"メールの送信に失敗しました\",\n\t\"settingsTestEmailSuccess\": \"テストメールが正常に送信されました\",\n\t\"settingsTestEmailFailed\": \"テストメールの送信に失敗しました\",\n\t\"settingsTestEmailFailedWithReason\": \"テストメールの送信に失敗しました: {{reason}}\",\n\t\"settingsTestEmailUnknownError\": \"不明なエラー\",\n\t\"statusMsg\": {\n\t\t\"paused\": \"監視が一時停止されています。\",\n\t\t\"up\": \"サイトが稼働中です。\",\n\t\t\"down\": \"サイトがダウンしています。\",\n\t\t\"pending\": \"保留中...\"\n\t},\n\t\"uptimeGeneralInstructions\": {\n\t\t\"http\": \"監視するURLまたはIPを入力（例: https://example.com/ または 192.168.1.100）し、ダッシュボードに表示される明確な表示名を追加。\",\n\t\t\"ping\": \"pingするIPアドレスまたはホスト名を入力（例: 192.168.1.100 または example.com）し、ダッシュボードに表示される明確な表示名を追加。\",\n\t\t\"docker\": \"コンテナのDocker IDを入力。Docker IDは64文字のフルDocker IDである必要があります。docker inspect <short_id>を実行してフルコンテナIDを取得できます。\",\n\t\t\"port\": \"サーバーのURLまたはIP、ポート番号、ダッシュボードに表示される明確な表示名を入力。\",\n\t\t\"game\": \"\",\n\t\t\"https\": \"\"\n\t},\n\t\"common\": {\n\t\t\"appName\": \"Checkmate\",\n\t\t\"monitoringAgentName\": \"Capture\",\n\t\t\"buttons\": {\n\t\t\t\"toggleTheme\": \"ライト＆ダークを切り替え\"\n\t\t},\n\t\t\"toasts\": {\n\t\t\t\"networkError\": \"ネットワークエラー\",\n\t\t\t\"checkConnection\": \"接続を確認してください\",\n\t\t\t\"unknownError\": \"不明なエラー\"\n\t\t}\n\t},\n\t\"auth\": {\n\t\t\"common\": {\n\t\t\t\"navigation\": {\n\t\t\t\t\"continue\": \"続行\",\n\t\t\t\t\"back\": \"戻る\"\n\t\t\t},\n\t\t\t\"inputs\": {\n\t\t\t\t\"email\": {\n\t\t\t\t\t\"label\": \"メール\",\n\t\t\t\t\t\"placeholder\": \"jordan.ellis@domain.com\",\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"続行するには、メールアドレスを入力してください\",\n\t\t\t\t\t\t\"invalid\": \"入力されたメールアドレスの有効性を再確認してください\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"password\": {\n\t\t\t\t\t\"label\": \"パスワード\",\n\t\t\t\t\t\"rules\": {\n\t\t\t\t\t\t\"length\": {\n\t\t\t\t\t\t\t\"beginning\": \"少なくとも\",\n\t\t\t\t\t\t\t\"highlighted\": \"8文字である必要があります\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"special\": {\n\t\t\t\t\t\t\t\"beginning\": \"少なくとも\",\n\t\t\t\t\t\t\t\"highlighted\": \"1つの特殊文字を含む必要があります\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"number\": {\n\t\t\t\t\t\t\t\"beginning\": \"少なくとも\",\n\t\t\t\t\t\t\t\"highlighted\": \"1つの数字を含む必要があります\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"uppercase\": {\n\t\t\t\t\t\t\t\"beginning\": \"少なくとも\",\n\t\t\t\t\t\t\t\"highlighted\": \"1つの大文字を含む必要があります\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"lowercase\": {\n\t\t\t\t\t\t\t\"beginning\": \"少なくとも\",\n\t\t\t\t\t\t\t\"highlighted\": \"1つの小文字を含む必要があります\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"match\": {\n\t\t\t\t\t\t\t\"beginning\": \"パスワードの確認とパスワードは\",\n\t\t\t\t\t\t\t\"highlighted\": \"一致する必要があります\"\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"パスワードを入力してください\",\n\t\t\t\t\t\t\"length\": \"パスワードは少なくとも8文字である必要があります\",\n\t\t\t\t\t\t\"uppercase\": \"パスワードは少なくとも1つの大文字を含む必要があります\",\n\t\t\t\t\t\t\"lowercase\": \"パスワードは少なくとも1つの小文字を含む必要があります\",\n\t\t\t\t\t\t\"number\": \"パスワードは少なくとも1つの数字を含む必要があります\",\n\t\t\t\t\t\t\"special\": \"パスワードは少なくとも1つの特殊文字を含む必要があります\",\n\t\t\t\t\t\t\"incorrect\": \"入力されたパスワードが記録と一致しません\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"passwordConfirm\": {\n\t\t\t\t\t\"label\": \"パスワードの確認\",\n\t\t\t\t\t\"placeholder\": \"確認のためにパスワードを再入力\",\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"確認のためにパスワードを再度入力してください（タイプミスを防ぐため）\",\n\t\t\t\t\t\t\"different\": \"入力されたパスワードが一致しないため、どちらかが間違っています\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"firstName\": {\n\t\t\t\t\t\"label\": \"名前\",\n\t\t\t\t\t\"placeholder\": \"太郎\",\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"名前を入力してください\",\n\t\t\t\t\t\t\"length\": \"名前は50文字未満である必要があります\",\n\t\t\t\t\t\t\"pattern\": \"名前は文字、スペース、アポストロフィ、またはハイフンのみを含む必要があります\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"lastName\": {\n\t\t\t\t\t\"label\": \"姓\",\n\t\t\t\t\t\"placeholder\": \"田中\",\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"姓を入力してください\",\n\t\t\t\t\t\t\"length\": \"姓は50文字未満である必要があります\",\n\t\t\t\t\t\t\"pattern\": \"姓は文字、スペース、アポストロフィ、またはハイフンのみを含む必要があります\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"errors\": {\n\t\t\t\t\"validation\": \"データの検証エラー。\"\n\t\t\t},\n\t\t\t\"fields\": {\n\t\t\t\t\"password\": {\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"incorrect\": \"入力されたパスワードが記録と一致しません\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"role\": {\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"min\": \"\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"login\": {\n\t\t\t\"heading\": \"ログイン\",\n\t\t\t\"subheadings\": {\n\t\t\t\t\"stepOne\": \"メールアドレスを入力\",\n\t\t\t\t\"stepTwo\": \"パスワードを入力\"\n\t\t\t},\n\t\t\t\"links\": {\n\t\t\t\t\"forgotPassword\": \"パスワードを忘れましたか？\",\n\t\t\t\t\"register\": \"アカウントをお持ちでないですか？\",\n\t\t\t\t\"forgotPasswordLink\": \"パスワードをリセット\",\n\t\t\t\t\"registerLink\": \"こちらで登録\"\n\t\t\t},\n\t\t\t\"toasts\": {\n\t\t\t\t\"success\": \"おかえりなさい！正常にログインしました。\",\n\t\t\t\t\"incorrectPassword\": \"パスワードが間違っています\"\n\t\t\t},\n\t\t\t\"errors\": {\n\t\t\t\t\"password\": {\n\t\t\t\t\t\"incorrect\": \"入力されたパスワードが記録と一致しません\"\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"welcome\": \"\"\n\t\t},\n\t\t\"registration\": {\n\t\t\t\"heading\": {\n\t\t\t\t\"superAdmin\": \"スーパー管理者を作成\",\n\t\t\t\t\"user\": \"サインアップ\"\n\t\t\t},\n\t\t\t\"subheadings\": {\n\t\t\t\t\"stepOne\": \"個人情報を入力\",\n\t\t\t\t\"stepTwo\": \"メールアドレスを入力\",\n\t\t\t\t\"stepThree\": \"パスワードを作成\"\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\t\"superAdmin\": \"スーパー管理者アカウントを作成して開始\",\n\t\t\t\t\"user\": \"ユーザーとしてサインアップし、スーパー管理者にモニターへのアクセスを求める\"\n\t\t\t},\n\t\t\t\"gettingStartedButton\": {\n\t\t\t\t\"superAdmin\": \"スーパー管理者アカウントを作成\",\n\t\t\t\t\"user\": \"一般ユーザーでサインアップ\"\n\t\t\t},\n\t\t\t\"termsAndPolicies\": \"アカウントを作成することで、<a1>利用規約</a1>と<a2>プライバシーポリシー</a2>に同意したことになります。\",\n\t\t\t\"links\": {\n\t\t\t\t\"login\": \"既にアカウントをお持ちですか？ <a>ログイン</a>\"\n\t\t\t},\n\t\t\t\"toasts\": {\n\t\t\t\t\"success\": \"ようこそ！アカウントが正常に作成されました。\"\n\t\t\t},\n\t\t\t\"welcome\": \"\"\n\t\t},\n\t\t\"forgotPassword\": {\n\t\t\t\"heading\": \"パスワードを忘れましたか？\",\n\t\t\t\"subheadings\": {\n\t\t\t\t\"stepOne\": \"ご心配なく、リセット手順をお送りします。\",\n\t\t\t\t\"stepTwo\": \"パスワードリセットリンクを <email/> に送信しました\",\n\t\t\t\t\"stepThree\": \"新しいパスワードは以前に使用したパスワードとは異なる必要があります。\",\n\t\t\t\t\"stepFour\": \"パスワードが正常にリセットされました。下記をクリックして魔法のようにログインしてください。\"\n\t\t\t},\n\t\t\t\"buttons\": {\n\t\t\t\t\"openEmail\": \"メールアプリを開く\",\n\t\t\t\t\"resetPassword\": \"パスワードをリセット\"\n\t\t\t},\n\t\t\t\"imageAlts\": {\n\t\t\t\t\"passwordKey\": \"パスワードキーアイコン\",\n\t\t\t\t\"email\": \"メールアイコン\",\n\t\t\t\t\"lock\": \"ロックアイコン\",\n\t\t\t\t\"passwordConfirm\": \"パスワード確認アイコン\"\n\t\t\t},\n\t\t\t\"links\": {\n\t\t\t\t\"login\": \"<a>ログイン</a>に戻る\",\n\t\t\t\t\"resend\": \"メールが届きませんか？ <a>クリックして再送信</a>\"\n\t\t\t},\n\t\t\t\"toasts\": {\n\t\t\t\t\"sent\": \"手順を <email/> に送信しました。\",\n\t\t\t\t\"emailNotFound\": \"メールが見つかりません。\",\n\t\t\t\t\"redirect\": \"<seconds/>秒後にリダイレクトします...\",\n\t\t\t\t\"success\": \"パスワードが正常にリセットされました。\",\n\t\t\t\t\"error\": \"パスワードをリセットできません。後でもう一度試すか、サポートにお問い合わせください。\"\n\t\t\t}\n\t\t}\n\t},\n\t\"errorPages\": {\n\t\t\"serverUnreachable\": {\n\t\t\t\"toasts\": {\n\t\t\t\t\"reconnected\": \"サーバーに正常に再接続しました。\",\n\t\t\t\t\"stillUnreachable\": \"サーバーにまだ到達できません。後でもう一度お試しください。\"\n\t\t\t},\n\t\t\t\"alertBox\": \"サーバー接続エラー\",\n\t\t\t\"description\": \"サーバーに接続できません。インターネット接続を確認するか、問題が続く場合はデプロイ設定を確認してください。\",\n\t\t\t\"retryButton\": {\n\t\t\t\t\"default\": \"接続を再試行\",\n\t\t\t\t\"processing\": \"接続中...\"\n\t\t\t}\n\t\t}\n\t},\n\t\"createNotifications\": {\n\t\t\"title\": \"通知チャンネルを作成\",\n\t\t\"nameSettings\": {\n\t\t\t\"title\": \"名前\",\n\t\t\t\"description\": \"統合の説明的な名前。\",\n\t\t\t\"nameLabel\": \"名前\",\n\t\t\t\"namePlaceholder\": \"例: Slack通知\"\n\t\t},\n\t\t\"typeSettings\": {\n\t\t\t\"title\": \"タイプ\",\n\t\t\t\"description\": \"作成したい通知チャンネルのタイプを選択。\",\n\t\t\t\"typeLabel\": \"タイプ\"\n\t\t},\n\t\t\"emailSettings\": {\n\t\t\t\"title\": \"メール\",\n\t\t\t\"description\": \"送信先メールアドレス。\",\n\t\t\t\"emailLabel\": \"メールアドレス\",\n\t\t\t\"emailPlaceholder\": \"例: john@example.com\"\n\t\t},\n\t\t\"slackSettings\": {\n\t\t\t\"title\": \"Slack\",\n\t\t\t\"description\": \"Slack Webhookをここで設定\",\n\t\t\t\"webhookLabel\": \"Slack Webhook URL\",\n\t\t\t\"webhookPlaceholder\": \"https://hooks.slack.com/services/...\"\n\t\t},\n\t\t\"pagerdutySettings\": {\n\t\t\t\"title\": \"PagerDuty\",\n\t\t\t\"description\": \"PagerDuty統合をここで設定\",\n\t\t\t\"integrationKeyLabel\": \"統合キー\",\n\t\t\t\"integrationKeyPlaceholder\": \"1234567890\"\n\t\t},\n\t\t\"discordSettings\": {\n\t\t\t\"title\": \"Discord\",\n\t\t\t\"description\": \"Discord Webhookをここで設定\",\n\t\t\t\"webhookLabel\": \"Discord Webhook URL\",\n\t\t\t\"webhookPlaceholder\": \"https://your-server.com/webhook\"\n\t\t},\n\t\t\"webhookSettings\": {\n\t\t\t\"title\": \"Webhook\",\n\t\t\t\"description\": \"Webhookをここで設定\",\n\t\t\t\"webhookLabel\": \"Webhook URL\",\n\t\t\t\"webhookPlaceholder\": \"https://your-server.com/webhook\"\n\t\t},\n\t\t\"testNotification\": \"テスト通知\",\n\t\t\"dialogDeleteTitle\": \"この通知を削除してもよろしいですか？\",\n\t\t\"dialogDeleteConfirm\": \"削除\"\n\t},\n\t\"notificationConfig\": {\n\t\t\"title\": \"通知\",\n\t\t\"description\": \"使用したい通知チャンネルを選択\"\n\t},\n\t\"monitorStatus\": {\n\t\t\"checkingEvery\": \"{{interval}}ごとにチェック\",\n\t\t\"withCaptureAgent\": \"Captureエージェント{{version}}で\",\n\t\t\"up\": \"アップ\",\n\t\t\"down\": \"ダウン\",\n\t\t\"paused\": \"一時停止\"\n\t},\n\t\"advancedMatching\": \"高度なマッチング\",\n\t\"sendTestNotifications\": \"テスト通知を送信\",\n\t\"selectAll\": \"すべて選択\",\n\t\"showAdminLoginLink\": \"ステータスページに「管理者？こちらでログイン」リンクを表示\",\n\t\"logsPage\": {\n\t\t\"title\": \"ログ\",\n\t\t\"description\": \"システムログ - 最新1000行\",\n\t\t\"tabs\": {\n\t\t\t\"queue\": \"ジョブキュー\",\n\t\t\t\"logs\": \"サーバーログ\",\n\t\t\t\"diagnostics\": \"診断\"\n\t\t},\n\t\t\"toast\": {\n\t\t\t\"fetchLogsSuccess\": \"ログが正常に取得されました\"\n\t\t},\n\t\t\"logLevelSelect\": {\n\t\t\t\"title\": \"ログレベル\",\n\t\t\t\"values\": {\n\t\t\t\t\"all\": \"すべて\",\n\t\t\t\t\"info\": \"情報\",\n\t\t\t\t\"warn\": \"警告\",\n\t\t\t\t\"error\": \"エラー\",\n\t\t\t\t\"debug\": \"デバッグ\"\n\t\t\t}\n\t\t}\n\t},\n\t\"queuePage\": {\n\t\t\"title\": \"キュー\",\n\t\t\"refreshButton\": \"更新\",\n\t\t\"flushButton\": \"キューをフラッシュ\",\n\t\t\"jobTable\": {\n\t\t\t\"title\": \"現在キューにあるジョブ\",\n\t\t\t\"idHeader\": \"モニターID\",\n\t\t\t\"urlHeader\": \"URL\",\n\t\t\t\"typeHeader\": \"タイプ\",\n\t\t\t\"activeHeader\": \"アクティブ\",\n\t\t\t\"lockedAtHeader\": \"ロック日時\",\n\t\t\t\"runCountHeader\": \"実行回数\",\n\t\t\t\"failCountHeader\": \"失敗回数\",\n\t\t\t\"lastRunHeader\": \"最終実行日時\",\n\t\t\t\"lastFinishedAtHeader\": \"最終完了日時\",\n\t\t\t\"lastRunTookHeader\": \"最終実行時間\",\n\t\t\t\"intervalHeader\": \"\"\n\t\t},\n\t\t\"metricsTable\": {\n\t\t\t\"title\": \"キューメトリック\",\n\t\t\t\"metricHeader\": \"メトリック\",\n\t\t\t\"valueHeader\": \"値\"\n\t\t},\n\t\t\"failedJobTable\": {\n\t\t\t\"title\": \"失敗したジョブ\",\n\t\t\t\"monitorIdHeader\": \"モニターID\",\n\t\t\t\"monitorUrlHeader\": \"モニターURL\",\n\t\t\t\"failCountHeader\": \"失敗回数\",\n\t\t\t\"failedAtHeader\": \"最終失敗日時\",\n\t\t\t\"failReasonHeader\": \"失敗理由\"\n\t\t}\n\t},\n\t\"export\": {\n\t\t\"title\": \"モニターをエクスポート\",\n\t\t\"success\": \"モニターが正常にエクスポートされました！\",\n\t\t\"failed\": \"モニターのエクスポートに失敗しました\"\n\t},\n\t\"monitorActions\": {\n\t\t\"title\": \"エクスポート/インポート\",\n\t\t\"import\": \"モニターをインポート\",\n\t\t\"export\": \"モニターをエクスポート\",\n\t\t\"deleteSuccess\": \"モニターが正常に削除されました\",\n\t\t\"deleteFailed\": \"モニターの削除に失敗しました\",\n\t\t\"details\": \"詳細\"\n\t},\n\t\"settingsPage\": {\n\t\t\"aboutSettings\": {\n\t\t\t\"labelDevelopedBy\": \"Bluewave Labsによる開発\",\n\t\t\t\"labelVersion\": \"バージョン\",\n\t\t\t\"title\": \"について\"\n\t\t},\n\t\t\"demoMonitorsSettings\": {\n\t\t\t\"buttonAddMonitors\": \"デモモニターを追加\",\n\t\t\t\"description\": \"デモンストレーション目的でサンプルモニターを追加。\",\n\t\t\t\"title\": \"デモモニター\"\n\t\t},\n\t\t\"emailSettings\": {\n\t\t\t\"buttonSendTestEmail\": \"テストメールを送信\",\n\t\t\t\"description\": \"システムのメール設定を構成。これは通知とアラートの送信に使用されます。\",\n\t\t\t\"descriptionTransport\": \"これはNodeMailer用のSMTPトランスポートを構築します\",\n\t\t\t\"labelAddress\": \"メールアドレス - 認証に使用\",\n\t\t\t\"labelConnectionHost\": \"メール接続ホスト - HELO/EHLO挨拶で使用するホスト名\",\n\t\t\t\"labelHost\": \"メールホスト - 接続するホスト名またはIPアドレス\",\n\t\t\t\"labelIgnoreTLS\": \"STARTTLSを無効化: サーバーがサポートしていてもTLSを使用しない\",\n\t\t\t\"labelPassword\": \"メールパスワード - 認証用パスワード\",\n\t\t\t\"labelPasswordSet\": \"パスワードが設定されています。変更するにはリセットをクリック。\",\n\t\t\t\"labelPool\": \"接続プーリングを有効化: パフォーマンス向上のため既存接続を再利用\",\n\t\t\t\"labelPort\": \"メールポート - 接続するポート\",\n\t\t\t\"labelRejectUnauthorized\": \"無効な証明書を拒否: 自己署名または信頼されていない証明書での接続を拒否\",\n\t\t\t\"labelRequireTLS\": \"STARTTLSを強制: TLSアップグレードを必須とし、サポートされていない場合は失敗\",\n\t\t\t\"labelSecure\": \"SSL使用（推奨）: SSL/TLSを使用して接続を暗号化\",\n\t\t\t\"labelTLSServername\": \"TLS Servername - ホストがIPの場合のTLS検証用オプションホスト名\",\n\t\t\t\"labelUser\": \"メールユーザー - 認証用ユーザー名、指定されている場合はメールアドレスを上書き\",\n\t\t\t\"linkTransport\": \"仕様はこちらを参照\",\n\t\t\t\"placeholderUser\": \"不要な場合は空白のまま\",\n\t\t\t\"title\": \"メール\",\n\t\t\t\"toastEmailRequiredFieldsError\": \"メールアドレス、ホスト、ポート、パスワードが必要です\"\n\t\t},\n\t\t\"pageSpeedSettings\": {\n\t\t\t\"description\": \"Google PageSpeed APIキーを入力してGoogle PageSpeed監視を有効化。キーを更新するにはリセットをクリック。\",\n\t\t\t\"labelApiKeySet\": \"APIキーが設定されています。変更するにはリセットをクリック。\",\n\t\t\t\"labelApiKey\": \"PageSpeed APIキー\",\n\t\t\t\"title\": \"Google PageSpeed APIキー\"\n\t\t},\n\t\t\"saveButtonLabel\": \"保存\",\n\t\t\"statsSettings\": {\n\t\t\t\"clearAllStatsButton\": \"すべての統計をクリア\",\n\t\t\t\"clearAllStatsDescription\": \"すべての統計をクリア。この操作は元に戻せません。\",\n\t\t\t\"clearAllStatsDialogConfirm\": \"はい、すべての統計をクリア\",\n\t\t\t\"clearAllStatsDialogDescription\": \"削除されると、監視履歴と統計は復元できません。\",\n\t\t\t\"clearAllStatsDialogTitle\": \"すべての統計をクリアしますか？\",\n\t\t\t\"description\": \"履歴データを保持する期間を定義。既存のデータをすべてクリアすることもできます。\",\n\t\t\t\"labelTTL\": \"監視履歴を保持したい日数。\",\n\t\t\t\"labelTTLOptional\": \"0で無限\",\n\t\t\t\"title\": \"モニター履歴\"\n\t\t},\n\t\t\"systemResetSettings\": {\n\t\t\t\"buttonRemoveAllMonitors\": \"すべてのモニターを削除\",\n\t\t\t\"description\": \"システムからすべてのモニターを削除。\",\n\t\t\t\"dialogConfirm\": \"はい、すべてのモニターを削除\",\n\t\t\t\"dialogDescription\": \"削除されると、モニターは復元できません。\",\n\t\t\t\"dialogTitle\": \"すべてのモニターを削除しますか？\",\n\t\t\t\"title\": \"システムリセット\"\n\t\t},\n\t\t\"timezoneSettings\": {\n\t\t\t\"description\": \"アプリケーション全体で日付と時刻を表示するために使用するタイムゾーンを選択。\",\n\t\t\t\"label\": \"表示タイムゾーン\",\n\t\t\t\"title\": \"表示タイムゾーン\"\n\t\t},\n\t\t\"title\": \"設定\",\n\t\t\"uiSettings\": {\n\t\t\t\"description\": \"ライトモードとダークモードを切り替えるか、ユーザーインターフェース言語を変更。\",\n\t\t\t\"labelLanguage\": \"言語\",\n\t\t\t\"labelTheme\": \"テーマモード\",\n\t\t\t\"title\": \"外観\"\n\t\t},\n\t\t\"urlSettings\": {\n\t\t\t\"description\": \"公開ステータスページでモニターのIPアドレスまたはURLを表示。無効にすると、機密情報を保護するためモニター名のみが表示されます。\",\n\t\t\t\"label\": \"ステータスページでIP/URLを表示\",\n\t\t\t\"selectDisabled\": \"無効\",\n\t\t\t\"selectEnabled\": \"有効\",\n\t\t\t\"title\": \"ステータスページのモニターIP/URL\"\n\t\t},\n\t\t\"globalThresholds\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\"\n\t\t}\n\t},\n\t\"statusPageCreate\": {\n\t\t\"buttonSave\": \"保存\"\n\t},\n\t\"incidentsOptionsHeaderFilterResolved\": \"解決済み\",\n\t\"settingsSave\": \"保存\",\n\t\"statusPageCreateAppearanceTitle\": \"外観\",\n\t\"confirmPassword\": \"パスワードの確認\",\n\t\"monitorHooks\": {\n\t\t\"failureAddDemoMonitors\": \"デモモニターの追加に失敗しました\",\n\t\t\"successAddDemoMonitors\": \"デモモニターが正常に追加されました\"\n\t},\n\t\"settingsAppearance\": \"外観\",\n\t\"settingsDisplayTimezone\": \"表示タイムゾーン\",\n\t\"settingsGeneralSettings\": \"一般設定\",\n\t\"incidentsOptionsHeaderTotalIncidents\": \"総インシデント\",\n\t\"statusPage\": {\n\t\t\"deleteSuccess\": \"ステータスページが正常に削除されました\",\n\t\t\"deleteFailed\": \"ステータスページの削除に失敗しました\",\n\t\t\"createSuccess\": \"ステータスページが正常に作成されました\",\n\t\t\"updateSuccess\": \"ステータスページが正常に更新されました\",\n\t\t\"generalSettings\": \"一般設定\",\n\t\t\"contents\": \"コンテンツ\",\n\t\t\"fallback\": {\n\t\t\t\"checks\": [\"\"],\n\t\t\t\"title\": \"\",\n\t\t\t\"actionButton\": \"\"\n\t\t}\n\t},\n\t\"testNotificationsDisabled\": \"このモニターには通知が設定されていません。「設定」ボタンをクリックして追加する必要があります\",\n\t\"incidentsTableResolvedAt\": \"解決日時\",\n\t\"incidentsTableActionResolve\": \"解決\",\n\t\"checkHooks\": {\n\t\t\"failureResolveOne\": \"インシデントの解決に失敗しました。\",\n\t\t\"failureResolveAll\": \"すべてのインシデントの解決に失敗しました。\",\n\t\t\"failureResolveMonitor\": \"\"\n\t},\n\t\"checkFormError\": \"フォームでエラーを確認してください。\",\n\t\"diagnosticsPage\": {\n\t\t\"diagnosticDescription\": \"システム診断\",\n\t\t\"statsDescription\": \"システム統計\",\n\t\t\"gauges\": {\n\t\t\t\"heapAllocationTitle\": \"ヒープ割り当て\",\n\t\t\t\"heapAllocationSubtitle\": \"利用可能メモリの%\",\n\t\t\t\"heapUsageTitle\": \"ヒープ使用量\",\n\t\t\t\"heapUsageSubtitle\": \"利用可能メモリの%\",\n\t\t\t\"heapUtilizationTitle\": \"ヒープ利用率\",\n\t\t\t\"heapUtilizationSubtitle\": \"割り当て済みの%\",\n\t\t\t\"instantCpuUsageTitle\": \"瞬間CPU使用率\",\n\t\t\t\"instantCpuUsageSubtitle\": \"CPUが使用した1秒の%\"\n\t\t},\n\t\t\"stats\": {\n\t\t\t\"eventLoopDelayTitle\": \"イベントループ遅延\",\n\t\t\t\"uptimeTitle\": \"稼働時間\",\n\t\t\t\"usedHeapSizeTitle\": \"使用ヒープサイズ\",\n\t\t\t\"totalHeapSizeTitle\": \"総ヒープサイズ\",\n\t\t\t\"osMemoryLimitTitle\": \"OSメモリ制限\"\n\t\t}\n\t},\n\t\"pageSpeedLighthouseAPI\": \"Lighthouse PageSpeed APIを使用してウェブサイトを監視\",\n\t\"time\": {\n\t\t\"threeMinutes\": \"3分\",\n\t\t\"fiveMinutes\": \"5分\",\n\t\t\"tenMinutes\": \"10分\",\n\t\t\"twentyMinutes\": \"20分\",\n\t\t\"oneHour\": \"1時間\",\n\t\t\"oneDay\": \"1日\",\n\t\t\"oneWeek\": \"1週間\",\n\t\t\"fourMinutes\": \"\",\n\t\t\"oneMinute\": \"\",\n\t\t\"twoMinutes\": \"\",\n\t\t\"fifteenSeconds\": \"\",\n\t\t\"thirtySeconds\": \"\"\n\t},\n\t\"general\": {\n\t\t\"noOptionsFound\": \"\"\n\t},\n\t\"infrastructureMonitor\": {\n\t\t\"fallback\": {\n\t\t\t\"checks\": [\"\"],\n\t\t\t\"title\": \"\",\n\t\t\t\"actionButton\": \"\"\n\t\t}\n\t},\n\t\"maintenanceWindow\": {\n\t\t\"fallback\": {\n\t\t\t\"checks\": [\"\"],\n\t\t\t\"title\": \"\",\n\t\t\t\"actionButton\": \"\"\n\t\t}\n\t},\n\t\"pageSpeed\": {\n\t\t\"fallback\": {\n\t\t\t\"checks\": [\"\"],\n\t\t\t\"title\": \"\",\n\t\t\t\"actionButton\": \"\"\n\t\t}\n\t},\n\t\"uptimeMonitor\": {\n\t\t\"fallback\": {\n\t\t\t\"checks\": [\"\"],\n\t\t\t\"title\": \"\",\n\t\t\t\"actionButton\": \"\"\n\t\t}\n\t},\n\t\"editUserPage\": {\n\t\t\"form\": {\n\t\t\t\"email\": \"\",\n\t\t\t\"firstName\": \"\",\n\t\t\t\"lastName\": \"\",\n\t\t\t\"role\": \"\",\n\t\t\t\"save\": \"\"\n\t\t},\n\t\t\"table\": {\n\t\t\t\"actionHeader\": \"\",\n\t\t\t\"roleHeader\": \"\"\n\t\t},\n\t\t\"title\": \"\",\n\t\t\"toast\": {\n\t\t\t\"successUserUpdate\": \"\",\n\t\t\t\"validationErrors\": \"\"\n\t\t}\n\t},\n\t\"incidentsPageActionResolveMonitor\": \"\",\n\t\"incidentsPageActionResolveAll\": \"\",\n\t\"matchMethodOptions\": {\n\t\t\"equal\": \"\",\n\t\t\"equalPlaceholder\": \"\",\n\t\t\"include\": \"\",\n\t\t\"includePlaceholder\": \"\",\n\t\t\"regex\": \"\",\n\t\t\"regexPlaceholder\": \"\",\n\t\t\"text\": \"\"\n\t},\n\t\"monitorType\": {\n\t\t\"docker\": {\n\t\t\t\"label\": \"\",\n\t\t\t\"namePlaceholder\": \"\",\n\t\t\t\"placeholder\": \"\"\n\t\t},\n\t\t\"http\": {\n\t\t\t\"label\": \"\",\n\t\t\t\"namePlaceholder\": \"\",\n\t\t\t\"placeholder\": \"\"\n\t\t},\n\t\t\"ping\": {\n\t\t\t\"label\": \"\",\n\t\t\t\"namePlaceholder\": \"\",\n\t\t\t\"placeholder\": \"\"\n\t\t},\n\t\t\"port\": {\n\t\t\t\"label\": \"\",\n\t\t\t\"namePlaceholder\": \"\",\n\t\t\t\"placeholder\": \"\"\n\t\t},\n\t\t\"game\": {\n\t\t\t\"label\": \"\",\n\t\t\t\"namePlaceholder\": \"\",\n\t\t\t\"placeholder\": \"\"\n\t\t}\n\t},\n\t\"uptimeAdvancedMatching\": {\n\t\t\"jsonPath\": \"\"\n\t},\n\t\"bytesPerSecond\": \"\",\n\t\"bytesReceived\": \"\",\n\t\"bytesSent\": \"\",\n\t\"chooseGame\": \"\",\n\t\"createMonitorPage\": {\n\t\t\"incidentConfigDescription\": \"\",\n\t\t\"incidentConfigStatusWindowLabel\": \"\",\n\t\t\"incidentConfigStatusWindowThresholdLabel\": \"\",\n\t\t\"incidentConfigTitle\": \"\",\n\t\t\"incidentConfigDescriptionV2\": \"\",\n\t\t\"incidentConfigStatusCheckNumber\": \"\",\n\t\t\"intervalTitle\": \"\",\n\t\t\"intervalDescription\": \"\"\n\t},\n\t\"dataRate\": \"\",\n\t\"dataReceived\": \"\",\n\t\"dataSent\": \"\",\n\t\"details\": \"\",\n\t\"drops\": \"\",\n\t\"errors\": \"\",\n\t\"errorsIn\": \"\",\n\t\"errorsOut\": \"\",\n\t\"gameServerMonitoring\": \"\",\n\t\"gameServerMonitoringDescription\": \"\",\n\t\"network\": \"\",\n\t\"networkDrops\": \"\",\n\t\"networkErrors\": \"\",\n\t\"networkInterface\": \"\",\n\t\"noNetworkStatsAvailable\": \"\",\n\t\"packetsPerSecond\": \"\",\n\t\"packetsReceived\": \"\",\n\t\"packetsReceivedRate\": \"\",\n\t\"packetsSent\": \"\",\n\t\"rate\": \"\",\n\t\"selectInterface\": \"\",\n\t\"v1\": {\n\t\t\"infrastructure\": {\n\t\t\t\"disk_selection_title\": \"ディスク選択\",\n\t\t\t\"disk_selection_info\": \"現在ディスクが検出されていません。\",\n\t\t\t\"disk_selection_description\": \"監視したい特定のディスクを選択してください。\"\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "client/src/locales/pt-BR.json",
    "content": "{\n\t\"submit\": \"Enviar\",\n\t\"title\": \"Título\",\n\t\"distributedStatusHeaderText\": \"Cobertura em tempo real e em dispositivos reais\",\n\t\"distributedStatusSubHeaderText\": \"Impulsionado por milhões de dispositivos em todo o mundo, visualize o desempenho do sistema por região global, país ou cidade\",\n\t\"settingsDisabled\": \"Desabilitado\",\n\t\"settingsSuccessSaved\": \"Configurações salvas com sucesso\",\n\t\"settingsFailedToSave\": \"Falha ao salvar as configurações\",\n\t\"settingsStatsCleared\": \"Estatísticas limpas com sucesso\",\n\t\"settingsFailedToClearStats\": \"Falha ao limpar estatísticas\",\n\t\"settingsMonitorsDeleted\": \"Todos os monitores foram excluídos com sucesso\",\n\t\"settingsFailedToDeleteMonitors\": \"Falha ao excluir todos os monitores\",\n\t\"starPromptTitle\": \"Star Checkmate\",\n\t\"starPromptDescription\": \"Veja os últimos lançamentos e ajude a expandir a comunidade no GitHub\",\n\t\"https\": \"HTTPS\",\n\t\"http\": \"HTTP\",\n\t\"monitor\": \"monitor\",\n\t\"aboutus\": \"Sobre nós\",\n\t\"now\": \"Agora\",\n\t\"delete\": \"Deletar\",\n\t\"configure\": \"Configurar\",\n\t\"responseTime\": \"Tempo de resposta\",\n\t\"ms\": \"ms\",\n\t\"bar\": \"Bar\",\n\t\"area\": \"Área\",\n\t\"country\": \"PAÍS\",\n\t\"city\": \"CIDADE\",\n\t\"response\": \"RESPOSTA\",\n\t\"monitorStatusUp\": \"O monitor {name} ({url}) agora está ATIVO e respondendo\",\n\t\"monitorStatusDown\": \"O monitor {name} ({url}) está INATIVO e não está respondendo\",\n\t\"webhookSendSuccess\": \"Notificação de webhook enviada com sucesso\",\n\t\"webhookSendError\": \"Erro ao enviar notificação de webhook para {platform}\",\n\t\"webhookUnsupportedPlatform\": \"Plataforma não suportada: {platform}\",\n\t\"distributedRightCategoryTitle\": \"Monitor\",\n\t\"distributedStatusServerMonitors\": \"Monitores de servidor\",\n\t\"distributedStatusServerMonitorsDescription\": \"Monitorar o status dos servidores relacionados\",\n\t\"distributedUptimeCreateSelectURL\": \"Aqui você pode selecionar a URL do host, juntamente com o tipo de monitor.\",\n\t\"distributedUptimeCreateChecks\": \"Verificações para realizar\",\n\t\"distributedUptimeCreateChecksDescription\": \"Você sempre pode adicionar ou remover verificações depois de adicionar seu site.\",\n\t\"distributedUptimeCreateIncidentNotification\": \"Notificações de incidentes\",\n\t\"distributedUptimeCreateIncidentDescription\": \"Quando ocorrer um incidente, notifique os usuários.\",\n\t\"distributedUptimeCreateAdvancedSettings\": \"Configurações avançadas\",\n\t\"distributedUptimeDetailsNoMonitorHistory\": \"Ainda não há histórico de verificações para este monitor.\",\n\t\"distributedUptimeDetailsStatusHeaderUptime\": \"Uptime:\",\n\t\"distributedUptimeDetailsStatusHeaderLastUpdate\": \"Última atualização\",\n\t\"notifications\": {\n\t\t\"enableNotifications\": \"Habilitar notificações da {{platform}}\",\n\t\t\"testNotification\": \"Notificação de teste\",\n\t\t\"addOrEditNotifications\": \"Adicionar ou editar notificações\",\n\t\t\"slack\": {\n\t\t\t\"label\": \"Slack\",\n\t\t\t\"description\": \"Para habilitar as notificações do Slack, crie um aplicativo Slack e habilite os webhooks de entrada. Depois disso, basta fornecer a URL do webhook aqui.\",\n\t\t\t\"webhookLabel\": \"Webhook URL\",\n\t\t\t\"webhookPlaceholder\": \"https://hooks.slack.com/services/...\",\n\t\t\t\"webhookRequired\": \"A URL do webhook do Slack é necessária\"\n\t\t},\n\t\t\"discord\": {\n\t\t\t\"label\": \"Discord\",\n\t\t\t\"description\": \"Para enviar dados para um canal do Discord a partir do Checkmate por meio de notificações do Discord usando webhooks, você pode usar o recurso de Webhooks de entrada do Discord.\",\n\t\t\t\"webhookLabel\": \"Discord Webhook URL\",\n\t\t\t\"webhookPlaceholder\": \"https://discord.com/api/webhooks/...\",\n\t\t\t\"webhookRequired\": \"A URL do webhook do Discord é necessária\"\n\t\t},\n\t\t\"telegram\": {\n\t\t\t\"label\": \"Telegram\",\n\t\t\t\"description\": \"Para habilitar as notificações do Telegram, crie um bot do Telegram usando o BotFather, um bot oficial para criar e gerenciar bots do Telegram. Em seguida, obtenha o token da API e o ID do chat e os coloque  aqui.\",\n\t\t\t\"tokenLabel\": \"Seu token de bot\",\n\t\t\t\"tokenPlaceholder\": \"123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11\",\n\t\t\t\"chatIdLabel\": \"Seu ID de bate-papo\",\n\t\t\t\"chatIdPlaceholder\": \"-1001234567890\",\n\t\t\t\"fieldsRequired\": \"O token do Telegram e o ID do chat são necessários\"\n\t\t},\n\t\t\"webhook\": {\n\t\t\t\"label\": \"Webhooks\",\n\t\t\t\"description\": \"Você pode configurar um webhook personalizado para receber notificações quando ocorrerem incidentes.\",\n\t\t\t\"urlLabel\": \"Webhook URL\",\n\t\t\t\"urlPlaceholder\": \"https://seu-servidor.com/webhook\",\n\t\t\t\"urlRequired\": \"URL do webhook é necessária\"\n\t\t},\n\t\t\"testNotificationDevelop\": \"Notificação de teste 2\",\n\t\t\"integrationButton\": \"Integração de notificação\",\n\t\t\"testSuccess\": \"Notificação de teste enviada com sucesso!\",\n\t\t\"testFailed\": \"Falha ao enviar notificação de teste\",\n\t\t\"unsupportedType\": \"Tipo de notificação não suportado\",\n\t\t\"networkError\": \"Ocorreu um erro de rede\",\n\t\t\"fallback\": {\n\t\t\t\"title\": \"Um canal de notificação é usado para:\",\n\t\t\t\"checks\": [\n\t\t\t\t\"Alerte as equipes sobre tempo de inatividade ou problemas de desempenho\",\n\t\t\t\t\"Informe os engenheiros sobre incidentes\",\n\t\t\t\t\"Mantenha os administradores informados sobre as mudanças no sistema\"\n\t\t\t],\n\t\t\t\"actionButton\": \"Vamos criar seu primeiro canal de notificação!\"\n\t\t},\n\t\t\"createButton\": \"Criar canal de notificação\",\n\t\t\"createTitle\": \"Canal de notificação\",\n\t\t\"create\": {\n\t\t\t\"success\": \"Notificação criada com sucesso\",\n\t\t\t\"failed\": \"Falha ao criar notificação\"\n\t\t},\n\t\t\"fetch\": {\n\t\t\t\"success\": \"Notificações obtidas com sucesso\",\n\t\t\t\"failed\": \"Falha ao buscar notificações\"\n\t\t},\n\t\t\"delete\": {\n\t\t\t\"success\": \"Notificação excluída com sucesso\",\n\t\t\t\"failed\": \"Falha ao excluir a notificação\"\n\t\t},\n\t\t\"edit\": {\n\t\t\t\"success\": \"Notificação atualizada com sucesso\",\n\t\t\t\"failed\": \"Falha ao atualizar a notificação\"\n\t\t},\n\t\t\"test\": {\n\t\t\t\"success\": \"Notificação de teste enviada com sucesso\",\n\t\t\t\"failed\": \"Falha ao enviar notificação de teste\"\n\t\t}\n\t},\n\t\"testLocale\": \"testLocale\",\n\t\"add\": \"Adicionar\",\n\t\"monitors\": \"monitores\",\n\t\"distributedUptimeStatusCreateStatusPage\": \"Pagina de status\",\n\t\"distributedUptimeStatusCreateStatusPageAccess\": \"Acesso\",\n\t\"distributedUptimeStatusCreateStatusPageReady\": \"Se sua página de status estiver pronta, você pode marcá-la como publicada.\",\n\t\"distributedUptimeStatusBasicInfoHeader\": \"Informação básica\",\n\t\"distributedUptimeStatusBasicInfoDescription\": \"Defina o nome da empresa e o subdomínio para o qual sua página de status aponta.\",\n\t\"distributedUptimeStatusLogoHeader\": \"Logo\",\n\t\"distributedUptimeStatusLogoDescription\": \"Carregue um logo para sua página de status\",\n\t\"distributedUptimeStatusLogoUploadButton\": \"Upload logo\",\n\t\"distributedUptimeStatusStandardMonitorsHeader\": \"Monitores padrão\",\n\t\"distributedUptimeStatusStandardMonitorsDescription\": \"Anexe monitores padrão à sua página de status.\",\n\t\"distributedUptimeStatusCreateYour\": \"Crie o seu\",\n\t\"distributedUptimeStatusEditYour\": \"Edite seu\",\n\t\"distributedUptimeStatusPublishedLabel\": \"Publicado e visível ao público\",\n\t\"distributedUptimeStatusCompanyNameLabel\": \"Nome da empresa\",\n\t\"distributedUptimeStatusPageAddressLabel\": \"Endereço da sua página de status\",\n\t\"distributedUptimeStatus30Days\": \"30 dias\",\n\t\"distributedUptimeStatus60Days\": \"60 dias\",\n\t\"distributedUptimeStatus90Days\": \"90 dias\",\n\t\"distributedUptimeStatusPageNotSetUp\": \"Uma página de status não está configurada.\",\n\t\"distributedUptimeStatusContactAdmin\": \"Entre em contato com seu administrador\",\n\t\"distributedUptimeStatusPageNotPublic\": \"Esta página de status não é pública.\",\n\t\"distributedUptimeStatusPageDeleteDialog\": \"Você quer excluir esta página de status?\",\n\t\"distributedUptimeStatusPageDeleteConfirm\": \"Sim, excluir página de status\",\n\t\"distributedUptimeStatusPageDeleteDescription\": \"Uma vez excluída, sua página de status não poderá ser recuperada.\",\n\t\"distributedUptimeStatusDevices\": \"Dispositivos\",\n\t\"distributedUptimeStatusUpt\": \"UPT\",\n\t\"distributedUptimeStatusUptBurned\": \"UPT queimado\",\n\t\"distributedUptimeStatusUptLogo\": \"Logo UPT\",\n\t\"incidentsTableNoIncidents\": \"Nenhum incidente registrado\",\n\t\"incidentsTablePaginationLabel\": \"incidentes\",\n\t\"incidentsTableMonitorName\": \"Nome do monitor\",\n\t\"incidentsTableStatus\": \"Status\",\n\t\"incidentsTableDateTime\": \"Data & Hora\",\n\t\"incidentsTableStatusCode\": \"Código de status\",\n\t\"incidentsTableMessage\": \"Mensagem\",\n\t\"incidentsOptionsHeader\": \"Incidentes para:\",\n\t\"incidentsOptionsHeaderFilterBy\": \"Filtrar por:\",\n\t\"incidentsOptionsHeaderFilterAll\": \"Todos\",\n\t\"incidentsOptionsHeaderFilterDown\": \"Inativos\",\n\t\"incidentsOptionsHeaderFilterCannotResolve\": \"Não é possível resolver\",\n\t\"incidentsOptionsHeaderShow\": \"Mostrar:\",\n\t\"incidentsOptionsHeaderLastHour\": \"Última hora\",\n\t\"incidentsOptionsHeaderLastDay\": \"Último dia\",\n\t\"incidentsOptionsHeaderLastWeek\": \"Ultima semana\",\n\t\"incidentsOptionsPlaceholderAllServers\": \"Todos os servidores\",\n\t\"infrastructureCreateYour\": \"Crie o seu\",\n\t\"infrastructureCreateGeneralSettingsDescription\": \"Aqui você pode inserir a URL do host, juntamente com o nome de exibição e o API secret de autorização para se conectar ao agente do servidor.\",\n\t\"infrastructureServerRequirement\": \"O servidor que você quer monitorar deve estar executando o\",\n\t\"infrastructureCustomizeAlerts\": \"Personalize alertas\",\n\t\"infrastructureAlertNotificationDescription\": \"Envie uma notificação ao(s) usuário(s) quando os limites excederem uma porcentagem especificada.\",\n\t\"infrastructureCreateMonitor\": \"Criar monitor de infraestrutura\",\n\t\"infrastructureProtocol\": \"Protocolo\",\n\t\"infrastructureServerUrlLabel\": \"URL do servidor\",\n\t\"infrastructureDisplayNameLabel\": \"Nome de exibição\",\n\t\"infrastructureAuthorizationSecretLabel\": \"API Secret\",\n\t\"gb\": \"GB\",\n\t\"mb\": \"MB\",\n\t\"mem\": \"Mem\",\n\t\"memoryUsage\": \"Uso de memória\",\n\t\"cpu\": \"CPU\",\n\t\"cpuUsage\": \"Uso da CPU\",\n\t\"cpuTemperature\": \"Temperatura da CPU\",\n\t\"diskUsage\": \"Uso de disco\",\n\t\"used\": \"Usado\",\n\t\"total\": \"Total\",\n\t\"cores\": \"Núcleos\",\n\t\"frequency\": \"Frequência\",\n\t\"status\": \"Status\",\n\t\"cpuPhysical\": \"CPU (Física)\",\n\t\"cpuLogical\": \"CPU (Lógica)\",\n\t\"cpuFrequency\": \"Frequência da CPU\",\n\t\"avgCpuTemperature\": \"Temperatura média da CPU\",\n\t\"memory\": \"Memória\",\n\t\"disk\": \"Disco\",\n\t\"uptime\": \"Uptime\",\n\t\"os\": \"OS\",\n\t\"host\": \"Host\",\n\t\"actions\": \"Ações\",\n\t\"integrations\": \"Integrações\",\n\t\"integrationsPrism\": \"Conecte o Prism ao seu serviço favorito.\",\n\t\"integrationsSlack\": \"Slack\",\n\t\"integrationsSlackInfo\": \"Conecte-se com o Slack e veja incidentes em um canal\",\n\t\"integrationsDiscord\": \"Discord\",\n\t\"integrationsDiscordInfo\": \"Conecte-se com o Discord e visualize incidentes diretamente em um canal\",\n\t\"integrationsZapier\": \"Zapier\",\n\t\"integrationsZapierInfo\": \"Envie todos os incidentes para o Zapier e veja-os em todos os lugares\",\n\t\"commonSave\": \"Salvar\",\n\t\"createYour\": \"Crie o seu\",\n\t\"createMonitor\": \"Criar monitor\",\n\t\"pause\": \"Pausar\",\n\t\"resume\": \"Resumir\",\n\t\"editing\": \"Editando...\",\n\t\"url\": \"URL\",\n\t\"access\": \"Acesso\",\n\t\"timezone\": \"Fuso horário\",\n\t\"features\": \"Recursos\",\n\t\"administrator\": \"Administrador?\",\n\t\"loginHere\": \"Login aqui\",\n\t\"displayName\": \"Nome de exibição\",\n\t\"urlMonitor\": \"URL do monitor\",\n\t\"portToMonitor\": \"Porta do monitor\",\n\t\"websiteMonitoring\": \"Monitoramento de sites\",\n\t\"websiteMonitoringDescription\": \"Use HTTP(s) para monitorar seu site ou API endpoint.\",\n\t\"pingMonitoring\": \"Monitoramento de ping\",\n\t\"pingMonitoringDescription\": \"Verifique se o seu servidor está disponível ou não.\",\n\t\"dockerContainerMonitoring\": \"Monitoramento de contêiner Docker\",\n\t\"dockerContainerMonitoringDescription\": \"Verifique se o seu contêiner Docker está em execução ou não.\",\n\t\"portMonitoring\": \"Monitoramento de porta\",\n\t\"portMonitoringDescription\": \"Verifique se sua porta está aberta ou não.\",\n\t\"createMaintenanceWindow\": \"Criar janela de manutenção\",\n\t\"createMaintenance\": \"Criar manutenção\",\n\t\"editMaintenance\": \"Editar manutenção\",\n\t\"maintenanceWindowName\": \"Nome da janela de manutenção\",\n\t\"friendlyNameInput\": \"Nome amigável\",\n\t\"friendlyNamePlaceholder\": \"Manutenção em __ : __ por ___ minutos\",\n\t\"maintenanceRepeat\": \"Repetição de manutenção\",\n\t\"maintenance\": \"manutenção\",\n\t\"duration\": \"Duração\",\n\t\"addMonitors\": \"Adicionar monitores\",\n\t\"window\": \"janela\",\n\t\"cancel\": \"Cancelar\",\n\t\"message\": \"Mensagem\",\n\t\"low\": \"baixo\",\n\t\"high\": \"alto\",\n\t\"statusCode\": \"Código de status\",\n\t\"date&Time\": \"Data & Hora\",\n\t\"type\": \"Tipo\",\n\t\"statusPageName\": \"Nome da página de status\",\n\t\"publicURL\": \"URL publica\",\n\t\"repeat\": \"Repetir\",\n\t\"edit\": \"Editar\",\n\t\"createA\": \"Crie um\",\n\t\"remove\": \"Remover\",\n\t\"maintenanceWindowDescription\": \"Seus pings não serão enviados durante esse período\",\n\t\"startTime\": \"Hora de início\",\n\t\"timeZoneInfo\": \"Todas as datas e horários estão no fuso horário GMT+0.\",\n\t\"monitorsToApply\": \"Monitores para aplicar a janela de manutenção\",\n\t\"nextWindow\": \"Próxima janela\",\n\t\"notFoundButton\": \"Vá para o painel principal\",\n\t\"pageSpeedConfigureSettingsDescription\": \"Aqui você pode selecionar a URL do host, juntamente com o tipo de monitor.\",\n\t\"monitorDisplayName\": \"Nome de exibição do monitor\",\n\t\"whenNewIncident\": \"Quando há um novo incidente,\",\n\t\"notifySMS\": \"Notificar via SMS (em breve)\",\n\t\"notifyEmails\": \"Também notificar por e-mail para vários endereços (em breve)\",\n\t\"seperateEmails\": \"Você pode separar vários e-mails com uma vírgula\",\n\t\"checkFrequency\": \"Verifique a frequência\",\n\t\"matchMethod\": \"Método de correspondência\",\n\t\"expectedValue\": \"Valor esperado\",\n\t\"deleteDialogTitle\": \"Você realmente deseja excluir este monitor?\",\n\t\"deleteDialogDescription\": \"Uma vez excluído, este monitor não poderá ser recuperado.\",\n\t\"pageSpeedMonitor\": \"Monitor PageSpeed\",\n\t\"shown\": \"Mostrado\",\n\t\"ago\": \"atrás\",\n\t\"companyName\": \"Nome da empresa\",\n\t\"pageSpeedDetailsPerformanceReport\": \"Os valores são estimados e podem variar.\",\n\t\"pageSpeedDetailsPerformanceReportCalculator\": \"Veja calculadora\",\n\t\"checkingEvery\": \"Verificando a cada\",\n\t\"statusPageCreateSettings\": \"Se sua página de status estiver pronta, você pode marcá-la como publicada.\",\n\t\"basicInformation\": \"Informações Básicas\",\n\t\"statusPageCreateBasicInfoDescription\": \"Defina o nome da empresa e o subdomínio para o qual sua página de status aponta.\",\n\t\"statusPageCreateSelectTimeZoneDescription\": \"Selecione o fuso horário em que será exibido na sua página de status.\",\n\t\"statusPageCreateAppearanceDescription\": \"Defina a aparência padrão da sua página de status pública.\",\n\t\"statusPageCreateSettingsCheckboxLabel\": \"Publicado e visível ao público\",\n\t\"statusPageCreateBasicInfoStatusPageAddress\": \"Endereço da sua página de status\",\n\t\"statusPageCreateTabsContent\": \"Servidores de páginas de status\",\n\t\"statusPageCreateTabsContentDescription\": \"Você pode adicionar quantos monitores quiser à sua página de status. Você também pode reordená-los para uma melhor experiência de visualização.\",\n\t\"statusPageCreateTabsContentFeaturesDescription\": \"Mostrar mais detalhes na página de status\",\n\t\"showCharts\": \"Mostrar gráficos\",\n\t\"showUptimePercentage\": \"Mostrar porcentagem de Uptime\",\n\t\"removeLogo\": \"Remover logo\",\n\t\"statusPageStatus\": \"Uma página de status pública não está configurada.\",\n\t\"statusPageStatusContactAdmin\": \"Entre em contato com seu administrador\",\n\t\"statusPageStatusNotPublic\": \"Esta página de status não é pública.\",\n\t\"statusPageStatusNoPage\": \"Não há página de status aqui.\",\n\t\"statusPageStatusServiceStatus\": \"Status do serviço\",\n\t\"deleteStatusPage\": \"Você quer excluir esta página de status?\",\n\t\"deleteStatusPageConfirm\": \"Sim, excluir página de status\",\n\t\"deleteStatusPageDescription\": \"Uma vez excluída, sua página de status não poderá ser recuperada.\",\n\t\"uptimeCreate\": \"O valor esperado é usado para corresponder ao resultado da resposta, e a correspondência determina o status.\",\n\t\"uptimeCreateJsonPath\": \"Esta expressão será avaliada em relação aos dados JSON de resposta e o resultado será usado para corresponder ao valor esperado. Veja\",\n\t\"uptimeCreateJsonPathQuery\": \"para documentação de linguagem de consulta.\",\n\t\"maintenanceTableActionMenuDialogTitle\": \"Você realmente deseja remover esta janela de manutenção?\",\n\t\"infrastructureEditYour\": \"Edite seu\",\n\t\"infrastructureEditMonitor\": \"Salvar Monitor de Infraestrutura\",\n\t\"infrastructureMonitorCreated\": \"Monitor de infraestrutura criado com sucesso!\",\n\t\"infrastructureMonitorUpdated\": \"Monitor de infraestrutura atualizado com sucesso!\",\n\t\"errorInvalidTypeId\": \"Tipo de notificação fornecido inválido\",\n\t\"errorInvalidFieldId\": \"ID do campo fornecido inválido\",\n\t\"inviteNoTokenFound\": \"Nenhum token de convite encontrado\",\n\t\"pageSpeedWarning\": \"Aviso: você ainda não adicionou uma chave de API do Google PageSpeed. Sem ela, o monitor PageSpeed ​​não funcionará.\",\n\t\"pageSpeedLearnMoreLink\": \"Clique aqui\",\n\t\"pageSpeedAddApiKey\": \"para adicionar sua chave de API.\",\n\t\"update\": \"Atualizar\",\n\t\"invalidFileFormat\": \"Formato de arquivo não suportado!\",\n\t\"invalidFileSize\": \"O tamanho do arquivo é muito grande!\",\n\t\"ClickUpload\": \"Clique para enviar\",\n\t\"DragandDrop\": \"arraste e solte\",\n\t\"MaxSize\": \"Tamanho Máximo\",\n\t\"SupportedFormats\": \"Formatos suportados\",\n\t\"FirstName\": \"Nome\",\n\t\"LastName\": \"Sobrenome\",\n\t\"EmailDescriptionText\": \"Este é seu endereço de e-mail atual — ele não pode ser alterado.\",\n\t\"YourPhoto\": \"Foto de perfil\",\n\t\"PhotoDescriptionText\": \"Esta foto será exibida na sua página de perfil.\",\n\t\"save\": \"Salvar\",\n\t\"DeleteDescriptionText\": \"Isso removerá a conta e todos os dados associados do servidor. Essa ação não é reversível.\",\n\t\"DeleteAccountWarning\": \"Remover sua conta significa que você não poderá fazer login novamente e todos os seus dados serão removidos. Isso não é reversível.\",\n\t\"DeleteWarningTitle\": \"Deseja realmente remover esta conta?\",\n\t\"bulkImport\": {\n\t\t\"title\": \"Bulk Import\",\n\t\t\"selectFileTips\": \"Selecione o arquivo CSV para enviar\",\n\t\t\"selectFileDescription\": \"Você pode baixar nosso <template>modelo</template> ou <sample>amostra</sample>\",\n\t\t\"selectFile\": \"Selecione o arquivo\",\n\t\t\"parsingFailed\": \"Falha na análise\",\n\t\t\"uploadSuccess\": \"Monitores criados com sucesso!\",\n\t\t\"validationFailed\": \"Falha na validação\",\n\t\t\"noFileSelected\": \"Nenhum arquivo selecionado\",\n\t\t\"fallbackPage\": \"Importe um arquivo para enviar uma lista de servidores em massa\",\n\t\t\"invalidFileType\": \"Tipo de arquivo inválido\",\n\t\t\"uploadFailed\": \"Falha no upload\"\n\t},\n\t\"DeleteAccountTitle\": \"Remover conta\",\n\t\"DeleteAccountButton\": \"Remover conta\",\n\t\"publicLink\": \"Link publico\",\n\t\"maskedPageSpeedKeyPlaceholder\": \"*************************************\",\n\t\"reset\": \"Resetar\",\n\t\"ignoreTLSError\": \"Ignorar erro TLS/SSL\",\n\t\"tlsErrorIgnored\": \"Erros TLS/SSL ignorados\",\n\t\"ignoreTLSErrorDescription\": \"Ignore os erros de TLS/SSL e continue verificando a disponibilidade do site\",\n\t\"createNew\": \"Criar novo\",\n\t\"greeting\": {\n\t\t\"prepend\": \"Ei\",\n\t\t\"append\": \"A tarde é seu playground — vamos torná-la épica!\",\n\t\t\"overview\": \"Aqui está uma visão geral dos seus monitores {{type}}.\"\n\t},\n\t\"roles\": {\n\t\t\"superAdmin\": \"Super Admin\",\n\t\t\"admin\": \"Admin\",\n\t\t\"teamMember\": \"Membro da equipe\",\n\t\t\"demoUser\": \"Usuário demo\"\n\t},\n\t\"teamPanel\": {\n\t\t\"teamMembers\": \"Membros da equipe\",\n\t\t\"filter\": {\n\t\t\t\"all\": \"Todos\",\n\t\t\t\"member\": \"Membro\"\n\t\t},\n\t\t\"inviteTeamMember\": \"Convidar um membro da equipe\",\n\t\t\"inviteNewTeamMember\": \"Convidar novo membro da equipe\",\n\t\t\"inviteDescription\": \"Ao adicionar um novo membro da equipe, ele terá acesso a todos os monitores.\",\n\t\t\"email\": \"E-mail\",\n\t\t\"selectRole\": \"Selecione a cargo\",\n\t\t\"inviteLink\": \"Link de convite\",\n\t\t\"cancel\": \"Cancelar\",\n\t\t\"noMembers\": \"Não há membros da equipe com este cargo\",\n\t\t\"getToken\": \"Obter token\",\n\t\t\"emailToken\": \"Token de e-mail\",\n\t\t\"table\": {\n\t\t\t\"name\": \"Nome\",\n\t\t\t\"email\": \"E-mail\",\n\t\t\t\"role\": \"Cargo\",\n\t\t\t\"created\": \"Criado\"\n\t\t},\n\t\t\"addTeamMember\": {\n\t\t\t\"addMemberMenu\": \"\",\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"addButton\": \"\"\n\t\t},\n\t\t\"register\": \"\",\n\t\t\"registerToast\": {\n\t\t\t\"success\": \"\",\n\t\t\t\"dbUserExists\": \"\",\n\t\t\t\"unknownError\": \"\"\n\t\t},\n\t\t\"registerTeamMember\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"auth\": {\n\t\t\t\t\"common\": {\n\t\t\t\t\t\"inputs\": {\n\t\t\t\t\t\t\"firstName\": {\n\t\t\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\t\t\"empty\": \"\",\n\t\t\t\t\t\t\t\t\"pattern\": \"\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"lastName\": {\n\t\t\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\t\t\"empty\": \"\",\n\t\t\t\t\t\t\t\t\"pattern\": \"\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"email\": {\n\t\t\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\t\t\"empty\": \"\",\n\t\t\t\t\t\t\t\t\"invalid\": \"\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"role\": {\n\t\t\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\t\t\"empty\": \"\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"role\": \"\",\n\t\t\"changeTeamPassword\": {\n\t\t\t\"changePasswordMenu\": \"\",\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"success\": \"\"\n\t\t}\n\t},\n\t\"monitorState\": {\n\t\t\"paused\": \"Pausado\",\n\t\t\"resumed\": \"Retomado\",\n\t\t\"active\": \"Ativo\"\n\t},\n\t\"menu\": {\n\t\t\"uptime\": \"Uptime\",\n\t\t\"pagespeed\": \"Pagespeed\",\n\t\t\"infrastructure\": \"Infraestrutura\",\n\t\t\"incidents\": \"Incidentes\",\n\t\t\"statusPages\": \"Pagina de status\",\n\t\t\"maintenance\": \"Manutenção\",\n\t\t\"integrations\": \"Integrações\",\n\t\t\"settings\": \"Configurações\",\n\t\t\"support\": \"Suporte\",\n\t\t\"discussions\": \"Discussões\",\n\t\t\"docs\": \"Docs\",\n\t\t\"changelog\": \"Changelog\",\n\t\t\"profile\": \"Perfil\",\n\t\t\"password\": \"Senha\",\n\t\t\"team\": \"Equipe\",\n\t\t\"logOut\": \"Sair\",\n\t\t\"notifications\": \"Notificações\",\n\t\t\"logs\": \"Registros\"\n\t},\n\t\"settingsEmailUser\": \"Usuário de e-mail - Nome de usuário para autenticação, substitui o endereço de e-mail, se especificado\",\n\t\"state\": \"Estado\",\n\t\"statusBreadCrumbsStatusPages\": \"Pagina de status\",\n\t\"statusBreadCrumbsDetails\": \"Detalhes\",\n\t\"commonSaving\": \"Salvando...\",\n\t\"navControls\": \"Controles\",\n\t\"incidentsPageTitle\": \"Incidentes\",\n\t\"passwordPanel\": {\n\t\t\"passwordChangedSuccess\": \"Sua senha foi alterada com sucesso.\",\n\t\t\"passwordInputIncorrect\": \"Sua senha digitada está incorreta.\",\n\t\t\"currentPassword\": \"Senha atual\",\n\t\t\"enterCurrentPassword\": \"Digite sua senha atual\",\n\t\t\"newPassword\": \"Nova Senha\",\n\t\t\"enterNewPassword\": \"Digite sua nova senha\",\n\t\t\"confirmNewPassword\": \"Confirme a nova senha\",\n\t\t\"passwordRequirements\": \"A nova senha deve conter pelo menos 8 caracteres e deve ter pelo menos uma letra maiúscula, uma letra minúscula, um número e um caractere especial.\",\n\t\t\"saving\": \"Salvando...\"\n\t},\n\t\"emailSent\": \"E-mail enviado com sucesso\",\n\t\"failedToSendEmail\": \"Falha ao enviar e-mail\",\n\t\"settingsTestEmailSuccess\": \"E-mail de teste enviado com sucesso\",\n\t\"settingsTestEmailFailed\": \"Falha ao enviar e-mail de teste\",\n\t\"settingsTestEmailFailedWithReason\": \"Falha ao enviar e-mail de teste: {{reason}}\",\n\t\"settingsTestEmailUnknownError\": \"Erro desconhecido\",\n\t\"statusMsg\": {\n\t\t\"paused\": \"O monitoramento está pausado.\",\n\t\t\"up\": \"Seu site está no ar.\",\n\t\t\"down\": \"Seu site está fora do ar.\",\n\t\t\"pending\": \"Pendente...\"\n\t},\n\t\"uptimeGeneralInstructions\": {\n\t\t\"http\": \"Insira a URL ou IP para monitorar (ex. https://exemplo.com.br/ ou 192.168.1.100) e adicione uma descrição que aparecerá na dashboard.\",\n\t\t\"ping\": \"Insira o endereço IP ou nome de domínio para ping (ex. 192.168.1.100 ou exemplo.com.br) e adicione uma descrição que aparecerá na dashboard.\",\n\t\t\"docker\": \"Insira o Docker Id do seu container. Docker Ids devem ser todos os 64 caracteres. Você pode executar docker inspect <short_id> para descobrir o Id completo.\",\n\t\t\"port\": \"Insira a URL ou o IP do servidor, aporta e uma descrição que aparecerá na dashboard.\",\n\t\t\"game\": \"\",\n\t\t\"https\": \"\"\n\t},\n\t\"common\": {\n\t\t\"appName\": \"Checkmate\",\n\t\t\"monitoringAgentName\": \"Capture\",\n\t\t\"buttons\": {\n\t\t\t\"toggleTheme\": \"Trocar claro e escuro\"\n\t\t},\n\t\t\"toasts\": {\n\t\t\t\"networkError\": \"Erro de rede\",\n\t\t\t\"checkConnection\": \"Por favor, verifique a conexão\",\n\t\t\t\"unknownError\": \"Erro desconhecido\"\n\t\t}\n\t},\n\t\"auth\": {\n\t\t\"common\": {\n\t\t\t\"navigation\": {\n\t\t\t\t\"continue\": \"Continuar\",\n\t\t\t\t\"back\": \"Voltar\"\n\t\t\t},\n\t\t\t\"inputs\": {\n\t\t\t\t\"email\": {\n\t\t\t\t\t\"label\": \"Email\",\n\t\t\t\t\t\"placeholder\": \"joao.silva@dominio.com.br\",\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"Para continuar, insira seu endereço de email\",\n\t\t\t\t\t\t\"invalid\": \"Por favor, confirme o endereço de email informado\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"password\": {\n\t\t\t\t\t\"label\": \"Senha\",\n\t\t\t\t\t\"rules\": {\n\t\t\t\t\t\t\"length\": {\n\t\t\t\t\t\t\t\"beginning\": \"Deve ter no mínimo\",\n\t\t\t\t\t\t\t\"highlighted\": \"8 caracteres de comprimento\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"special\": {\n\t\t\t\t\t\t\t\"beginning\": \"Deve conter pelo menos\",\n\t\t\t\t\t\t\t\"highlighted\": \"um caractere especial\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"number\": {\n\t\t\t\t\t\t\t\"beginning\": \"Deve ter pelo menos\",\n\t\t\t\t\t\t\t\"highlighted\": \"um número\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"uppercase\": {\n\t\t\t\t\t\t\t\"beginning\": \"Deve ter pelo menos\",\n\t\t\t\t\t\t\t\"highlighted\": \"uma letra maiúscula\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"lowercase\": {\n\t\t\t\t\t\t\t\"beginning\": \"Deve ter pelo menos\",\n\t\t\t\t\t\t\t\"highlighted\": \"uma letra minúscula\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"match\": {\n\t\t\t\t\t\t\t\"beginning\": \"Senha e confirmação de senha\",\n\t\t\t\t\t\t\t\"highlighted\": \"devem combinar\"\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"Por favor, digite sua senha\",\n\t\t\t\t\t\t\"length\": \"A senha deve ter pelo menos 8 caracteres\",\n\t\t\t\t\t\t\"uppercase\": \"A senha deve conter pelo menos 1 letra maiúscula\",\n\t\t\t\t\t\t\"lowercase\": \"Senha deve ter pelo menos uma letra minúscula\",\n\t\t\t\t\t\t\"number\": \"Senha deve ter pelo menos um número\",\n\t\t\t\t\t\t\"special\": \"Senha deve ter pelo menos um caractere especial\",\n\t\t\t\t\t\t\"incorrect\": \"A senha que você forneceu não está registrada\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"passwordConfirm\": {\n\t\t\t\t\t\"label\": \"Confirme a senha\",\n\t\t\t\t\t\"placeholder\": \"Informe a senha novamente para confirmar\",\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"Por favor, informe a senha novamente para confirmação (cuidado com erros de digitação)\",\n\t\t\t\t\t\t\"different\": \"As senhas informadas não combinam, então uma deve estar errada\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"firstName\": {\n\t\t\t\t\t\"label\": \"Nome\",\n\t\t\t\t\t\"placeholder\": \"João\",\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"Por favor, insira seu nome\",\n\t\t\t\t\t\t\"length\": \"Nome deve ter menos de 50 caracteres\",\n\t\t\t\t\t\t\"pattern\": \"Nome deve conter apenas letras, espaços, apóstrofos ou hífens\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"lastName\": {\n\t\t\t\t\t\"label\": \"Sobrenome\",\n\t\t\t\t\t\"placeholder\": \"Silva\",\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"Por favor, insira seu sobrenome\",\n\t\t\t\t\t\t\"length\": \"Sobrenome deve ter menos de 50 caracteres\",\n\t\t\t\t\t\t\"pattern\": \"Sobrenome deve conter apenas letras, espaços, apóstrofos ou hífens\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"errors\": {\n\t\t\t\t\"validation\": \"Erro de validação de dados.\"\n\t\t\t},\n\t\t\t\"fields\": {\n\t\t\t\t\"password\": {\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"incorrect\": \"A senha que você forneceu não corresponde aos nossos registros\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"role\": {\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"min\": \"Pelo menos uma função é necessária\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"login\": {\n\t\t\t\"heading\": \"Entrar\",\n\t\t\t\"subheadings\": {\n\t\t\t\t\"stepOne\": \"Insira seu email\",\n\t\t\t\t\"stepTwo\": \"Insira sua senha\"\n\t\t\t},\n\t\t\t\"links\": {\n\t\t\t\t\"forgotPassword\": \"Esqueceu sua senha?\",\n\t\t\t\t\"register\": \"Não tem uma conta?\",\n\t\t\t\t\"forgotPasswordLink\": \"Redefinir senha\",\n\t\t\t\t\"registerLink\": \"Registre-se aqui\"\n\t\t\t},\n\t\t\t\"toasts\": {\n\t\t\t\t\"success\": \"Bem-vindo de volta! Você está autenticado.\",\n\t\t\t\t\"incorrectPassword\": \"Senha incorreta\"\n\t\t\t},\n\t\t\t\"errors\": {\n\t\t\t\t\"password\": {\n\t\t\t\t\t\"incorrect\": \"A senha que você forneceu não corresponde aos nossos registros\"\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"welcome\": \"\"\n\t\t},\n\t\t\"registration\": {\n\t\t\t\"heading\": {\n\t\t\t\t\"superAdmin\": \"Crie um usuário administrador\",\n\t\t\t\t\"user\": \"Se inscrever\"\n\t\t\t},\n\t\t\t\"subheadings\": {\n\t\t\t\t\"stepOne\": \"Informe seus dados pessoais\",\n\t\t\t\t\"stepTwo\": \"Informe seu email\",\n\t\t\t\t\"stepThree\": \"Crie sua senha\"\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\t\"superAdmin\": \"Crie sua conta de superadministrador para começar\",\n\t\t\t\t\"user\": \"Cadastre-se como usuário e peça ao superadministrador acesso aos seus monitores\"\n\t\t\t},\n\t\t\t\"gettingStartedButton\": {\n\t\t\t\t\"superAdmin\": \"Criar conta de superadministrador\",\n\t\t\t\t\"user\": \"Cadastre-se como usuário normal\"\n\t\t\t},\n\t\t\t\"termsAndPolicies\": \"Ao criar uma conta, você concorda com nossos <a1>Termos de Serviço</a1> e <a2>Política de Privacidade</a2>.\",\n\t\t\t\"links\": {\n\t\t\t\t\"login\": \"Já tem uma conta? <a>Entrar</a>\"\n\t\t\t},\n\t\t\t\"toasts\": {\n\t\t\t\t\"success\": \"Bem-vindo! Sua conta foi criada com sucesso.\"\n\t\t\t},\n\t\t\t\"welcome\": \"\"\n\t\t},\n\t\t\"forgotPassword\": {\n\t\t\t\"heading\": \"Esqueceu sua senha?\",\n\t\t\t\"subheadings\": {\n\t\t\t\t\"stepOne\": \"Não se preocupe, enviaremos instruções de redefinição.\",\n\t\t\t\t\"stepTwo\": \"Enviamos um link de redefinição de senha para <email/>\",\n\t\t\t\t\"stepThree\": \"Sua nova senha deve ser diferente das senhas usadas anteriormente.\",\n\t\t\t\t\"stepFour\": \"Sua senha foi redefinida com sucesso. Clique abaixo para fazer login magicamente.\"\n\t\t\t},\n\t\t\t\"buttons\": {\n\t\t\t\t\"openEmail\": \"Abra o aplicativo de e-mail\",\n\t\t\t\t\"resetPassword\": \"Redefinir senha\"\n\t\t\t},\n\t\t\t\"imageAlts\": {\n\t\t\t\t\"passwordKey\": \"Ícone de chave de senha\",\n\t\t\t\t\"email\": \"Ícone de e-mail\",\n\t\t\t\t\"lock\": \"Ícone de cadeado\",\n\t\t\t\t\"passwordConfirm\": \"Ícone de confirmação de senha\"\n\t\t\t},\n\t\t\t\"links\": {\n\t\t\t\t\"login\": \"Voltar para o <a>login</a>\",\n\t\t\t\t\"resend\": \"Não recebeu o email? <a>Clique para reenviar</a>\"\n\t\t\t},\n\t\t\t\"toasts\": {\n\t\t\t\t\"sent\": \"Instruções enviadas para <email/>.\",\n\t\t\t\t\"emailNotFound\": \"E-mail não encontrado.\",\n\t\t\t\t\"redirect\": \"Redirecionando em <segundos/>...\",\n\t\t\t\t\"success\": \"Sua senha foi redefinida com sucesso.\",\n\t\t\t\t\"error\": \"Não foi possível redefinir a senha. Tente novamente mais tarde ou entre em contato com o suporte.\"\n\t\t\t}\n\t\t}\n\t},\n\t\"errorPages\": {\n\t\t\"serverUnreachable\": {\n\t\t\t\"toasts\": {\n\t\t\t\t\"reconnected\": \"Reconectado ao servidor com sucesso.\",\n\t\t\t\t\"stillUnreachable\": \"O servidor ainda está inacessível. Tente novamente mais tarde.\"\n\t\t\t},\n\t\t\t\"alertBox\": \"Erro de conexão do servidor\",\n\t\t\t\"description\": \"Não conseguimos conectar ao servidor. Verifique sua conexão com a internet ou sua configuração de implantação se o problema persistir.\",\n\t\t\t\"retryButton\": {\n\t\t\t\t\"default\": \"Tentar conectar novamente\",\n\t\t\t\t\"processing\": \"Conectando...\"\n\t\t\t}\n\t\t}\n\t},\n\t\"createNotifications\": {\n\t\t\"title\": \"Criar canal de notificação\",\n\t\t\"nameSettings\": {\n\t\t\t\"title\": \"Nome\",\n\t\t\t\"description\": \"Um nome descritivo para sua integração.\",\n\t\t\t\"nameLabel\": \"Nome\",\n\t\t\t\"namePlaceholder\": \"por exemplo, notificações do Slack\"\n\t\t},\n\t\t\"typeSettings\": {\n\t\t\t\"title\": \"Tipo\",\n\t\t\t\"description\": \"Selecione o tipo de canal de notificação que você deseja criar.\",\n\t\t\t\"typeLabel\": \"Tipo\"\n\t\t},\n\t\t\"emailSettings\": {\n\t\t\t\"title\": \"E-mail\",\n\t\t\t\"description\": \"Endereços de e-mail de destino.\",\n\t\t\t\"emailLabel\": \"Endereço de email\",\n\t\t\t\"emailPlaceholder\": \"por exemplo john@example.com\"\n\t\t},\n\t\t\"slackSettings\": {\n\t\t\t\"title\": \"Folga\",\n\t\t\t\"description\": \"Configure seu webhook do Slack aqui\",\n\t\t\t\"webhookLabel\": \"URL do webhook do Slack\",\n\t\t\t\"webhookPlaceholder\": \"https://hooks.slack.com/services/...\"\n\t\t},\n\t\t\"pagerdutySettings\": {\n\t\t\t\"title\": \"PagerDuty\",\n\t\t\t\"description\": \"Configure sua integração com o PagerDuty aqui\",\n\t\t\t\"integrationKeyLabel\": \"Chave de integração\",\n\t\t\t\"integrationKeyPlaceholder\": \"1234567890\"\n\t\t},\n\t\t\"discordSettings\": {\n\t\t\t\"title\": \"Discórdia\",\n\t\t\t\"description\": \"Configure seu webhook do Discord aqui\",\n\t\t\t\"webhookLabel\": \"URL do webhook do Discord\",\n\t\t\t\"webhookPlaceholder\": \"https://seu-servidor.com/webhook\"\n\t\t},\n\t\t\"webhookSettings\": {\n\t\t\t\"title\": \"Webhook\",\n\t\t\t\"description\": \"Configure seu webhook aqui\",\n\t\t\t\"webhookLabel\": \"URL do webhook\",\n\t\t\t\"webhookPlaceholder\": \"https://seu-servidor.com/webhook\"\n\t\t},\n\t\t\"testNotification\": \"Notificação de teste\",\n\t\t\"dialogDeleteTitle\": \"Tem certeza de que deseja excluir esta notificação?\",\n\t\t\"dialogDeleteConfirm\": \"Excluir\"\n\t},\n\t\"notificationConfig\": {\n\t\t\"title\": \"Notificações\",\n\t\t\"description\": \"Selecione os canais de notificação que deseja usar\"\n\t},\n\t\"monitorStatus\": {\n\t\t\"checkingEvery\": \"Verificando a cada {{intervalo}}\",\n\t\t\"withCaptureAgent\": \"com agente de captura {{versão}}\",\n\t\t\"up\": \"acima\",\n\t\t\"down\": \"abaixo\",\n\t\t\"paused\": \"pausado\"\n\t},\n\t\"advancedMatching\": \"Correspondência avançada\",\n\t\"sendTestNotifications\": \"Enviar notificações de teste\",\n\t\"selectAll\": \"Selecionar tudo\",\n\t\"showAdminLoginLink\": \"Mostrar o link \\\"Administrador? Efetue login aqui\\\" na página de status\",\n\t\"logsPage\": {\n\t\t\"title\": \"Registros\",\n\t\t\"description\": \"Logs do sistema - últimas 1000 linhas\",\n\t\t\"tabs\": {\n\t\t\t\"queue\": \"Fila de tarefas\",\n\t\t\t\"logs\": \"Logs do servidor\",\n\t\t\t\"diagnostics\": \"Diagnóstico\"\n\t\t},\n\t\t\"toast\": {\n\t\t\t\"fetchLogsSuccess\": \"Logs obtidos com sucesso\"\n\t\t},\n\t\t\"logLevelSelect\": {\n\t\t\t\"title\": \"Nível de log\",\n\t\t\t\"values\": {\n\t\t\t\t\"all\": \"Todos\",\n\t\t\t\t\"info\": \"Informações\",\n\t\t\t\t\"warn\": \"Avisar\",\n\t\t\t\t\"error\": \"Erro\",\n\t\t\t\t\"debug\": \"Depurar\"\n\t\t\t}\n\t\t}\n\t},\n\t\"queuePage\": {\n\t\t\"title\": \"Fila\",\n\t\t\"refreshButton\": \"Atualizar\",\n\t\t\"flushButton\": \"Fila de descarga\",\n\t\t\"jobTable\": {\n\t\t\t\"title\": \"Empregos atualmente na fila\",\n\t\t\t\"idHeader\": \"ID do monitor\",\n\t\t\t\"urlHeader\": \"URL\",\n\t\t\t\"typeHeader\": \"Tipo\",\n\t\t\t\"activeHeader\": \"Ativo\",\n\t\t\t\"lockedAtHeader\": \"Trancado em\",\n\t\t\t\"runCountHeader\": \"Contagem de corridas\",\n\t\t\t\"failCountHeader\": \"Contagem de falhas\",\n\t\t\t\"lastRunHeader\": \"Última corrida em\",\n\t\t\t\"lastFinishedAtHeader\": \"Última conclusão em\",\n\t\t\t\"lastRunTookHeader\": \"A última corrida aconteceu\",\n\t\t\t\"intervalHeader\": \"\"\n\t\t},\n\t\t\"metricsTable\": {\n\t\t\t\"title\": \"Métricas de fila\",\n\t\t\t\"metricHeader\": \"Métrica\",\n\t\t\t\"valueHeader\": \"Valor\"\n\t\t},\n\t\t\"failedJobTable\": {\n\t\t\t\"title\": \"Trabalhos com falha\",\n\t\t\t\"monitorIdHeader\": \"ID do monitor\",\n\t\t\t\"monitorUrlHeader\": \"URL do monitor\",\n\t\t\t\"failCountHeader\": \"Contagem de falhas\",\n\t\t\t\"failedAtHeader\": \"Última falha em\",\n\t\t\t\"failReasonHeader\": \"Motivo da falha\"\n\t\t}\n\t},\n\t\"export\": {\n\t\t\"title\": \"Monitores de Exportação\",\n\t\t\"success\": \"Monitores exportados com sucesso!\",\n\t\t\"failed\": \"Falha ao exportar monitores\"\n\t},\n\t\"monitorActions\": {\n\t\t\"title\": \"Exportação/Importação\",\n\t\t\"import\": \"Monitores de importação\",\n\t\t\"export\": \"Monitores de Exportação\",\n\t\t\"deleteSuccess\": \"Monitor excluído com sucesso\",\n\t\t\"deleteFailed\": \"Falha ao excluir o monitor\",\n\t\t\"details\": \"Detalhes\"\n\t},\n\t\"settingsPage\": {\n\t\t\"aboutSettings\": {\n\t\t\t\"labelDevelopedBy\": \"Desenvolvido pela Bluewave Labs\",\n\t\t\t\"labelVersion\": \"Versão\",\n\t\t\t\"title\": \"Sobre\"\n\t\t},\n\t\t\"demoMonitorsSettings\": {\n\t\t\t\"buttonAddMonitors\": \"Adicionar monitores de demonstração\",\n\t\t\t\"description\": \"Adicione monitores de amostra para fins de demonstração.\",\n\t\t\t\"title\": \"Monitores de demonstração\"\n\t\t},\n\t\t\"emailSettings\": {\n\t\t\t\"buttonSendTestEmail\": \"Enviar e-mail de teste\",\n\t\t\t\"description\": \"Configure as configurações de e-mail do seu sistema. Elas são usadas para enviar notificações e alertas.\",\n\t\t\t\"descriptionTransport\": \"Isso cria um transporte SMTP para o NodeMailer\",\n\t\t\t\"labelAddress\": \"Endereço de e-mail - Usado para autenticação\",\n\t\t\t\"labelConnectionHost\": \"Host de conexão de e-mail - Nome do host a ser usado na saudação HELO/EHLO\",\n\t\t\t\"labelHost\": \"Host de e-mail - Nome do host ou endereço IP para conectar\",\n\t\t\t\"labelIgnoreTLS\": \"Desabilitar STARTTLS: Não use TLS mesmo que o servidor suporte\",\n\t\t\t\"labelPassword\": \"Senha de e-mail - Senha para autenticação\",\n\t\t\t\"labelPasswordSet\": \"A senha foi definida. Clique em Redefinir para alterá-la.\",\n\t\t\t\"labelPool\": \"Habilitar pool de conexões: Reutilize conexões existentes para melhorar o desempenho\",\n\t\t\t\"labelPort\": \"Porta de e-mail - Porta para conectar\",\n\t\t\t\"labelRejectUnauthorized\": \"Rejeitar certificados inválidos: rejeitar conexões com certificados autoassinados ou não confiáveis\",\n\t\t\t\"labelRequireTLS\": \"Forçar STARTTLS: requer atualização de TLS, falha se não for suportado\",\n\t\t\t\"labelSecure\": \"Usar SSL (recomendado): criptografar a conexão usando SSL/TLS\",\n\t\t\t\"labelTLSServername\": \"Nome do servidor TLS - Nome do host opcional para validação TLS quando o host é um IP\",\n\t\t\t\"labelUser\": \"Usuário de e-mail - Nome de usuário para autenticação, substitui o endereço de e-mail, se especificado\",\n\t\t\t\"linkTransport\": \"Veja as especificações aqui\",\n\t\t\t\"placeholderUser\": \"Deixe em branco se não for necessário\",\n\t\t\t\"title\": \"E-mail\",\n\t\t\t\"toastEmailRequiredFieldsError\": \"Endereço de e-mail, host, porta e senha são obrigatórios\"\n\t\t},\n\t\t\"pageSpeedSettings\": {\n\t\t\t\"description\": \"Insira sua chave da API do Google PageSpeed para ativar o monitoramento do Google PageSpeed. Clique em Redefinir para atualizar a chave.\",\n\t\t\t\"labelApiKeySet\": \"A chave de API está definida. Clique em Redefinir para alterá-la.\",\n\t\t\t\"labelApiKey\": \"Chave da API do PageSpeed\",\n\t\t\t\"title\": \"Chave da API do Google PageSpeed\"\n\t\t},\n\t\t\"saveButtonLabel\": \"Salvar\",\n\t\t\"statsSettings\": {\n\t\t\t\"clearAllStatsButton\": \"Limpar todas as estatísticas\",\n\t\t\t\"clearAllStatsDescription\": \"Limpe todas as estatísticas. Isso é irreversível.\",\n\t\t\t\"clearAllStatsDialogConfirm\": \"Sim, limpar todas as estatísticas\",\n\t\t\t\"clearAllStatsDialogDescription\": \"Uma vez removido, o histórico de monitoramento e as estatísticas não podem ser recuperados.\",\n\t\t\t\"clearAllStatsDialogTitle\": \"Você quer limpar todas as estatísticas?\",\n\t\t\t\"description\": \"Defina por quanto tempo você deseja manter os dados históricos. Você também pode limpar todos os dados existentes.\",\n\t\t\t\"labelTTL\": \"Os dias em que você deseja continuar monitorando o histórico.\",\n\t\t\t\"labelTTLOptional\": \"0 para infinito\",\n\t\t\t\"title\": \"Histórico do monitor\"\n\t\t},\n\t\t\"systemResetSettings\": {\n\t\t\t\"buttonRemoveAllMonitors\": \"Remover todos os monitores\",\n\t\t\t\"description\": \"Remova todos os monitores do seu sistema.\",\n\t\t\t\"dialogConfirm\": \"Sim, remova todos os monitores\",\n\t\t\t\"dialogDescription\": \"Uma vez removidos, os monitores não podem ser recuperados.\",\n\t\t\t\"dialogTitle\": \"Você deseja remover todos os monitores?\",\n\t\t\t\"title\": \"Reinicialização do sistema\"\n\t\t},\n\t\t\"timezoneSettings\": {\n\t\t\t\"description\": \"Selecione o fuso horário usado para exibir datas e horas em todo o aplicativo.\",\n\t\t\t\"label\": \"Exibir fuso horário\",\n\t\t\t\"title\": \"Exibir fuso horário\"\n\t\t},\n\t\t\"title\": \"Configurações\",\n\t\t\"uiSettings\": {\n\t\t\t\"description\": \"Alterne entre o modo claro e escuro ou altere o idioma da interface do usuário.\",\n\t\t\t\"labelLanguage\": \"Linguagem\",\n\t\t\t\"labelTheme\": \"Modo de tema\",\n\t\t\t\"title\": \"Aparência\"\n\t\t},\n\t\t\"urlSettings\": {\n\t\t\t\"description\": \"Exiba o endereço IP ou URL do monitor na página de status pública. Se estiver desabilitado, apenas o nome do monitor será exibido para proteger informações confidenciais.\",\n\t\t\t\"label\": \"Exibir IP/URL na página de status\",\n\t\t\t\"selectDisabled\": \"Desabilitado\",\n\t\t\t\"selectEnabled\": \"Habilitado\",\n\t\t\t\"title\": \"Monitorar IP/URL na página de status\"\n\t\t},\n\t\t\"globalThresholds\": {\n\t\t\t\"title\": \"Limites Globais\",\n\t\t\t\"description\": \"Configurar limites globais da CPU, Memória, Disco e Temperatura. Se um valor for fornecido, o monitoramento será ativado automaticamente\"\n\t\t}\n\t},\n\t\"statusPageCreate\": {\n\t\t\"buttonSave\": \"Salvar\"\n\t},\n\t\"incidentsOptionsHeaderFilterResolved\": \"Resolvido\",\n\t\"settingsSave\": \"Salvar\",\n\t\"statusPageCreateAppearanceTitle\": \"Aparência\",\n\t\"confirmPassword\": \"Confirme sua senha\",\n\t\"monitorHooks\": {\n\t\t\"failureAddDemoMonitors\": \"Falha ao adicionar monitores de demonstração\",\n\t\t\"successAddDemoMonitors\": \"Monitores de demonstração adicionados com sucesso\"\n\t},\n\t\"settingsAppearance\": \"Aparência\",\n\t\"settingsDisplayTimezone\": \"Exibir fuso horário\",\n\t\"settingsGeneralSettings\": \"Configurações gerais\",\n\t\"incidentsOptionsHeaderTotalIncidents\": \"Total de incidentes\",\n\t\"statusPage\": {\n\t\t\"deleteSuccess\": \"Página de status excluída com sucesso\",\n\t\t\"deleteFailed\": \"Falha ao excluir a página de status\",\n\t\t\"createSuccess\": \"Página de status criada com sucesso\",\n\t\t\"updateSuccess\": \"Página de status atualizada com sucesso\",\n\t\t\"generalSettings\": \"Configurações gerais\",\n\t\t\"contents\": \"Conteúdo\",\n\t\t\"fallback\": {\n\t\t\t\"checks\": [\n\t\t\t\t\"Monitore e exiba a integridade dos seus serviços em tempo real\",\n\t\t\t\t\"Acompanhe vários serviços e compartilhe seus status\",\n\t\t\t\t\"Mantenha os usuários informados sobre interrupções e desempenho\"\n\t\t\t],\n\t\t\t\"title\": \"Uma página de status é usada para:\",\n\t\t\t\"actionButton\": \"Vamos criar sua primeira página de status!\"\n\t\t}\n\t},\n\t\"testNotificationsDisabled\": \"Não há notificações configuradas para este monitor. Você precisa adicionar uma clicando no botão \\\"Configurar\\\".\",\n\t\"incidentsTableResolvedAt\": \"Resolvido em\",\n\t\"incidentsTableActionResolve\": \"Resolver\",\n\t\"checkHooks\": {\n\t\t\"failureResolveOne\": \"Falha ao resolver o incidente.\",\n\t\t\"failureResolveAll\": \"Falha ao resolver todos os incidentes.\",\n\t\t\"failureResolveMonitor\": \"Falha ao resolver incidentes do monitor.\"\n\t},\n\t\"checkFormError\": \"Verifique se há erros no formulário.\",\n\t\"diagnosticsPage\": {\n\t\t\"diagnosticDescription\": \"Diagnóstico do sistema\",\n\t\t\"statsDescription\": \"Estatísticas do sistema\",\n\t\t\"gauges\": {\n\t\t\t\"heapAllocationTitle\": \"Alocação de heap\",\n\t\t\t\"heapAllocationSubtitle\": \"% de memória disponível\",\n\t\t\t\"heapUsageTitle\": \"Uso de heap\",\n\t\t\t\"heapUsageSubtitle\": \"% de memória disponível\",\n\t\t\t\"heapUtilizationTitle\": \"Utilização de heap\",\n\t\t\t\"heapUtilizationSubtitle\": \"% do alocado\",\n\t\t\t\"instantCpuUsageTitle\": \"Uso instantâneo da CPU\",\n\t\t\t\"instantCpuUsageSubtitle\": \"% de 1s usados pela CPU\"\n\t\t},\n\t\t\"stats\": {\n\t\t\t\"eventLoopDelayTitle\": \"Atraso do loop de eventos\",\n\t\t\t\"uptimeTitle\": \"Tempo de atividade\",\n\t\t\t\"usedHeapSizeTitle\": \"Tamanho de heap usado\",\n\t\t\t\"totalHeapSizeTitle\": \"Tamanho total do heap\",\n\t\t\t\"osMemoryLimitTitle\": \"Limite de memória do sistema operacional\"\n\t\t}\n\t},\n\t\"pageSpeedLighthouseAPI\": \"Use a API Lighthouse PageSpeed para monitorar seu site\",\n\t\"time\": {\n\t\t\"threeMinutes\": \"3 minutos\",\n\t\t\"fiveMinutes\": \"5 minutos\",\n\t\t\"tenMinutes\": \"10 minutos\",\n\t\t\"twentyMinutes\": \"20 minutos\",\n\t\t\"oneHour\": \"1 hora\",\n\t\t\"oneDay\": \"1 dia\",\n\t\t\"oneWeek\": \"1 semana\",\n\t\t\"fourMinutes\": \"4 minutos\",\n\t\t\"oneMinute\": \"1 minuto\",\n\t\t\"twoMinutes\": \"2 minutos\",\n\t\t\"fifteenSeconds\": \"\",\n\t\t\"thirtySeconds\": \"\"\n\t},\n\t\"general\": {\n\t\t\"noOptionsFound\": \"Nenhuma {{unidade}} encontrada\"\n\t},\n\t\"infrastructureMonitor\": {\n\t\t\"fallback\": {\n\t\t\t\"checks\": [\n\t\t\t\t\"Acompanhe o desempenho dos seus servidores\",\n\t\t\t\t\"Identifique gargalos e otimize o uso\",\n\t\t\t\t\"Garanta a confiabilidade com monitoramento em tempo real\"\n\t\t\t],\n\t\t\t\"title\": \"Um monitor de infraestrutura é usado para:\",\n\t\t\t\"actionButton\": \"Vamos criar seu primeiro monitor de infraestrutura!\"\n\t\t}\n\t},\n\t\"maintenanceWindow\": {\n\t\t\"fallback\": {\n\t\t\t\"checks\": [\n\t\t\t\t\"Marque seus períodos de manutenção\",\n\t\t\t\t\"Elimine qualquer mal-entendido\",\n\t\t\t\t\"Pare de enviar alertas em janelas de manutenção\"\n\t\t\t],\n\t\t\t\"title\": \"Uma janela de manutenção é usada para:\",\n\t\t\t\"actionButton\": \"Vamos criar sua primeira janela de manutenção!\"\n\t\t}\n\t},\n\t\"pageSpeed\": {\n\t\t\"fallback\": {\n\t\t\t\"checks\": [\n\t\t\t\t\"Relatar a experiência do usuário em uma página\",\n\t\t\t\t\"Ajudar a analisar a velocidade da página\",\n\t\t\t\t\"Dar sugestões sobre como a página pode ser melhorada\"\n\t\t\t],\n\t\t\t\"title\": \"Um monitor PageSpeed é usado para:\",\n\t\t\t\"actionButton\": \"Vamos criar seu primeiro monitor PageSpeed!\"\n\t\t}\n\t},\n\t\"uptimeMonitor\": {\n\t\t\"fallback\": {\n\t\t\t\"checks\": [\n\t\t\t\t\"Verifique se sites ou servidores estão online e responsivos\",\n\t\t\t\t\"Alerte as equipes sobre tempo de inatividade ou problemas de desempenho\",\n\t\t\t\t\"Monitore endpoints HTTP, pings, contêineres e portas\",\n\t\t\t\t\"Acompanhe o histórico de tempo de atividade e tendências de confiabilidade\"\n\t\t\t],\n\t\t\t\"title\": \"Um monitor de tempo de atividade é usado para:\",\n\t\t\t\"actionButton\": \"Vamos criar seu primeiro monitor de tempo de atividade!\"\n\t\t}\n\t},\n\t\"editUserPage\": {\n\t\t\"form\": {\n\t\t\t\"email\": \"E-mail\",\n\t\t\t\"firstName\": \"Primeiro nome\",\n\t\t\t\"lastName\": \"Sobrenome\",\n\t\t\t\"role\": \"Funções\",\n\t\t\t\"save\": \"Salvar\"\n\t\t},\n\t\t\"table\": {\n\t\t\t\"actionHeader\": \"Ação\",\n\t\t\t\"roleHeader\": \"Papel\"\n\t\t},\n\t\t\"title\": \"Editar usuário\",\n\t\t\"toast\": {\n\t\t\t\"successUserUpdate\": \"Usuário atualizado com sucesso\",\n\t\t\t\"validationErrors\": \"Erros de validação\"\n\t\t}\n\t},\n\t\"incidentsPageActionResolveMonitor\": \"Resolver incidentes de monitoramento\",\n\t\"incidentsPageActionResolveAll\": \"Resolver todos os incidentes\",\n\t\"matchMethodOptions\": {\n\t\t\"equal\": \"\",\n\t\t\"equalPlaceholder\": \"\",\n\t\t\"include\": \"\",\n\t\t\"includePlaceholder\": \"\",\n\t\t\"regex\": \"Regex\",\n\t\t\"regexPlaceholder\": \"\",\n\t\t\"text\": \"\"\n\t},\n\t\"monitorType\": {\n\t\t\"docker\": {\n\t\t\t\"label\": \"\",\n\t\t\t\"namePlaceholder\": \"Meu Contêiner\",\n\t\t\t\"placeholder\": \"abcd1234\"\n\t\t},\n\t\t\"http\": {\n\t\t\t\"label\": \"URL para monitorar\",\n\t\t\t\"namePlaceholder\": \"Google\",\n\t\t\t\"placeholder\": \"google.com\"\n\t\t},\n\t\t\"ping\": {\n\t\t\t\"label\": \"Endereço IP para monitorar\",\n\t\t\t\"namePlaceholder\": \"Google\",\n\t\t\t\"placeholder\": \"1.1.1.1\"\n\t\t},\n\t\t\"port\": {\n\t\t\t\"label\": \"URL para monitorar\",\n\t\t\t\"namePlaceholder\": \"Localhost:5173\",\n\t\t\t\"placeholder\": \"localhost\"\n\t\t},\n\t\t\"game\": {\n\t\t\t\"label\": \"\",\n\t\t\t\"namePlaceholder\": \"\",\n\t\t\t\"placeholder\": \"\"\n\t\t}\n\t},\n\t\"uptimeAdvancedMatching\": {\n\t\t\"jsonPath\": \"\"\n\t},\n\t\"bytesPerSecond\": \"\",\n\t\"bytesReceived\": \"\",\n\t\"bytesSent\": \"\",\n\t\"chooseGame\": \"\",\n\t\"createMonitorPage\": {\n\t\t\"incidentConfigDescription\": \"\",\n\t\t\"incidentConfigStatusWindowLabel\": \"\",\n\t\t\"incidentConfigStatusWindowThresholdLabel\": \"\",\n\t\t\"incidentConfigTitle\": \"\",\n\t\t\"incidentConfigDescriptionV2\": \"\",\n\t\t\"incidentConfigStatusCheckNumber\": \"\",\n\t\t\"intervalTitle\": \"\",\n\t\t\"intervalDescription\": \"\"\n\t},\n\t\"dataRate\": \"\",\n\t\"dataReceived\": \"\",\n\t\"dataSent\": \"\",\n\t\"details\": \"\",\n\t\"drops\": \"\",\n\t\"errors\": \"\",\n\t\"errorsIn\": \"\",\n\t\"errorsOut\": \"\",\n\t\"gameServerMonitoring\": \"\",\n\t\"gameServerMonitoringDescription\": \"\",\n\t\"network\": \"\",\n\t\"networkDrops\": \"\",\n\t\"networkErrors\": \"\",\n\t\"networkInterface\": \"\",\n\t\"noNetworkStatsAvailable\": \"\",\n\t\"packetsPerSecond\": \"\",\n\t\"packetsReceived\": \"\",\n\t\"packetsReceivedRate\": \"\",\n\t\"packetsSent\": \"\",\n\t\"rate\": \"\",\n\t\"selectInterface\": \"\",\n\t\"v1\": {\n\t\t\"infrastructure\": {\n\t\t\t\"disk_selection_title\": \"Seleção de Discos\",\n\t\t\t\"disk_selection_info\": \"Nenhum disco detectado no momento.\",\n\t\t\t\"disk_selection_description\": \"Selecione os discos específicos que você deseja monitorar.\"\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "client/src/locales/ru.json",
    "content": "{\n\t\"submit\": \"Подтвердить\",\n\t\"title\": \"Название\",\n\t\"distributedStatusHeaderText\": \"Охват реального времени и реального устройства\",\n\t\"distributedStatusSubHeaderText\": \"Работает на миллионах устройств по всему миру, просматривайте производительность системы по глобальному региону, стране или городу\",\n\t\"settingsDisabled\": \"Выключено\",\n\t\"settingsSuccessSaved\": \"Настройки успешно сохранены\",\n\t\"settingsFailedToSave\": \"Не удалось сохранить настройки\",\n\t\"settingsStatsCleared\": \"Статистика успешно очищена\",\n\t\"settingsFailedToClearStats\": \"Не удалось очистить статистику\",\n\t\"settingsMonitorsDeleted\": \"Успешно удалены все мониторы\",\n\t\"settingsFailedToDeleteMonitors\": \"Не удалось удалить все мониторы\",\n\t\"starPromptTitle\": \"Запустить Checkmate.\",\n\t\"starPromptDescription\": \"Ознакомьтесь с последними релизами и помогите развить сообщество на GitHub\",\n\t\"https\": \"HTTPS\",\n\t\"http\": \"HTTP\",\n\t\"monitor\": \"монитор\",\n\t\"aboutus\": \"О Нас\",\n\t\"now\": \"Сейчас\",\n\t\"delete\": \"Удалить\",\n\t\"configure\": \"Настроить\",\n\t\"responseTime\": \"Время ответа:\",\n\t\"ms\": \"мс\",\n\t\"bar\": \"Bar\",\n\t\"area\": \"Area\",\n\t\"country\": \"СТРАНА\",\n\t\"city\": \"ГОРОД\",\n\t\"response\": \"ОТВЕТ\",\n\t\"monitorStatusUp\": \"Монитор {name} ({url}) теперь включен и отвечает\",\n\t\"monitorStatusDown\": \"Монитор {name} ({url}) ОТКЛЮЧЕН и не отвечает\",\n\t\"webhookSendSuccess\": \"Уведомление Webhook успешно отправлено\",\n\t\"webhookSendError\": \"Ошибка отправки уведомления webhook на {platform}\",\n\t\"webhookUnsupportedPlatform\": \"Неподдерживаемая платформа: {platform}\",\n\t\"distributedRightCategoryTitle\": \"Монитор\",\n\t\"distributedStatusServerMonitors\": \"Серверные мониторы\",\n\t\"distributedStatusServerMonitorsDescription\": \"Мониторинг состояния связанных серверов\",\n\t\"distributedUptimeCreateSelectURL\": \"Здесь вы можете выбрать URL-адрес хоста, а также тип монитора.\",\n\t\"distributedUptimeCreateChecks\": \"Проверки, которые необходимо выполнить\",\n\t\"distributedUptimeCreateChecksDescription\": \"Вы всегда можете добавить или удалить проверки после добавления своего сайта.\",\n\t\"distributedUptimeCreateIncidentNotification\": \"Уведомления об инцидентах\",\n\t\"distributedUptimeCreateIncidentDescription\": \"В случае возникновения инцидента сообщите об этом пользователям.\",\n\t\"distributedUptimeCreateAdvancedSettings\": \"Расширенные настройки\",\n\t\"distributedUptimeDetailsNoMonitorHistory\": \"Для этого монитора пока нет истории проверок.\",\n\t\"distributedUptimeDetailsStatusHeaderUptime\": \"Аптайм:\",\n\t\"distributedUptimeDetailsStatusHeaderLastUpdate\": \"Последнее обновление\",\n\t\"notifications\": {\n\t\t\"enableNotifications\": \"Включить уведомления {{platform}}\",\n\t\t\"testNotification\": \"Тестовое уведомление\",\n\t\t\"addOrEditNotifications\": \"Добавить или изменить уведомления\",\n\t\t\"slack\": {\n\t\t\t\"label\": \"Slack\",\n\t\t\t\"description\": \"Чтобы включить уведомления Slack, создайте приложение Slack и включите входящие вебхуки. После этого просто укажите URL вебхука здесь.\",\n\t\t\t\"webhookLabel\": \"URL вебхука\",\n\t\t\t\"webhookPlaceholder\": \"https://hooks.slack.com/services/...\",\n\t\t\t\"webhookRequired\": \"Требуется URL-адрес Slack webhook\"\n\t\t},\n\t\t\"discord\": {\n\t\t\t\"label\": \"Discord\",\n\t\t\t\"description\": \"Чтобы отправить данные на канал Discord из Checkmate через уведомления Discord с использованием веб-хуков, вы можете использовать функцию входящих веб-хуков Discord.\",\n\t\t\t\"webhookLabel\": \"Discord Webhook URL\",\n\t\t\t\"webhookPlaceholder\": \"https://discord.com/api/webhooks/...\",\n\t\t\t\"webhookRequired\": \"Требуется URL-адрес веб-сайта Discord webhook\"\n\t\t},\n\t\t\"telegram\": {\n\t\t\t\"label\": \"Telegram\",\n\t\t\t\"description\": \"Чтобы включить уведомления Telegram, создайте бота Telegram с помощью BotFather, официального бота для создания и управления ботами Telegram. Затем получите токен API и идентификатор чата и запишите их здесь.\",\n\t\t\t\"tokenLabel\": \"Ваш токен бота\",\n\t\t\t\"tokenPlaceholder\": \"123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11\",\n\t\t\t\"chatIdLabel\": \"ID Вашего Чата\",\n\t\t\t\"chatIdPlaceholder\": \"-1001234567890\",\n\t\t\t\"fieldsRequired\": \"Требуется токен Telegram и ID чата\"\n\t\t},\n\t\t\"webhook\": {\n\t\t\t\"label\": \"Вебхуки\",\n\t\t\t\"description\": \"Вы можете настроить пользовательский вебхук для получения уведомлений о возникновении инцидентов.\",\n\t\t\t\"urlLabel\": \"URL вебхука\",\n\t\t\t\"urlPlaceholder\": \"https://your-server.com/webhook\",\n\t\t\t\"urlRequired\": \"Требуется URL-адрес webhook\"\n\t\t},\n\t\t\"testNotificationDevelop\": \"Тестовое уведомление 2\",\n\t\t\"integrationButton\": \"Интеграция уведомлений\",\n\t\t\"testSuccess\": \"Уведомление о тестировании отправлено успешно!\",\n\t\t\"testFailed\": \"Не удалось отправить тестовое уведомление\",\n\t\t\"unsupportedType\": \"Неподдерживаемый тип уведомления\",\n\t\t\"networkError\": \"Произошла сетевая ошибка\",\n\t\t\"fallback\": {\n\t\t\t\"title\": \"Канал уведомлений используется для:\",\n\t\t\t\"checks\": [\n\t\t\t\t\"Дайте знать команде, если сервер ложится или что-то виснет\",\n\t\t\t\t\"Сообщите инженерам, когда появляется какая-то проблема\",\n\t\t\t\t\"Уведомляйте админов, если в системе что-то поменялось\"\n\t\t\t],\n\t\t\t\"actionButton\": \"Давайте создадим ваш первый канал уведомлений!\"\n\t\t},\n\t\t\"createButton\": \"Создать канал уведомлений\",\n\t\t\"createTitle\": \"Канал уведомлений\",\n\t\t\"create\": {\n\t\t\t\"success\": \"Уведомление успешно создано\",\n\t\t\t\"failed\": \"Не удалось создать уведомление.\"\n\t\t},\n\t\t\"fetch\": {\n\t\t\t\"success\": \"Уведомления успешно получены\",\n\t\t\t\"failed\": \"Не удалось получить уведомления.\"\n\t\t},\n\t\t\"delete\": {\n\t\t\t\"success\": \"Уведомление успешно удалено\",\n\t\t\t\"failed\": \"Не удалось удалить уведомление.\"\n\t\t},\n\t\t\"edit\": {\n\t\t\t\"success\": \"Уведомление успешно обновлено\",\n\t\t\t\"failed\": \"Не удалось обновить уведомление.\"\n\t\t},\n\t\t\"test\": {\n\t\t\t\"success\": \"Тестовое уведомление успешно отправлено\",\n\t\t\t\"failed\": \"Не удалось отправить тестовое уведомление.\"\n\t\t}\n\t},\n\t\"testLocale\": \"testLocale\",\n\t\"add\": \"Добавить\",\n\t\"monitors\": \"мониторы\",\n\t\"distributedUptimeStatusCreateStatusPage\": \"страница статуса\",\n\t\"distributedUptimeStatusCreateStatusPageAccess\": \"Доступ\",\n\t\"distributedUptimeStatusCreateStatusPageReady\": \"Если ваша страница статуса готова, вы можете отметить ее как опубликованную.\",\n\t\"distributedUptimeStatusBasicInfoHeader\": \"Основная информация\",\n\t\"distributedUptimeStatusBasicInfoDescription\": \"Определите название компании и поддомен, на который ссылается ваша страница статуса.\",\n\t\"distributedUptimeStatusLogoHeader\": \"Логотип\",\n\t\"distributedUptimeStatusLogoDescription\": \"Загрузите логотип для своей страницы статуса\",\n\t\"distributedUptimeStatusLogoUploadButton\": \"Загрузить логотип\",\n\t\"distributedUptimeStatusStandardMonitorsHeader\": \"Стандартные Мониторы\",\n\t\"distributedUptimeStatusStandardMonitorsDescription\": \"Прикрепите стандартные мониторы к своей странице статуса.\",\n\t\"distributedUptimeStatusCreateYour\": \"Создайте свой\",\n\t\"distributedUptimeStatusEditYour\": \"Отредактируйте свой\",\n\t\"distributedUptimeStatusPublishedLabel\": \"Опубликовано и доступно для общественности\",\n\t\"distributedUptimeStatusCompanyNameLabel\": \"Название компании\",\n\t\"distributedUptimeStatusPageAddressLabel\": \"Адрес вашей страницы статуса\",\n\t\"distributedUptimeStatus30Days\": \"30 дней\",\n\t\"distributedUptimeStatus60Days\": \"60 дней\",\n\t\"distributedUptimeStatus90Days\": \"90 дней\",\n\t\"distributedUptimeStatusPageNotSetUp\": \"Страница статуса не настроена.\",\n\t\"distributedUptimeStatusContactAdmin\": \"Пожалуйста, свяжитесь с вашим администратором\",\n\t\"distributedUptimeStatusPageNotPublic\": \"Эта страница статуса не является публичной.\",\n\t\"distributedUptimeStatusPageDeleteDialog\": \"Вы хотите удалить эту страницу статуса?\",\n\t\"distributedUptimeStatusPageDeleteConfirm\": \"Да, удалить страницу статуса\",\n\t\"distributedUptimeStatusPageDeleteDescription\": \"После удаления ваша страница статуса не может быть восстановлена.\",\n\t\"distributedUptimeStatusDevices\": \"Устройства\",\n\t\"distributedUptimeStatusUpt\": \"UPT\",\n\t\"distributedUptimeStatusUptBurned\": \"UPT Burned\",\n\t\"distributedUptimeStatusUptLogo\": \"Upt Logo\",\n\t\"incidentsTableNoIncidents\": \"Инцидентов не зафиксировано\",\n\t\"incidentsTablePaginationLabel\": \"инциденты\",\n\t\"incidentsTableMonitorName\": \"Имя Монитора\",\n\t\"incidentsTableStatus\": \"Статус\",\n\t\"incidentsTableDateTime\": \"Дата и Время\",\n\t\"incidentsTableStatusCode\": \"Код Статуса\",\n\t\"incidentsTableMessage\": \"Сообщение\",\n\t\"incidentsOptionsHeader\": \"Инцидент для:\",\n\t\"incidentsOptionsHeaderFilterBy\": \"Фильтровать по:\",\n\t\"incidentsOptionsHeaderFilterAll\": \"Все\",\n\t\"incidentsOptionsHeaderFilterDown\": \"Недоступно\",\n\t\"incidentsOptionsHeaderFilterCannotResolve\": \"Невозможно решить\",\n\t\"incidentsOptionsHeaderShow\": \"Показать:\",\n\t\"incidentsOptionsHeaderLastHour\": \"Последний час\",\n\t\"incidentsOptionsHeaderLastDay\": \"Последний день\",\n\t\"incidentsOptionsHeaderLastWeek\": \"Последняя неделя\",\n\t\"incidentsOptionsPlaceholderAllServers\": \"Все сервера\",\n\t\"infrastructureCreateYour\": \"Создайте свой\",\n\t\"infrastructureCreateGeneralSettingsDescription\": \"Здесь вы можете выбрать URL-адрес хоста, а также понятное имя и секретный ключ авторизации для подключения к агенту сервера.\",\n\t\"infrastructureServerRequirement\": \"Сервер, который вы отслеживаете, должен быть запущен\",\n\t\"infrastructureCustomizeAlerts\": \"Настройте оповещения\",\n\t\"infrastructureAlertNotificationDescription\": \"Отправлять уведомления пользователям, когда пороговые значения превышают указанный процент.\",\n\t\"infrastructureCreateMonitor\": \"Создать Монитор Инфраструктуры\",\n\t\"infrastructureProtocol\": \"Протокол\",\n\t\"infrastructureServerUrlLabel\": \"URL Сервера\",\n\t\"infrastructureDisplayNameLabel\": \"Отображаемое имя\",\n\t\"infrastructureAuthorizationSecretLabel\": \"Секрет авторизации\",\n\t\"gb\": \"ГБ\",\n\t\"mb\": \"МБ\",\n\t\"mem\": \"Mem\",\n\t\"memoryUsage\": \"Использование памяти\",\n\t\"cpu\": \"CPU\",\n\t\"cpuUsage\": \"Использование CPU\",\n\t\"cpuTemperature\": \"Температура CPU\",\n\t\"diskUsage\": \"Использование диска\",\n\t\"used\": \"Использовал\",\n\t\"total\": \"Всего\",\n\t\"cores\": \"Ядра\",\n\t\"frequency\": \"Частота\",\n\t\"status\": \"Статус\",\n\t\"cpuPhysical\": \"CPU (физический)\",\n\t\"cpuLogical\": \"CPU (логический)\",\n\t\"cpuFrequency\": \"Частота CPU\",\n\t\"avgCpuTemperature\": \"Средняя температура CPU\",\n\t\"memory\": \"Память\",\n\t\"disk\": \"Диск\",\n\t\"uptime\": \"Аптайм\",\n\t\"os\": \"ОС\",\n\t\"host\": \"Хост\",\n\t\"actions\": \"Действия\",\n\t\"integrations\": \"Интеграции\",\n\t\"integrationsPrism\": \"Подключите Prism к вашему любимому сервису.\",\n\t\"integrationsSlack\": \"Slack\",\n\t\"integrationsSlackInfo\": \"Подключитесь к Slack и просматривайте инциденты в канале\",\n\t\"integrationsDiscord\": \"Discord\",\n\t\"integrationsDiscordInfo\": \"Подключитесь к Discord и просматривайте инциденты прямо в канале\",\n\t\"integrationsZapier\": \"Zapier\",\n\t\"integrationsZapierInfo\": \"Отправляйте все инциденты в Zapier, и тогда вы сможете видеть их везде\",\n\t\"commonSave\": \"Сохранить\",\n\t\"createYour\": \"Создать свой\",\n\t\"createMonitor\": \"Создать монитор\",\n\t\"pause\": \"Пауза\",\n\t\"resume\": \"Продолжить\",\n\t\"editing\": \"Редактирование...\",\n\t\"url\": \"URL\",\n\t\"access\": \"Доступ\",\n\t\"timezone\": \"Часовой пояс\",\n\t\"features\": \"Функции\",\n\t\"administrator\": \"Администратор?\",\n\t\"loginHere\": \"Войти здесь\",\n\t\"displayName\": \"Отображаемое имя\",\n\t\"urlMonitor\": \"URL для монитора\",\n\t\"portToMonitor\": \"Порт для монитора\",\n\t\"websiteMonitoring\": \"Мониторинг сайта\",\n\t\"websiteMonitoringDescription\": \"Используйте HTTP(s) для вашего веб-сайта или API-endpoint.\",\n\t\"pingMonitoring\": \"Ping мониторинг\",\n\t\"pingMonitoringDescription\": \"Проверьте, доступен ли ваш сервер.\",\n\t\"dockerContainerMonitoring\": \"Мониторинг Docker-контейнера\",\n\t\"dockerContainerMonitoringDescription\": \"Проверьте, запущен ли ваш Docker-контейнер.\",\n\t\"portMonitoring\": \"Мониторинг портов\",\n\t\"portMonitoringDescription\": \"Проверьте, открыт ли ваш порт.\",\n\t\"createMaintenanceWindow\": \"Создать окно техобслуживания\",\n\t\"createMaintenance\": \"Создание техобслуживания\",\n\t\"editMaintenance\": \"Редактировать техобслуживание\",\n\t\"maintenanceWindowName\": \"Название окна техобслуживания\",\n\t\"friendlyNameInput\": \"Дружественное имя\",\n\t\"friendlyNamePlaceholder\": \"Техническое обслуживание в __ : __ в течение ___ минут\",\n\t\"maintenanceRepeat\": \"Повторное техническое обслуживание\",\n\t\"maintenance\": \"техобслуживание\",\n\t\"duration\": \"Продолжительность\",\n\t\"addMonitors\": \"Добавить мониторы\",\n\t\"window\": \"окно\",\n\t\"cancel\": \"Отмена\",\n\t\"message\": \"Сообщение\",\n\t\"low\": \"низкий\",\n\t\"high\": \"высокий\",\n\t\"statusCode\": \"Код статуса\",\n\t\"date&Time\": \"Дата и Время\",\n\t\"type\": \"Тип\",\n\t\"statusPageName\": \"Имя страница статуса\",\n\t\"publicURL\": \"Публичный URL\",\n\t\"repeat\": \"Повторить\",\n\t\"edit\": \"Редактировать\",\n\t\"createA\": \"Создать\",\n\t\"remove\": \"Удалить\",\n\t\"maintenanceWindowDescription\": \"Ваши запросы не будут отправляться в этот период времени.\",\n\t\"startTime\": \"Время начала\",\n\t\"timeZoneInfo\": \"Все даты и время указаны в часовом поясе GMT+0.\",\n\t\"monitorsToApply\": \"Мониторы, к которым применяется окно техобслуживания\",\n\t\"nextWindow\": \"Следующее окно\",\n\t\"notFoundButton\": \"Перейти на главную панель управления\",\n\t\"pageSpeedConfigureSettingsDescription\": \"Здесь вы можете выбрать URL-адрес хоста, а также тип монитора.\",\n\t\"monitorDisplayName\": \"Отображаемое имя монитора\",\n\t\"whenNewIncident\": \"Когда происходит новый инцидент,\",\n\t\"notifySMS\": \"Уведомить по SMS (скоро)\",\n\t\"notifyEmails\": \"Также уведомлять по электронной почте на несколько адресов (скоро)\",\n\t\"seperateEmails\": \"Вы можете разделить несколько адресов электронной почты запятой.\",\n\t\"checkFrequency\": \"Проверить частоту\",\n\t\"matchMethod\": \"Метод сопоставления\",\n\t\"expectedValue\": \"Ожидаемое значение\",\n\t\"deleteDialogTitle\": \"Вы действительно хотите удалить этот монитор?\",\n\t\"deleteDialogDescription\": \"После удаления этот монитор не может быть восстановлен.\",\n\t\"pageSpeedMonitor\": \"PageSpeed ​​монитор\",\n\t\"shown\": \"Показано\",\n\t\"ago\": \"назад\",\n\t\"companyName\": \"Название компании\",\n\t\"pageSpeedDetailsPerformanceReport\": \"Значения являются приблизительными и могут отличаться.\",\n\t\"pageSpeedDetailsPerformanceReportCalculator\": \"Посмотреть калькулятор\",\n\t\"checkingEvery\": \"Проверка каждого\",\n\t\"statusPageCreateSettings\": \"Если ваша страница статуса готова, вы можете отметить ее как опубликованную.\",\n\t\"basicInformation\": \"Основная информация\",\n\t\"statusPageCreateBasicInfoDescription\": \"Определите название компании и поддомен, на который ссылается ваша страница статуса.\",\n\t\"statusPageCreateSelectTimeZoneDescription\": \"Выберите часовой пояс, в котором будет отображаться ваша страница статуса.\",\n\t\"statusPageCreateAppearanceDescription\": \"Определите внешний вид и содержание вашей публичной страницы статуса по умолчанию.\",\n\t\"statusPageCreateSettingsCheckboxLabel\": \"Опубликовано и доступно для общественности\",\n\t\"statusPageCreateBasicInfoStatusPageAddress\": \"Адрес вашей страницы статуса\",\n\t\"statusPageCreateTabsContent\": \"Серверы страниц состояния\",\n\t\"statusPageCreateTabsContentDescription\": \"Вы можете добавить любое количество серверов, которые вы отслеживаете, на свою страницу статуса. Вы также можете изменить их порядок для лучшего просмотра.\",\n\t\"statusPageCreateTabsContentFeaturesDescription\": \"Показать больше подробностей на странице статуса\",\n\t\"showCharts\": \"Показать графики\",\n\t\"showUptimePercentage\": \"Показать процент работоспособности\",\n\t\"removeLogo\": \"Удалить логотип\",\n\t\"statusPageStatus\": \"Публичная страница статуса не создана.\",\n\t\"statusPageStatusContactAdmin\": \"Пожалуйста, свяжитесь с вашим администратором.\",\n\t\"statusPageStatusNotPublic\": \"Эта страница статуса не является публичной.\",\n\t\"statusPageStatusNoPage\": \"Здесь нет страницы статуса.\",\n\t\"statusPageStatusServiceStatus\": \"Статус услуги\",\n\t\"deleteStatusPage\": \"Вы хотите удалить эту страницу статуса?\",\n\t\"deleteStatusPageConfirm\": \"Да, удалить страницу статуса\",\n\t\"deleteStatusPageDescription\": \"После удаления ваша страница статуса не может быть восстановлена.\",\n\t\"uptimeCreate\": \"Ожидаемое значение используется для сопоставления с результатом ответа, и совпадение определяет статус.\",\n\t\"uptimeCreateJsonPath\": \"Это выражение будет оценено по данным ответа JSON, а результат будет использован для сопоставления с ожидаемым значением. См.\",\n\t\"uptimeCreateJsonPathQuery\": \"для документации по языку запросов.\",\n\t\"maintenanceTableActionMenuDialogTitle\": \"Вы действительно хотите удалить это окно обслуживания?\",\n\t\"infrastructureEditYour\": \"Отредактируйте свой\",\n\t\"infrastructureEditMonitor\": \"Сохранить Монитор Инфраструктуры\",\n\t\"infrastructureMonitorCreated\": \"Монитор инфраструктуры успешно создан!\",\n\t\"infrastructureMonitorUpdated\": \"Монитор инфраструктуры успешно обновлен!\",\n\t\"errorInvalidTypeId\": \"Указанный неверный тип уведомления\",\n\t\"errorInvalidFieldId\": \"Указан неверный идентификатор поля\",\n\t\"inviteNoTokenFound\": \"Токен приглашения не найден\",\n\t\"pageSpeedWarning\": \"Внимание: Вы еще не добавили API-ключ Google PageSpeed. Без него PageSpeed монитор не будет работать.\",\n\t\"pageSpeedLearnMoreLink\": \"Нажми здесь\",\n\t\"pageSpeedAddApiKey\": \"чтобы добавить свой API-ключ.\",\n\t\"update\": \"Обновить\",\n\t\"invalidFileFormat\": \"Неподдерживаемый формат файла!\",\n\t\"invalidFileSize\": \"Размер файла слишком велик!\",\n\t\"ClickUpload\": \"Нажмите, чтобы загрузить\",\n\t\"DragandDrop\": \"drag and drop\",\n\t\"MaxSize\": \"Максимальный размер\",\n\t\"SupportedFormats\": \"Поддерживаемые форматы\",\n\t\"FirstName\": \"Имя\",\n\t\"LastName\": \"Фамилия\",\n\t\"EmailDescriptionText\": \"Это ваш текущий адрес электронной почты — он не может быть изменен.\",\n\t\"YourPhoto\": \"Фотография профиля\",\n\t\"PhotoDescriptionText\": \"Эта фотография будет отображена на странице вашего профиля.\",\n\t\"save\": \"Сохранить\",\n\t\"DeleteDescriptionText\": \"Это приведет к удалению учетной записи и всех связанных с ней данных с сервера. Это необратимо.\",\n\t\"DeleteAccountWarning\": \"Удаление вашей учетной записи означает, что вы не сможете снова войти в систему, и все ваши данные будут удалены. Это необратимо.\",\n\t\"DeleteWarningTitle\": \"Действительно удаляете эту учетную запись?\",\n\t\"bulkImport\": {\n\t\t\"title\": \"Массовый импорт\",\n\t\t\"selectFileTips\": \"Выберите CSV-файл для загрузки\",\n\t\t\"selectFileDescription\": \"Вы можете скачать наш <template> шаблон</template> или <sample>образец</sample>\",\n\t\t\"selectFile\": \"Выберите файл\",\n\t\t\"parsingFailed\": \"Не удалось выполнить синтаксический анализ\",\n\t\t\"uploadSuccess\": \"Мониторы успешно созданы!\",\n\t\t\"validationFailed\": \"Не удалось выполнить проверку\",\n\t\t\"noFileSelected\": \"Файл не выбран\",\n\t\t\"fallbackPage\": \"Импортируйте файл для массовой загрузки списка серверов\",\n\t\t\"invalidFileType\": \"Неверный тип файла\",\n\t\t\"uploadFailed\": \"Загрузка не удалась\"\n\t},\n\t\"DeleteAccountTitle\": \"Удалить аккаунт\",\n\t\"DeleteAccountButton\": \"Удалить аккаунт\",\n\t\"publicLink\": \"Публичная ссылка\",\n\t\"maskedPageSpeedKeyPlaceholder\": \"*************************************\",\n\t\"reset\": \"Сброс\",\n\t\"ignoreTLSError\": \"Игнорировать ошибку TLS/SSL\",\n\t\"tlsErrorIgnored\": \"Ошибки TLS/SSL игнорируются\",\n\t\"ignoreTLSErrorDescription\": \"Игнорируйте ошибки TLS/SSL и продолжайте проверять доступность веб-сайта\",\n\t\"createNew\": \"Создавать новые\",\n\t\"greeting\": {\n\t\t\"prepend\": \"Эй там\",\n\t\t\"append\": \"Вторая половина дня — это ваша игровая площадка - давайте сделаем ее эпичной!\",\n\t\t\"overview\": \"Вот обзор ваших мониторов {{type}}.\"\n\t},\n\t\"roles\": {\n\t\t\"superAdmin\": \"Главный админ\",\n\t\t\"admin\": \"Админ\",\n\t\t\"teamMember\": \"Член команды\",\n\t\t\"demoUser\": \"Демо пользователь\"\n\t},\n\t\"teamPanel\": {\n\t\t\"teamMembers\": \"Члены команды\",\n\t\t\"filter\": {\n\t\t\t\"all\": \"Все\",\n\t\t\t\"member\": \"Член\"\n\t\t},\n\t\t\"inviteTeamMember\": \"Пригласить члена команды\",\n\t\t\"inviteNewTeamMember\": \"Пригласите нового члена команды\",\n\t\t\"inviteDescription\": \"Когда вы добавите нового члена команды, он получит доступ ко всем мониторам.\",\n\t\t\"email\": \"Email\",\n\t\t\"selectRole\": \"Выберите роль\",\n\t\t\"inviteLink\": \"Ссылка для приглашения\",\n\t\t\"cancel\": \"Отменить\",\n\t\t\"noMembers\": \"В команде нет членов с такой ролью\",\n\t\t\"getToken\": \"Получить токен\",\n\t\t\"emailToken\": \"E-mail токен\",\n\t\t\"table\": {\n\t\t\t\"name\": \"Имя\",\n\t\t\t\"email\": \"Email\",\n\t\t\t\"role\": \"Роль\",\n\t\t\t\"created\": \"Создано\"\n\t\t},\n\t\t\"addTeamMember\": {\n\t\t\t\"addMemberMenu\": \"Добавить члена команды\",\n\t\t\t\"title\": \"Зарегистрируйте нового члена команды\",\n\t\t\t\"description\": \"Создайте нового пользователя и передайте ему учётные данные. Этот метод даёт участнику мгновенный доступ ко всем мониторам.\",\n\t\t\t\"addButton\": \"Добавить участника\"\n\t\t},\n\t\t\"register\": \"Зарегистрируйте члена команды\",\n\t\t\"registerToast\": {\n\t\t\t\"success\": \"Созданный пользователем, безопасный обмен учетными данными с участником.\",\n\t\t\t\"dbUserExists\": \"Пользователь уже существует.\",\n\t\t\t\"unknownError\": \"Произошла неизвестная ошибка.\"\n\t\t},\n\t\t\"registerTeamMember\": {\n\t\t\t\"title\": \"Зарегистрировать члена команды\",\n\t\t\t\"auth\": {\n\t\t\t\t\"common\": {\n\t\t\t\t\t\"inputs\": {\n\t\t\t\t\t\t\"firstName\": {\n\t\t\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\t\t\"empty\": \"Пожалуйста, введите имя\",\n\t\t\t\t\t\t\t\t\"pattern\": \"Имя должно содержать только буквы, пробелы, апострофы или дефисы.\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"lastName\": {\n\t\t\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\t\t\"empty\": \"Пожалуйста, введите фамилию\",\n\t\t\t\t\t\t\t\t\"pattern\": \"Фамилия должна содержать только буквы, пробелы, апострофы или дефисы.\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"email\": {\n\t\t\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\t\t\"empty\": \"Чтобы продолжить, введите адрес электронной почты.\",\n\t\t\t\t\t\t\t\t\"invalid\": \"Пожалуйста, перепроверьте правильность введенного адреса электронной почты.\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"role\": {\n\t\t\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\t\t\"empty\": \"Требуется роль\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"role\": \"Роль\",\n\t\t\"changeTeamPassword\": {\n\t\t\t\"changePasswordMenu\": \"Сбросить пароль\",\n\t\t\t\"title\": \"Сбросить пароль члена команды\",\n\t\t\t\"description\": \"Создайте новый пароль для этого члена команды. Вам необходимо будет сообщить ему пароль по секретному адресу.\",\n\t\t\t\"success\": \"Пароль успешно сброшен. Убедитесь, что вы предоставили учётные данные участнику безопасным способом.\"\n\t\t}\n\t},\n\t\"monitorState\": {\n\t\t\"paused\": \"Остановлено\",\n\t\t\"resumed\": \"Продолжено\",\n\t\t\"active\": \"Активно\"\n\t},\n\t\"menu\": {\n\t\t\"uptime\": \"Аптайм\",\n\t\t\"pagespeed\": \"Pagespeed\",\n\t\t\"infrastructure\": \"Инфраструктура\",\n\t\t\"incidents\": \"Инциденты\",\n\t\t\"statusPages\": \"Страницы статуса\",\n\t\t\"maintenance\": \"Обслуживание\",\n\t\t\"integrations\": \"Интеграции\",\n\t\t\"settings\": \"Настройки\",\n\t\t\"support\": \"Поддержка\",\n\t\t\"discussions\": \"Обсуждения\",\n\t\t\"docs\": \"Документация\",\n\t\t\"changelog\": \"Журнал изменений\",\n\t\t\"profile\": \"Профиль\",\n\t\t\"password\": \"Пароль\",\n\t\t\"team\": \"Команда\",\n\t\t\"logOut\": \"Выйти\",\n\t\t\"notifications\": \"Уведомления\",\n\t\t\"logs\": \"Логи\"\n\t},\n\t\"settingsEmailUser\": \"Email пользователь\",\n\t\"state\": \"Состояние\",\n\t\"statusBreadCrumbsStatusPages\": \"Страницы статуса\",\n\t\"statusBreadCrumbsDetails\": \"Подробности\",\n\t\"commonSaving\": \"Сохранение...\",\n\t\"navControls\": \"Управления\",\n\t\"incidentsPageTitle\": \"Инциденты\",\n\t\"passwordPanel\": {\n\t\t\"passwordChangedSuccess\": \"Ваш пароль был успешно изменен.\",\n\t\t\"passwordInputIncorrect\": \"Ваш пароль был введен неверно.\",\n\t\t\"currentPassword\": \"Current пароль\",\n\t\t\"enterCurrentPassword\": \"Введите свой текущий пароль\",\n\t\t\"newPassword\": \"Новый пароль\",\n\t\t\"enterNewPassword\": \"Введите свой новый пароль\",\n\t\t\"confirmNewPassword\": \"Подтвердите новый пароль\",\n\t\t\"passwordRequirements\": \"Новый пароль должен содержать не менее 8 символов и содержать как минимум одну заглавную букву, одну строчную букву, одну цифру и один специальный символ.\",\n\t\t\"saving\": \"Сохранение...\"\n\t},\n\t\"emailSent\": \"Письмо успешно отправлено\",\n\t\"failedToSendEmail\": \"Не удалось отправить письмо\",\n\t\"settingsTestEmailSuccess\": \"Тестовое письмо успешно отправлено\",\n\t\"settingsTestEmailFailed\": \"Не удалось отправить тестовое письмо\",\n\t\"settingsTestEmailFailedWithReason\": \"Не удалось отправить тестовое письмо: {{reason}}\",\n\t\"settingsTestEmailUnknownError\": \"Неизвестная ошибка\",\n\t\"statusMsg\": {\n\t\t\"paused\": \"Мониторинг приостановлен\",\n\t\t\"up\": \"Ваш сайт запущен.\",\n\t\t\"down\": \"Сайт оффлайн.\",\n\t\t\"pending\": \"Ожидание...\"\n\t},\n\t\"uptimeGeneralInstructions\": {\n\t\t\"http\": \"Введите URL-адрес или IP-адрес для мониторинга (например, https://example.com/ или 192.168.1.100) и добавьте понятное имя, которое будет отображаться на панели инструментов.\",\n\t\t\"ping\": \"Ведите IP-адрес или имя хоста для пинга (например, 192.168.1.100 или example.com) и добавьте понятное имя, которое будет отображаться на панели инструментов.\",\n\t\t\"docker\": \"Введите Docker ID вашего контейнера. Docker ID должен быть полным 64-символьным Docker ID. Вы можете запустить docker inspect <short_id>, чтобы получить полный ID контейнера.\",\n\t\t\"port\": \"Введите URL-адрес или IP-адрес сервера, номер порта и понятное имя, которое будет отображаться на панели инструментов.\",\n\t\t\"game\": \"Введите IP-адрес или имя хоста и номер порта для пинга (например, 192.168.1.100 или example.com) и выберите тип игры.\",\n\t\t\"https\": \"Введите URL-адрес или IP-адрес для мониторинга (например, https://example.com/ или 192.168.1.100) и добавьте понятное отображаемое имя, которое будет отображаться на панели управления.\"\n\t},\n\t\"common\": {\n\t\t\"appName\": \"Checkmate\",\n\t\t\"monitoringAgentName\": \"Захватить\",\n\t\t\"buttons\": {\n\t\t\t\"toggleTheme\": \"Переключить тему\"\n\t\t},\n\t\t\"toasts\": {\n\t\t\t\"networkError\": \"Ошибка сети\",\n\t\t\t\"checkConnection\": \"Пожалуйста, проверьте свое сетевое соединение\",\n\t\t\t\"unknownError\": \"Неизвестная ошибка\"\n\t\t}\n\t},\n\t\"auth\": {\n\t\t\"common\": {\n\t\t\t\"navigation\": {\n\t\t\t\t\"continue\": \"Продолжить\",\n\t\t\t\t\"back\": \"Назад\"\n\t\t\t},\n\t\t\t\"inputs\": {\n\t\t\t\t\"email\": {\n\t\t\t\t\t\"label\": \"Электронная почта\",\n\t\t\t\t\t\"placeholder\": \"jordan.ellis@domain.com\",\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"Для продолжения введите свой адрес электронной почты\",\n\t\t\t\t\t\t\"invalid\": \"Пожалуйста, проверьте правильность введённого адреса электронной почты\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"password\": {\n\t\t\t\t\t\"label\": \"Пароль\",\n\t\t\t\t\t\"rules\": {\n\t\t\t\t\t\t\"length\": {\n\t\t\t\t\t\t\t\"beginning\": \"Должен быть как минимум\",\n\t\t\t\t\t\t\t\"highlighted\": \"8 символов в длину\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"special\": {\n\t\t\t\t\t\t\t\"beginning\": \"Должен содержать как минимум\",\n\t\t\t\t\t\t\t\"highlighted\": \"один спецсимвол\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"number\": {\n\t\t\t\t\t\t\t\"beginning\": \"Должен содержать как минимум\",\n\t\t\t\t\t\t\t\"highlighted\": \"одно число\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"uppercase\": {\n\t\t\t\t\t\t\t\"beginning\": \"Должен содержать как минимум\",\n\t\t\t\t\t\t\t\"highlighted\": \"одну заглавную букву\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"lowercase\": {\n\t\t\t\t\t\t\t\"beginning\": \"Должен содержать как минимум\",\n\t\t\t\t\t\t\t\"highlighted\": \"одну прописную букву\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"match\": {\n\t\t\t\t\t\t\t\"beginning\": \"Пароли\",\n\t\t\t\t\t\t\t\"highlighted\": \"должны совпадать\"\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"Пожалуйста, введите пароль\",\n\t\t\t\t\t\t\"length\": \"Пароль должен быть длиной не менее 8 символов\",\n\t\t\t\t\t\t\"uppercase\": \"Пароль должен содержать минимум 1 прописную букву\",\n\t\t\t\t\t\t\"lowercase\": \"Пароль должен содержать минимум 1 строчную букву\",\n\t\t\t\t\t\t\"number\": \"Пароль должен содержать минимум 1 цифру\",\n\t\t\t\t\t\t\"special\": \"Пароль должен содержать минимум 1 спецсимвол\",\n\t\t\t\t\t\t\"incorrect\": \"Предоставленный вами пароль не соответствует нашим записям\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"passwordConfirm\": {\n\t\t\t\t\t\"label\": \"Подтвердите пароль\",\n\t\t\t\t\t\"placeholder\": \"Введите пароль еще раз для подтверждения\",\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"Пожалуйста, введите свой пароль еще раз для подтверждения (помогает избежать опечаток)\",\n\t\t\t\t\t\t\"different\": \"Введённые пароли не совпадают, вероятно, один из них напечатан с ошибкой\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"firstName\": {\n\t\t\t\t\t\"label\": \"Имя\",\n\t\t\t\t\t\"placeholder\": \"Jordan\",\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"Пожалуйста, введите свое имя\",\n\t\t\t\t\t\t\"length\": \"Имя должно быть короче 50 символов\",\n\t\t\t\t\t\t\"pattern\": \"Имя должно содержать только буквы, пробелы, апострофы или дефисы\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"lastName\": {\n\t\t\t\t\t\"label\": \"Фамилия\",\n\t\t\t\t\t\"placeholder\": \"Ellis\",\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"Пожалуйста, введите свою фамилию\",\n\t\t\t\t\t\t\"length\": \"Фамилия должна быть короче 50 символов\",\n\t\t\t\t\t\t\"pattern\": \"Фамилия должна содержать только буквы, пробелы, апострофы или дефисы\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"errors\": {\n\t\t\t\t\"validation\": \"Ошибка при проверке данных.\"\n\t\t\t},\n\t\t\t\"fields\": {\n\t\t\t\t\"password\": {\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"incorrect\": \"Введённый вами пароль неверный\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"role\": {\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"min\": \"Требуется хотя бы одна роль\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"login\": {\n\t\t\t\"heading\": \"Войдите, чтобы продолжить\",\n\t\t\t\"subheadings\": {\n\t\t\t\t\"stepOne\": \"Введите свою электронную почту\",\n\t\t\t\t\"stepTwo\": \"Введите свой пароль\"\n\t\t\t},\n\t\t\t\"links\": {\n\t\t\t\t\"forgotPassword\": \"Забыли пароль?\",\n\t\t\t\t\"register\": \"У вас нет учетной записи?\",\n\t\t\t\t\"forgotPasswordLink\": \"Сбросить пароль\",\n\t\t\t\t\"registerLink\": \"Зарегистрируйтесь здесь\"\n\t\t\t},\n\t\t\t\"toasts\": {\n\t\t\t\t\"success\": \"С возвращением! Вы успешно вошли в систему.\",\n\t\t\t\t\"incorrectPassword\": \"Неверный пароль\"\n\t\t\t},\n\t\t\t\"errors\": {\n\t\t\t\t\"password\": {\n\t\t\t\t\t\"incorrect\": \"Предоставленный вами пароль не соответствует нашим записям.\"\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"welcome\": \"Добро пожаловать обратно в Checkmate!\"\n\t\t},\n\t\t\"registration\": {\n\t\t\t\"heading\": {\n\t\t\t\t\"superAdmin\": \"Создать супер-администратора\",\n\t\t\t\t\"user\": \"Зарегистрироваться\"\n\t\t\t},\n\t\t\t\"subheadings\": {\n\t\t\t\t\"stepOne\": \"Введите свои личные данные\",\n\t\t\t\t\"stepTwo\": \"Введите вашу электронную почту\",\n\t\t\t\t\"stepThree\": \"Создайте свой пароль\"\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\t\"superAdmin\": \"Создайте свой аккаунт супер-администратора, чтобы начать\",\n\t\t\t\t\"user\": \"Зарегистрируйтесь как пользователь и обратитесь к супер-администратору для доступа к вашим мониторам\"\n\t\t\t},\n\t\t\t\"gettingStartedButton\": {\n\t\t\t\t\"superAdmin\": \"Создать учетную запись супер-администратора\",\n\t\t\t\t\"user\": \"Зарегистрироваться как обычный пользователь\"\n\t\t\t},\n\t\t\t\"termsAndPolicies\": \"Создавая учетную запись, вы соглашаетесь с нашими <a1>Условиями предоставления услуг</a1> и <a2>Политикой конфиденциальности</a2>.\",\n\t\t\t\"links\": {\n\t\t\t\t\"login\": \"Уже есть учетная запись? <a>Войти</a>\"\n\t\t\t},\n\t\t\t\"toasts\": {\n\t\t\t\t\"success\": \"Добро пожаловать! Ваша учетная запись была создана успешно.\"\n\t\t\t},\n\t\t\t\"welcome\": \"Добро пожаловать в Checkmate!\"\n\t\t},\n\t\t\"forgotPassword\": {\n\t\t\t\"heading\": \"Забыли пароль?\",\n\t\t\t\"subheadings\": {\n\t\t\t\t\"stepOne\": \"Не волнуйтесь, мы вышлем вам инструкции для сброса.\",\n\t\t\t\t\"stepTwo\": \"Мы выслали ссылку для сброса пароля на <email/>\",\n\t\t\t\t\"stepThree\": \"Ваш новый пароль должен отличаться от ваших предыдущих пароей.\",\n\t\t\t\t\"stepFour\": \"Ваш пароль был успешно сброшен. Нажмите ниже, чтобы волшебным образом войти в систему.\"\n\t\t\t},\n\t\t\t\"buttons\": {\n\t\t\t\t\"openEmail\": \"Открыть Gmail\",\n\t\t\t\t\"resetPassword\": \"Сбросить пароль\"\n\t\t\t},\n\t\t\t\"imageAlts\": {\n\t\t\t\t\"passwordKey\": \"Password key icon\",\n\t\t\t\t\"email\": \"Email icon\",\n\t\t\t\t\"lock\": \"Lock icon\",\n\t\t\t\t\"passwordConfirm\": \"Password confirm icon\"\n\t\t\t},\n\t\t\t\"links\": {\n\t\t\t\t\"login\": \"Вернуться к <a>Входу</a>\",\n\t\t\t\t\"resend\": \"Не получили письмо? <a>Нажмите, чтобы отправить повторно</a>\"\n\t\t\t},\n\t\t\t\"toasts\": {\n\t\t\t\t\"sent\": \"Инструкция отправлена на <email/>.\",\n\t\t\t\t\"emailNotFound\": \"Email не найден.\",\n\t\t\t\t\"redirect\": \"Перенаправление через <seconds/>...\",\n\t\t\t\t\"success\": \"Ваш пароль успешно сброшен.\",\n\t\t\t\t\"error\": \"Не удалось сбросить пароль. Повторите попытку позже или обратитесь в службу поддержки.\"\n\t\t\t}\n\t\t}\n\t},\n\t\"errorPages\": {\n\t\t\"serverUnreachable\": {\n\t\t\t\"toasts\": {\n\t\t\t\t\"reconnected\": \"Успешное повторное подключение к серверу.\",\n\t\t\t\t\"stillUnreachable\": \"Сервер по-прежнему недоступен. Повторите попытку позже.\"\n\t\t\t},\n\t\t\t\"alertBox\": \"Ошибка подключения к серверу\",\n\t\t\t\"description\": \"Не удаётся подключиться к серверу. Проверьте подключение к Интернету или конфигурацию развёртывания, если проблема не устранена.\",\n\t\t\t\"retryButton\": {\n\t\t\t\t\"default\": \"Повторите попытку подключения\",\n\t\t\t\t\"processing\": \"Подключение...\"\n\t\t\t}\n\t\t}\n\t},\n\t\"createNotifications\": {\n\t\t\"title\": \"Создать канал уведомлений\",\n\t\t\"nameSettings\": {\n\t\t\t\"title\": \"Имя\",\n\t\t\t\"description\": \"Описательное имя для вашей интеграции.\",\n\t\t\t\"nameLabel\": \"Имя\",\n\t\t\t\"namePlaceholder\": \"например, уведомления Slack\"\n\t\t},\n\t\t\"typeSettings\": {\n\t\t\t\"title\": \"Тип\",\n\t\t\t\"description\": \"Выберите тип канала уведомлений, который вы хотите создать.\",\n\t\t\t\"typeLabel\": \"Тип\"\n\t\t},\n\t\t\"emailSettings\": {\n\t\t\t\"title\": \"Электронная почта\",\n\t\t\t\"description\": \"Адреса электронной почты получателей.\",\n\t\t\t\"emailLabel\": \"Адрес электронной почты\",\n\t\t\t\"emailPlaceholder\": \"например, john@example.com\"\n\t\t},\n\t\t\"slackSettings\": {\n\t\t\t\"title\": \"Slack\",\n\t\t\t\"description\": \"Настройте свой вебхук Slack здесь\",\n\t\t\t\"webhookLabel\": \"Slack вебхук URL\",\n\t\t\t\"webhookPlaceholder\": \"https://hooks.slack.com/services/...\"\n\t\t},\n\t\t\"pagerdutySettings\": {\n\t\t\t\"title\": \"PagerDuty\",\n\t\t\t\"description\": \"Настройте интеграцию PagerDuty здесь\",\n\t\t\t\"integrationKeyLabel\": \"Интеграционный ключ\",\n\t\t\t\"integrationKeyPlaceholder\": \"1234567890\"\n\t\t},\n\t\t\"discordSettings\": {\n\t\t\t\"title\": \"Discord\",\n\t\t\t\"description\": \"Настройте вебхук Discord здесь\",\n\t\t\t\"webhookLabel\": \"Discord вебхук URL\",\n\t\t\t\"webhookPlaceholder\": \"https://your-server.com/webhook\"\n\t\t},\n\t\t\"webhookSettings\": {\n\t\t\t\"title\": \"Вебхук\",\n\t\t\t\"description\": \"Настройте свой вебхук здесь\",\n\t\t\t\"webhookLabel\": \"URL-адрес веб-перехватчика\",\n\t\t\t\"webhookPlaceholder\": \"https://your-server.com/webhook\"\n\t\t},\n\t\t\"testNotification\": \"Тестовое уведомление\",\n\t\t\"dialogDeleteTitle\": \"Вы уверены, что хотите удалить это уведомление?\",\n\t\t\"dialogDeleteConfirm\": \"Удалить\"\n\t},\n\t\"notificationConfig\": {\n\t\t\"title\": \"Уведомления\",\n\t\t\"description\": \"Выберите каналы уведомлений, которые вы хотите использовать\"\n\t},\n\t\"monitorStatus\": {\n\t\t\"checkingEvery\": \"Проверка каждый {{interval}}\",\n\t\t\"withCaptureAgent\": \"с агентом захвата {{version}}\",\n\t\t\"up\": \"вверх\",\n\t\t\"down\": \"вниз\",\n\t\t\"paused\": \"приостановлено\"\n\t},\n\t\"advancedMatching\": \"Расширенное сопоставление\",\n\t\"sendTestNotifications\": \"Отправить тестовое уведомление\",\n\t\"selectAll\": \"Выбрать все\",\n\t\"showAdminLoginLink\": \"Показывать ссылку «Администратор? Войти здесь» на странице статуса\",\n\t\"logsPage\": {\n\t\t\"title\": \"Логи\",\n\t\t\"description\": \"Системные логи - последние 1000 строк\",\n\t\t\"tabs\": {\n\t\t\t\"queue\": \"Очередь заданий\",\n\t\t\t\"logs\": \"Серверные логи\",\n\t\t\t\"diagnostics\": \"Диагностика\"\n\t\t},\n\t\t\"toast\": {\n\t\t\t\"fetchLogsSuccess\": \"Логи успешно получены\"\n\t\t},\n\t\t\"logLevelSelect\": {\n\t\t\t\"title\": \"Уровень логов\",\n\t\t\t\"values\": {\n\t\t\t\t\"all\": \"Все\",\n\t\t\t\t\"info\": \"Информация\",\n\t\t\t\t\"warn\": \"Предупреждение\",\n\t\t\t\t\"error\": \"Ошибка\",\n\t\t\t\t\"debug\": \"Дебаг\"\n\t\t\t}\n\t\t}\n\t},\n\t\"queuePage\": {\n\t\t\"title\": \"Очередь\",\n\t\t\"refreshButton\": \"Обновить\",\n\t\t\"flushButton\": \"Очистить очередь\",\n\t\t\"jobTable\": {\n\t\t\t\"title\": \"Задачи в настоящее время в очереди\",\n\t\t\t\"idHeader\": \"ID монитора\",\n\t\t\t\"urlHeader\": \"URL\",\n\t\t\t\"typeHeader\": \"Тип\",\n\t\t\t\"activeHeader\": \"Активный\",\n\t\t\t\"lockedAtHeader\": \"Заблокировано на\",\n\t\t\t\"runCountHeader\": \"Количество запусков\",\n\t\t\t\"failCountHeader\": \"Количество неудач\",\n\t\t\t\"lastRunHeader\": \"Последний запуск в\",\n\t\t\t\"lastFinishedAtHeader\": \"Последний раз закончил в\",\n\t\t\t\"lastRunTookHeader\": \"Последний забег занял\",\n\t\t\t\"intervalHeader\": \"Интервал\"\n\t\t},\n\t\t\"metricsTable\": {\n\t\t\t\"title\": \"Метрики очереди\",\n\t\t\t\"metricHeader\": \"Метрическая\",\n\t\t\t\"valueHeader\": \"Ценить\"\n\t\t},\n\t\t\"failedJobTable\": {\n\t\t\t\"title\": \"Неудачные задачи\",\n\t\t\t\"monitorIdHeader\": \"ID монитора\",\n\t\t\t\"monitorUrlHeader\": \"URL монитора\",\n\t\t\t\"failCountHeader\": \"Количество падений\",\n\t\t\t\"failedAtHeader\": \"Последнее падение в\",\n\t\t\t\"failReasonHeader\": \"Причина падения\"\n\t\t}\n\t},\n\t\"export\": {\n\t\t\"title\": \"Экспорт мониторов\",\n\t\t\"success\": \"Мониторы успешно экспортированы!\",\n\t\t\"failed\": \"Не удалось экспортировать мониторы\"\n\t},\n\t\"monitorActions\": {\n\t\t\"title\": \"Экспорт/Импорт\",\n\t\t\"import\": \"Импортные мониторы\",\n\t\t\"export\": \"Экспорт мониторов\",\n\t\t\"deleteSuccess\": \"Монитор успешно удален\",\n\t\t\"deleteFailed\": \"Не удалось удалить монитор\",\n\t\t\"details\": \"Подробности\"\n\t},\n\t\"settingsPage\": {\n\t\t\"aboutSettings\": {\n\t\t\t\"labelDevelopedBy\": \"Разработано Bluewave Labs\",\n\t\t\t\"labelVersion\": \"Версия\",\n\t\t\t\"title\": \"Об\"\n\t\t},\n\t\t\"demoMonitorsSettings\": {\n\t\t\t\"buttonAddMonitors\": \"Добавить демо мониторы\",\n\t\t\t\"description\": \"Добавьте образцы мониторов для демонстрации.\",\n\t\t\t\"title\": \"Демо мониторы\"\n\t\t},\n\t\t\"emailSettings\": {\n\t\t\t\"buttonSendTestEmail\": \"Отправить тестовое письмо\",\n\t\t\t\"description\": \"Настройте параметры электронной почты в вашей системе. Она используется для отправки уведомлений и оповещений.\",\n\t\t\t\"descriptionTransport\": \"Это создает SMTP-транспорт для NodeMailer.\",\n\t\t\t\"labelAddress\": \"Адрес электронной почты — используется для аутентификации.\",\n\t\t\t\"labelConnectionHost\": \"Хост подключения электронной почты — имя хоста для использования в приветствии HELO/EHLO.\",\n\t\t\t\"labelHost\": \"Хост электронной почты — имя хоста или IP-адрес для подключения.\",\n\t\t\t\"labelIgnoreTLS\": \"Отключить STARTTLS: не использовать TLS, даже если сервер его поддерживает.\",\n\t\t\t\"labelPassword\": \"Пароль электронной почты - Пароль для аутентификации\",\n\t\t\t\"labelPasswordSet\": \"Пароль установлен. Нажмите «Сброс», чтобы изменить его.\",\n\t\t\t\"labelPool\": \"Включить пул соединений: повторно использовать существующие соединения для повышения производительности.\",\n\t\t\t\"labelPort\": \"Порт электронной почты — порт для подключения\",\n\t\t\t\"labelRejectUnauthorized\": \"Отклонять недействительные сертификаты: отклонять соединения с самоподписанными или ненадежными сертификатами.\",\n\t\t\t\"labelRequireTLS\": \"Принудительный STARTTLS: требуется обновление TLS, выдается ошибка, если не поддерживается\",\n\t\t\t\"labelSecure\": \"Использовать SSL (рекомендуется): зашифровать соединение с помощью SSL/TLS.\",\n\t\t\t\"labelTLSServername\": \"Имя сервера TLS — необязательное имя хоста для проверки TLS, если хост — это IP-адрес.\",\n\t\t\t\"labelUser\": \"Пользователь электронной почты — имя пользователя для аутентификации, переопределяет адрес электронной почты, если указан\",\n\t\t\t\"linkTransport\": \"Технические характеристики смотрите здесь.\",\n\t\t\t\"placeholderUser\": \"Оставьте пустым, если не требуется\",\n\t\t\t\"title\": \"Электронная почта\",\n\t\t\t\"toastEmailRequiredFieldsError\": \"Требуется адрес электронной почты, хост, порт и пароль\"\n\t\t},\n\t\t\"pageSpeedSettings\": {\n\t\t\t\"description\": \"Введите ключ API Google PageSpeed, чтобы включить мониторинг Google PageSpeed. Нажмите «Сбросить», чтобы обновить ключ.\",\n\t\t\t\"labelApiKeySet\": \"API-ключ установлен. Нажмите «Сброс», чтобы изменить его.\",\n\t\t\t\"labelApiKey\": \"API-ключ PageSpeed\",\n\t\t\t\"title\": \"API-ключ Google PageSpeed\"\n\t\t},\n\t\t\"saveButtonLabel\": \"Сохранить\",\n\t\t\"statsSettings\": {\n\t\t\t\"clearAllStatsButton\": \"Очистить всю статистику\",\n\t\t\t\"clearAllStatsDescription\": \"Очистить всю статистику. Это необратимо.\",\n\t\t\t\"clearAllStatsDialogConfirm\": \"Да, очистить всю статистику\",\n\t\t\t\"clearAllStatsDialogDescription\": \"После удаления история и статистика мониторинга не могут быть восстановлены.\",\n\t\t\t\"clearAllStatsDialogTitle\": \"Вы хотите очистить всю статистику?\",\n\t\t\t\"description\": \"Укажите, как долго вы хотите хранить данные. Вы также можете удалить все существующие данные.\",\n\t\t\t\"labelTTL\": \"Дни, за которые вы хотите посмотреть историю.\",\n\t\t\t\"labelTTLOptional\": \"0 для бесконечности\",\n\t\t\t\"title\": \"История монитора\"\n\t\t},\n\t\t\"systemResetSettings\": {\n\t\t\t\"buttonRemoveAllMonitors\": \"Удалить все мониторы\",\n\t\t\t\"description\": \"Удалите все мониторы из вашей системы.\",\n\t\t\t\"dialogConfirm\": \"Да, удалить все мониторы\",\n\t\t\t\"dialogDescription\": \"После удаления, мониторы нельзя будет воостановить.\",\n\t\t\t\"dialogTitle\": \"Вы хотите удалить все мониторы?\",\n\t\t\t\"title\": \"Сброс системы\"\n\t\t},\n\t\t\"timezoneSettings\": {\n\t\t\t\"description\": \"Выберите часовой пояс, используемый для отображения даты и времени в приложении.\",\n\t\t\t\"label\": \"Отображение часового пояса\",\n\t\t\t\"title\": \"Отображение часового пояса\"\n\t\t},\n\t\t\"title\": \"Настройки\",\n\t\t\"uiSettings\": {\n\t\t\t\"description\": \"Переключайтесь между светлым и темным режимами или меняйте язык пользовательского интерфейса.\",\n\t\t\t\"labelLanguage\": \"Язык\",\n\t\t\t\"labelTheme\": \"Режим темы\",\n\t\t\t\"title\": \"Появление\"\n\t\t},\n\t\t\"urlSettings\": {\n\t\t\t\"description\": \"Отображение IP-адреса или URL-адреса монитора на общедоступной странице состояния. Если эта опция отключена, для защиты конфиденциальной информации будет отображаться только имя монитора.\",\n\t\t\t\"label\": \"Отображать IP/URL на странице статуса\",\n\t\t\t\"selectDisabled\": \"Выключено\",\n\t\t\t\"selectEnabled\": \"Включено\",\n\t\t\t\"title\": \"Мониторинг IP/URL на странице статуса\"\n\t\t},\n\t\t\"globalThresholds\": {\n\t\t\t\"title\": \"Глобальные пороги\",\n\t\t\t\"description\": \"Настройте глобальные пороговые значения для процессора, памяти, диска и температуры. Если значение указано, оно будет автоматически включено для мониторинга.\"\n\t\t}\n\t},\n\t\"statusPageCreate\": {\n\t\t\"buttonSave\": \"Сохранить\"\n\t},\n\t\"incidentsOptionsHeaderFilterResolved\": \"Решено\",\n\t\"settingsSave\": \"Сохранить\",\n\t\"statusPageCreateAppearanceTitle\": \"Внешний вид\",\n\t\"confirmPassword\": \"Подтвердите пароль\",\n\t\"monitorHooks\": {\n\t\t\"failureAddDemoMonitors\": \"Не удалось добавить демонстрационные мониторы.\",\n\t\t\"successAddDemoMonitors\": \"Демонстрационные мониторы успешно добавлены\"\n\t},\n\t\"settingsAppearance\": \"Внешний вид\",\n\t\"settingsDisplayTimezone\": \"Отображение часового пояса\",\n\t\"settingsGeneralSettings\": \"Общие настройки\",\n\t\"incidentsOptionsHeaderTotalIncidents\": \"Всего инцидентов\",\n\t\"statusPage\": {\n\t\t\"deleteSuccess\": \"Страница статуса успешно удалена\",\n\t\t\"deleteFailed\": \"Не удалось удалить страницу статуса\",\n\t\t\"createSuccess\": \"Страница статуса успешно создана\",\n\t\t\"updateSuccess\": \"Страница статуса успешно обновлена\",\n\t\t\"generalSettings\": \"Общие настройки\",\n\t\t\"contents\": \"Содержание\",\n\t\t\"fallback\": {\n\t\t\t\"checks\": [\n\t\t\t\t\"Мониторинг и отображение состояния ваших сервисов в режиме реального времени\",\n\t\t\t\t\"Отслеживайте состояние нескольких сервисов и делитесь их статусом\",\n\t\t\t\t\"Дайте пользователям информацию о сбоях и производительности\"\n\t\t\t],\n\t\t\t\"title\": \"Страница статуса используется для:\",\n\t\t\t\"actionButton\": \"Давайте создадим вашу первую страницу статуса!\"\n\t\t}\n\t},\n\t\"testNotificationsDisabled\": \"Для этого монитора не настроены уведомления. Вам нужно добавить их, нажав кнопку «Настроить».\",\n\t\"incidentsTableResolvedAt\": \"Решено в\",\n\t\"incidentsTableActionResolve\": \"Решено\",\n\t\"checkHooks\": {\n\t\t\"failureResolveOne\": \"Не удалось разрешить инцидент.\",\n\t\t\"failureResolveAll\": \"Не удалось разрешить все инциденты.\",\n\t\t\"failureResolveMonitor\": \"Не удалось устранить инциденты с монитором.\"\n\t},\n\t\"checkFormError\": \"Пожалуйста, проверьте форму на наличие ошибок.\",\n\t\"diagnosticsPage\": {\n\t\t\"diagnosticDescription\": \"Системная диагностика\",\n\t\t\"statsDescription\": \"Системная статистика\",\n\t\t\"gauges\": {\n\t\t\t\"heapAllocationTitle\": \"Использовано кучи\",\n\t\t\t\"heapAllocationSubtitle\": \"% доступной памяти\",\n\t\t\t\"heapUsageTitle\": \"Выделено памяти в куче\",\n\t\t\t\"heapUsageSubtitle\": \"% доступно памяти\",\n\t\t\t\"heapUtilizationTitle\": \"Использовано кучи\",\n\t\t\t\"heapUtilizationSubtitle\": \"% от доступного\",\n\t\t\t\"instantCpuUsageTitle\": \"Загруженность CPU\",\n\t\t\t\"instantCpuUsageSubtitle\": \"% загрузка CPU за 1s\"\n\t\t},\n\t\t\"stats\": {\n\t\t\t\"eventLoopDelayTitle\": \"Задержка цикла событий\",\n\t\t\t\"uptimeTitle\": \"Аптайм\",\n\t\t\t\"usedHeapSizeTitle\": \"Размер используемой кучи\",\n\t\t\t\"totalHeapSizeTitle\": \"Общий размер кучи\",\n\t\t\t\"osMemoryLimitTitle\": \"Ограничение памяти ОS\"\n\t\t}\n\t},\n\t\"pageSpeedLighthouseAPI\": \"Используйте API Lighthouse PageSpeed для мониторинга вашего сайта\",\n\t\"time\": {\n\t\t\"threeMinutes\": \"3 минуты\",\n\t\t\"fiveMinutes\": \"5 минут\",\n\t\t\"tenMinutes\": \"10 минут\",\n\t\t\"twentyMinutes\": \"20 минут\",\n\t\t\"oneHour\": \"1 час\",\n\t\t\"oneDay\": \"1 день\",\n\t\t\"oneWeek\": \"1 неделя\",\n\t\t\"fourMinutes\": \"4 минуты\",\n\t\t\"oneMinute\": \"1 минута\",\n\t\t\"twoMinutes\": \"2 минуты\",\n\t\t\"fifteenSeconds\": \"15 секунд\",\n\t\t\"thirtySeconds\": \"30 секунд\"\n\t},\n\t\"general\": {\n\t\t\"noOptionsFound\": \"{{unit}} не найдено\"\n\t},\n\t\"infrastructureMonitor\": {\n\t\t\"fallback\": {\n\t\t\t\"checks\": [\n\t\t\t\t\"Отслеживайте производительность серверов\",\n\t\t\t\t\"Выявляйте узкие места и оптимизируйте использование\",\n\t\t\t\t\"Обеспечивайте надежность с помощью мониторинга в режиме реального времени\"\n\t\t\t],\n\t\t\t\"title\": \"Монитор инфраструктуры используется для:\",\n\t\t\t\"actionButton\": \"Давайте создадим ваш первый монитор инфраструктуры!\"\n\t\t}\n\t},\n\t\"maintenanceWindow\": {\n\t\t\"fallback\": {\n\t\t\t\"checks\": [\n\t\t\t\t\"Отметьте периоды технического обслуживания.\",\n\t\t\t\t\"Устраните любые недопонимания.\",\n\t\t\t\t\"Прекратите отправку оповещений в периоды технического обслуживания.\"\n\t\t\t],\n\t\t\t\"title\": \"Период технического обслуживания используется для:\",\n\t\t\t\"actionButton\": \"Давайте создадим ваше первое окно технического обслуживания!\"\n\t\t}\n\t},\n\t\"pageSpeed\": {\n\t\t\"fallback\": {\n\t\t\t\"checks\": [\n\t\t\t\t\"Отчет об удобстве использования страницы\",\n\t\t\t\t\"Помощь в анализе скорости загрузки веб-страницы\",\n\t\t\t\t\"Предложение о том, как можно улучшить страницу\"\n\t\t\t],\n\t\t\t\"title\": \"Монитор PageSpeed используется для:\",\n\t\t\t\"actionButton\": \"Давайте создадим ваш первый монитор PageSpeed!\"\n\t\t}\n\t},\n\t\"uptimeMonitor\": {\n\t\t\"fallback\": {\n\t\t\t\"checks\": [\n\t\t\t\t\"Проверьте, доступны ли веб-сайты или серверы и отвечают ли они\",\n\t\t\t\t\"Оповещайте команды о сбоях или проблемах с производительностью\",\n\t\t\t\t\"Мониторинг конечных точек HTTP, пингов, контейнеров и портов\",\n\t\t\t\t\"Отслеживайте динамику времени безотказной работы и надежности\"\n\t\t\t],\n\t\t\t\"title\": \"Монитор работоспособности используется для:\",\n\t\t\t\"actionButton\": \"Давайте создадим ваш первый монитор времени безотказной работы!\"\n\t\t}\n\t},\n\t\"editUserPage\": {\n\t\t\"form\": {\n\t\t\t\"email\": \"Электронная почта\",\n\t\t\t\"firstName\": \"Имя\",\n\t\t\t\"lastName\": \"Фамилия\",\n\t\t\t\"role\": \"Роли\",\n\t\t\t\"save\": \"Сохранить\"\n\t\t},\n\t\t\"table\": {\n\t\t\t\"actionHeader\": \"Действие\",\n\t\t\t\"roleHeader\": \"Роль\"\n\t\t},\n\t\t\"title\": \"Редактировать пользователя\",\n\t\t\"toast\": {\n\t\t\t\"successUserUpdate\": \"Пользователь успешно обновлен\",\n\t\t\t\"validationErrors\": \"Ошибки проверки\"\n\t\t}\n\t},\n\t\"incidentsPageActionResolveMonitor\": \"Разрешение инцидентов мониторинга\",\n\t\"incidentsPageActionResolveAll\": \"Решить все инциденты\",\n\t\"matchMethodOptions\": {\n\t\t\"equal\": \"Равный\",\n\t\t\"equalPlaceholder\": \"успех\",\n\t\t\"include\": \"Включить\",\n\t\t\"includePlaceholder\": \"хорошо\",\n\t\t\"regex\": \"Regex\",\n\t\t\"regexPlaceholder\": \"^(success|ok)$\",\n\t\t\"text\": \"Метод сопоставления\"\n\t},\n\t\"monitorType\": {\n\t\t\"docker\": {\n\t\t\t\"label\": \"Имя/ID контейнера\",\n\t\t\t\"namePlaceholder\": \"Мой контейнер\",\n\t\t\t\"placeholder\": \"my-app или abcd1234\"\n\t\t},\n\t\t\"http\": {\n\t\t\t\"label\": \"URL для мониторинга\",\n\t\t\t\"namePlaceholder\": \"Google\",\n\t\t\t\"placeholder\": \"google.com\"\n\t\t},\n\t\t\"ping\": {\n\t\t\t\"label\": \"IP-адрес для мониторинга\",\n\t\t\t\"namePlaceholder\": \"Google\",\n\t\t\t\"placeholder\": \"1.1.1.1\"\n\t\t},\n\t\t\"port\": {\n\t\t\t\"label\": \"URL для мониторинга\",\n\t\t\t\"namePlaceholder\": \"Локальный хост:5173\",\n\t\t\t\"placeholder\": \"локальный хост\"\n\t\t},\n\t\t\"game\": {\n\t\t\t\"label\": \"URL для мониторинга\",\n\t\t\t\"namePlaceholder\": \"localhost:5173\",\n\t\t\t\"placeholder\": \"localhost\"\n\t\t}\n\t},\n\t\"uptimeAdvancedMatching\": {\n\t\t\"jsonPath\": \"путь к JSON\"\n\t},\n\t\"bytesPerSecond\": \"Байты в секунду\",\n\t\"bytesReceived\": \"Получено байтов\",\n\t\"bytesSent\": \"Отправлено байтов\",\n\t\"chooseGame\": \"Выбрать игру\",\n\t\"createMonitorPage\": {\n\t\t\"incidentConfigDescription\": \"Мониторинг использует скользящее окно, чтобы понять, когда ресурс недоступен. Статус изменится, если нужный процент проверок покажет сбой.\",\n\t\t\"incidentConfigStatusWindowLabel\": \"Сколько проверок должно быть в скользящем окне?\",\n\t\t\"incidentConfigStatusWindowThresholdLabel\": \"Какой процент проверок в скользящем окне завершается неудачей/успешностью до изменения статуса монитора?\",\n\t\t\"incidentConfigTitle\": \"Инциденты\",\n\t\t\"incidentConfigDescriptionV2\": \"Количество последовательных проверок, необходимых для изменения статуса монитора. Максимум 25.\",\n\t\t\"incidentConfigStatusCheckNumber\": \"Сколько проверок перед сменой статуса?\",\n\t\t\"intervalTitle\": \"Интервал проверки\",\n\t\t\"intervalDescription\": \"Как часто следует проверять монитор.\"\n\t},\n\t\"dataRate\": \"Скорость передачи данных\",\n\t\"dataReceived\": \"Данные получены\",\n\t\"dataSent\": \"Данные отправлены\",\n\t\"details\": \"Подробности\",\n\t\"drops\": \"Падений\",\n\t\"errors\": \"Ошибки\",\n\t\"errorsIn\": \"Ошибки в\",\n\t\"errorsOut\": \"Ошибки вне\",\n\t\"gameServerMonitoring\": \"Мониторинг игрового сервера\",\n\t\"gameServerMonitoringDescription\": \"Проверьте, запущен ли ваш игровой сервер.\",\n\t\"network\": \"Сеть\",\n\t\"networkDrops\": \"Сетевые падения\",\n\t\"networkErrors\": \"Ошибки сети\",\n\t\"networkInterface\": \"Сетевой интерфейс\",\n\t\"noNetworkStatsAvailable\": \"Статистика сети отсутствует.\",\n\t\"packetsPerSecond\": \"Пакетов в секунду\",\n\t\"packetsReceived\": \"Получено пакетов\",\n\t\"packetsReceivedRate\": \"Скорость получения пакетов\",\n\t\"packetsSent\": \"Отправлено пакетов\",\n\t\"rate\": \"коэффициент\",\n\t\"selectInterface\": \"Выберите интерфейс\",\n\t\"v1\": {\n\t\t\"infrastructure\": {\n\t\t\t\"disk_selection_title\": \"Выбор дисков\",\n\t\t\t\"disk_selection_info\": \"На данный момент диск не обнаружен.\",\n\t\t\t\"disk_selection_description\": \"Выберите конкретные диски, которые вы хотите отслеживать.\"\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "client/src/locales/th.json",
    "content": "{\n\t\"submit\": \"ยอมรับ\",\n\t\"title\": \"หัวข้อ\",\n\t\"distributedStatusHeaderText\": \"ตรวจสอบแบบเรียลไทม์บนอุปกรณ์จริง\",\n\t\"distributedStatusSubHeaderText\": \"ระบบทำงานด้วยอุปกรณ์นับล้านทั่วโลก ให้คุณตรวจสอบประสิทธิภาพระบบตามภูมิภาค ประเทศ หรือเมืองได้\",\n\t\"settingsDisabled\": \"ปิดการใช้งาน\",\n\t\"settingsSuccessSaved\": \"บันทึกการตั้งค่าเรียบร้อยแล้ว\",\n\t\"settingsFailedToSave\": \"ไม่สามารถบันทึกการตั้งค่าได้\",\n\t\"settingsStatsCleared\": \"สถิติถูกล้างเรียบร้อยแล้ว\",\n\t\"settingsFailedToClearStats\": \"ไม่สามารถล้างสถิติได้\",\n\t\"settingsMonitorsDeleted\": \"ลบมอนิเตอร์ออกทั้งหมดเรียบร้อยแล้ว\",\n\t\"settingsFailedToDeleteMonitors\": \"ไม่สามารถลบมอนิเตอร์ออกทั้งหมดได้\",\n\t\"starPromptTitle\": \"ให้ดาวกับฉัน\",\n\t\"starPromptDescription\": \"ดูการอัปเดตล่าสุด และมีส่วนร่วมในการขยายชุมชนบน GitHub\",\n\t\"https\": \"HTTPS\",\n\t\"http\": \"HTTP\",\n\t\"monitor\": \"monitor\",\n\t\"aboutus\": \"เกี่ยวกับฉัน\",\n\t\"now\": \"ตอนนี้\",\n\t\"delete\": \"ลบ\",\n\t\"configure\": \"ตั้งค่า\",\n\t\"responseTime\": \"ระยะเวลาการตอบสนอง\",\n\t\"ms\": \"ms\",\n\t\"bar\": \"Bar\",\n\t\"area\": \"พื้นที่\",\n\t\"country\": \"ประเทศ\",\n\t\"city\": \"จังหวัด\",\n\t\"response\": \"การตอบสนอง\",\n\t\"monitorStatusUp\": \"มอนิเตอร์ {name} ({url}) สถานะตอนนี้ออนไลน์และตอบสนองปกติ\",\n\t\"monitorStatusDown\": \"มอนิเตอร์ {name} ({url}) สถานะตอนนี้ล่มและไม่ตอบสนอง\",\n\t\"webhookSendSuccess\": \"การแจ้งเตือนผ่าน Webhook ถูกส่งเรียบร้อยแล้ว\",\n\t\"webhookSendError\": \"ไม่สามารถส่งการแจ้งเตือนผ่าน Webhook ไปที่ {platform} ได้\",\n\t\"webhookUnsupportedPlatform\": \"ระบบไม่รองรับแพลตฟอร์ม {platform} นี้\",\n\t\"distributedRightCategoryTitle\": \"มอนิเตอร์\",\n\t\"distributedStatusServerMonitors\": \"มอนิเตอร์เชิร์ฟเวอร์\",\n\t\"distributedStatusServerMonitorsDescription\": \"ตรวจสอบสถานะของเซิร์ฟเวอร์ที่เกี่ยวข้อง\",\n\t\"distributedUptimeCreateSelectURL\": \"คุณสามารถระบุ URL ของโฮสต์และเลือกประเภทของตัวตรวจสอบได้ที่นี่\",\n\t\"distributedUptimeCreateChecks\": \"รายการตรวจสอบ\",\n\t\"distributedUptimeCreateChecksDescription\": \"คุณสามารถเพิ่มหรือลบการตรวจสอบได้เสมอหลังจากเพิ่มเว็บไซต์ของคุณแล้ว\",\n\t\"distributedUptimeCreateIncidentNotification\": \"การแจ้งเตือนปัญหา\",\n\t\"distributedUptimeCreateIncidentDescription\": \"เมื่อเกิดเหตุการณ์ผิดปกติ ให้แจ้งเตือนผู้ใช้งาน\",\n\t\"distributedUptimeCreateAdvancedSettings\": \"ตั้งค่าขั้นสูง\",\n\t\"distributedUptimeDetailsNoMonitorHistory\": \"ยังไม่มีประวัติการตรวจสอบสำหรับมอนิเตอร์นี้\",\n\t\"distributedUptimeDetailsStatusHeaderUptime\": \"เวลาระบบทำงาน:\",\n\t\"distributedUptimeDetailsStatusHeaderLastUpdate\": \"แก้ไขล่าสุด\",\n\t\"notifications\": {\n\t\t\"enableNotifications\": \"เปิดการแจ้งเตือนของแพลตฟอร์ม {{platform}} นี้\",\n\t\t\"testNotification\": \"ทดสอบระบบการแจ้งเตือน\",\n\t\t\"addOrEditNotifications\": \"เพิ่มและแก้ไขระบบการแจ้งเตือน\",\n\t\t\"slack\": {\n\t\t\t\"label\": \"Slack\",\n\t\t\t\"description\": \"เพื่อเปิดใช้งานการแจ้งเตือนผ่าน Slack ให้สร้างแอป Slack และเปิดใช้งาน Incoming Webhooks หลังจากนั้น เพียงใส่ URL ของ Webhook ที่นี่\",\n\t\t\t\"webhookLabel\": \"URL ของ Webhook/เว็บฮุค\",\n\t\t\t\"webhookPlaceholder\": \"https://hooks.slack.com/services/...\",\n\t\t\t\"webhookRequired\": \"ต้องระบุ URL ของ Slack webhook\"\n\t\t},\n\t\t\"discord\": {\n\t\t\t\"label\": \"Discord\",\n\t\t\t\"description\": \"เพื่อส่งข้อมูลไปยังช่อง Discord ผ่าน Discord notifications โดยใช้ Webhooks ให้เปิดใช้งาน Incoming Webhooks ของ Discord\",\n\t\t\t\"webhookLabel\": \"URL ของ Webhook/เว็บฮุค สำหรับ Discord\",\n\t\t\t\"webhookPlaceholder\": \"https://discord.com/api/webhooks/...\",\n\t\t\t\"webhookRequired\": \"ต้องระบุ URL ของ Discord webhook\"\n\t\t},\n\t\t\"telegram\": {\n\t\t\t\"label\": \"Telegram\",\n\t\t\t\"description\": \"เพื่อเปิดใช้งานการแจ้งเตือนผ่าน Telegram ให้สร้างบอท Telegram โดยใช้ BotFather ซึ่งเป็นบอททางการสำหรับสร้างและจัดการบอท Telegram จากนั้นนำ API token และ Chat ID มาใส่ที่นี่\",\n\t\t\t\"tokenLabel\": \"Token/โทเคน ของบอท\",\n\t\t\t\"tokenPlaceholder\": \"123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11\",\n\t\t\t\"chatIdLabel\": \"Chat ID\",\n\t\t\t\"chatIdPlaceholder\": \"-1001234567890\",\n\t\t\t\"fieldsRequired\": \"ต้องระบุโทเค็นและรหัสแชทของ Telegram\"\n\t\t},\n\t\t\"webhook\": {\n\t\t\t\"label\": \"Webhooks\",\n\t\t\t\"description\": \"คุณสามารถตั้งค่าเว็บฮุคแบบกำหนดเองเพื่อรับการแจ้งเตือนเมื่อเกิดเหตุการณ์ผิดปกติ\",\n\t\t\t\"urlLabel\": \"URL ของ Webhook\",\n\t\t\t\"urlPlaceholder\": \"https://your-server.com/webhook\",\n\t\t\t\"urlRequired\": \"ต้องระบุ URL ของ Webhook\"\n\t\t},\n\t\t\"testNotificationDevelop\": \"ทดสอบการแจ้งเตือน 2\",\n\t\t\"integrationButton\": \"การรวมการแจ้งเตือน\",\n\t\t\"testSuccess\": \"ส่งการแจ้งเตือนทดสอบเรียบร้อยแล้ว!\",\n\t\t\"testFailed\": \"ไม่สามารถส่งการแจ้งเตือนทดสอบได้\",\n\t\t\"unsupportedType\": \"การแจ้งเตือนไม่ได้รับการสนับสนุนประเภทนี้\",\n\t\t\"networkError\": \"เกิดข้อผิดพลาดของเครือข่าย\",\n\t\t\"fallback\": {\n\t\t\t\"title\": \"ช่องทางแจ้งเตือนใช้เพื่อ:\",\n\t\t\t\"checks\": [\n\t\t\t\t\"แจ้งทีมเกี่ยวกับการหยุดทำงานหรือปัญหาประสิทธิภาพ\",\n\t\t\t\t\"แจ้งวิศวกรเมื่อเกิดเหตุการณ์\",\n\t\t\t\t\"ให้ผู้ดูแลระบบทราบเกี่ยวกับการเปลี่ยนแปลงของระบบ\"\n\t\t\t],\n\t\t\t\"actionButton\": \"มาสร้างช่องทางการแจ้งเตือนแรกของคุณกันเถอะ!\"\n\t\t},\n\t\t\"createButton\": \"สร้างช่องทางแจ้งเตือน\",\n\t\t\"createTitle\": \"ช่องทางแจ้งเตือน\",\n\t\t\"create\": {\n\t\t\t\"success\": \"สร้างช่องทางแจ้งเตือนสำเร็จแล้ว\",\n\t\t\t\"failed\": \"ไม่สามารถสร้างช่องทางแจ้งเตือนได้\"\n\t\t},\n\t\t\"fetch\": {\n\t\t\t\"success\": \"ดึงข้อมูลการแจ้งเตือนสำเร็จแล้ว\",\n\t\t\t\"failed\": \"ไม่สามารถดึงข้อมูลการแจ้งเตือนได้\"\n\t\t},\n\t\t\"delete\": {\n\t\t\t\"success\": \"ลบช่องทางแจ้งเตือนสำเร็จแล้ว\",\n\t\t\t\"failed\": \"ไม่สามารถลบช่องทางแจ้งเตือนได้\"\n\t\t},\n\t\t\"edit\": {\n\t\t\t\"success\": \"ปรับปรุงช่องทางแจ้งเตือนสำเร็จแล้ว\",\n\t\t\t\"failed\": \"ไม่สามารถปรับปรุงการแจ้งเตือนได้\"\n\t\t},\n\t\t\"test\": {\n\t\t\t\"success\": \"ส่งการแจ้งเตือนทดสอบสำเร็จแล้ว\",\n\t\t\t\"failed\": \"ไม่สามารถส่งการแจ้งเตือนทดสอบได้\"\n\t\t}\n\t},\n\t\"testLocale\": \"testLocale\",\n\t\"add\": \"เพิ่ม\",\n\t\"monitors\": \"monitors\",\n\t\"distributedUptimeStatusCreateStatusPage\": \"หน้าตรวจสอบสถานะระบบ\",\n\t\"distributedUptimeStatusCreateStatusPageAccess\": \"สิทธิ์เข้าถึง\",\n\t\"distributedUptimeStatusCreateStatusPageReady\": \"เมื่อหน้าสถานะพร้อม คุณสามารถตั้งค่าเป็นเผยแพร่สู่สาธารณะได้\",\n\t\"distributedUptimeStatusBasicInfoHeader\": \"ข้อมูลทั่วไป\",\n\t\"distributedUptimeStatusBasicInfoDescription\": \"ระบุชื่อบริษัทและซับโดเมนสำหรับหน้าสถานะของคุณ\",\n\t\"distributedUptimeStatusLogoHeader\": \"โลโก้\",\n\t\"distributedUptimeStatusLogoDescription\": \"อัปโหลดโลโก้ให้ Status Page ของคุณ\",\n\t\"distributedUptimeStatusLogoUploadButton\": \"อัพโหลดโลโก้\",\n\t\"distributedUptimeStatusStandardMonitorsHeader\": \"มอนิเตอร์พื้นฐาน\",\n\t\"distributedUptimeStatusStandardMonitorsDescription\": \"เพิ่มตัวตรวจสอบมาตรฐานไปยัง Status Page ของคุณ\",\n\t\"distributedUptimeStatusCreateYour\": \"Create your\",\n\t\"distributedUptimeStatusEditYour\": \"Edit your\",\n\t\"distributedUptimeStatusPublishedLabel\": \"เผยแพร่และมองเห็นได้ต่อสาธารณะ\",\n\t\"distributedUptimeStatusCompanyNameLabel\": \"ชื่อบริษัท\",\n\t\"distributedUptimeStatusPageAddressLabel\": \"ที่อยู่หน้าสถานะของคุณ\",\n\t\"distributedUptimeStatus30Days\": \"30 วัน\",\n\t\"distributedUptimeStatus60Days\": \"60 วัน\",\n\t\"distributedUptimeStatus90Days\": \"90 วัน\",\n\t\"distributedUptimeStatusPageNotSetUp\": \"หน้าสถานะยังไม่ถูกสร้างขึ้น\",\n\t\"distributedUptimeStatusContactAdmin\": \"กรุณาติดต่อผู้ดูแลระบบของคุณ เพื่อขอความช่วยเหลือ\",\n\t\"distributedUptimeStatusPageNotPublic\": \"หน้าสถานะนี้ไม่เปิดเผยต่อสาธารณะ\",\n\t\"distributedUptimeStatusPageDeleteDialog\": \"คุณต้องการลบหน้าสถานะนี้หรือไม่?\",\n\t\"distributedUptimeStatusPageDeleteConfirm\": \"ใช่ ฉันต้องการลบหน้าสถานะนี้\",\n\t\"distributedUptimeStatusPageDeleteDescription\": \"เมื่อถูกลบแล้ว หน้าสถานะของคุณจะไม่สามารถกู้คืนได้\",\n\t\"distributedUptimeStatusDevices\": \"อุปกรณ์\",\n\t\"distributedUptimeStatusUpt\": \"UPT\",\n\t\"distributedUptimeStatusUptBurned\": \"UPT Burned\",\n\t\"distributedUptimeStatusUptLogo\": \"Upt Logo\",\n\t\"incidentsTableNoIncidents\": \"ยังไม่มีเหตุการณ์ผิดปกติบันทึกไว้\",\n\t\"incidentsTablePaginationLabel\": \"เหตุการณ์ผิดปกติ\",\n\t\"incidentsTableMonitorName\": \"ชื่อมอนิเตอร์\",\n\t\"incidentsTableStatus\": \"สถานะ\",\n\t\"incidentsTableDateTime\": \"วันและเวลา\",\n\t\"incidentsTableStatusCode\": \"รหัสสถานะ\",\n\t\"incidentsTableMessage\": \"ข้อความ\",\n\t\"incidentsOptionsHeader\": \"เหตุการณ์ผิดปกติสำหรับ:\",\n\t\"incidentsOptionsHeaderFilterBy\": \"กรองโดย:\",\n\t\"incidentsOptionsHeaderFilterAll\": \"ท้ังหมด\",\n\t\"incidentsOptionsHeaderFilterDown\": \"ล่ม\",\n\t\"incidentsOptionsHeaderFilterCannotResolve\": \"ไม่แก้ไข/หาสาเหตุไม่ได้\",\n\t\"incidentsOptionsHeaderShow\": \"แสดง:\",\n\t\"incidentsOptionsHeaderLastHour\": \"ชั่วโมงที่แล้ว\",\n\t\"incidentsOptionsHeaderLastDay\": \"วันที่แล้ว\",\n\t\"incidentsOptionsHeaderLastWeek\": \"สัปดาห์ที่แล้ว\",\n\t\"incidentsOptionsPlaceholderAllServers\": \"เชิร์ฟเวอร์ทั้งหมด\",\n\t\"infrastructureCreateYour\": \"สร้าง\",\n\t\"infrastructureCreateGeneralSettingsDescription\": \"คุณสามารถเลือก URL ของโฮสต์ พร้อมกับชื่อที่เป็นมิตร Friendly Name และรหัสลับการอนุญาตเพื่อเชื่อมต่อกับตัวแทนเซิร์ฟเวอร์ Server Agent\",\n\t\"infrastructureServerRequirement\": \"เซิร์ฟเวอร์ที่คุณมอนิเตอร์ต้องกำลังทำงานด้วย\",\n\t\"infrastructureCustomizeAlerts\": \"ปรับแต่งการแจ้งเตือน\",\n\t\"infrastructureAlertNotificationDescription\": \"ส่งการแจ้งเตือนถึงผู้ใช้เมื่อค่าขีดจำกัดเกินเปอร์เซ็นต์ที่กำหนด\",\n\t\"infrastructureCreateMonitor\": \"สร้าง Infrastructure Monitor\",\n\t\"infrastructureProtocol\": \"โปรโตคอล\",\n\t\"infrastructureServerUrlLabel\": \"URL ของเซิร์ฟเวอร์\",\n\t\"infrastructureDisplayNameLabel\": \"ชื่อที่แสดง\",\n\t\"infrastructureAuthorizationSecretLabel\": \"Authorization secret / คีย์ลับสำหรับการยืนยันตัวตน\",\n\t\"gb\": \"กิกะไบต์ GB\",\n\t\"mb\": \"เมกะไบต์ MB\",\n\t\"mem\": \"แรม\",\n\t\"memoryUsage\": \"การใช้งานแรม\",\n\t\"cpu\": \"ซีพียู\",\n\t\"cpuUsage\": \"การใช้งาน CPU\",\n\t\"cpuTemperature\": \"อุณหภูมิ CPU\",\n\t\"diskUsage\": \"การใช้งาน Disk\",\n\t\"used\": \"ใช้งาน\",\n\t\"total\": \"ทั้งหมด\",\n\t\"cores\": \"คอร์\",\n\t\"frequency\": \"ความถี่\",\n\t\"status\": \"สถานะ\",\n\t\"cpuPhysical\": \"ซีพียู (คอร์หลัก)\",\n\t\"cpuLogical\": \"ซีพียู (คอร์เสมือน)\",\n\t\"cpuFrequency\": \"ความถี่ของ CPU\",\n\t\"avgCpuTemperature\": \"อุณหภูมิเฉลี่ยของซีพียู\",\n\t\"memory\": \"แรม\",\n\t\"disk\": \"ดิส/พื้นที่\",\n\t\"uptime\": \"\",\n\t\"os\": \"ระบบปฏิบัติการ\",\n\t\"host\": \"โฮส\",\n\t\"actions\": \"จัดการ\",\n\t\"integrations\": \"การรวมระบบ\",\n\t\"integrationsPrism\": \"เชื่อมต่อ Prism กับบริการที่คุณชื่นชอบ\",\n\t\"integrationsSlack\": \"Slack\",\n\t\"integrationsSlackInfo\": \"เชื่อมต่อกับ Slack และดูเหตุการณ์ผิดปกติในช่องทาง\",\n\t\"integrationsDiscord\": \"Discord\",\n\t\"integrationsDiscordInfo\": \"เชื่อมต่อกับ Discord และดูเหตุการณ์ผิดปกติได้โดยตรงในช่องทาง\",\n\t\"integrationsZapier\": \"Zapier\",\n\t\"integrationsZapierInfo\": \"ส่งเหตุการณ์ทั้งหมดไปยัง Zapier แล้วสามารถดูได้ทุกที่\",\n\t\"commonSave\": \"บันทึก\",\n\t\"createYour\": \"Create your\",\n\t\"createMonitor\": \"\",\n\t\"pause\": \"พักชั่วคราว\",\n\t\"resume\": \"ดำเนินการต่อ\",\n\t\"editing\": \"กำลังปรับปรุง…\",\n\t\"url\": \"URL\",\n\t\"access\": \"การเข้าถึง\",\n\t\"timezone\": \"เขตเวลา\",\n\t\"features\": \"ฟีเจอร์\",\n\t\"administrator\": \"ผู้ดูแลระบบ\",\n\t\"loginHere\": \"กรุณาเข้าสู่ระบบที่นี่\",\n\t\"displayName\": \"ชื่อที่แสดง\",\n\t\"urlMonitor\": \"ลิงก์ที่จะมอนิเตอร์\",\n\t\"portToMonitor\": \"พอร์ตที่จะมอนิเตอร์\",\n\t\"websiteMonitoring\": \"เว็บไชต์ที่จะมอนิเตอร์\",\n\t\"websiteMonitoringDescription\": \"ใช้ HTTP(s) เพื่อตรวจสอบเว็บไซต์หรือ API endpoint ของคุณ\",\n\t\"pingMonitoring\": \"มอนิเตอร์แบบ Ping\",\n\t\"pingMonitoringDescription\": \"ตรวจสอบว่าเซิร์ฟเวอร์ของคุณพร้อมใช้งานหรือไม่\",\n\t\"dockerContainerMonitoring\": \"มอนิเตอร์คอนเทนเนอร์ใน Docker\",\n\t\"dockerContainerMonitoringDescription\": \"ตรวจสอบว่าคอนเทนเนอร์ Docker ของคุณกำลังทำงานอยู่หรือไม่\",\n\t\"portMonitoring\": \"มอนิเตอร์แบบ Ping\",\n\t\"portMonitoringDescription\": \"ตรวจสอบว่าพอร์ตของคุณเปิดอยู่หรือไม่\",\n\t\"createMaintenanceWindow\": \"สร้างช่วงเวลาบำรุงรักษา\",\n\t\"createMaintenance\": \"สร้างการบำรุงรักษา\",\n\t\"editMaintenance\": \"แก้ไขการบำรุงรักษา\",\n\t\"maintenanceWindowName\": \"ชื่อหน้าบำรุงรักษา\",\n\t\"friendlyNameInput\": \"ชื่อแสดงผล\",\n\t\"friendlyNamePlaceholder\": \"Maintenance เริ่มต้นเวลา __ : __ และใช้เวลา ___ นาที\",\n\t\"maintenanceRepeat\": \"ทำซ้ำการบำรุงรักษา\",\n\t\"maintenance\": \"การบำรุงรักษา\",\n\t\"duration\": \"ระยะเวลา\",\n\t\"addMonitors\": \"เพิ่มมอนิเตอร์\",\n\t\"window\": \"ช่วงเวลา\",\n\t\"cancel\": \"ยกเลิก\",\n\t\"message\": \"ข้อความ\",\n\t\"low\": \"Low\",\n\t\"high\": \"High\",\n\t\"statusCode\": \"รหัสสถานะ\",\n\t\"date&Time\": \"วันที่และเวลา\",\n\t\"type\": \"ประเภท\",\n\t\"statusPageName\": \"ชื่อ Status Page\",\n\t\"publicURL\": \"URL สาธารณะ\",\n\t\"repeat\": \"ทำซ้ำ\",\n\t\"edit\": \"แก้ไข\",\n\t\"createA\": \"สร้าง A\",\n\t\"remove\": \"ลบ\",\n\t\"maintenanceWindowDescription\": \"ช่วงเวลาการบำรุงรักษา การตรวจสอบทั้งหมดของมอนิเตอร์ที่ถูกเลือกจะถูกระงับ ไม่ทำการตรวจสอบเครือข่ายใด ๆ ทำให้ไม่มีการอัปเดตสถานะหรือแจ้งเตือนเกิดขึ้น มอนิเตอร์ของคุณจะคงแสดงสถานะล่าสุดที่ทราบ และหน้าสถานะจะมีสัญลักษณ์บ่งบอกว่ากำลังอยู่ระหว่างการบำรุงรักษา เมื่อเวลาการบำรุงรักษาสิ้นสุด การตรวจสอบจะกลับมาทำงานโดยอัตโนมัติ และหากพบปัญหา การแจ้งเตือนจะถูกส่งออก ช่วงเวลาการบำรุงรักษาจะไม่ถูกนับรวมในการคำนวณความพร้อมใช้งาน\",\n\t\"startTime\": \"เวลาเริ่มต้น\",\n\t\"timeZoneInfo\": \"วันที่และเวลาทั้งหมดเป็นเวลาตามโซน GMT+0\",\n\t\"monitorsToApply\": \"มอนิเตอร์ที่จะใช้ช่วงเวลาการบำรุงรักษา\",\n\t\"nextWindow\": \"ช่วงเวลาถัดไป\",\n\t\"notFoundButton\": \"ไปยังหน้าจอแดชบอร์ดหลัก\",\n\t\"pageSpeedConfigureSettingsDescription\": \"คุณสามารถเลือก URL ของโฮสต์ พร้อมกับประเภทของมอนิเตอร์ได้\",\n\t\"monitorDisplayName\": \"ชื่อที่แสดงของมอนิเตอร์\",\n\t\"whenNewIncident\": \"เมื่อเกิดเหตุการณ์ใหม่\",\n\t\"notifySMS\": \"แจ้งเตือนทางSMS (กำลังจะมา)\",\n\t\"notifyEmails\": \"แจ้งเตือนทางอีเมลไปยังหลายที่อยู่ด้วย (กำลังจะมา)\",\n\t\"seperateEmails\": \"คุณสามารถแยกอีเมลหลายอันด้วยเครื่องหมายจุลภาค , ได้\",\n\t\"checkFrequency\": \"ความถี่ในการตรวจสอบ\",\n\t\"matchMethod\": \"วิธีการจับคู่\",\n\t\"expectedValue\": \"ค่าที่คาดหวัง\",\n\t\"deleteDialogTitle\": \"คุณแน่ใจหรือว่าต้องการลบมอนิเตอร์นี้ไหม\",\n\t\"deleteDialogDescription\": \"เมื่อลบแล้ว มอนิเตอร์นี้ไม่สามารถกู้คืนได้\",\n\t\"pageSpeedMonitor\": \"มอนิเตอร์ความเร็วหน้าเว็บ\",\n\t\"shown\": \"แสดง\",\n\t\"ago\": \"ที่ผ่านมา\",\n\t\"companyName\": \"ชื่อบริษัท\",\n\t\"pageSpeedDetailsPerformanceReport\": \"เป็นค่าโดยประมาณและอาจแตกต่างกันไป\",\n\t\"pageSpeedDetailsPerformanceReportCalculator\": \"ดูเครื่องคิดเลข\",\n\t\"checkingEvery\": \"ตรวจสอบทุก\",\n\t\"statusPageCreateSettings\": \"หากหน้าสถานะของคุณพร้อมแล้ว คุณสามารถทำเครื่องหมายว่าเผยแพร่แล้วได้\",\n\t\"basicInformation\": \"ข้อมูลพื้นฐาน\",\n\t\"statusPageCreateBasicInfoDescription\": \"กำหนดชื่อบริษัทและซับโดเมนที่หน้าสถานะของคุณชี้ไป\",\n\t\"statusPageCreateSelectTimeZoneDescription\": \"เลือกเขตเวลาที่หน้าสถานะของคุณจะแสดง\",\n\t\"statusPageCreateAppearanceDescription\": \"กําหนดรูปลักษณ์เริ่มต้นของหน้าสถานะสาธารณะของคุณ\",\n\t\"statusPageCreateSettingsCheckboxLabel\": \"เผยแพร่และเปิดเผยต่อสาธารณะ\",\n\t\"statusPageCreateBasicInfoStatusPageAddress\": \"ที่อยู่หน้าสถานะของคุณ\",\n\t\"statusPageCreateTabsContent\": \"หน้าสถานะเซิร์ฟเวอร์\",\n\t\"statusPageCreateTabsContentDescription\": \"คุณสามารถเพิ่มเซิร์ฟเวอร์ที่คุณตรวจสอบเข้าไปยังหน้าสถานะของคุณได้จำนวนเท่าใดก็ได้ และสามารถจัดลำดับใหม่เพื่อการแสดงผลที่ดีที่สุด\",\n\t\"statusPageCreateTabsContentFeaturesDescription\": \"แสดงรายละเอียดเพิ่มเติมบนหน้าสถานะ\",\n\t\"showCharts\": \"แสดงแผนภูมิ\",\n\t\"showUptimePercentage\": \"แสดงเปอร์เซ็นต์ความพร้อมใช้งาน\",\n\t\"removeLogo\": \"ลบโลโก้\",\n\t\"statusPageStatus\": \"ยังไม่ได้ตั้งค่าหน้าสถานะสาธารณะ\",\n\t\"statusPageStatusContactAdmin\": \"กรุณาติดต่อผู้ดูแลระบบของคุณ\",\n\t\"statusPageStatusNotPublic\": \"หน้าสถานะนี้ไม่เป็นสาธารณะ\",\n\t\"statusPageStatusNoPage\": \"ที่นี่ยังไม่มีหน้าสถานะ\",\n\t\"statusPageStatusServiceStatus\": \"สถานะบริการ\",\n\t\"deleteStatusPage\": \"คุณต้องการลบหน้าสถานะนี้หรือไม่ไหม?\",\n\t\"deleteStatusPageConfirm\": \"ใช่ ลบหน้าสถานะ\",\n\t\"deleteStatusPageDescription\": \"เมื่อลบแล้ว หน้าสถานะของคุณไม่สามารถกู้คืนได้\",\n\t\"uptimeCreate\": \"ค่าที่คาดหวังถูกใช้เพื่อตรวจสอบผลลัพธ์การตอบกลับ และการจับคู่จะเป็นตัวกำหนดสถานะ\",\n\t\"uptimeCreateJsonPath\": \"นิพจน์นี้จะถูกประเมินกับข้อมูล JSON ที่ตอบกลับ และผลลัพธ์จะถูกใช้เพื่อตรวจสอบกับค่าที่คาดหวัง ดู\",\n\t\"uptimeCreateJsonPathQuery\": \"for query language documentation.\",\n\t\"maintenanceTableActionMenuDialogTitle\": \"คุณแน่ใจหรือว่าต้องการลบช่วงเวลาการบำรุงรักษานี้?\",\n\t\"infrastructureEditYour\": \"Edit your\",\n\t\"infrastructureEditMonitor\": \"บันทึก Infrastructure มอนิเตอร์\",\n\t\"infrastructureMonitorCreated\": \"สร้างมอนิเตอร์ Infrastructure เรียบร้อยแล้ว!\",\n\t\"infrastructureMonitorUpdated\": \"อัพเดทมอนิเตอร์ Infrastructure เรียบร้อยแล้ว!\",\n\t\"errorInvalidTypeId\": \"ประเภทการแจ้งเตือนที่ระบุไม่ถูกต้อง\",\n\t\"errorInvalidFieldId\": \"รหัสฟิลด์ที่ระบุไม่ถูกต้อง\",\n\t\"inviteNoTokenFound\": \"ไม่พบโทเค็นคำเชิญ\",\n\t\"pageSpeedWarning\": \"คำเตือน: คุณยังไม่ได้เพิ่มคีย์ Google PageSpeed API หากไม่มีคีย์นี้ มอนิเตอร์ความเร็วหน้าเว็บจะไม่ทำงาน\",\n\t\"pageSpeedLearnMoreLink\": \"คลิกที่นี่\",\n\t\"pageSpeedAddApiKey\": \"เพื่อเพิ่มคีย์ API ของคุณ\",\n\t\"update\": \"อัปเดต\",\n\t\"invalidFileFormat\": \"รูปแบบไฟล์ไม่รองรับ!\",\n\t\"invalidFileSize\": \"ขนาดไฟล์ใหญ่เกินไป!\",\n\t\"ClickUpload\": \"คลิกเพื่ออัปโหลด\",\n\t\"DragandDrop\": \"ลากและวางเลย\",\n\t\"MaxSize\": \"ขนาดสูงสุด\",\n\t\"SupportedFormats\": \"รูปแบบที่รองรับ\",\n\t\"FirstName\": \"ชื่อจริง\",\n\t\"LastName\": \"นามสกุล\",\n\t\"EmailDescriptionText\": \"นี่คือที่อยู่อีเมลปัจจุบันของคุณ — ไม่สามารถแก้ไขได้\",\n\t\"YourPhoto\": \"รูปโปรไฟล์\",\n\t\"PhotoDescriptionText\": \"รูปนี้จะแสดงบนหน้าประวัติของคุณ\",\n\t\"save\": \"บันทึก\",\n\t\"DeleteDescriptionText\": \"การทำเช่นนี้จะลบบัญชีและข้อมูลทั้งหมดที่เกี่ยวข้องบนเซิร์ฟเวอร์ ไม่สามารถกู้คืนได้\",\n\t\"DeleteAccountWarning\": \"การลบบัญชีหมายความว่าคุณจะไม่สามารถเข้าสู่ระบบอีก และข้อมูลทั้งหมดของคุณจะถูกลบ ไม่สามารถกู้คืนได้\",\n\t\"DeleteWarningTitle\": \"คุณแน่ใจหรือว่าต้องการลบบัญชีนี้?\",\n\t\"bulkImport\": {\n\t\t\"title\": \"นำเข้าจำนวนมาก\",\n\t\t\"selectFileTips\": \"เลือกไฟล์ CSV เพื่อนำเข้า\",\n\t\t\"selectFileDescription\": \"คุณสามารถดาวน์โหลด <template>template</template> หรือ <sample>sample</sample> ของเราได้\",\n\t\t\"selectFile\": \"เลือกไฟล์\",\n\t\t\"parsingFailed\": \"การแยกวิเคราะห์ล้มเหลว\",\n\t\t\"uploadSuccess\": \"สร้างมอนิเตอร์เรียบร้อยแล้ว!\",\n\t\t\"validationFailed\": \"การตรวจสอบล้มเหลว\",\n\t\t\"noFileSelected\": \"ยังไม่ได้เลือกไฟล์\",\n\t\t\"fallbackPage\": \"นำเข้าไฟล์เพื่ออัปโหลดรายการเซิร์ฟเวอร์เป็นกลุ่ม\",\n\t\t\"invalidFileType\": \"ประเภทไฟล์ไม่ถูกต้อง\",\n\t\t\"uploadFailed\": \"อัปโหลดล้มเหลว\"\n\t},\n\t\"DeleteAccountTitle\": \"ลบบัญชี\",\n\t\"DeleteAccountButton\": \"ลบบัญชี\",\n\t\"publicLink\": \"ลิงก์สาธารณะ\",\n\t\"maskedPageSpeedKeyPlaceholder\": \"*************************************\",\n\t\"reset\": \"รีเช็ต\",\n\t\"ignoreTLSError\": \"ละเว้นข้อผิดพลาด TLS/SSL\",\n\t\"tlsErrorIgnored\": \"ละเว้นข้อผิดพลาด TLS/SSL แล้ว\",\n\t\"ignoreTLSErrorDescription\": \"ละเว้นข้อผิดพลาด TLS/SSL และดำเนินการตรวจสอบความพร้อมใช้งานของเว็บไซต์ต่อ\",\n\t\"createNew\": \"สร้างใหม่\",\n\t\"greeting\": {\n\t\t\"prepend\": \"สวัสดี\",\n\t\t\"append\": \"ช่วงบ่ายคือเวลาเล่นของคุณ—มาทำให้สุดยอดกันเถอะ!\",\n\t\t\"overview\": \"นี่คือภาพรวมระบบมอนิเตอร์ประเภท {{type}} ของคุณ\"\n\t},\n\t\"roles\": {\n\t\t\"superAdmin\": \"Super admin\",\n\t\t\"admin\": \"แอดมิน\",\n\t\t\"teamMember\": \"สมาชิกในทีม\",\n\t\t\"demoUser\": \"ผู้ใช้ Demo\"\n\t},\n\t\"teamPanel\": {\n\t\t\"teamMembers\": \"สมาชิกในทีม\",\n\t\t\"filter\": {\n\t\t\t\"all\": \"ทั้งหมด\",\n\t\t\t\"member\": \"สมาชิก\"\n\t\t},\n\t\t\"inviteTeamMember\": \"เชิญสมาชิกเข้าทีม\",\n\t\t\"inviteNewTeamMember\": \"เชิญสมาชิกทีมใหม่\",\n\t\t\"inviteDescription\": \"เมื่อคุณเพิ่มสมาชิกทีมใหม่ เขาจะสามารถเข้าถึงมอนิเตอร์ทั้งหมดได้\",\n\t\t\"email\": \"อีเมล\",\n\t\t\"selectRole\": \"เลือกบทบาท\",\n\t\t\"inviteLink\": \"ลิงก์เชิญ\",\n\t\t\"cancel\": \"ยกเลิก\",\n\t\t\"noMembers\": \"ยังไม่มีสมาชิกทีมในบทบาทนี้\",\n\t\t\"getToken\": \"รับโทเค็น\",\n\t\t\"emailToken\": \"Token ทางอีเมล\",\n\t\t\"table\": {\n\t\t\t\"name\": \"ชื่อ\",\n\t\t\t\"email\": \"อีเมล\",\n\t\t\t\"role\": \"บทบาท\",\n\t\t\t\"created\": \"สร้างเมื่อ\"\n\t\t},\n\t\t\"addTeamMember\": {\n\t\t\t\"addMemberMenu\": \"เพิ่มสมาชิกทีม\",\n\t\t\t\"title\": \"ลงทะเบียนสมาชิกทีมใหม่\",\n\t\t\t\"description\": \"สร้างผู้ใช้ใหม่และแชร์ข้อมูลการเข้าสู่ระบบให้กับพวกเขา วิธีนี้จะทำให้สมาชิกสามารถเข้าถึงตัวตรวจสอบทั้งหมดได้ทันที\",\n\t\t\t\"addButton\": \"เพิ่มสมาชิก\"\n\t\t},\n\t\t\"register\": \"ลงทะเบียนสมาชิกทีม\",\n\t\t\"registerToast\": {\n\t\t\t\"success\": \"สร้างผู้ใช้เรียบร้อยแล้ว กรุณาแชร์ข้อมูลการเข้าสู่ระบบให้สมาชิกอย่างปลอดภัย\",\n\t\t\t\"dbUserExists\": \"ผู้ใช้นี้มีอยู่แล้ว\",\n\t\t\t\"unknownError\": \"เกิดข้อผิดพลาดที่ไม่ทราบสาเหตุ\"\n\t\t},\n\t\t\"registerTeamMember\": {\n\t\t\t\"title\": \"ลงทะเบียนสมาชิกทีม\",\n\t\t\t\"auth\": {\n\t\t\t\t\"common\": {\n\t\t\t\t\t\"inputs\": {\n\t\t\t\t\t\t\"firstName\": {\n\t\t\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\t\t\"empty\": \"กรุณากรอกชื่อ\",\n\t\t\t\t\t\t\t\t\"pattern\": \"ชื่อต้องมีเฉพาะตัวอักษร เว้นวรรค เครื่องหมายอัญประกาศ หรือขีดกลาง\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"lastName\": {\n\t\t\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\t\t\"empty\": \"กรุณากรอกนามสกุล\",\n\t\t\t\t\t\t\t\t\"pattern\": \"นามสกุลต้องมีเฉพาะตัวอักษร เว้นวรรค เครื่องหมายอัญประกาศ หรือขีดกลาง\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"email\": {\n\t\t\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\t\t\"empty\": \"กรุณากรอกอีเมลเพื่อดำเนินการต่อ\",\n\t\t\t\t\t\t\t\t\"invalid\": \"กรุณาตรวจสอบความถูกต้องของอีเมลอีกครั้ง\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"role\": {\n\t\t\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\t\t\"empty\": \"ต้องระบุบทบาท\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"role\": \"บทบาท\",\n\t\t\"changeTeamPassword\": {\n\t\t\t\"changePasswordMenu\": \"\",\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"success\": \"\"\n\t\t}\n\t},\n\t\"monitorState\": {\n\t\t\"paused\": \"หยุดชั่วคราว\",\n\t\t\"resumed\": \"ดำเนินการต่อ\",\n\t\t\"active\": \"ใช้งานอยู่\"\n\t},\n\t\"menu\": {\n\t\t\"uptime\": \"ความพร้อมใช้งาน\",\n\t\t\"pagespeed\": \"ความเร็วหน้าเว็บ\",\n\t\t\"infrastructure\": \"โครงสร้างพื้นฐาน\",\n\t\t\"incidents\": \"เหตุการณ์\",\n\t\t\"statusPages\": \"หน้าสถานะ\",\n\t\t\"maintenance\": \"การบำรุงรักษา\",\n\t\t\"integrations\": \"การรวมระบบ\",\n\t\t\"settings\": \"การตั้งค่า\",\n\t\t\"support\": \"การสนับสนุน\",\n\t\t\"discussions\": \"การสนทนา\",\n\t\t\"docs\": \"เอกสาร\",\n\t\t\"changelog\": \"บันทึกการเปลี่ยนแปลง\",\n\t\t\"profile\": \"โปรไฟล์\",\n\t\t\"password\": \"รหัสผ่าน\",\n\t\t\"team\": \"ทีม\",\n\t\t\"logOut\": \"ออกจากระบบ\",\n\t\t\"notifications\": \"การแจ้งเตือน\",\n\t\t\"logs\": \"Logs\"\n\t},\n\t\"settingsEmailUser\": \"อีเมลผู้ใช้ - ชื่อผู้ใช้สำหรับการยืนยันตัวตน จะใช้แทนอีเมลหากระบุไว้\",\n\t\"state\": \"สถานะ\",\n\t\"statusBreadCrumbsStatusPages\": \"หน้าสถานะ\",\n\t\"statusBreadCrumbsDetails\": \"รายละเอียด\",\n\t\"commonSaving\": \"กำลังบันทึก...\",\n\t\"navControls\": \"การควบคุม\",\n\t\"incidentsPageTitle\": \"เหตุการณ์\",\n\t\"passwordPanel\": {\n\t\t\"passwordChangedSuccess\": \"รหัสผ่านของคุณถูกเปลี่ยนเรียบร้อยแล้ว\",\n\t\t\"passwordInputIncorrect\": \"คุณป้อนรหัสผ่านที่ไม่ถูกต้อง\",\n\t\t\"currentPassword\": \"รหัสผ่านปัจจุบัน\",\n\t\t\"enterCurrentPassword\": \"กรอกรหัสผ่านปัจจุบันของคุณ\",\n\t\t\"newPassword\": \"รหัสผ่านใหม่\",\n\t\t\"enterNewPassword\": \"กรอกรหัสผ่านใหม่ของคุณ\",\n\t\t\"confirmNewPassword\": \"ยืนยันรหัสผ่านใหม่อีกครั้ง\",\n\t\t\"passwordRequirements\": \"รหัสผ่านใหม่ต้องมีอย่างน้อย 8 ตัวอักษร และต้องมีตัวอักษรใหญ่ ตัวอักษรเล็ก ตัวเลข และอักขระพิเศษอย่างละอย่าง 1\",\n\t\t\"saving\": \"กำลังบันทึก...\"\n\t},\n\t\"emailSent\": \"ส่งอีเมลเรียบร้อยแล้ว\",\n\t\"failedToSendEmail\": \"ส่งอีเมลล้มเหลว\",\n\t\"settingsTestEmailSuccess\": \"ส่งอีเมลทดสอบเรียบร้อยแล้ว\",\n\t\"settingsTestEmailFailed\": \"ส่งอีเมลทดสอบล้มเหลว\",\n\t\"settingsTestEmailFailedWithReason\": \"ส่งอีเมลทดสอบล้มเหลว: {{reason}}\",\n\t\"settingsTestEmailUnknownError\": \"ข้อผิดพลาดไม่ทราบสาเหตุ\",\n\t\"statusMsg\": {\n\t\t\"paused\": \"การตรวจสอบถูกพักชั่วคราว\",\n\t\t\"up\": \"เว็บไซต์ของคุณใช้งานได้\",\n\t\t\"down\": \"เว็บไซต์ของคุณล่ม\",\n\t\t\"pending\": \"รอดำเนินการ...\"\n\t},\n\t\"uptimeGeneralInstructions\": {\n\t\t\"http\": \"กรอก URL หรือ IP ที่ต้องการตรวจสอบ (เช่น https://example.com/\\n หรือ 192.168.1.100) และตั้งชื่อที่ชัดเจนให้แสดงบนแดชบอร์ด\",\n\t\t\"ping\": \"กรอกที่อยู่ IP หรือชื่อโฮสต์ที่ต้องการ ping (เช่น 192.168.1.100 หรือ example.com) และตั้งชื่อที่ชัดเจนให้แสดงบนแดชบอร์ด\",\n\t\t\"docker\": \"กรอกชื่อหรือ ID ของคอนเทนเนอร์ Docker คุณสามารถใช้ชื่อคอนเทนเนอร์ (เช่น my-app) หรือ ID ของคอนเทนเนอร์ (ID เต็ม 64 ตัวอักษร หรือ ID สั้น)\",\n\t\t\"port\": \"กรอก URL หรือ IP ของเซิร์ฟเวอร์ หมายเลขพอร์ต และตั้งชื่อที่ชัดเจนให้แสดงบนแดชบอร์ด\",\n\t\t\"game\": \"กรอกที่อยู่ IP หรือชื่อโฮสต์และหมายเลขพอร์ตเพื่อทำการ ping (เช่น 192.168.1.100 หรือ example.com) และเลือกประเภทเกม\",\n\t\t\"https\": \"\"\n\t},\n\t\"common\": {\n\t\t\"appName\": \"Checkmate\",\n\t\t\"monitoringAgentName\": \"Capture\",\n\t\t\"buttons\": {\n\t\t\t\"toggleTheme\": \"สลับโหมดสว่าง & มืด\"\n\t\t},\n\t\t\"toasts\": {\n\t\t\t\"networkError\": \"ข้อผิดพลาดเครือข่าย\",\n\t\t\t\"checkConnection\": \"กรุณาตรวจสอบการเชื่อมต่อของคุณ\",\n\t\t\t\"unknownError\": \"ข้อผิดพลาดไม่ทราบสาเหตุ\"\n\t\t}\n\t},\n\t\"auth\": {\n\t\t\"common\": {\n\t\t\t\"navigation\": {\n\t\t\t\t\"continue\": \"ดำเนินการต่อ\",\n\t\t\t\t\"back\": \"ย้อนกลับ\"\n\t\t\t},\n\t\t\t\"inputs\": {\n\t\t\t\t\"email\": {\n\t\t\t\t\t\"label\": \"อีเมล\",\n\t\t\t\t\t\"placeholder\": \"jordan.ellis@domain.com\",\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"เพื่อดำเนินการต่อ กรุณากรอกที่อยู่อีเมลของคุณ\",\n\t\t\t\t\t\t\"invalid\": \"กรุณาตรวจสอบความถูกต้องของอีเมลที่กรอก\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"password\": {\n\t\t\t\t\t\"label\": \"รหัสผ่าน\",\n\t\t\t\t\t\"rules\": {\n\t\t\t\t\t\t\"length\": {\n\t\t\t\t\t\t\t\"beginning\": \"ต้องมีความยาวอย่างน้อย\",\n\t\t\t\t\t\t\t\"highlighted\": \"8 ตัวอักษร\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"special\": {\n\t\t\t\t\t\t\t\"beginning\": \"ต้องมีอย่างน้อย\",\n\t\t\t\t\t\t\t\"highlighted\": \"อักขระพิเศษ 1 ตัว\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"number\": {\n\t\t\t\t\t\t\t\"beginning\": \"ต้องมีอย่างน้อย\",\n\t\t\t\t\t\t\t\"highlighted\": \"ตัวเลข 1 ตัว\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"uppercase\": {\n\t\t\t\t\t\t\t\"beginning\": \"ต้องมีอย่างน้อย\",\n\t\t\t\t\t\t\t\"highlighted\": \"ตัวอักษรใหญ่ 1 ตัว\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"lowercase\": {\n\t\t\t\t\t\t\t\"beginning\": \"ต้องมีอย่างน้อย\",\n\t\t\t\t\t\t\t\"highlighted\": \"ตัวอักษรเล็ก 1 ตัว\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"match\": {\n\t\t\t\t\t\t\t\"beginning\": \"รหัสผ่าน\",\n\t\t\t\t\t\t\t\"highlighted\": \"ต้องตรงกัน\"\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"กรุณากรอกรหัสผ่านของคุณ\",\n\t\t\t\t\t\t\"length\": \"รหัสผ่านต้องมีความยาวอย่างน้อย 8 ตัวอักษร\",\n\t\t\t\t\t\t\"uppercase\": \"รหัสผ่านต้องมีตัวอักษรใหญ่อย่างน้อย 1 ตัว\",\n\t\t\t\t\t\t\"lowercase\": \"รหัสผ่านต้องมีตัวอักษรเล็กอย่างน้อย 1 ตัว\",\n\t\t\t\t\t\t\"number\": \"รหัสผ่านต้องมีตัวเลขอย่างน้อย 1 ตัว\",\n\t\t\t\t\t\t\"special\": \"รหัสผ่านต้องมีอักขระพิเศษอย่างน้อย 1 ตัว\",\n\t\t\t\t\t\t\"incorrect\": \"รหัสผ่านที่คุณกรอกไม่ตรงกับข้อมูลของเรา\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"passwordConfirm\": {\n\t\t\t\t\t\"label\": \"ยืนยันรหัสผ่าน\",\n\t\t\t\t\t\"placeholder\": \"กรอกรหัสผ่านอีกครั้งเพื่อยืนยัน\",\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"กรุณากรอกรหัสผ่านอีกครั้งเพื่อยืนยัน (ช่วยลดข้อผิดพลาดจากการพิมพ์ผิด)\",\n\t\t\t\t\t\t\"different\": \"รหัสผ่านที่กรอกไม่ตรงกัน อาจมีตัวใดตัวหนึ่งพิมพ์ผิด\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"firstName\": {\n\t\t\t\t\t\"label\": \"ชื่อ\",\n\t\t\t\t\t\"placeholder\": \"Brownyroll\",\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"กรุณากรอกชื่อของคุณ\",\n\t\t\t\t\t\t\"length\": \"ชื่อต้องมีความยาวไม่เกิน 50 ตัวอักษร\",\n\t\t\t\t\t\t\"pattern\": \"ชื่อต้องประกอบด้วยตัวอักษร ช่องว่าง เครื่องหมาย ' หรือ - เท่านั้น\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"lastName\": {\n\t\t\t\t\t\"label\": \"นามสกุล\",\n\t\t\t\t\t\"placeholder\": \".\",\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"กรุณากรอกนามสกุลของคุณ\",\n\t\t\t\t\t\t\"length\": \"นามสกุลต้องมีความยาวไม่เกิน 50 ตัวอักษร\",\n\t\t\t\t\t\t\"pattern\": \"นามสกุลต้องประกอบด้วยตัวอักษร ช่องว่าง เครื่องหมาย ' หรือ - เท่านั้น\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"errors\": {\n\t\t\t\t\"validation\": \"เกิดข้อผิดพลาดในการตรวจสอบข้อมูล\"\n\t\t\t},\n\t\t\t\"fields\": {\n\t\t\t\t\"password\": {\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"incorrect\": \"รหัสผ่านที่คุณป้อนไม่ตรงกับข้อมูลของเรา\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"role\": {\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"min\": \"ต้องมีอย่างน้อยหนึ่งบทบาท\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"login\": {\n\t\t\t\"heading\": \"เข้าสู่ระบบเพื่อดำเนินการต่อ\",\n\t\t\t\"subheadings\": {\n\t\t\t\t\"stepOne\": \"กรอกอีเมลของคุณ\",\n\t\t\t\t\"stepTwo\": \"กรอกรหัสผ่านของคุณ\"\n\t\t\t},\n\t\t\t\"links\": {\n\t\t\t\t\"forgotPassword\": \"ลืมรหัสผ่าน?\",\n\t\t\t\t\"register\": \"ยังไม่มีบัญชีใช่ไหม?\",\n\t\t\t\t\"forgotPasswordLink\": \"รีเซ็ตรหัสผ่าน\",\n\t\t\t\t\"registerLink\": \"สมัครสมาชิกที่นี่\"\n\t\t\t},\n\t\t\t\"toasts\": {\n\t\t\t\t\"success\": \"ยินดีต้อนรับกลับ! คุณเข้าสู่ระบบเรียบร้อยแล้ว\",\n\t\t\t\t\"incorrectPassword\": \"รหัสผ่านไม่ถูกต้อง\"\n\t\t\t},\n\t\t\t\"errors\": {\n\t\t\t\t\"password\": {\n\t\t\t\t\t\"incorrect\": \"รหัสผ่านที่คุณป้อนไม่ตรงกับข้อมูลของเรา\"\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"welcome\": \"ยินดีต้อนรับกลับสู่ Checkmate!\"\n\t\t},\n\t\t\"registration\": {\n\t\t\t\"heading\": {\n\t\t\t\t\"superAdmin\": \"สร้าง Super Admin\",\n\t\t\t\t\"user\": \"สมัครสมาชิก\"\n\t\t\t},\n\t\t\t\"subheadings\": {\n\t\t\t\t\"stepOne\": \"กรอกรายละเอียดส่วนตัวของคุณ\",\n\t\t\t\t\"stepTwo\": \"กรอกอีเมลของคุณ\",\n\t\t\t\t\"stepThree\": \"สร้างรหัสผ่านของคุณ\"\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\t\"superAdmin\": \"สร้างบัญชี Super Admin เพื่อเริ่มต้นใช้งาน\",\n\t\t\t\t\"user\": \"สมัครสมาชิกผู้ใช้และขอสิทธิ์เข้าถึงมอนิเตอร์จาก Super Admin\"\n\t\t\t},\n\t\t\t\"gettingStartedButton\": {\n\t\t\t\t\"superAdmin\": \"สร้างบัญชี Super Admin\",\n\t\t\t\t\"user\": \"สมัครสมาชิกผู้ใช้ทั่วไป\"\n\t\t\t},\n\t\t\t\"termsAndPolicies\": \"การสร้างบัญชีถือว่าคุณยอมรับ <a1>ข้อกำหนดการให้บริการ</a1> และ <a2>นโยบายความเป็นส่วนตัว</a2> ของเรา\",\n\t\t\t\"links\": {\n\t\t\t\t\"login\": \"มีบัญชีแล้ว? <a>เข้าสู่ระบบ</a>\"\n\t\t\t},\n\t\t\t\"toasts\": {\n\t\t\t\t\"success\": \"ยินดีต้อนรับ! สร้างบัญชีเรียบร้อยแล้ว\"\n\t\t\t},\n\t\t\t\"welcome\": \"ยินดีต้อนรับสู่ Checkmate!\"\n\t\t},\n\t\t\"forgotPassword\": {\n\t\t\t\"heading\": \"ลืมรหัสผ่าน?\",\n\t\t\t\"subheadings\": {\n\t\t\t\t\"stepOne\": \"ไม่ต้องกังวล เราจะส่งคำแนะนำเพื่อรีเซ็ตรหัสผ่านให้คุณ\",\n\t\t\t\t\"stepTwo\": \"เราได้ส่งลิงก์รีเซ็ตรหัสผ่านไปยัง <email/>\",\n\t\t\t\t\"stepThree\": \"รหัสผ่านใหม่ต้องแตกต่างจากรหัสผ่านที่ใช้ก่อนหน้านี้\",\n\t\t\t\t\"stepFour\": \"รีเซ็ตรหัสผ่านเรียบร้อยแล้ว คลิกด้านล่างเพื่อเข้าสู่ระบบทันที\"\n\t\t\t},\n\t\t\t\"buttons\": {\n\t\t\t\t\"openEmail\": \"เปิดแอปอีเมล\",\n\t\t\t\t\"resetPassword\": \"รีเซ็ตรหัสผ่าน\"\n\t\t\t},\n\t\t\t\"imageAlts\": {\n\t\t\t\t\"passwordKey\": \"\",\n\t\t\t\t\"email\": \"\",\n\t\t\t\t\"lock\": \"\",\n\t\t\t\t\"passwordConfirm\": \"\"\n\t\t\t},\n\t\t\t\"links\": {\n\t\t\t\t\"login\": \"กลับไปที่ <a>เข้าสู่ระบบ</a>\",\n\t\t\t\t\"resend\": \"ไม่ได้รับอีเมล? <a>คลิกเพื่อส่งอีกครั้ง</a>\"\n\t\t\t},\n\t\t\t\"toasts\": {\n\t\t\t\t\"sent\": \"คำแนะนำถูกส่งไปยัง <email/>.\",\n\t\t\t\t\"emailNotFound\": \"ไม่พบอีเมลนี้\",\n\t\t\t\t\"redirect\": \"กำลังเปลี่ยนหน้าใน <seconds/>...\",\n\t\t\t\t\"success\": \"รีเซ็ตรหัสผ่านสำเร็จแล้ว\",\n\t\t\t\t\"error\": \"ไม่สามารถรีเซ็ตรหัสผ่านได้ กรุณาลองอีกครั้งภายหลังหรือติดต่อฝ่ายสนับสนุน\"\n\t\t\t}\n\t\t}\n\t},\n\t\"errorPages\": {\n\t\t\"serverUnreachable\": {\n\t\t\t\"toasts\": {\n\t\t\t\t\"reconnected\": \"เชื่อมต่อกับเซิร์ฟเวอร์สำเร็จแล้ว\",\n\t\t\t\t\"stillUnreachable\": \"เซิร์ฟเวอร์ยังไม่สามารถเข้าถึงได้ กรุณาลองอีกครั้งภายหลัง\"\n\t\t\t},\n\t\t\t\"alertBox\": \"เกิดข้อผิดพลาดการเชื่อมต่อเซิร์ฟเวอร์\",\n\t\t\t\"description\": \"ไม่สามารถเชื่อมต่อกับเซิร์ฟเวอร์ได้ กรุณาตรวจสอบการเชื่อมต่ออินเทอร์เน็ตของคุณหรือยืนยันการตั้งค่า deployment หากปัญหายังคงอยู่\",\n\t\t\t\"retryButton\": {\n\t\t\t\t\"default\": \"ลองเชื่อมต่ออีกครั้ง\",\n\t\t\t\t\"processing\": \"กำลังเชื่อมต่อ…\"\n\t\t\t}\n\t\t}\n\t},\n\t\"createNotifications\": {\n\t\t\"title\": \"สร้างช่องทางแจ้งเตือน\",\n\t\t\"nameSettings\": {\n\t\t\t\"title\": \"ชื่อ\",\n\t\t\t\"description\": \"ชื่อที่บ่งบอกถึงการตั้งค่าการรวมระบบของคุณ\",\n\t\t\t\"nameLabel\": \"ชื่อ\",\n\t\t\t\"namePlaceholder\": \"เช่น การแจ้งเตือนผ่าน Slack\"\n\t\t},\n\t\t\"typeSettings\": {\n\t\t\t\"title\": \"ประเภท\",\n\t\t\t\"description\": \"เลือกประเภทของช่องทางแจ้งเตือนที่คุณต้องการสร้าง\",\n\t\t\t\"typeLabel\": \"ประเภท\"\n\t\t},\n\t\t\"emailSettings\": {\n\t\t\t\"title\": \"อีเมล\",\n\t\t\t\"description\": \"ที่อยู่อีเมลปลายทาง\",\n\t\t\t\"emailLabel\": \"อีเมล\",\n\t\t\t\"emailPlaceholder\": \"e.g. john@example.com\"\n\t\t},\n\t\t\"slackSettings\": {\n\t\t\t\"title\": \"Slack\",\n\t\t\t\"description\": \"ตั้งค่า Slack webhook ของคุณที่นี่\",\n\t\t\t\"webhookLabel\": \"URL ของ Slack webhook\",\n\t\t\t\"webhookPlaceholder\": \"https://hooks.slack.com/services/...\"\n\t\t},\n\t\t\"pagerdutySettings\": {\n\t\t\t\"title\": \"PagerDuty\",\n\t\t\t\"description\": \"ตั้งค่าการรวมระบบ PagerDuty ของคุณที่นี่\",\n\t\t\t\"integrationKeyLabel\": \"คีย์การรวมระบบ\",\n\t\t\t\"integrationKeyPlaceholder\": \"1234567890\"\n\t\t},\n\t\t\"discordSettings\": {\n\t\t\t\"title\": \"Discord\",\n\t\t\t\"description\": \"ตั้งค่า Discord webhook ของคุณที่นี่\",\n\t\t\t\"webhookLabel\": \"URL ของ Discord Webhook\",\n\t\t\t\"webhookPlaceholder\": \"https://your-server.com/webhook\"\n\t\t},\n\t\t\"webhookSettings\": {\n\t\t\t\"title\": \"Webhook\",\n\t\t\t\"description\": \"ตั้งค่า webhook ของคุณที่นี่\",\n\t\t\t\"webhookLabel\": \"Webhook URL\",\n\t\t\t\"webhookPlaceholder\": \"https://your-server.com/webhook\"\n\t\t},\n\t\t\"testNotification\": \"ทดสอบการแจ้งเตือน\",\n\t\t\"dialogDeleteTitle\": \"คุณแน่ใจหรือไม่ว่าต้องการลบการแจ้งเตือนนี้?\",\n\t\t\"dialogDeleteConfirm\": \"ลบ\"\n\t},\n\t\"notificationConfig\": {\n\t\t\"title\": \"การแจ้งเตือน\",\n\t\t\"description\": \"เลือกช่องทางแจ้งเตือนที่คุณต้องการใช้\"\n\t},\n\t\"monitorStatus\": {\n\t\t\"checkingEvery\": \"ตรวจสอบทุก {{interval}}\",\n\t\t\"withCaptureAgent\": \"โดยใช้ Capture agent {{version}}\",\n\t\t\"up\": \"ออนไลน์\",\n\t\t\"down\": \"ออฟไลน์\",\n\t\t\"paused\": \"หยุดชั่วคราว\"\n\t},\n\t\"advancedMatching\": \"การจับคู่ขั้นสูง\",\n\t\"sendTestNotifications\": \"ส่งการแจ้งเตือนทดสอบ\",\n\t\"selectAll\": \"Select all\",\n\t\"showAdminLoginLink\": \"แสดงลิงก์ \\\"ผู้ดูแลระบบ? เข้าสู่ระบบที่นี่\\\" บนหน้าสถานะ\",\n\t\"logsPage\": {\n\t\t\"title\": \"Logs\",\n\t\t\"description\": \"ระบบ Logs 1000 บรรทัดล่าสุด\",\n\t\t\"tabs\": {\n\t\t\t\"queue\": \"คิวงาน\",\n\t\t\t\"logs\": \"Logs เซิร์ฟเวอร์\",\n\t\t\t\"diagnostics\": \"วินิจฉัย\"\n\t\t},\n\t\t\"toast\": {\n\t\t\t\"fetchLogsSuccess\": \"ดึง Logs สำเร็จแล้ว\"\n\t\t},\n\t\t\"logLevelSelect\": {\n\t\t\t\"title\": \"Logs level\",\n\t\t\t\"values\": {\n\t\t\t\t\"all\": \"All\",\n\t\t\t\t\"info\": \"Info\",\n\t\t\t\t\"warn\": \"Warn\",\n\t\t\t\t\"error\": \"Error\",\n\t\t\t\t\"debug\": \"Debug\"\n\t\t\t}\n\t\t}\n\t},\n\t\"queuePage\": {\n\t\t\"title\": \"Queue\",\n\t\t\"refreshButton\": \"Refresh\",\n\t\t\"flushButton\": \"Flush queue\",\n\t\t\"jobTable\": {\n\t\t\t\"title\": \"งานที่อยู่ในคิวปัจจุบัน\",\n\t\t\t\"idHeader\": \"รหัสมอนิเตอร์\",\n\t\t\t\"urlHeader\": \"URL\",\n\t\t\t\"typeHeader\": \"Type\",\n\t\t\t\"activeHeader\": \"ใช้งานอยู่\",\n\t\t\t\"lockedAtHeader\": \"ล็อกเมื่อ\",\n\t\t\t\"runCountHeader\": \"จำนวนรัน\",\n\t\t\t\"failCountHeader\": \"จำนวนล้มเหลว\",\n\t\t\t\"lastRunHeader\": \"รันล่าสุดเมื่อ\",\n\t\t\t\"lastFinishedAtHeader\": \"เสร็จสิ้นล่าสุดเมื่อ\",\n\t\t\t\"lastRunTookHeader\": \"รันครั้งล่าสุดใช้เวลา\",\n\t\t\t\"intervalHeader\": \"ช่วงเวลา\"\n\t\t},\n\t\t\"metricsTable\": {\n\t\t\t\"title\": \"คิวเมตริก\",\n\t\t\t\"metricHeader\": \"เมตริก\",\n\t\t\t\"valueHeader\": \"Value\"\n\t\t},\n\t\t\"failedJobTable\": {\n\t\t\t\"title\": \"งานที่ล้มเหลว\",\n\t\t\t\"monitorIdHeader\": \"รหัสมอนิเตอร์\",\n\t\t\t\"monitorUrlHeader\": \"URL มอนิเตอร์\",\n\t\t\t\"failCountHeader\": \"จำนวนล้มเหลว\",\n\t\t\t\"failedAtHeader\": \"ล้มเหลวล่าสุดเมื่อ\",\n\t\t\t\"failReasonHeader\": \"สาเหตุที่ล้มเหลว\"\n\t\t}\n\t},\n\t\"export\": {\n\t\t\"title\": \"ส่งออกมอนิเตอร์\",\n\t\t\"success\": \"ส่งออกมอนิเตอร์สำเร็จแล้ว\",\n\t\t\"failed\": \"ไม่สามารถส่งออกมอนิเตอร์ได้\"\n\t},\n\t\"monitorActions\": {\n\t\t\"title\": \"ส่งออก/นำเข้า\",\n\t\t\"import\": \"นำเข้ามอนิเตอร์\",\n\t\t\"export\": \"ส่งออกมอนิเตอร์\",\n\t\t\"deleteSuccess\": \"ลบมอนิเตอร์สำเร็จ\",\n\t\t\"deleteFailed\": \"ลบมอนิเตอร์ล้มเหลว\",\n\t\t\"details\": \"รายละเอียด\"\n\t},\n\t\"settingsPage\": {\n\t\t\"aboutSettings\": {\n\t\t\t\"labelDevelopedBy\": \"พัฒนาโดย Bluewave Labs\",\n\t\t\t\"labelVersion\": \"เวอร์ชัน\",\n\t\t\t\"title\": \"เกี่ยวกับ\"\n\t\t},\n\t\t\"demoMonitorsSettings\": {\n\t\t\t\"buttonAddMonitors\": \"เพิ่มมอนิเตอร์ตัวอย่าง\",\n\t\t\t\"description\": \"เพิ่มมอนิเตอร์ตัวอย่างเพื่อการสาธิต\",\n\t\t\t\"title\": \"มอนิเตอร์สาธิต\"\n\t\t},\n\t\t\"emailSettings\": {\n\t\t\t\"buttonSendTestEmail\": \"ส่งอีเมลทดสอบ\",\n\t\t\t\"description\": \"ตั้งค่าอีเมลสำหรับระบบของคุณ ใช้สำหรับส่งการแจ้งเตือนและเตือนภัย\",\n\t\t\t\"descriptionTransport\": \"สร้าง SMTP transport สำหรับ NodeMailer\",\n\t\t\t\"labelAddress\": \"ที่อยู่อีเมล - ใช้สำหรับการยืนยันตัวตน\",\n\t\t\t\"labelConnectionHost\": \"โฮสต์เชื่อมต่ออีเมล - ชื่อโฮสต์ที่ใช้ในคำทักทาย HELO/EHLO\",\n\t\t\t\"labelHost\": \"โฮสต์อีเมล - ชื่อโฮสต์หรือ IP สำหรับเชื่อมต่อ\",\n\t\t\t\"labelIgnoreTLS\": \"ปิดใช้งาน STARTTLS: ไม่ใช้ TLS แม้เซิร์ฟเวอร์รองรับ\",\n\t\t\t\"labelPassword\": \"รหัสผ่านอีเมล - สำหรับยืนยันตัวตน\",\n\t\t\t\"labelPasswordSet\": \"ตั้งรหัสผ่านเรียบร้อยแล้ว คลิก รีเซ็ต เพื่อเปลี่ยน\",\n\t\t\t\"labelPool\": \"เปิดใช้ connection pooling: ใช้การเชื่อมต่อเดิมซ้ำเพื่อเพิ่มประสิทธิภาพ\",\n\t\t\t\"labelPort\": \"พอร์ตอีเมล - พอร์ตสำหรับเชื่อมต่อ\",\n\t\t\t\"labelRejectUnauthorized\": \"ปฏิเสธใบรับรองไม่ถูกต้อง: ปฏิเสธการเชื่อมต่อที่ใช้ใบรับรอง self-signed หรือไม่เชื่อถือ\",\n\t\t\t\"labelRequireTLS\": \"บังคับ STARTTLS: ต้องการอัปเกรด TLS ล้มเหลวหากไม่รองรับ\",\n\t\t\t\"labelSecure\": \"ใช้ SSL (แนะนำ): เข้ารหัสการเชื่อมต่อด้วย SSL/TLS\",\n\t\t\t\"labelTLSServername\": \"ชื่อเซิร์ฟเวอร์ TLS - ชื่อโฮสต์เสริมสำหรับตรวจสอบ TLS เมื่อโฮสต์เป็น IP\",\n\t\t\t\"labelUser\": \"ผู้ใช้อีเมล - ชื่อผู้ใช้สำหรับยืนยันตัวตน ใช้แทนที่อีเมลถ้ามีการระบุ\",\n\t\t\t\"linkTransport\": \"ดูข้อกำหนดที่นี่\",\n\t\t\t\"placeholderUser\": \"ปล่อยว่างหากไม่จำเป็น\",\n\t\t\t\"title\": \"อีเมล\",\n\t\t\t\"toastEmailRequiredFieldsError\": \"ต้องระบุอีเมล, โฮสต์, พอร์ต และรหัสผ่าน\"\n\t\t},\n\t\t\"pageSpeedSettings\": {\n\t\t\t\"description\": \"ใส่ Google PageSpeed API Key ของคุณเพื่อเปิดใช้งานการตรวจสอบ PageSpeed ของ Google คลิก รีเซ็ต เพื่ออัปเดต Key\",\n\t\t\t\"labelApiKeySet\": \"ตั้งค่า API key แล้ว คลิก รีเซ็ต เพื่อเปลี่ยน\",\n\t\t\t\"labelApiKey\": \"PageSpeed API key\",\n\t\t\t\"title\": \"Google PageSpeed API key\"\n\t\t},\n\t\t\"saveButtonLabel\": \"บันทึก\",\n\t\t\"statsSettings\": {\n\t\t\t\"clearAllStatsButton\": \"ล้างสถิติทั้งหมด\",\n\t\t\t\"clearAllStatsDescription\": \"ล้างสถิติทั้งหมด การกระทำนี้ไม่สามารถย้อนกลับได้\",\n\t\t\t\"clearAllStatsDialogConfirm\": \"ใช่ ล้างสถิติทั้งหมด\",\n\t\t\t\"clearAllStatsDialogDescription\": \"เมื่อถูกลบแล้ว ประวัติการตรวจสอบและสถิติไม่สามารถกู้คืนได้\",\n\t\t\t\"clearAllStatsDialogTitle\": \"คุณต้องการล้างสถิติทั้งหมดหรือไม่?\",\n\t\t\t\"description\": \"กำหนดระยะเวลาที่ต้องการเก็บข้อมูลประวัติ คุณยังสามารถล้างข้อมูลทั้งหมดที่มีอยู่ได้\",\n\t\t\t\"labelTTL\": \"จำนวนวันที่ต้องการเก็บประวัติการตรวจสอบ\",\n\t\t\t\"labelTTLOptional\": \"0 หมายถึงไม่จำกัด\",\n\t\t\t\"title\": \"ประวัติการตรวจสอบ\"\n\t\t},\n\t\t\"systemResetSettings\": {\n\t\t\t\"buttonRemoveAllMonitors\": \"ลบมอนิเตอร์ทั้งหมด\",\n\t\t\t\"description\": \"ลบมอนิเตอร์ทั้งหมดออกจากระบบของคุณ\",\n\t\t\t\"dialogConfirm\": \"ใช่ ลบมอนิเตอร์ทั้งหมด\",\n\t\t\t\"dialogDescription\": \"เมื่อถูกลบแล้ว มอนิเตอร์ไม่สามารถกู้คืนได้\",\n\t\t\t\"dialogTitle\": \"คุณต้องการลบมอนิเตอร์ทั้งหมดหรือไม่?\",\n\t\t\t\"title\": \"รีเซ็ตระบบ\"\n\t\t},\n\t\t\"timezoneSettings\": {\n\t\t\t\"description\": \"เลือกโซนเวลาที่ใช้แสดงวันที่และเวลาในแอปทั้งหมด\",\n\t\t\t\"label\": \"โซนเวลาที่แสดง\",\n\t\t\t\"title\": \"โซนเวลาที่แสดง\"\n\t\t},\n\t\t\"title\": \"การตั้งค่า\",\n\t\t\"uiSettings\": {\n\t\t\t\"description\": \"สลับโหมดสว่าง/มืด หรือเปลี่ยนภาษาอินเทอร์เฟซผู้ใช้\",\n\t\t\t\"labelLanguage\": \"ภาษา\",\n\t\t\t\"labelTheme\": \"โหมดธีม\",\n\t\t\t\"title\": \"รูปลักษณ์\"\n\t\t},\n\t\t\"urlSettings\": {\n\t\t\t\"description\": \"แสดง IP/URL ของมอนิเตอร์บนหน้าสถานะสาธารณะ หากปิดใช้งาน จะแสดงเฉพาะชื่อมอนิเตอร์เพื่อป้องกันข้อมูลสำคัญ\",\n\t\t\t\"label\": \"แสดง IP/URL บนหน้าสถานะ\",\n\t\t\t\"selectDisabled\": \"ปิดใช้งาน\",\n\t\t\t\"selectEnabled\": \"เปิดใช้งาน\",\n\t\t\t\"title\": \"IP/URL ของมอนิเตอร์บนหน้าสถานะ\"\n\t\t},\n\t\t\"globalThresholds\": {\n\t\t\t\"title\": \"เกณฑ์การตรวจสอบแบบรวม\",\n\t\t\t\"description\": \"กำหนดค่าเกณฑ์ของ CPU, หน่วยความจำ, ดิสก์ และอุณหภูมิ หากระบุค่าไว้ ระบบจะเปิดใช้งานการตรวจสอบโดยอัตโนมัติ\"\n\t\t}\n\t},\n\t\"statusPageCreate\": {\n\t\t\"buttonSave\": \"บันทึก\"\n\t},\n\t\"incidentsOptionsHeaderFilterResolved\": \"แก้ไขแล้ว\",\n\t\"settingsSave\": \"บันทึก\",\n\t\"statusPageCreateAppearanceTitle\": \"รูปลักษณ์\",\n\t\"confirmPassword\": \"ยืนยันรหัสผ่าน\",\n\t\"monitorHooks\": {\n\t\t\"failureAddDemoMonitors\": \"ไม่สามารถเพิ่มมอนิเตอร์ตัวอย่างได้\",\n\t\t\"successAddDemoMonitors\": \"เพิ่มมอนิเตอร์ตัวอย่างสำเร็จ\"\n\t},\n\t\"settingsAppearance\": \"รูปลักษณ์\",\n\t\"settingsDisplayTimezone\": \"โซนเวลาที่แสดง\",\n\t\"settingsGeneralSettings\": \"การตั้งค่าทั่วไป\",\n\t\"incidentsOptionsHeaderTotalIncidents\": \"จำนวนเหตุการณ์ทั้งหมด\",\n\t\"statusPage\": {\n\t\t\"deleteSuccess\": \"ลบหน้าสถานะสำเร็จ\",\n\t\t\"deleteFailed\": \"ลบหน้าสถานะล้มเหลว\",\n\t\t\"createSuccess\": \"สร้างหน้าสถานะสำเร็จ\",\n\t\t\"updateSuccess\": \"อัปเดตหน้าสถานะสำเร็จ\",\n\t\t\"generalSettings\": \"การตั้งค่าทั่วไป\",\n\t\t\"contents\": \"เนื้อหา\",\n\t\t\"fallback\": {\n\t\t\t\"checks\": [\n\t\t\t\t\"ตรวจสอบและแสดงสุขภาพของบริการแบบเรียลไทม์\",\n\t\t\t\t\"ติดตามหลายบริการและแชร์สถานะ\",\n\t\t\t\t\"แจ้งผู้ใช้ให้ทราบเกี่ยวกับการหยุดทำงานและประสิทธิภาพ\"\n\t\t\t],\n\t\t\t\"title\": \"หน้าสถานะใช้สำหรับ:\",\n\t\t\t\"actionButton\": \"มาสร้างหน้าสถานะแรกกันเถอะ!\"\n\t\t}\n\t},\n\t\"testNotificationsDisabled\": \"ยังไม่มีการตั้งค่าการแจ้งเตือนสำหรับมอนิเตอร์นี้ คุณต้องเพิ่มโดยคลิกปุ่ม 'ตั้งค่า'\",\n\t\"incidentsTableResolvedAt\": \"แก้ไขเมื่อ\",\n\t\"incidentsTableActionResolve\": \"แก้ไข\",\n\t\"checkHooks\": {\n\t\t\"failureResolveOne\": \"แก้ไขเหตุการณ์ล้มเหลว\",\n\t\t\"failureResolveAll\": \"แก้ไขเหตุการณ์ทั้งหมดล้มเหลว\",\n\t\t\"failureResolveMonitor\": \"ไม่สามารถแก้ไขเหตุการณ์ของตัวตรวจสอบได้\"\n\t},\n\t\"checkFormError\": \"กรุณาตรวจสอบแบบฟอร์มสำหรับข้อผิดพลาด\",\n\t\"diagnosticsPage\": {\n\t\t\"diagnosticDescription\": \"วินิจฉัยระบบ\",\n\t\t\"statsDescription\": \"สถิติระบบ\",\n\t\t\"gauges\": {\n\t\t\t\"heapAllocationTitle\": \"การจัดสรร Heap\",\n\t\t\t\"heapAllocationSubtitle\": \"% ของหน่วยความจำที่ใช้ได้\",\n\t\t\t\"heapUsageTitle\": \"การใช้งาน Heap\",\n\t\t\t\"heapUsageSubtitle\": \"% ของหน่วยความจำที่ใช้ได้\",\n\t\t\t\"heapUtilizationTitle\": \"การใช้งาน Heap\",\n\t\t\t\"heapUtilizationSubtitle\": \"% ของที่จัดสรรแล้ว\",\n\t\t\t\"instantCpuUsageTitle\": \"การใช้งาน CPU ทันที\",\n\t\t\t\"instantCpuUsageSubtitle\": \"% ของเวลา 1 วินาทีที่ CPU ใช้\"\n\t\t},\n\t\t\"stats\": {\n\t\t\t\"eventLoopDelayTitle\": \"ความล่าช้าวงจร Event Loop\",\n\t\t\t\"uptimeTitle\": \"เวลาทำงาน\",\n\t\t\t\"usedHeapSizeTitle\": \"ขนาดที่ใช้ Heap\",\n\t\t\t\"totalHeapSizeTitle\": \"รวมขนาด Heap\",\n\t\t\t\"osMemoryLimitTitle\": \"ขีดจำกัดหน่วยความจำ OS\"\n\t\t}\n\t},\n\t\"pageSpeedLighthouseAPI\": \"ใช้ Lighthouse PageSpeed API เพื่อตรวจสอบเว็บไซต์ของคุณ\",\n\t\"time\": {\n\t\t\"threeMinutes\": \"3 นาที\",\n\t\t\"fiveMinutes\": \"5 นาที\",\n\t\t\"tenMinutes\": \"10 นาที\",\n\t\t\"twentyMinutes\": \"20 นาที\",\n\t\t\"oneHour\": \"1 ชั่วโมง\",\n\t\t\"oneDay\": \"1 วัน\",\n\t\t\"oneWeek\": \"1 สัปดาห์\",\n\t\t\"fourMinutes\": \"4 นาที\",\n\t\t\"oneMinute\": \"1 นาที\",\n\t\t\"twoMinutes\": \"2 นาที\",\n\t\t\"fifteenSeconds\": \"15 วินาที\",\n\t\t\"thirtySeconds\": \"30 วินาที\"\n\t},\n\t\"general\": {\n\t\t\"noOptionsFound\": \"ไม่พบ {{unit}}\"\n\t},\n\t\"infrastructureMonitor\": {\n\t\t\"fallback\": {\n\t\t\t\"checks\": [\n\t\t\t\t\"ติดตามประสิทธิภาพของเซิร์ฟเวอร์ของคุณ\",\n\t\t\t\t\"ระบุจุดคอขวดและเพิ่มประสิทธิภาพการใช้งาน\",\n\t\t\t\t\"มั่นใจในความเสถียรด้วยการตรวจสอบแบบเรียลไทม์\"\n\t\t\t],\n\t\t\t\"title\": \"ตัวตรวจสอบโครงสร้างพื้นฐานใช้สำหรับ:\",\n\t\t\t\"actionButton\": \"มาสร้างตัวตรวจสอบโครงสร้างพื้นฐานตัวแรกกันเถอะ!\"\n\t\t}\n\t},\n\t\"maintenanceWindow\": {\n\t\t\"fallback\": {\n\t\t\t\"checks\": [\n\t\t\t\t\"กำหนดช่วงเวลาบำรุงรักษา\",\n\t\t\t\t\"ลดความเข้าใจผิด\",\n\t\t\t\t\"หยุดส่งการแจ้งเตือนในช่วงเวลาบำรุงรักษา\"\n\t\t\t],\n\t\t\t\"title\": \"ช่วงเวลาบำรุงรักษาใช้สำหรับ:\",\n\t\t\t\"actionButton\": \"มาสร้างช่วงเวลาบำรุงรักษาแรกกันเถอะ!\"\n\t\t}\n\t},\n\t\"pageSpeed\": {\n\t\t\"fallback\": {\n\t\t\t\"checks\": [\n\t\t\t\t\"รายงานเกี่ยวกับประสบการณ์ผู้ใช้ของหน้าเว็บ\",\n\t\t\t\t\"ช่วยวิเคราะห์ความเร็วของหน้าเว็บ\",\n\t\t\t\t\"ให้คำแนะนำในการปรับปรุงหน้าเว็บ\"\n\t\t\t],\n\t\t\t\"title\": \"ตัวตรวจสอบ PageSpeed ใช้สำหรับ:\",\n\t\t\t\"actionButton\": \"มาสร้างตัวตรวจสอบ PageSpeed ตัวแรกกันเถอะ!\"\n\t\t}\n\t},\n\t\"uptimeMonitor\": {\n\t\t\"fallback\": {\n\t\t\t\"checks\": [\n\t\t\t\t\"ตรวจสอบว่าเว็บไซต์หรือเซิร์ฟเวอร์ออนไลน์และตอบสนองหรือไม่\",\n\t\t\t\t\"แจ้งทีมเมื่อเกิดปัญหาการหยุดทำงานหรือประสิทธิภาพ\",\n\t\t\t\t\"ตรวจสอบ HTTP endpoints, ping, คอนเทนเนอร์ และพอร์ต\",\n\t\t\t\t\"ติดตามสถิติ uptime และความเสถียรย้อนหลัง\"\n\t\t\t],\n\t\t\t\"title\": \"ตัวตรวจสอบ Uptime ใช้สำหรับ:\",\n\t\t\t\"actionButton\": \"มาสร้างตัวตรวจสอบ Uptime ตัวแรกกันเถอะ!\"\n\t\t}\n\t},\n\t\"editUserPage\": {\n\t\t\"form\": {\n\t\t\t\"email\": \"อีเมล\",\n\t\t\t\"firstName\": \"ชื่อจริง\",\n\t\t\t\"lastName\": \"นามสกุล\",\n\t\t\t\"role\": \"บทบาท\",\n\t\t\t\"save\": \"บันทึก\"\n\t\t},\n\t\t\"table\": {\n\t\t\t\"actionHeader\": \"การดำเนินการ\",\n\t\t\t\"roleHeader\": \"บทบาท\"\n\t\t},\n\t\t\"title\": \"แก้ไขผู้ใช้\",\n\t\t\"toast\": {\n\t\t\t\"successUserUpdate\": \"อัปเดตผู้ใช้เรียบร้อยแล้ว\",\n\t\t\t\"validationErrors\": \"ข้อผิดพลาดในการตรวจสอบข้อมูล\"\n\t\t}\n\t},\n\t\"incidentsPageActionResolveMonitor\": \"แก้ไขเหตุการณ์ของตัวตรวจสอบ\",\n\t\"incidentsPageActionResolveAll\": \"แก้ไขเหตุการณ์ทั้งหมด\",\n\t\"matchMethodOptions\": {\n\t\t\"equal\": \"Equal\",\n\t\t\"equalPlaceholder\": \"success\",\n\t\t\"include\": \"Include\",\n\t\t\"includePlaceholder\": \"ok\",\n\t\t\"regex\": \"Regex\",\n\t\t\"regexPlaceholder\": \"^(success|ok)$\",\n\t\t\"text\": \"วิธีการจับคู่\"\n\t},\n\t\"monitorType\": {\n\t\t\"docker\": {\n\t\t\t\"label\": \"ชื่อ/ID คอนเทนเนอร์\",\n\t\t\t\"namePlaceholder\": \"คอนเทนเนอร์ของฉัน\",\n\t\t\t\"placeholder\": \"my-app or abcd1234\"\n\t\t},\n\t\t\"http\": {\n\t\t\t\"label\": \"URL ที่ต้องการตรวจสอบ\",\n\t\t\t\"namePlaceholder\": \"Google\",\n\t\t\t\"placeholder\": \"google.com\"\n\t\t},\n\t\t\"ping\": {\n\t\t\t\"label\": \"ที่อยู่ IP ที่ต้องการตรวจสอบ\",\n\t\t\t\"namePlaceholder\": \"Google\",\n\t\t\t\"placeholder\": \"1.1.1.1\"\n\t\t},\n\t\t\"port\": {\n\t\t\t\"label\": \"ที่อยู่ IP ที่ต้องการตรวจสอบ\",\n\t\t\t\"namePlaceholder\": \"Localhost:5173\",\n\t\t\t\"placeholder\": \"localhost\"\n\t\t},\n\t\t\"game\": {\n\t\t\t\"label\": \"URL ที่ต้องการมอนิเตอร์\",\n\t\t\t\"namePlaceholder\": \"localhost:5173\",\n\t\t\t\"placeholder\": \"localhost\"\n\t\t}\n\t},\n\t\"uptimeAdvancedMatching\": {\n\t\t\"jsonPath\": \"JSON Path\"\n\t},\n\t\"bytesPerSecond\": \"ไบต์ต่อวินาที\",\n\t\"bytesReceived\": \"ไบต์ที่รับ\",\n\t\"bytesSent\": \"ไบต์ที่ส่ง\",\n\t\"chooseGame\": \"เลือกเกม\",\n\t\"createMonitorPage\": {\n\t\t\"incidentConfigDescription\": \"การใช้หน้าต่างเลื่อนจะช่วยกำหนดเวลาที่ตัวตรวจสอบล้มเหลว สถานะของตัวตรวจสอบจะเปลี่ยนก็ต่อเมื่อเปอร์เซ็นต์ของการตรวจสอบในหน้าต่างเลื่อนตรงตามค่าที่กำหนด\",\n\t\t\"incidentConfigStatusWindowLabel\": \"ต้องมีการตรวจสอบกี่ครั้งในหน้าต่างเลื่อน?\",\n\t\t\"incidentConfigStatusWindowThresholdLabel\": \"ต้องการให้กี่เปอร์เซ็นต์ของการตรวจสอบในหน้าต่างเลื่อนล้มเหลว/สำเร็จ ก่อนที่จะเปลี่ยนสถานะของตัวตรวจสอบ?\",\n\t\t\"incidentConfigTitle\": \"เหตุการณ์\",\n\t\t\"incidentConfigDescriptionV2\": \"\",\n\t\t\"incidentConfigStatusCheckNumber\": \"\",\n\t\t\"intervalTitle\": \"\",\n\t\t\"intervalDescription\": \"\"\n\t},\n\t\"dataRate\": \"อัตราการส่งข้อมูล\",\n\t\"dataReceived\": \"ข้อมูลที่รับ\",\n\t\"dataSent\": \"ข้อมูลที่ส่ง\",\n\t\"details\": \"รายละเอียด\",\n\t\"drops\": \"แพ็กเก็ตที่หล่น\",\n\t\"errors\": \"ข้อผิดพลาด\",\n\t\"errorsIn\": \"ข้อผิดพลาดขาเข้า\",\n\t\"errorsOut\": \"ข้อผิดพลาดขาออก\",\n\t\"gameServerMonitoring\": \"มอนิเตอร์เซิร์ฟเวอร์เกม\",\n\t\"gameServerMonitoringDescription\": \"ตรวจสอบว่าเซิร์ฟเวอร์เกมของคุณกำลังทำงานอยู่หรือไม่\",\n\t\"network\": \"เน็ตเวอร์\",\n\t\"networkDrops\": \"การดรอปของเน็ตเวอร์\",\n\t\"networkErrors\": \"เน็ตเวอร์ ล้มเหลว\",\n\t\"networkInterface\": \"เน็ตเวอร์ อินเทอร์เฟซ\",\n\t\"noNetworkStatsAvailable\": \"ไม่มีสถิติของเน็ตเวอร์\",\n\t\"packetsPerSecond\": \"แพ็กเก็ตต่อวินาที\",\n\t\"packetsReceived\": \"แพ็กเก็ตที่รับ\",\n\t\"packetsReceivedRate\": \"อัตราการรับแพ็กเก็ต\",\n\t\"packetsSent\": \"แพ็กเก็ตที่ส่ง\",\n\t\"rate\": \"อัตรา\",\n\t\"selectInterface\": \"เลือกอินเทอร์เฟซ\",\n\t\"v1\": {\n\t\t\"infrastructure\": {\n\t\t\t\"disk_selection_title\": \"การเลือกดิสก์\",\n\t\t\t\"disk_selection_info\": \"ไม่พบดิสก์ในขณะนี้\",\n\t\t\t\"disk_selection_description\": \"เลือกดิสก์ที่คุณต้องการตรวจสอบ\"\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "client/src/locales/tr.json",
    "content": "{\n\t\"submit\": \"Gönder\",\n\t\"title\": \"Başlık\",\n\t\"distributedStatusHeaderText\": \"Gerçek zamanlı, Gerçek cihazlar kapsamı\",\n\t\"distributedStatusSubHeaderText\": \"Dünya çapında milyonlarca cihaz tarafından desteklenen sistem performansını küresel bölgeye, ülkeye veya şehre göre görüntüleyin\",\n\t\"settingsDisabled\": \"Devre dışı\",\n\t\"settingsSuccessSaved\": \"Ayarlar başarıyla kaydedildi\",\n\t\"settingsFailedToSave\": \"Ayarlar kaydedilemedi\",\n\t\"settingsStatsCleared\": \"İstatistikler başarıyla temizlendi\",\n\t\"settingsFailedToClearStats\": \"İstatistikler temizlenemedi\",\n\t\"settingsMonitorsDeleted\": \"Tüm monitörler başarıyla silindi\",\n\t\"settingsFailedToDeleteMonitors\": \"Monitörler silinemedi\",\n\t\"starPromptTitle\": \"Checkmate yıldızla değerlendirin\",\n\t\"starPromptDescription\": \"En son sürümleri görün ve GitHub'daki topluluğun büyümesine yardımcı olun\",\n\t\"https\": \"HTTPS\",\n\t\"http\": \"HTTP\",\n\t\"monitor\": \"monitör\",\n\t\"aboutus\": \"Hakkımızda\",\n\t\"now\": \"Şimdi\",\n\t\"delete\": \"Sil\",\n\t\"configure\": \"Yapılandır\",\n\t\"responseTime\": \"Yanıt süresi:\",\n\t\"ms\": \"ms\",\n\t\"bar\": \"Çubuk\",\n\t\"area\": \"Alan\",\n\t\"country\": \"ÜLKE\",\n\t\"city\": \"ŞEHİR\",\n\t\"response\": \"YANIT\",\n\t\"monitorStatusUp\": \"Monitör {name} ({url}) ayakta ve yanıt veriyor\",\n\t\"monitorStatusDown\": \"Monitör {name} ({url}) yanıt vermiyor\",\n\t\"webhookSendSuccess\": \"Web kanca bildirimi başarıyla gönderildi\",\n\t\"webhookSendError\": \"Web kanca bildirimi bu platforma gönderilemedi: {platform}\",\n\t\"webhookUnsupportedPlatform\": \"Desteklenmeyen platform: {platform}\",\n\t\"distributedRightCategoryTitle\": \"Monitör\",\n\t\"distributedStatusServerMonitors\": \"Sunucu monitörleri\",\n\t\"distributedStatusServerMonitorsDescription\": \"İlgili sunucuların monitör durumları\",\n\t\"distributedUptimeCreateSelectURL\": \"Burada sunucu adresini (URL) ve monitör türünü girebilirsiniz.\",\n\t\"distributedUptimeCreateChecks\": \"Yapılacak kontroller\",\n\t\"distributedUptimeCreateChecksDescription\": \"Adresi girdikten sonra kontrol ekleyebilir ya da çıkartabilirsiniz.\",\n\t\"distributedUptimeCreateIncidentNotification\": \"Olay bildirimleri\",\n\t\"distributedUptimeCreateIncidentDescription\": \"Bir olay olduğunda kullanıcıları bilgilendir.\",\n\t\"distributedUptimeCreateAdvancedSettings\": \"Gelişmiş ayarlar\",\n\t\"distributedUptimeDetailsNoMonitorHistory\": \"Bu monitör için henüz bir denetim günlüğü oluşturulmadı.\",\n\t\"distributedUptimeDetailsStatusHeaderUptime\": \"Erişilebilirlik\",\n\t\"distributedUptimeDetailsStatusHeaderLastUpdate\": \"Son güncelleme\",\n\t\"notifications\": {\n\t\t\"enableNotifications\": \"{{platform}} bildirimlerini etkinleştir\",\n\t\t\"testNotification\": \"Bildirimi test et\",\n\t\t\"addOrEditNotifications\": \"Bildirimleri ekle ya da düzenle\",\n\t\t\"slack\": {\n\t\t\t\"label\": \"Slack\",\n\t\t\t\"description\": \"Slack bildirimlerini etkinleştirmek için bir Slack uygulaması oluşturun ve gelen web kancalarını etkinleştirin. Daha sonra, webhook URL’sini buraya girmeniz yeterlidir.\\n\\n\\n\\n\\n\\n\",\n\t\t\t\"webhookLabel\": \"Web kanca URL:\",\n\t\t\t\"webhookPlaceholder\": \"https://hooks.slack.com/services/...\",\n\t\t\t\"webhookRequired\": \"Slack webhook URL'si gereklidir\"\n\t\t},\n\t\t\"discord\": {\n\t\t\t\"label\": \"Discord\",\n\t\t\t\"description\": \"Checkmate’ten Discord bildirimleri aracılığıyla bir Discord kanalına veri göndermek için Discord’un gelen web kancaları özelliğini kullanabilirsiniz.\\n\\n\\n\\n\\n\\n\\n\\n\",\n\t\t\t\"webhookLabel\": \"Discord web kanca URL\",\n\t\t\t\"webhookPlaceholder\": \"https://discord.com/api/webhooks/...\",\n\t\t\t\"webhookRequired\": \"Discord webhook URL'si gerekli\"\n\t\t},\n\t\t\"telegram\": {\n\t\t\t\"label\": \"Telegram\",\n\t\t\t\"description\": \"Telegram bildirimlerini etkinleştirmek için, Telegram botlarını oluşturup yönetmek için kullanılan resmi bot BotFather ile bir Telegram botu oluşturun. Daha sonra, API jetonunu (token) ve sohbet kimliğini (chat ID) alın ve buraya yazın.\",\n\t\t\t\"tokenLabel\": \"Bot jetonu (token)\",\n\t\t\t\"tokenPlaceholder\": \"123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11\",\n\t\t\t\"chatIdLabel\": \"Sohbet ID\",\n\t\t\t\"chatIdPlaceholder\": \"-1001234567890\",\n\t\t\t\"fieldsRequired\": \"Telegram token ve sohbet kimliği gereklidir\"\n\t\t},\n\t\t\"webhook\": {\n\t\t\t\"label\": \"Web kancaları\",\n\t\t\t\"description\": \"Olaylar meydana geldiğinde bildirim almak için özel bir web kancası ayarlayabilirsiniz.\",\n\t\t\t\"urlLabel\": \"Web kanca URL:\",\n\t\t\t\"urlPlaceholder\": \"https://sunucu-adresiniz.com/webhook\",\n\t\t\t\"urlRequired\": \"Webhook URL'si gerekli\"\n\t\t},\n\t\t\"testNotificationDevelop\": \"Test bildirimi 2\",\n\t\t\"integrationButton\": \"Bildirim Entegrasyonu\",\n\t\t\"testSuccess\": \"Test bildirimi başarıyla gönderildi\",\n\t\t\"testFailed\": \"Test bildirimi gönderilemedi\",\n\t\t\"unsupportedType\": \"Desteklenmeyen bildirim türü\",\n\t\t\"networkError\": \"Ağ hatası oluştu\",\n\t\t\"fallback\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"checks\": [\"\"],\n\t\t\t\"actionButton\": \"\"\n\t\t},\n\t\t\"createButton\": \"Bildirim kanalı oluştur\",\n\t\t\"createTitle\": \"Bildirim kanalı\",\n\t\t\"create\": {\n\t\t\t\"success\": \"\",\n\t\t\t\"failed\": \"Bildirim kanalı oluşturulamadı\"\n\t\t},\n\t\t\"fetch\": {\n\t\t\t\"success\": \"Bildirimler başarıyla alındı\",\n\t\t\t\"failed\": \"Bildirimler alınamadı\"\n\t\t},\n\t\t\"delete\": {\n\t\t\t\"success\": \"Bildirim başarıyla silindi\",\n\t\t\t\"failed\": \"Bildirim silinemedi\"\n\t\t},\n\t\t\"edit\": {\n\t\t\t\"success\": \"Bildirim başarıyla güncellendi\",\n\t\t\t\"failed\": \"Bildirim güncellenemedi\"\n\t\t},\n\t\t\"test\": {\n\t\t\t\"success\": \"Test bildirimi başarıyla gönderildi\",\n\t\t\t\"failed\": \"\"\n\t\t}\n\t},\n\t\"testLocale\": \"TEST13 UPLOAD\",\n\t\"add\": \"Ekle\",\n\t\"monitors\": \"Monitörler\",\n\t\"distributedUptimeStatusCreateStatusPage\": \"durum sayfası\",\n\t\"distributedUptimeStatusCreateStatusPageAccess\": \"Erişim\",\n\t\"distributedUptimeStatusCreateStatusPageReady\": \"Durum sayfanız hazırsa yayınlayabilirsiniz.\",\n\t\"distributedUptimeStatusBasicInfoHeader\": \"Temel bilgiler\",\n\t\"distributedUptimeStatusBasicInfoDescription\": \"Şirket adınızı ve durum sayfanızın işaret ettiği alt alan adını tanımlayın.\",\n\t\"distributedUptimeStatusLogoHeader\": \"Logo\",\n\t\"distributedUptimeStatusLogoDescription\": \"Durum sayfanız için bir logo yükleyin\",\n\t\"distributedUptimeStatusLogoUploadButton\": \"Logo yükle\",\n\t\"distributedUptimeStatusStandardMonitorsHeader\": \"Standart monitörler\",\n\t\"distributedUptimeStatusStandardMonitorsDescription\": \"Durum sayfanıza standart monitörleri ekleyin.\",\n\t\"distributedUptimeStatusCreateYour\": \"Oluştur:\",\n\t\"distributedUptimeStatusEditYour\": \"Düzenle:\",\n\t\"distributedUptimeStatusPublishedLabel\": \"Yayında ve herkes tarafından görülebilir\",\n\t\"distributedUptimeStatusCompanyNameLabel\": \"Şirket adı\",\n\t\"distributedUptimeStatusPageAddressLabel\": \"Durum sayfası adresi\",\n\t\"distributedUptimeStatus30Days\": \"30 gün\",\n\t\"distributedUptimeStatus60Days\": \"60 gün\",\n\t\"distributedUptimeStatus90Days\": \"90 gün\",\n\t\"distributedUptimeStatusPageNotSetUp\": \"Henüz bir durum sayfası oluşturulmadı.\",\n\t\"distributedUptimeStatusContactAdmin\": \"Lütfen yöneticiniz ile görüşün\",\n\t\"distributedUptimeStatusPageNotPublic\": \"Bu durum sayfası herkese açık değil\",\n\t\"distributedUptimeStatusPageDeleteDialog\": \"Bu durum sayfasını silmek istiyor musunuz? \",\n\t\"distributedUptimeStatusPageDeleteConfirm\": \"Evet, durum sayfasını sil\",\n\t\"distributedUptimeStatusPageDeleteDescription\": \"Silindiği zaman durum sayfalarını geri getiremezsiniz.\",\n\t\"distributedUptimeStatusDevices\": \"Cihazlar\",\n\t\"distributedUptimeStatusUpt\": \"UPT\",\n\t\"distributedUptimeStatusUptBurned\": \"Yakılan UPT\",\n\t\"distributedUptimeStatusUptLogo\": \"Upt Logo\",\n\t\"incidentsTableNoIncidents\": \"Hiç olay kaydedilmedi\",\n\t\"incidentsTablePaginationLabel\": \"olaylar\",\n\t\"incidentsTableMonitorName\": \"Monitör adı\",\n\t\"incidentsTableStatus\": \"Durum\",\n\t\"incidentsTableDateTime\": \"Tarih ve saat\",\n\t\"incidentsTableStatusCode\": \"Durum kodu\",\n\t\"incidentsTableMessage\": \"Mesaj\",\n\t\"incidentsOptionsHeader\": \"Servisler:\",\n\t\"incidentsOptionsHeaderFilterBy\": \"Filtrele:\",\n\t\"incidentsOptionsHeaderFilterAll\": \"Tümü\",\n\t\"incidentsOptionsHeaderFilterDown\": \"Erişilemiyor\",\n\t\"incidentsOptionsHeaderFilterCannotResolve\": \"Çözümlenemiyor\",\n\t\"incidentsOptionsHeaderShow\": \"Göster:\",\n\t\"incidentsOptionsHeaderLastHour\": \"Son saat\",\n\t\"incidentsOptionsHeaderLastDay\": \"Son gün\",\n\t\"incidentsOptionsHeaderLastWeek\": \"Son hafta\",\n\t\"incidentsOptionsPlaceholderAllServers\": \"Tüm sunucular\",\n\t\"infrastructureCreateYour\": \"Oluştur:\",\n\t\"infrastructureCreateGeneralSettingsDescription\": \"Burada, sunucu aracısına bağlanmak için kolay ad ve yetkilendirme sırrıyla birlikte ana bilgisayarın URL'sini seçebilirsiniz.\",\n\t\"infrastructureServerRequirement\": \"İzlediğiniz sunucunun şu şekilde çalışması gerekir:\",\n\t\"infrastructureCustomizeAlerts\": \"Alarmları özelleştir\",\n\t\"infrastructureAlertNotificationDescription\": \"Eşikler belirtilen bir yüzdeyi aştığında kullanıcıya bildirim gönder.\",\n\t\"infrastructureCreateMonitor\": \"Altyapı Monitörü oluştur\",\n\t\"infrastructureProtocol\": \"Protokol\",\n\t\"infrastructureServerUrlLabel\": \"Sunucu adresi\",\n\t\"infrastructureDisplayNameLabel\": \"Görünen adı\",\n\t\"infrastructureAuthorizationSecretLabel\": \"Kimlik denetimi parolası\",\n\t\"gb\": \"GB\",\n\t\"mb\": \"MB\",\n\t\"mem\": \"Bellek\",\n\t\"memoryUsage\": \"Bellek kullanımı\",\n\t\"cpu\": \"CPU\",\n\t\"cpuUsage\": \"CPU kullanımı\",\n\t\"cpuTemperature\": \"CPU sıcaklığı\",\n\t\"diskUsage\": \"Disk kullanımı\",\n\t\"used\": \"Kullanılan\",\n\t\"total\": \"Toplam\",\n\t\"cores\": \"Çekirdek\",\n\t\"frequency\": \"Frekans\",\n\t\"status\": \"Durum\",\n\t\"cpuPhysical\": \"CPU (fiziksel)\",\n\t\"cpuLogical\": \"CPU (Mantıksal)\",\n\t\"cpuFrequency\": \"CPU Frekansı\",\n\t\"avgCpuTemperature\": \"Ortalama CPU Isısı\",\n\t\"memory\": \"Bellek\",\n\t\"disk\": \"Disk\",\n\t\"uptime\": \"Çalışma süresi\",\n\t\"os\": \"İşletim sistemi\",\n\t\"host\": \"Makine\",\n\t\"actions\": \"İşlemler\",\n\t\"integrations\": \"Entegrasyonlar\",\n\t\"integrationsPrism\": \"Prism'i favori servisinize bağlayın.\",\n\t\"integrationsSlack\": \"Slack\",\n\t\"integrationsSlackInfo\": \"Slack'e bağlanın ve bir kanaldaki olayları görün\",\n\t\"integrationsDiscord\": \"Discord\",\n\t\"integrationsDiscordInfo\": \"Discord'a bağlanın ve olayları doğrudan bir kanalda görüntüleyin\",\n\t\"integrationsZapier\": \"Zapier\",\n\t\"integrationsZapierInfo\": \"Tüm olayları Zapier'a gönderin ve sonra her yerde görün\",\n\t\"commonSave\": \"Kaydet\",\n\t\"createYour\": \"Senin yarat\",\n\t\"createMonitor\": \"Monitör oluştur\",\n\t\"pause\": \"Beklet\",\n\t\"resume\": \"Yeniden başlat\",\n\t\"editing\": \"Düzenleniyor...\",\n\t\"url\": \"URL\",\n\t\"access\": \"Erişim\",\n\t\"timezone\": \"Zaman dilimi\",\n\t\"features\": \"Özellikler\",\n\t\"administrator\": \"Yönetici misin?\",\n\t\"loginHere\": \"Buradan giriş yap\",\n\t\"displayName\": \"Görüntülenecek isim\",\n\t\"urlMonitor\": \"Monitör edilecek URL\",\n\t\"portToMonitor\": \"Monitör edilecek port\",\n\t\"websiteMonitoring\": \"Web sitesi monitörü\",\n\t\"websiteMonitoringDescription\": \"Web sitenizi veya API uç noktanızı izlemek için HTTP(s) kullanın.\",\n\t\"pingMonitoring\": \"Ping monitörü\",\n\t\"pingMonitoringDescription\": \"Sitenizin ayakta olup olmadığını denetleyin.\",\n\t\"dockerContainerMonitoring\": \"Docker konteyner monitörü\",\n\t\"dockerContainerMonitoringDescription\": \"Docker konteynerinizin ayakta olup olmadığını denetleyin.\",\n\t\"portMonitoring\": \"Port monitörü\",\n\t\"portMonitoringDescription\": \"Portunuzun açık olup olmadığını denetleyin.\",\n\t\"createMaintenanceWindow\": \"Bakım aralığı oluşturun\",\n\t\"createMaintenance\": \"Bakım oluştur\",\n\t\"editMaintenance\": \"Bakımı düzenle\",\n\t\"maintenanceWindowName\": \"Bakım aralığı adı\",\n\t\"friendlyNameInput\": \"Görünen ad\",\n\t\"friendlyNamePlaceholder\": \"__:__ saatinde __ dakika boyunca bakım var\",\n\t\"maintenanceRepeat\": \"Bakım Tekrarı\",\n\t\"maintenance\": \"bakım\",\n\t\"duration\": \"Süre\",\n\t\"addMonitors\": \"Monitör ekle\",\n\t\"window\": \"pencere\",\n\t\"cancel\": \"İptal\",\n\t\"message\": \"Mesaj\",\n\t\"low\": \"düşük\",\n\t\"high\": \"yüksek\",\n\t\"statusCode\": \"Durum kodu\",\n\t\"date&Time\": \"Tarih & saat\",\n\t\"type\": \"Tür\",\n\t\"statusPageName\": \"Durum sayfası adı\",\n\t\"publicURL\": \"Genel URL\",\n\t\"repeat\": \"Tekrarla\",\n\t\"edit\": \"Düzenle\",\n\t\"createA\": \"Bir tane oluştur\",\n\t\"remove\": \"Kaldırmak\",\n\t\"maintenanceWindowDescription\": \"Bu zaman diliminde pingleriniz gönderilmeyecek\",\n\t\"startTime\": \"Başlangıç saati\",\n\t\"timeZoneInfo\": \"Tüm tarihler ve saatler GMT+0 zaman dilimindedir.\",\n\t\"monitorsToApply\": \"Bakım penceresini uygulamak için monitörler\",\n\t\"nextWindow\": \"Sonraki pencere\",\n\t\"notFoundButton\": \"Ana panoya git\",\n\t\"pageSpeedConfigureSettingsDescription\": \"Burada, monitör tipiyle birlikte sunucunun URL'sini seçebilirsiniz.\",\n\t\"monitorDisplayName\": \"Monitör görüntüleme adı\",\n\t\"whenNewIncident\": \"Yeni bir olay oluştuğunda,\",\n\t\"notifySMS\": \"SMS ile bildir (yakında)\",\n\t\"notifyEmails\": \"Ayrıca birden fazla eposta adresine bildirim gönderebilirsiniz (yakında geliyor)\",\n\t\"seperateEmails\": \"Birden fazla epostayı virgülle ayırabilirsiniz\",\n\t\"checkFrequency\": \"Frekansı denetle\",\n\t\"matchMethod\": \"Eşleşme yöntemi\",\n\t\"expectedValue\": \"Beklenen değer\",\n\t\"deleteDialogTitle\": \"Gerçekten bu monitörü silmek istiyor musunuz?\",\n\t\"deleteDialogDescription\": \"Bir kez silindiği zaman tekrar getiremezsiniz.\",\n\t\"pageSpeedMonitor\": \"Sayfa Hızı Monitörü\",\n\t\"shown\": \"Gösteriliyor: \",\n\t\"ago\": \"önce\",\n\t\"companyName\": \"Firma adı\",\n\t\"pageSpeedDetailsPerformanceReport\": \"Değerler yaklaşıktır ve değişebilir\",\n\t\"pageSpeedDetailsPerformanceReportCalculator\": \"Hesap makinesini gör\",\n\t\"checkingEvery\": \"Denetleme sıklığı\",\n\t\"statusPageCreateSettings\": \"Eğer durum sayfanız hazırsa, herkese açık yayınlayabilirsiniz\",\n\t\"basicInformation\": \"Temel Bilgiler\",\n\t\"statusPageCreateBasicInfoDescription\": \"Şirket adınızı ve durum sayfanızın işaret ettiği alt alan adını tanımlayın.\",\n\t\"statusPageCreateSelectTimeZoneDescription\": \"Durum sayfanızın hangi zaman diliminde görüntüleneceğini seçin.\",\n\t\"statusPageCreateAppearanceDescription\": \"Genel durum sayfanızın varsayılan görünümünü ve hissini tanımlayın.\",\n\t\"statusPageCreateSettingsCheckboxLabel\": \"Yayınlandı ve herkese açık\",\n\t\"statusPageCreateBasicInfoStatusPageAddress\": \"Durum sayfası adresiniz\",\n\t\"statusPageCreateTabsContent\": \"Durum sayfası sunucuları\",\n\t\"statusPageCreateTabsContentDescription\": \"İzlediğiniz herhangi bir sayıda sunucuyu durum sayfanıza ekleyebilirsiniz. Ayrıca en iyi görüntüleme deneyimi için bunları yeniden sıralayabilirsiniz.\",\n\t\"statusPageCreateTabsContentFeaturesDescription\": \"Durum sayfasında daha fazla bilgi göster\",\n\t\"showCharts\": \"Çizelgeleri göster\",\n\t\"showUptimePercentage\": \"Çalışma süresi yüzdesini göster\",\n\t\"removeLogo\": \"Logoyu sil\",\n\t\"statusPageStatus\": \"Herkese açık bir durum sayfası henüz oluşturulmadı.\",\n\t\"statusPageStatusContactAdmin\": \"Lütfen yöneticinizle iletişime geçin.\",\n\t\"statusPageStatusNotPublic\": \"Durum sayfası herkese açık değil.\",\n\t\"statusPageStatusNoPage\": \"Burada bir durum sayfası bulunmuyor.\",\n\t\"statusPageStatusServiceStatus\": \"Servis durumu\",\n\t\"deleteStatusPage\": \"Gerçekten bu durum sayfasını silmek istiyor musunuz?\",\n\t\"deleteStatusPageConfirm\": \"Evet, durum sayfasını sil\",\n\t\"deleteStatusPageDescription\": \"Silindikten sonra durum sayfasını geri getiremezsiniz.\",\n\t\"uptimeCreate\": \"Beklenen değer, yanıt sonucuyla eşleştirilir ve bu eşleşme durumu belirler.\",\n\t\"uptimeCreateJsonPath\": \"Bu ifade, yanıt JSON verisi üzerinde değerlendirilir, ortaya çıkan sonuç beklenen değerle karşılaştırılır. Bkz:\",\n\t\"uptimeCreateJsonPathQuery\": \"Sorgu dili dokümantasyonu için.\",\n\t\"maintenanceTableActionMenuDialogTitle\": \"Gerçekten bu bakım aralığını silmek istiyor musunuz?\",\n\t\"infrastructureEditYour\": \"Düzenle\",\n\t\"infrastructureEditMonitor\": \"Altyapı İzlemeyi Kaydet\",\n\t\"infrastructureMonitorCreated\": \"Altyapı izleyicisi başarıyla oluşturuldu!\",\n\t\"infrastructureMonitorUpdated\": \"Altyapı izleyicisi başarıyla güncellendi!\",\n\t\"errorInvalidTypeId\": \"Geçersiz bildirim türü sağlandı\",\n\t\"errorInvalidFieldId\": \"Geçersiz alan kimliği sağlandı\",\n\t\"inviteNoTokenFound\": \"Davet belirteci bulunamadı\",\n\t\"pageSpeedWarning\": \"Uyarı: Henüz bir Google PageSpeed API anahtarı eklemediniz. Bu olmadan PageSpeed izleyicisi çalışmayacaktır.\",\n\t\"pageSpeedLearnMoreLink\": \"Buraya tıklayın\",\n\t\"pageSpeedAddApiKey\": \"(API anahtarınızı eklemek için)\",\n\t\"update\": \"Güncelleme\",\n\t\"invalidFileFormat\": \"Desteklenmeyen dosya biçimi!\",\n\t\"invalidFileSize\": \"Dosya boyutu çok büyük!\",\n\t\"ClickUpload\": \"Yüklemek için tıklayın\",\n\t\"DragandDrop\": \"sürükle ve bırak\",\n\t\"MaxSize\": \"Azami Boyut\",\n\t\"SupportedFormats\": \"Desteklenen formatlar\",\n\t\"FirstName\": \"İsim\",\n\t\"LastName\": \"Soyisim\",\n\t\"EmailDescriptionText\": \"Geçerli epostanız - bu eposta değiştirilemez.\",\n\t\"YourPhoto\": \"Profil fotoğrafı\",\n\t\"PhotoDescriptionText\": \"Bu fotoğrafınız profil sayfasında görüntülenecektir.\",\n\t\"save\": \"Kaydet\",\n\t\"DeleteDescriptionText\": \"Bu, hesabı ve ilişkili tüm verileri sunucudan kaldıracaktır. Bu geri alınamaz.\",\n\t\"DeleteAccountWarning\": \"Hesabınızı kaldırmanız, tekrar oturum açamayacağınız ve tüm verilerinizin silineceği anlamına gelir. Bu geri alınamaz.\",\n\t\"DeleteWarningTitle\": \"Gerçekten bu hesabı silmek istiyor musunuz?\",\n\t\"bulkImport\": {\n\t\t\"title\": \"Toplu içeri alma\",\n\t\t\"selectFileTips\": \"Yüklenecek CSV dosyasını seçin\",\n\t\t\"selectFileDescription\": \"<template>Şablonumuzu</template> veya <sample>örneğimizi</sample> indirebilirsiniz\",\n\t\t\"selectFile\": \"Dosyayı seçin\",\n\t\t\"parsingFailed\": \"Ayrıştırma başarısız oldu\",\n\t\t\"uploadSuccess\": \"Monitör başarıyla oluşturuldu!\",\n\t\t\"validationFailed\": \"Doğrulama başarısız oldu\",\n\t\t\"noFileSelected\": \"Hiçbir dosya seçilmedi\",\n\t\t\"fallbackPage\": \"Toplu olarak sunucu listesini yüklemek için bir dosyayı içe aktarın\",\n\t\t\"invalidFileType\": \"\",\n\t\t\"uploadFailed\": \"\"\n\t},\n\t\"DeleteAccountTitle\": \"Hesabı sil\",\n\t\"DeleteAccountButton\": \"Hesabı sil\",\n\t\"publicLink\": \"Herkese açık bağlantı\",\n\t\"maskedPageSpeedKeyPlaceholder\": \"*************************************\",\n\t\"reset\": \"Sıfırla\",\n\t\"ignoreTLSError\": \"TLS/SSL hatalarını gözardı et\",\n\t\"tlsErrorIgnored\": \"TLS/SSL hataları gözardı ediliyor\",\n\t\"ignoreTLSErrorDescription\": \"TLS/SSL hatalarını gözardı et ve websitesinin ayakta olduğunu denetle\",\n\t\"createNew\": \"Yeni oluştur\",\n\t\"greeting\": {\n\t\t\"prepend\": \"Merhaba\",\n\t\t\"append\": \"Öğleden sonra muhteşem geçsin!\",\n\t\t\"overview\": \"\"\n\t},\n\t\"roles\": {\n\t\t\"superAdmin\": \"Süper yönetici\",\n\t\t\"admin\": \"Yönetici\",\n\t\t\"teamMember\": \"Ekip elemanı\",\n\t\t\"demoUser\": \"Demo kullanıcısı\"\n\t},\n\t\"teamPanel\": {\n\t\t\"teamMembers\": \"Ekip elemanları\",\n\t\t\"filter\": {\n\t\t\t\"all\": \"Tümü\",\n\t\t\t\"member\": \"Eleman\"\n\t\t},\n\t\t\"inviteTeamMember\": \"Ekip elemanı davet et\",\n\t\t\"inviteNewTeamMember\": \"Yeni ekip elemanı davet et\",\n\t\t\"inviteDescription\": \"\",\n\t\t\"email\": \"Eposta\",\n\t\t\"selectRole\": \"Rolü seçin\",\n\t\t\"inviteLink\": \"Davet linki\",\n\t\t\"cancel\": \"İptal\",\n\t\t\"noMembers\": \"Bu role sahip hiç üye yok\",\n\t\t\"getToken\": \"\",\n\t\t\"emailToken\": \"\",\n\t\t\"table\": {\n\t\t\t\"name\": \"İsim\",\n\t\t\t\"email\": \"Eposta\",\n\t\t\t\"role\": \"Rol\",\n\t\t\t\"created\": \"Oluşturulma\"\n\t\t},\n\t\t\"addTeamMember\": {\n\t\t\t\"addMemberMenu\": \"\",\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"addButton\": \"\"\n\t\t},\n\t\t\"register\": \"\",\n\t\t\"registerToast\": {\n\t\t\t\"success\": \"\",\n\t\t\t\"dbUserExists\": \"\",\n\t\t\t\"unknownError\": \"\"\n\t\t},\n\t\t\"registerTeamMember\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"auth\": {\n\t\t\t\t\"common\": {\n\t\t\t\t\t\"inputs\": {\n\t\t\t\t\t\t\"firstName\": {\n\t\t\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\t\t\"empty\": \"\",\n\t\t\t\t\t\t\t\t\"pattern\": \"\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"lastName\": {\n\t\t\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\t\t\"empty\": \"\",\n\t\t\t\t\t\t\t\t\"pattern\": \"\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"email\": {\n\t\t\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\t\t\"empty\": \"\",\n\t\t\t\t\t\t\t\t\"invalid\": \"\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"role\": {\n\t\t\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\t\t\"empty\": \"\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"role\": \"\",\n\t\t\"changeTeamPassword\": {\n\t\t\t\"changePasswordMenu\": \"\",\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"success\": \"\"\n\t\t}\n\t},\n\t\"monitorState\": {\n\t\t\"paused\": \"Durduruldu\",\n\t\t\"resumed\": \"Yeniden başlatıldı\",\n\t\t\"active\": \"Aktif\"\n\t},\n\t\"menu\": {\n\t\t\"uptime\": \"\",\n\t\t\"pagespeed\": \"Sayfa hızı\",\n\t\t\"infrastructure\": \"\",\n\t\t\"incidents\": \"Olaylar\",\n\t\t\"statusPages\": \"Durum sayfaları\",\n\t\t\"maintenance\": \"Bakım\",\n\t\t\"integrations\": \"Entegrasyonlar\",\n\t\t\"settings\": \"Ayarlar\",\n\t\t\"support\": \"Destek\",\n\t\t\"discussions\": \"Soru-cevap\",\n\t\t\"docs\": \"Dokümanlar\",\n\t\t\"changelog\": \"Değişiklik günlüğü\",\n\t\t\"profile\": \"Profil\",\n\t\t\"password\": \"Parola\",\n\t\t\"team\": \"Ekip\",\n\t\t\"logOut\": \"Çıkış yap\",\n\t\t\"notifications\": \"Bildirimler\",\n\t\t\"logs\": \"Günlükler\"\n\t},\n\t\"settingsEmailUser\": \"E-posta kullanıcısı – Kimlik doğrulama için kullanıcı adı; belirtilirse e-posta adresinin yerine geçer.\",\n\t\"state\": \"Durum\",\n\t\"statusBreadCrumbsStatusPages\": \"Durum sayfası\",\n\t\"statusBreadCrumbsDetails\": \"Detaylar\",\n\t\"commonSaving\": \"Kaydediliyor.\",\n\t\"navControls\": \"Kontroller\",\n\t\"incidentsPageTitle\": \"Olaylar\",\n\t\"passwordPanel\": {\n\t\t\"passwordChangedSuccess\": \"Şifreniz başarı ile değiştirildi.\",\n\t\t\"passwordInputIncorrect\": \"Şifreniz hatalı\",\n\t\t\"currentPassword\": \"Mevcut parola\",\n\t\t\"enterCurrentPassword\": \"Mevcut parolanızı girin\",\n\t\t\"newPassword\": \"Yeni parola\",\n\t\t\"enterNewPassword\": \"Yeni parolanızı girin\",\n\t\t\"confirmNewPassword\": \"Yeni şifrenizi onaylayın\",\n\t\t\"passwordRequirements\": \"Yeni şifreniz en az 8 karakterden oluşmalı ve en az bir büyük harf, bir küçük harf, bir rakam ve bir özel karakter içermelidir.\",\n\t\t\"saving\": \"Kaydediliyor...\"\n\t},\n\t\"emailSent\": \"E-posta başarı ile gönderildi.\",\n\t\"failedToSendEmail\": \"E-posta gönderimi başarısız.\",\n\t\"settingsTestEmailSuccess\": \"Test E-postası başarı ile gönderildi.\",\n\t\"settingsTestEmailFailed\": \"Test E-postası gönderimi başarısız.\",\n\t\"settingsTestEmailFailedWithReason\": \"Test E-postası gönderimi başarısız: {{reason}}\",\n\t\"settingsTestEmailUnknownError\": \"Bilinmeyen hata.\",\n\t\"statusMsg\": {\n\t\t\"paused\": \"İzleme duraklatıldı.\",\n\t\t\"up\": \"Siteniz yayında.\",\n\t\t\"down\": \"Siteniz kapalı.\",\n\t\t\"pending\": \"Sırada..\"\n\t},\n\t\"uptimeGeneralInstructions\": {\n\t\t\"http\": \"\",\n\t\t\"ping\": \"\",\n\t\t\"docker\": \"\",\n\t\t\"port\": \"\",\n\t\t\"game\": \"\",\n\t\t\"https\": \"\"\n\t},\n\t\"common\": {\n\t\t\"appName\": \"Checkmate\",\n\t\t\"monitoringAgentName\": \"\",\n\t\t\"buttons\": {\n\t\t\t\"toggleTheme\": \"\"\n\t\t},\n\t\t\"toasts\": {\n\t\t\t\"networkError\": \"\",\n\t\t\t\"checkConnection\": \"Lütfen bağlantınızı kontrol edin\",\n\t\t\t\"unknownError\": \"Bilinmeyen hata\"\n\t\t}\n\t},\n\t\"auth\": {\n\t\t\"common\": {\n\t\t\t\"navigation\": {\n\t\t\t\t\"continue\": \"Devam et\",\n\t\t\t\t\"back\": \"Geri\"\n\t\t\t},\n\t\t\t\"inputs\": {\n\t\t\t\t\"email\": {\n\t\t\t\t\t\"label\": \"Eposta\",\n\t\t\t\t\t\"placeholder\": \"\",\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"Devam etmek için eposta adresinizi girin\",\n\t\t\t\t\t\t\"invalid\": \"\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"password\": {\n\t\t\t\t\t\"label\": \"Parola\",\n\t\t\t\t\t\"rules\": {\n\t\t\t\t\t\t\"length\": {\n\t\t\t\t\t\t\t\"beginning\": \"\",\n\t\t\t\t\t\t\t\"highlighted\": \"8 karakter uzunluğunda\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"special\": {\n\t\t\t\t\t\t\t\"beginning\": \"En az içermelidir: \",\n\t\t\t\t\t\t\t\"highlighted\": \"bir özel karakter\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"number\": {\n\t\t\t\t\t\t\t\"beginning\": \"En az içermelidir: \",\n\t\t\t\t\t\t\t\"highlighted\": \"bir sayı\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"uppercase\": {\n\t\t\t\t\t\t\t\"beginning\": \"En az içermelidir: \",\n\t\t\t\t\t\t\t\"highlighted\": \"Bir büyük harf\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"lowercase\": {\n\t\t\t\t\t\t\t\"beginning\": \"En az içermelidir: \",\n\t\t\t\t\t\t\t\"highlighted\": \"Bir küçük harf\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"match\": {\n\t\t\t\t\t\t\t\"beginning\": \"\",\n\t\t\t\t\t\t\t\"highlighted\": \"eşleşmelidir\"\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"Lütfen parolanızı girin\",\n\t\t\t\t\t\t\"length\": \"Parolanız en az 8 karakter uzunluğunda olmalıdır\",\n\t\t\t\t\t\t\"uppercase\": \"Parola en az 1 büyük harf içermelidir\",\n\t\t\t\t\t\t\"lowercase\": \"Parola en az 1 küçük harf içermelidir\",\n\t\t\t\t\t\t\"number\": \"Parola en az 1 sayı içermelidir\",\n\t\t\t\t\t\t\"special\": \"Parola en az 1 özel karakter içermelidir\",\n\t\t\t\t\t\t\"incorrect\": \"Parolanız sistemdeki ile uyuşmuyor\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"passwordConfirm\": {\n\t\t\t\t\t\"label\": \"Parolayı onayla\",\n\t\t\t\t\t\"placeholder\": \"Onaylamak için parolayı yeniden gir\",\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"\",\n\t\t\t\t\t\t\"different\": \"\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"firstName\": {\n\t\t\t\t\t\"label\": \"\",\n\t\t\t\t\t\"placeholder\": \"Jordan\",\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"Lütfen adınızı girin\",\n\t\t\t\t\t\t\"length\": \"İsim 50 karakterden az olmalıdır\",\n\t\t\t\t\t\t\"pattern\": \"İsim yalnızca harfler, boşluklar, kesme işaretleri veya tireler içerebilir\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"lastName\": {\n\t\t\t\t\t\"label\": \"Soyadı\",\n\t\t\t\t\t\"placeholder\": \"Ellis\",\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"Lütfen soyadınızı girin\",\n\t\t\t\t\t\t\"length\": \"Soyadı en çok 50 karakter olmalıdır\",\n\t\t\t\t\t\t\"pattern\": \"Soyad yalnızca harfler, boşluklar, kesme işaretleri veya tireler içerebilir\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"errors\": {\n\t\t\t\t\"validation\": \"Veriyi işlerken hata oluştu.\"\n\t\t\t},\n\t\t\t\"fields\": {\n\t\t\t\t\"password\": {\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"incorrect\": \"\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"role\": {\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"min\": \"\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"login\": {\n\t\t\t\"heading\": \"Giriş yap\",\n\t\t\t\"subheadings\": {\n\t\t\t\t\"stepOne\": \"Eposta adresinizi girin\",\n\t\t\t\t\"stepTwo\": \"Parolanızı girin\"\n\t\t\t},\n\t\t\t\"links\": {\n\t\t\t\t\"forgotPassword\": \"Parolanızı mı unuttunuz?\",\n\t\t\t\t\"register\": \"Hesabınız yok mu?\",\n\t\t\t\t\"forgotPasswordLink\": \"Parolayı sıfırla\",\n\t\t\t\t\"registerLink\": \"Buradan kayıt olun\"\n\t\t\t},\n\t\t\t\"toasts\": {\n\t\t\t\t\"success\": \"Tekrar hoşgeldiniz! Başarıyla sisteme giriş yaptınız.\",\n\t\t\t\t\"incorrectPassword\": \"Hatalı parola\"\n\t\t\t},\n\t\t\t\"errors\": {\n\t\t\t\t\"password\": {\n\t\t\t\t\t\"incorrect\": \"Giriş yaptığınız parola sistemdekiyle uyuşmuyor\"\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"welcome\": \"\"\n\t\t},\n\t\t\"registration\": {\n\t\t\t\"heading\": {\n\t\t\t\t\"superAdmin\": \"Süper yönetici oluştur\",\n\t\t\t\t\"user\": \"Kayıt ol\"\n\t\t\t},\n\t\t\t\"subheadings\": {\n\t\t\t\t\"stepOne\": \"Kişisel bilgilerinizi girin\",\n\t\t\t\t\"stepTwo\": \"Eposta adresinizi girin\",\n\t\t\t\t\"stepThree\": \"Parolanızı oluturun\"\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\t\"superAdmin\": \"Başlamak için süper yönetici hesabı oluşturun\",\n\t\t\t\t\"user\": \"\"\n\t\t\t},\n\t\t\t\"gettingStartedButton\": {\n\t\t\t\t\"superAdmin\": \"Süper yönetici hesabı oluşturun\",\n\t\t\t\t\"user\": \"\"\n\t\t\t},\n\t\t\t\"termsAndPolicies\": \"Bir hesap oluşturarak <a1>Hizmet Şartları</a1> ve <a2>Gizlilik Politikası</a2>'nı kabul etmiş olursunuz.\",\n\t\t\t\"links\": {\n\t\t\t\t\"login\": \"Bir hesabınız mı var? <a>Giriş yapın</a>\"\n\t\t\t},\n\t\t\t\"toasts\": {\n\t\t\t\t\"success\": \"Hoşgeldiniz! Hesabınız başarıyla oluşturuldu.\"\n\t\t\t},\n\t\t\t\"welcome\": \"\"\n\t\t},\n\t\t\"forgotPassword\": {\n\t\t\t\"heading\": \"Parolanızı mı kaybettiniz?\",\n\t\t\t\"subheadings\": {\n\t\t\t\t\"stepOne\": \"Endişelenmeyin, sıfırlamak için gerekli bilgileri göndereceğiz.\",\n\t\t\t\t\"stepTwo\": \"Parola sıfırlama için gerekli bilgileri <email/> hesabına ilettik.\",\n\t\t\t\t\"stepThree\": \"Parolanız daha önce kullandığınız paroladan farklı olmalıdır.\",\n\t\t\t\t\"stepFour\": \"Parolanız başarıyla sıfırlandı. Buraya tıklayarak giriş yapabilirsiniz.\"\n\t\t\t},\n\t\t\t\"buttons\": {\n\t\t\t\t\"openEmail\": \"Eposta uygulamasını aç\",\n\t\t\t\t\"resetPassword\": \"Parolayı sıfırla\"\n\t\t\t},\n\t\t\t\"imageAlts\": {\n\t\t\t\t\"passwordKey\": \"\",\n\t\t\t\t\"email\": \"\",\n\t\t\t\t\"lock\": \"\",\n\t\t\t\t\"passwordConfirm\": \"\"\n\t\t\t},\n\t\t\t\"links\": {\n\t\t\t\t\"login\": \"\",\n\t\t\t\t\"resend\": \"\"\n\t\t\t},\n\t\t\t\"toasts\": {\n\t\t\t\t\"sent\": \"\",\n\t\t\t\t\"emailNotFound\": \"Eposta bulunamadı.\",\n\t\t\t\t\"redirect\": \"\",\n\t\t\t\t\"success\": \"\",\n\t\t\t\t\"error\": \"\"\n\t\t\t}\n\t\t}\n\t},\n\t\"errorPages\": {\n\t\t\"serverUnreachable\": {\n\t\t\t\"toasts\": {\n\t\t\t\t\"reconnected\": \"\",\n\t\t\t\t\"stillUnreachable\": \"\"\n\t\t\t},\n\t\t\t\"alertBox\": \"Sunucu bağlantı hatası\",\n\t\t\t\"description\": \"\",\n\t\t\t\"retryButton\": {\n\t\t\t\t\"default\": \"Bağlantıyı tekrarla\",\n\t\t\t\t\"processing\": \"Bağlanıyor...\"\n\t\t\t}\n\t\t}\n\t},\n\t\"createNotifications\": {\n\t\t\"title\": \"Bildirim kanalları oluştur\",\n\t\t\"nameSettings\": {\n\t\t\t\"title\": \"İsim\",\n\t\t\t\"description\": \"Entegrasyon için açıklama\",\n\t\t\t\"nameLabel\": \"İsim\",\n\t\t\t\"namePlaceholder\": \"örn. Slack bildirimleri\"\n\t\t},\n\t\t\"typeSettings\": {\n\t\t\t\"title\": \"Tür\",\n\t\t\t\"description\": \"\",\n\t\t\t\"typeLabel\": \"Tür\"\n\t\t},\n\t\t\"emailSettings\": {\n\t\t\t\"title\": \"Eposta\",\n\t\t\t\"description\": \"Hedef eposta adresi\",\n\t\t\t\"emailLabel\": \"Eposta adresi\",\n\t\t\t\"emailPlaceholder\": \"örn. john@example.com\"\n\t\t},\n\t\t\"slackSettings\": {\n\t\t\t\"title\": \"Slack\",\n\t\t\t\"description\": \"Slack webhook'u burada tanımlayın\",\n\t\t\t\"webhookLabel\": \"Slack webhook adresi\",\n\t\t\t\"webhookPlaceholder\": \"https://hooks.slack.com/services/...\\n\"\n\t\t},\n\t\t\"pagerdutySettings\": {\n\t\t\t\"title\": \"PagerDuty\",\n\t\t\t\"description\": \"PagerDuty entegrasyonunu burada yapın\",\n\t\t\t\"integrationKeyLabel\": \"Entegrasyon anahtarı\",\n\t\t\t\"integrationKeyPlaceholder\": \"1234567890\"\n\t\t},\n\t\t\"discordSettings\": {\n\t\t\t\"title\": \"Discord\",\n\t\t\t\"description\": \"Discord webhook'u buradan ayarlayın\",\n\t\t\t\"webhookLabel\": \"Discord Webhook adresi\",\n\t\t\t\"webhookPlaceholder\": \"https://sunucu-adı.com/webhook\\n\"\n\t\t},\n\t\t\"webhookSettings\": {\n\t\t\t\"title\": \"Webhook\",\n\t\t\t\"description\": \"\",\n\t\t\t\"webhookLabel\": \"\",\n\t\t\t\"webhookPlaceholder\": \"https://sunucu-adı.com/webhook\\n\"\n\t\t},\n\t\t\"testNotification\": \"Test bildirimi\",\n\t\t\"dialogDeleteTitle\": \"Gerçekten bu bildirimi silmek istiyor musunuz?\",\n\t\t\"dialogDeleteConfirm\": \"Sil\"\n\t},\n\t\"notificationConfig\": {\n\t\t\"title\": \"Bildirimler\",\n\t\t\"description\": \"\"\n\t},\n\t\"monitorStatus\": {\n\t\t\"checkingEvery\": \"\",\n\t\t\"withCaptureAgent\": \"\",\n\t\t\"up\": \"ayakta\",\n\t\t\"down\": \"çalışmıyor\",\n\t\t\"paused\": \"beklemede\"\n\t},\n\t\"advancedMatching\": \"Gelişmiş eşleştirme\",\n\t\"sendTestNotifications\": \"Bildirimleri dene\",\n\t\"selectAll\": \"Tümünü seç\",\n\t\"showAdminLoginLink\": \"\",\n\t\"logsPage\": {\n\t\t\"title\": \"Günlükler\",\n\t\t\"description\": \"Sistem günlükleri - son 1000 satır\",\n\t\t\"tabs\": {\n\t\t\t\"queue\": \"İş kuyruğu\",\n\t\t\t\"logs\": \"Sunucu günlükleri\",\n\t\t\t\"diagnostics\": \"Teşhis\"\n\t\t},\n\t\t\"toast\": {\n\t\t\t\"fetchLogsSuccess\": \"Günlükler başarıyla alındı\"\n\t\t},\n\t\t\"logLevelSelect\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"values\": {\n\t\t\t\t\"all\": \"\",\n\t\t\t\t\"info\": \"\",\n\t\t\t\t\"warn\": \"\",\n\t\t\t\t\"error\": \"\",\n\t\t\t\t\"debug\": \"\"\n\t\t\t}\n\t\t}\n\t},\n\t\"queuePage\": {\n\t\t\"title\": \"\",\n\t\t\"refreshButton\": \"\",\n\t\t\"flushButton\": \"\",\n\t\t\"jobTable\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"idHeader\": \"\",\n\t\t\t\"urlHeader\": \"\",\n\t\t\t\"typeHeader\": \"\",\n\t\t\t\"activeHeader\": \"Aktif\",\n\t\t\t\"lockedAtHeader\": \"\",\n\t\t\t\"runCountHeader\": \"\",\n\t\t\t\"failCountHeader\": \"\",\n\t\t\t\"lastRunHeader\": \"\",\n\t\t\t\"lastFinishedAtHeader\": \"Son tamamlama\",\n\t\t\t\"lastRunTookHeader\": \"\",\n\t\t\t\"intervalHeader\": \"\"\n\t\t},\n\t\t\"metricsTable\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"metricHeader\": \"Metrik\",\n\t\t\t\"valueHeader\": \"Değer\"\n\t\t},\n\t\t\"failedJobTable\": {\n\t\t\t\"title\": \"Tamamlanamayan işler\",\n\t\t\t\"monitorIdHeader\": \"Monitör ID\",\n\t\t\t\"monitorUrlHeader\": \"Monitör URL\",\n\t\t\t\"failCountHeader\": \"Hata sayısı\",\n\t\t\t\"failedAtHeader\": \"\",\n\t\t\t\"failReasonHeader\": \"\"\n\t\t}\n\t},\n\t\"export\": {\n\t\t\"title\": \"Monitörleri dışarı al\",\n\t\t\"success\": \"Monitörler başarıyla dışarıya alındı\",\n\t\t\"failed\": \"Monitörleri dışarıya alırken bir hata oluştu\"\n\t},\n\t\"monitorActions\": {\n\t\t\"title\": \"Dışarı/İçeri al\",\n\t\t\"import\": \"\",\n\t\t\"export\": \"\",\n\t\t\"deleteSuccess\": \"Monitör başarıyla silindi\",\n\t\t\"deleteFailed\": \"Monitör silinemedi\",\n\t\t\"details\": \"Detaylar\"\n\t},\n\t\"settingsPage\": {\n\t\t\"aboutSettings\": {\n\t\t\t\"labelDevelopedBy\": \"\",\n\t\t\t\"labelVersion\": \"\",\n\t\t\t\"title\": \"\"\n\t\t},\n\t\t\"demoMonitorsSettings\": {\n\t\t\t\"buttonAddMonitors\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"title\": \"\"\n\t\t},\n\t\t\"emailSettings\": {\n\t\t\t\"buttonSendTestEmail\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"descriptionTransport\": \"\",\n\t\t\t\"labelAddress\": \"\",\n\t\t\t\"labelConnectionHost\": \"\",\n\t\t\t\"labelHost\": \"\",\n\t\t\t\"labelIgnoreTLS\": \"\",\n\t\t\t\"labelPassword\": \"\",\n\t\t\t\"labelPasswordSet\": \"\",\n\t\t\t\"labelPool\": \"\",\n\t\t\t\"labelPort\": \"\",\n\t\t\t\"labelRejectUnauthorized\": \"\",\n\t\t\t\"labelRequireTLS\": \"\",\n\t\t\t\"labelSecure\": \"\",\n\t\t\t\"labelTLSServername\": \"\",\n\t\t\t\"labelUser\": \"\",\n\t\t\t\"linkTransport\": \"\",\n\t\t\t\"placeholderUser\": \"Eğer gerekmiyorsa boş bırakabilirsiniz\",\n\t\t\t\"title\": \"Eposta\",\n\t\t\t\"toastEmailRequiredFieldsError\": \"\"\n\t\t},\n\t\t\"pageSpeedSettings\": {\n\t\t\t\"description\": \"Google PageSpeed izlemeyi etkinleştirmek için Google PageSpeed API anahtarınızı girin. Anahtarı güncellemek için Sıfırla'ya tıklayın.\",\n\t\t\t\"labelApiKeySet\": \"API key tanımlandı. Sıfırla düğmesine tıklayarak değiştirebilirsiniz.\",\n\t\t\t\"labelApiKey\": \"PageSpeed API anahtarı\",\n\t\t\t\"title\": \"Google PageSpeed API anahtarı\"\n\t\t},\n\t\t\"saveButtonLabel\": \"Kaydet\",\n\t\t\"statsSettings\": {\n\t\t\t\"clearAllStatsButton\": \"\",\n\t\t\t\"clearAllStatsDescription\": \"\",\n\t\t\t\"clearAllStatsDialogConfirm\": \"\",\n\t\t\t\"clearAllStatsDialogDescription\": \"\",\n\t\t\t\"clearAllStatsDialogTitle\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"labelTTL\": \"\",\n\t\t\t\"labelTTLOptional\": \"Sonsuz için 0\",\n\t\t\t\"title\": \"İzleme geçmişi\"\n\t\t},\n\t\t\"systemResetSettings\": {\n\t\t\t\"buttonRemoveAllMonitors\": \"Tüm monitörleri sil\",\n\t\t\t\"description\": \"Sistemden tüm monitörleri sil\",\n\t\t\t\"dialogConfirm\": \"Evet, tüm monitörleri sil\",\n\t\t\t\"dialogDescription\": \"\",\n\t\t\t\"dialogTitle\": \"Gerçekten tüm monitörleri silmek istiyor musunuz?\",\n\t\t\t\"title\": \"Sistemi sıfırla\"\n\t\t},\n\t\t\"timezoneSettings\": {\n\t\t\t\"description\": \"\",\n\t\t\t\"label\": \"Görünüm zaman dilimi\",\n\t\t\t\"title\": \"Görünüm zaman dilimi\"\n\t\t},\n\t\t\"title\": \"Ayarlar\",\n\t\t\"uiSettings\": {\n\t\t\t\"description\": \"Aydınlık ve karanlık mod arasında geçiş yapın ya da kullanıcı arayüzü dilini değiştirin.\",\n\t\t\t\"labelLanguage\": \"Dil\",\n\t\t\t\"labelTheme\": \"Tema modu\",\n\t\t\t\"title\": \"Görünüm\"\n\t\t},\n\t\t\"urlSettings\": {\n\t\t\t\"description\": \"\",\n\t\t\t\"label\": \"\",\n\t\t\t\"selectDisabled\": \"Kapalı\",\n\t\t\t\"selectEnabled\": \"Etkin\",\n\t\t\t\"title\": \"\"\n\t\t},\n\t\t\"globalThresholds\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\"\n\t\t}\n\t},\n\t\"statusPageCreate\": {\n\t\t\"buttonSave\": \"\"\n\t},\n\t\"incidentsOptionsHeaderFilterResolved\": \"\",\n\t\"settingsSave\": \"\",\n\t\"statusPageCreateAppearanceTitle\": \"\",\n\t\"confirmPassword\": \"\",\n\t\"monitorHooks\": {\n\t\t\"failureAddDemoMonitors\": \"\",\n\t\t\"successAddDemoMonitors\": \"\"\n\t},\n\t\"settingsAppearance\": \"\",\n\t\"settingsDisplayTimezone\": \"\",\n\t\"settingsGeneralSettings\": \"\",\n\t\"incidentsOptionsHeaderTotalIncidents\": \"\",\n\t\"statusPage\": {\n\t\t\"deleteSuccess\": \"Durum sayfası başarıyla silindi\",\n\t\t\"deleteFailed\": \"Durum sayfası silinemedi\",\n\t\t\"createSuccess\": \"Durum sayfası başarıyla oluşturuldu\",\n\t\t\"updateSuccess\": \"Durum sayfası başarıyla güncellendi\",\n\t\t\"generalSettings\": \"Genel ayarlar\",\n\t\t\"contents\": \"İçerikler\",\n\t\t\"fallback\": {\n\t\t\t\"checks\": [\"\"],\n\t\t\t\"title\": \"\",\n\t\t\t\"actionButton\": \"\"\n\t\t}\n\t},\n\t\"testNotificationsDisabled\": \"Bu izleyici için ayarlanmış bir bildirim yok. 'Yapılandır' düğmesine tıklayarak bir bildirim eklemeniz gerekiyor.\",\n\t\"incidentsTableResolvedAt\": \"\",\n\t\"incidentsTableActionResolve\": \"Çözümle\",\n\t\"checkHooks\": {\n\t\t\"failureResolveOne\": \"Olay çözümlenirken bir hata oluştu.\",\n\t\t\"failureResolveAll\": \"Tüm olayları çözümlerken bir hata oluştu.\",\n\t\t\"failureResolveMonitor\": \"\"\n\t},\n\t\"checkFormError\": \"Formda hatalar var. Lütfen kontrol edin.\",\n\t\"diagnosticsPage\": {\n\t\t\"diagnosticDescription\": \"\",\n\t\t\"statsDescription\": \"\",\n\t\t\"gauges\": {\n\t\t\t\"heapAllocationTitle\": \"\",\n\t\t\t\"heapAllocationSubtitle\": \"\",\n\t\t\t\"heapUsageTitle\": \"\",\n\t\t\t\"heapUsageSubtitle\": \"\",\n\t\t\t\"heapUtilizationTitle\": \"\",\n\t\t\t\"heapUtilizationSubtitle\": \"\",\n\t\t\t\"instantCpuUsageTitle\": \"\",\n\t\t\t\"instantCpuUsageSubtitle\": \"\"\n\t\t},\n\t\t\"stats\": {\n\t\t\t\"eventLoopDelayTitle\": \"\",\n\t\t\t\"uptimeTitle\": \"\",\n\t\t\t\"usedHeapSizeTitle\": \"\",\n\t\t\t\"totalHeapSizeTitle\": \"\",\n\t\t\t\"osMemoryLimitTitle\": \"\"\n\t\t}\n\t},\n\t\"pageSpeedLighthouseAPI\": \"\",\n\t\"time\": {\n\t\t\"threeMinutes\": \"\",\n\t\t\"fiveMinutes\": \"\",\n\t\t\"tenMinutes\": \"\",\n\t\t\"twentyMinutes\": \"\",\n\t\t\"oneHour\": \"1 saat\",\n\t\t\"oneDay\": \"1 gün\",\n\t\t\"oneWeek\": \"1 hafta\",\n\t\t\"fourMinutes\": \"\",\n\t\t\"oneMinute\": \"\",\n\t\t\"twoMinutes\": \"\",\n\t\t\"fifteenSeconds\": \"\",\n\t\t\"thirtySeconds\": \"\"\n\t},\n\t\"general\": {\n\t\t\"noOptionsFound\": \"\"\n\t},\n\t\"infrastructureMonitor\": {\n\t\t\"fallback\": {\n\t\t\t\"checks\": [\"\"],\n\t\t\t\"title\": \"\",\n\t\t\t\"actionButton\": \"\"\n\t\t}\n\t},\n\t\"maintenanceWindow\": {\n\t\t\"fallback\": {\n\t\t\t\"checks\": [\"\"],\n\t\t\t\"title\": \"\",\n\t\t\t\"actionButton\": \"\"\n\t\t}\n\t},\n\t\"pageSpeed\": {\n\t\t\"fallback\": {\n\t\t\t\"checks\": [\"\"],\n\t\t\t\"title\": \"\",\n\t\t\t\"actionButton\": \"\"\n\t\t}\n\t},\n\t\"uptimeMonitor\": {\n\t\t\"fallback\": {\n\t\t\t\"checks\": [\"\"],\n\t\t\t\"title\": \"\",\n\t\t\t\"actionButton\": \"\"\n\t\t}\n\t},\n\t\"editUserPage\": {\n\t\t\"form\": {\n\t\t\t\"email\": \"\",\n\t\t\t\"firstName\": \"\",\n\t\t\t\"lastName\": \"\",\n\t\t\t\"role\": \"\",\n\t\t\t\"save\": \"\"\n\t\t},\n\t\t\"table\": {\n\t\t\t\"actionHeader\": \"\",\n\t\t\t\"roleHeader\": \"\"\n\t\t},\n\t\t\"title\": \"\",\n\t\t\"toast\": {\n\t\t\t\"successUserUpdate\": \"\",\n\t\t\t\"validationErrors\": \"\"\n\t\t}\n\t},\n\t\"incidentsPageActionResolveMonitor\": \"\",\n\t\"incidentsPageActionResolveAll\": \"\",\n\t\"matchMethodOptions\": {\n\t\t\"equal\": \"\",\n\t\t\"equalPlaceholder\": \"\",\n\t\t\"include\": \"\",\n\t\t\"includePlaceholder\": \"\",\n\t\t\"regex\": \"\",\n\t\t\"regexPlaceholder\": \"\",\n\t\t\"text\": \"\"\n\t},\n\t\"monitorType\": {\n\t\t\"docker\": {\n\t\t\t\"label\": \"\",\n\t\t\t\"namePlaceholder\": \"\",\n\t\t\t\"placeholder\": \"\"\n\t\t},\n\t\t\"http\": {\n\t\t\t\"label\": \"\",\n\t\t\t\"namePlaceholder\": \"\",\n\t\t\t\"placeholder\": \"\"\n\t\t},\n\t\t\"ping\": {\n\t\t\t\"label\": \"\",\n\t\t\t\"namePlaceholder\": \"\",\n\t\t\t\"placeholder\": \"\"\n\t\t},\n\t\t\"port\": {\n\t\t\t\"label\": \"\",\n\t\t\t\"namePlaceholder\": \"\",\n\t\t\t\"placeholder\": \"\"\n\t\t},\n\t\t\"game\": {\n\t\t\t\"label\": \"\",\n\t\t\t\"namePlaceholder\": \"\",\n\t\t\t\"placeholder\": \"\"\n\t\t}\n\t},\n\t\"uptimeAdvancedMatching\": {\n\t\t\"jsonPath\": \"\"\n\t},\n\t\"bytesPerSecond\": \"\",\n\t\"bytesReceived\": \"\",\n\t\"bytesSent\": \"\",\n\t\"chooseGame\": \"\",\n\t\"createMonitorPage\": {\n\t\t\"incidentConfigDescription\": \"\",\n\t\t\"incidentConfigStatusWindowLabel\": \"\",\n\t\t\"incidentConfigStatusWindowThresholdLabel\": \"\",\n\t\t\"incidentConfigTitle\": \"\",\n\t\t\"incidentConfigDescriptionV2\": \"\",\n\t\t\"incidentConfigStatusCheckNumber\": \"\",\n\t\t\"intervalTitle\": \"\",\n\t\t\"intervalDescription\": \"\"\n\t},\n\t\"dataRate\": \"\",\n\t\"dataReceived\": \"\",\n\t\"dataSent\": \"\",\n\t\"details\": \"\",\n\t\"drops\": \"\",\n\t\"errors\": \"\",\n\t\"errorsIn\": \"\",\n\t\"errorsOut\": \"\",\n\t\"gameServerMonitoring\": \"\",\n\t\"gameServerMonitoringDescription\": \"\",\n\t\"network\": \"\",\n\t\"networkDrops\": \"\",\n\t\"networkErrors\": \"\",\n\t\"networkInterface\": \"\",\n\t\"noNetworkStatsAvailable\": \"\",\n\t\"packetsPerSecond\": \"\",\n\t\"packetsReceived\": \"\",\n\t\"packetsReceivedRate\": \"\",\n\t\"packetsSent\": \"\",\n\t\"rate\": \"\",\n\t\"selectInterface\": \"\"\n}\n"
  },
  {
    "path": "client/src/locales/uk.json",
    "content": "{\n\t\"submit\": \"\",\n\t\"title\": \"\",\n\t\"distributedStatusHeaderText\": \"\",\n\t\"distributedStatusSubHeaderText\": \"\",\n\t\"settingsDisabled\": \"\",\n\t\"settingsSuccessSaved\": \"\",\n\t\"settingsFailedToSave\": \"\",\n\t\"settingsStatsCleared\": \"\",\n\t\"settingsFailedToClearStats\": \"\",\n\t\"settingsFailedToAddDemoMonitors\": \"\",\n\t\"settingsMonitorsDeleted\": \"\",\n\t\"settingsFailedToDeleteMonitors\": \"\",\n\t\"starPromptTitle\": \"\",\n\t\"starPromptDescription\": \"\",\n\t\"https\": \"\",\n\t\"http\": \"\",\n\t\"monitor\": \"\",\n\t\"aboutus\": \"\",\n\t\"now\": \"\",\n\t\"delete\": \"\",\n\t\"configure\": \"\",\n\t\"responseTime\": \"\",\n\t\"ms\": \"\",\n\t\"bar\": \"\",\n\t\"area\": \"\",\n\t\"country\": \"\",\n\t\"city\": \"\",\n\t\"response\": \"\",\n\t\"monitorStatusUp\": \"\",\n\t\"monitorStatusDown\": \"\",\n\t\"webhookSendSuccess\": \"\",\n\t\"webhookSendError\": \"\",\n\t\"webhookUnsupportedPlatform\": \"\",\n\t\"distributedRightCategoryTitle\": \"\",\n\t\"distributedStatusServerMonitors\": \"\",\n\t\"distributedStatusServerMonitorsDescription\": \"\",\n\t\"distributedUptimeCreateSelectURL\": \"\",\n\t\"distributedUptimeCreateChecks\": \"\",\n\t\"distributedUptimeCreateChecksDescription\": \"\",\n\t\"distributedUptimeCreateIncidentNotification\": \"\",\n\t\"distributedUptimeCreateIncidentDescription\": \"\",\n\t\"distributedUptimeCreateAdvancedSettings\": \"\",\n\t\"distributedUptimeDetailsNoMonitorHistory\": \"\",\n\t\"distributedUptimeDetailsStatusHeaderUptime\": \"\",\n\t\"distributedUptimeDetailsStatusHeaderLastUpdate\": \"\",\n\t\"notifications\": {\n\t\t\"enableNotifications\": \"\",\n\t\t\"testNotification\": \"\",\n\t\t\"addOrEditNotifications\": \"\",\n\t\t\"slack\": {\n\t\t\t\"label\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"webhookLabel\": \"\",\n\t\t\t\"webhookPlaceholder\": \"\",\n\t\t\t\"webhookRequired\": \"\"\n\t\t},\n\t\t\"discord\": {\n\t\t\t\"label\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"webhookLabel\": \"\",\n\t\t\t\"webhookPlaceholder\": \"\",\n\t\t\t\"webhookRequired\": \"\"\n\t\t},\n\t\t\"telegram\": {\n\t\t\t\"label\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"tokenLabel\": \"\",\n\t\t\t\"tokenPlaceholder\": \"\",\n\t\t\t\"chatIdLabel\": \"\",\n\t\t\t\"chatIdPlaceholder\": \"\",\n\t\t\t\"fieldsRequired\": \"\"\n\t\t},\n\t\t\"webhook\": {\n\t\t\t\"label\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"urlLabel\": \"\",\n\t\t\t\"urlPlaceholder\": \"\",\n\t\t\t\"urlRequired\": \"\"\n\t\t},\n\t\t\"testNotificationDevelop\": \"\",\n\t\t\"integrationButton\": \"\",\n\t\t\"testSuccess\": \"\",\n\t\t\"testFailed\": \"\",\n\t\t\"unsupportedType\": \"\",\n\t\t\"networkError\": \"\",\n\t\t\"fallback\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"checks\": [\"\"]\n\t\t},\n\t\t\"createButton\": \"\",\n\t\t\"createTitle\": \"\",\n\t\t\"create\": {\n\t\t\t\"success\": \"\",\n\t\t\t\"failed\": \"\"\n\t\t},\n\t\t\"fetch\": {\n\t\t\t\"success\": \"\",\n\t\t\t\"failed\": \"\"\n\t\t},\n\t\t\"delete\": {\n\t\t\t\"success\": \"\",\n\t\t\t\"failed\": \"\"\n\t\t},\n\t\t\"edit\": {\n\t\t\t\"success\": \"\",\n\t\t\t\"failed\": \"\"\n\t\t},\n\t\t\"test\": {\n\t\t\t\"success\": \"\",\n\t\t\t\"failed\": \"\"\n\t\t}\n\t},\n\t\"testLocale\": \"\",\n\t\"add\": \"\",\n\t\"monitors\": \"\",\n\t\"distributedUptimeStatusCreateStatusPage\": \"\",\n\t\"distributedUptimeStatusCreateStatusPageAccess\": \"\",\n\t\"distributedUptimeStatusCreateStatusPageReady\": \"\",\n\t\"distributedUptimeStatusBasicInfoHeader\": \"\",\n\t\"distributedUptimeStatusBasicInfoDescription\": \"\",\n\t\"distributedUptimeStatusLogoHeader\": \"\",\n\t\"distributedUptimeStatusLogoDescription\": \"\",\n\t\"distributedUptimeStatusLogoUploadButton\": \"\",\n\t\"distributedUptimeStatusStandardMonitorsHeader\": \"\",\n\t\"distributedUptimeStatusStandardMonitorsDescription\": \"\",\n\t\"distributedUptimeStatusCreateYour\": \"\",\n\t\"distributedUptimeStatusEditYour\": \"\",\n\t\"distributedUptimeStatusPublishedLabel\": \"\",\n\t\"distributedUptimeStatusCompanyNameLabel\": \"\",\n\t\"distributedUptimeStatusPageAddressLabel\": \"\",\n\t\"distributedUptimeStatus30Days\": \"\",\n\t\"distributedUptimeStatus60Days\": \"\",\n\t\"distributedUptimeStatus90Days\": \"\",\n\t\"distributedUptimeStatusPageNotSetUp\": \"\",\n\t\"distributedUptimeStatusContactAdmin\": \"\",\n\t\"distributedUptimeStatusPageNotPublic\": \"\",\n\t\"distributedUptimeStatusPageDeleteDialog\": \"\",\n\t\"distributedUptimeStatusPageDeleteConfirm\": \"\",\n\t\"distributedUptimeStatusPageDeleteDescription\": \"\",\n\t\"distributedUptimeStatusDevices\": \"\",\n\t\"distributedUptimeStatusUpt\": \"\",\n\t\"distributedUptimeStatusUptBurned\": \"\",\n\t\"distributedUptimeStatusUptLogo\": \"\",\n\t\"incidentsTableNoIncidents\": \"\",\n\t\"incidentsTablePaginationLabel\": \"\",\n\t\"incidentsTableMonitorName\": \"\",\n\t\"incidentsTableStatus\": \"\",\n\t\"incidentsTableDateTime\": \"\",\n\t\"incidentsTableStatusCode\": \"\",\n\t\"incidentsTableMessage\": \"\",\n\t\"incidentsOptionsHeader\": \"\",\n\t\"incidentsOptionsHeaderFilterBy\": \"\",\n\t\"incidentsOptionsHeaderFilterAll\": \"\",\n\t\"incidentsOptionsHeaderFilterDown\": \"\",\n\t\"incidentsOptionsHeaderFilterCannotResolve\": \"\",\n\t\"incidentsOptionsHeaderShow\": \"\",\n\t\"incidentsOptionsHeaderLastHour\": \"\",\n\t\"incidentsOptionsHeaderLastDay\": \"\",\n\t\"incidentsOptionsHeaderLastWeek\": \"\",\n\t\"incidentsOptionsPlaceholderAllServers\": \"\",\n\t\"infrastructureCreateYour\": \"\",\n\t\"infrastructureCreateGeneralSettingsDescription\": \"\",\n\t\"infrastructureServerRequirement\": \"\",\n\t\"infrastructureCustomizeAlerts\": \"\",\n\t\"infrastructureAlertNotificationDescription\": \"\",\n\t\"infrastructureCreateMonitor\": \"\",\n\t\"infrastructureProtocol\": \"\",\n\t\"infrastructureServerUrlLabel\": \"\",\n\t\"infrastructureDisplayNameLabel\": \"\",\n\t\"infrastructureAuthorizationSecretLabel\": \"\",\n\t\"gb\": \"\",\n\t\"mb\": \"\",\n\t\"mem\": \"\",\n\t\"memoryUsage\": \"\",\n\t\"cpu\": \"\",\n\t\"cpuUsage\": \"\",\n\t\"cpuTemperature\": \"\",\n\t\"diskUsage\": \"\",\n\t\"used\": \"\",\n\t\"total\": \"\",\n\t\"cores\": \"\",\n\t\"frequency\": \"\",\n\t\"status\": \"\",\n\t\"cpuPhysical\": \"\",\n\t\"cpuLogical\": \"\",\n\t\"cpuFrequency\": \"\",\n\t\"avgCpuTemperature\": \"\",\n\t\"memory\": \"\",\n\t\"disk\": \"\",\n\t\"uptime\": \"\",\n\t\"os\": \"\",\n\t\"host\": \"\",\n\t\"actions\": \"\",\n\t\"integrations\": \"\",\n\t\"integrationsPrism\": \"\",\n\t\"integrationsSlack\": \"\",\n\t\"integrationsSlackInfo\": \"\",\n\t\"integrationsDiscord\": \"\",\n\t\"integrationsDiscordInfo\": \"\",\n\t\"integrationsZapier\": \"\",\n\t\"integrationsZapierInfo\": \"\",\n\t\"commonSave\": \"\",\n\t\"createYour\": \"\",\n\t\"createMonitor\": \"\",\n\t\"pause\": \"\",\n\t\"resume\": \"\",\n\t\"editing\": \"\",\n\t\"url\": \"\",\n\t\"access\": \"\",\n\t\"timezone\": \"\",\n\t\"features\": \"\",\n\t\"administrator\": \"\",\n\t\"loginHere\": \"\",\n\t\"displayName\": \"\",\n\t\"urlMonitor\": \"\",\n\t\"portToMonitor\": \"\",\n\t\"websiteMonitoring\": \"\",\n\t\"websiteMonitoringDescription\": \"\",\n\t\"pingMonitoring\": \"\",\n\t\"pingMonitoringDescription\": \"\",\n\t\"dockerContainerMonitoring\": \"\",\n\t\"dockerContainerMonitoringDescription\": \"\",\n\t\"portMonitoring\": \"\",\n\t\"portMonitoringDescription\": \"\",\n\t\"createMaintenanceWindow\": \"\",\n\t\"createMaintenance\": \"\",\n\t\"editMaintenance\": \"\",\n\t\"maintenanceWindowName\": \"\",\n\t\"friendlyNameInput\": \"\",\n\t\"friendlyNamePlaceholder\": \"\",\n\t\"maintenanceRepeat\": \"\",\n\t\"maintenance\": \"\",\n\t\"duration\": \"\",\n\t\"addMonitors\": \"\",\n\t\"window\": \"\",\n\t\"cancel\": \"\",\n\t\"message\": \"\",\n\t\"low\": \"\",\n\t\"high\": \"\",\n\t\"statusCode\": \"\",\n\t\"date&Time\": \"\",\n\t\"type\": \"\",\n\t\"statusPageName\": \"\",\n\t\"publicURL\": \"\",\n\t\"repeat\": \"\",\n\t\"edit\": \"\",\n\t\"createA\": \"\",\n\t\"remove\": \"\",\n\t\"maintenanceWindowDescription\": \"\",\n\t\"startTime\": \"\",\n\t\"timeZoneInfo\": \"\",\n\t\"monitorsToApply\": \"\",\n\t\"nextWindow\": \"\",\n\t\"notFoundButton\": \"\",\n\t\"pageSpeedConfigureSettingsDescription\": \"\",\n\t\"monitorDisplayName\": \"\",\n\t\"whenNewIncident\": \"\",\n\t\"notifySMS\": \"\",\n\t\"notifyEmails\": \"\",\n\t\"seperateEmails\": \"\",\n\t\"checkFrequency\": \"\",\n\t\"chooseGame\": \"\",\n\t\"matchMethod\": \"\",\n\t\"expectedValue\": \"\",\n\t\"deleteDialogTitle\": \"\",\n\t\"deleteDialogDescription\": \"\",\n\t\"pageSpeedMonitor\": \"\",\n\t\"shown\": \"\",\n\t\"ago\": \"\",\n\t\"companyName\": \"\",\n\t\"pageSpeedDetailsPerformanceReport\": \"\",\n\t\"pageSpeedDetailsPerformanceReportCalculator\": \"\",\n\t\"checkingEvery\": \"\",\n\t\"statusPageCreateSettings\": \"\",\n\t\"basicInformation\": \"\",\n\t\"statusPageCreateBasicInfoDescription\": \"\",\n\t\"statusPageCreateSelectTimeZoneDescription\": \"\",\n\t\"statusPageCreateAppearanceDescription\": \"\",\n\t\"statusPageCreateSettingsCheckboxLabel\": \"\",\n\t\"statusPageCreateBasicInfoStatusPageAddress\": \"\",\n\t\"statusPageCreateTabsContent\": \"\",\n\t\"statusPageCreateTabsContentDescription\": \"\",\n\t\"statusPageCreateTabsContentFeaturesDescription\": \"\",\n\t\"showCharts\": \"\",\n\t\"showUptimePercentage\": \"\",\n\t\"removeLogo\": \"\",\n\t\"statusPageStatus\": \"\",\n\t\"statusPageStatusContactAdmin\": \"\",\n\t\"statusPageStatusNotPublic\": \"\",\n\t\"statusPageStatusNoPage\": \"\",\n\t\"statusPageStatusServiceStatus\": \"\",\n\t\"deleteStatusPage\": \"\",\n\t\"deleteStatusPageConfirm\": \"\",\n\t\"deleteStatusPageDescription\": \"\",\n\t\"uptimeCreate\": \"\",\n\t\"uptimeCreateJsonPath\": \"\",\n\t\"uptimeCreateJsonPathQuery\": \"\",\n\t\"maintenanceTableActionMenuDialogTitle\": \"\",\n\t\"infrastructureEditYour\": \"\",\n\t\"infrastructureEditMonitor\": \"\",\n\t\"infrastructureMonitorCreated\": \"\",\n\t\"infrastructureMonitorUpdated\": \"\",\n\t\"errorInvalidTypeId\": \"\",\n\t\"errorInvalidFieldId\": \"\",\n\t\"inviteNoTokenFound\": \"\",\n\t\"pageSpeedWarning\": \"\",\n\t\"pageSpeedLearnMoreLink\": \"\",\n\t\"pageSpeedAddApiKey\": \"\",\n\t\"update\": \"\",\n\t\"invalidFileFormat\": \"\",\n\t\"invalidFileSize\": \"\",\n\t\"ClickUpload\": \"\",\n\t\"DragandDrop\": \"\",\n\t\"MaxSize\": \"\",\n\t\"SupportedFormats\": \"\",\n\t\"FirstName\": \"\",\n\t\"LastName\": \"\",\n\t\"EmailDescriptionText\": \"\",\n\t\"YourPhoto\": \"\",\n\t\"PhotoDescriptionText\": \"\",\n\t\"save\": \"\",\n\t\"DeleteDescriptionText\": \"\",\n\t\"DeleteAccountWarning\": \"\",\n\t\"DeleteWarningTitle\": \"\",\n\t\"bulkImport\": {\n\t\t\"title\": \"\",\n\t\t\"selectFileTips\": \"\",\n\t\t\"selectFileDescription\": \"\",\n\t\t\"selectFile\": \"\",\n\t\t\"parsingFailed\": \"\",\n\t\t\"uploadSuccess\": \"\",\n\t\t\"validationFailed\": \"\",\n\t\t\"noFileSelected\": \"\",\n\t\t\"fallbackPage\": \"\"\n\t},\n\t\"DeleteAccountTitle\": \"\",\n\t\"DeleteAccountButton\": \"\",\n\t\"publicLink\": \"\",\n\t\"maskedPageSpeedKeyPlaceholder\": \"\",\n\t\"reset\": \"\",\n\t\"ignoreTLSError\": \"\",\n\t\"tlsErrorIgnored\": \"\",\n\t\"ignoreTLSErrorDescription\": \"\",\n\t\"createNew\": \"\",\n\t\"greeting\": {\n\t\t\"prepend\": \"\",\n\t\t\"append\": \"\",\n\t\t\"overview\": \"\"\n\t},\n\t\"roles\": {\n\t\t\"superAdmin\": \"\",\n\t\t\"admin\": \"\",\n\t\t\"teamMember\": \"\",\n\t\t\"demoUser\": \"\"\n\t},\n\t\"teamPanel\": {\n\t\t\"teamMembers\": \"\",\n\t\t\"filter\": {\n\t\t\t\"all\": \"\",\n\t\t\t\"member\": \"\"\n\t\t},\n\t\t\"inviteTeamMember\": \"\",\n\t\t\"inviteNewTeamMember\": \"\",\n\t\t\"inviteDescription\": \"\",\n\t\t\"email\": \"\",\n\t\t\"selectRole\": \"\",\n\t\t\"inviteLink\": \"\",\n\t\t\"cancel\": \"\",\n\t\t\"noMembers\": \"\",\n\t\t\"getToken\": \"\",\n\t\t\"emailToken\": \"\",\n\t\t\"table\": {\n\t\t\t\"name\": \"\",\n\t\t\t\"email\": \"\",\n\t\t\t\"role\": \"\",\n\t\t\t\"created\": \"\"\n\t\t}\n\t},\n\t\"monitorState\": {\n\t\t\"paused\": \"\",\n\t\t\"resumed\": \"\",\n\t\t\"active\": \"\"\n\t},\n\t\"menu\": {\n\t\t\"uptime\": \"\",\n\t\t\"pagespeed\": \"\",\n\t\t\"infrastructure\": \"\",\n\t\t\"incidents\": \"\",\n\t\t\"statusPages\": \"\",\n\t\t\"maintenance\": \"\",\n\t\t\"integrations\": \"\",\n\t\t\"settings\": \"\",\n\t\t\"support\": \"\",\n\t\t\"discussions\": \"\",\n\t\t\"docs\": \"\",\n\t\t\"changelog\": \"\",\n\t\t\"profile\": \"\",\n\t\t\"password\": \"\",\n\t\t\"team\": \"\",\n\t\t\"logOut\": \"\",\n\t\t\"notifications\": \"\",\n\t\t\"logs\": \"\"\n\t},\n\t\"settingsEmailUser\": \"\",\n\t\"state\": \"\",\n\t\"statusBreadCrumbsStatusPages\": \"\",\n\t\"statusBreadCrumbsDetails\": \"\",\n\t\"commonSaving\": \"\",\n\t\"navControls\": \"\",\n\t\"incidentsPageTitle\": \"\",\n\t\"passwordPanel\": {\n\t\t\"passwordChangedSuccess\": \"\",\n\t\t\"passwordInputIncorrect\": \"\",\n\t\t\"currentPassword\": \"\",\n\t\t\"enterCurrentPassword\": \"\",\n\t\t\"newPassword\": \"\",\n\t\t\"enterNewPassword\": \"\",\n\t\t\"confirmNewPassword\": \"\",\n\t\t\"passwordRequirements\": \"\",\n\t\t\"saving\": \"\"\n\t},\n\t\"emailSent\": \"\",\n\t\"failedToSendEmail\": \"\",\n\t\"settingsTestEmailSuccess\": \"\",\n\t\"settingsTestEmailFailed\": \"\",\n\t\"settingsTestEmailFailedWithReason\": \"\",\n\t\"settingsTestEmailUnknownError\": \"\",\n\t\"statusMsg\": {\n\t\t\"paused\": \"\",\n\t\t\"up\": \"\",\n\t\t\"down\": \"\",\n\t\t\"pending\": \"\"\n\t},\n\t\"uptimeGeneralInstructions\": {\n\t\t\"http\": \"\",\n\t\t\"ping\": \"\",\n\t\t\"docker\": \"\",\n\t\t\"port\": \"\",\n\t\t\"game\": \"\"\n\t},\n\t\"common\": {\n\t\t\"appName\": \"\",\n\t\t\"monitoringAgentName\": \"\",\n\t\t\"buttons\": {\n\t\t\t\"toggleTheme\": \"\"\n\t\t},\n\t\t\"toasts\": {\n\t\t\t\"networkError\": \"\",\n\t\t\t\"checkConnection\": \"\",\n\t\t\t\"unknownError\": \"\"\n\t\t}\n\t},\n\t\"auth\": {\n\t\t\"common\": {\n\t\t\t\"navigation\": {\n\t\t\t\t\"continue\": \"\",\n\t\t\t\t\"back\": \"\"\n\t\t\t},\n\t\t\t\"inputs\": {\n\t\t\t\t\"email\": {\n\t\t\t\t\t\"label\": \"\",\n\t\t\t\t\t\"placeholder\": \"\",\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"\",\n\t\t\t\t\t\t\"invalid\": \"\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"password\": {\n\t\t\t\t\t\"label\": \"\",\n\t\t\t\t\t\"rules\": {\n\t\t\t\t\t\t\"length\": {\n\t\t\t\t\t\t\t\"beginning\": \"\",\n\t\t\t\t\t\t\t\"highlighted\": \"\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"special\": {\n\t\t\t\t\t\t\t\"beginning\": \"\",\n\t\t\t\t\t\t\t\"highlighted\": \"\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"number\": {\n\t\t\t\t\t\t\t\"beginning\": \"\",\n\t\t\t\t\t\t\t\"highlighted\": \"\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"uppercase\": {\n\t\t\t\t\t\t\t\"beginning\": \"\",\n\t\t\t\t\t\t\t\"highlighted\": \"\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"lowercase\": {\n\t\t\t\t\t\t\t\"beginning\": \"\",\n\t\t\t\t\t\t\t\"highlighted\": \"\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"match\": {\n\t\t\t\t\t\t\t\"beginning\": \"\",\n\t\t\t\t\t\t\t\"highlighted\": \"\"\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"\",\n\t\t\t\t\t\t\"length\": \"\",\n\t\t\t\t\t\t\"uppercase\": \"\",\n\t\t\t\t\t\t\"lowercase\": \"\",\n\t\t\t\t\t\t\"number\": \"\",\n\t\t\t\t\t\t\"special\": \"\",\n\t\t\t\t\t\t\"incorrect\": \"\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"passwordConfirm\": {\n\t\t\t\t\t\"label\": \"\",\n\t\t\t\t\t\"placeholder\": \"\",\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"\",\n\t\t\t\t\t\t\"different\": \"\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"firstName\": {\n\t\t\t\t\t\"label\": \"\",\n\t\t\t\t\t\"placeholder\": \"\",\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"\",\n\t\t\t\t\t\t\"length\": \"\",\n\t\t\t\t\t\t\"pattern\": \"\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"lastName\": {\n\t\t\t\t\t\"label\": \"\",\n\t\t\t\t\t\"placeholder\": \"\",\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"\",\n\t\t\t\t\t\t\"length\": \"\",\n\t\t\t\t\t\t\"pattern\": \"\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"errors\": {\n\t\t\t\t\"validation\": \"\"\n\t\t\t},\n\t\t\t\"fields\": {\n\t\t\t\t\"password\": {\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"incorrect\": \"\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"login\": {\n\t\t\t\"heading\": \"\",\n\t\t\t\"subheadings\": {\n\t\t\t\t\"stepOne\": \"\",\n\t\t\t\t\"stepTwo\": \"\"\n\t\t\t},\n\t\t\t\"links\": {\n\t\t\t\t\"forgotPassword\": \"\",\n\t\t\t\t\"register\": \"\",\n\t\t\t\t\"forgotPasswordLink\": \"\",\n\t\t\t\t\"registerLink\": \"\"\n\t\t\t},\n\t\t\t\"toasts\": {\n\t\t\t\t\"success\": \"\",\n\t\t\t\t\"incorrectPassword\": \"\"\n\t\t\t},\n\t\t\t\"errors\": {\n\t\t\t\t\"password\": {\n\t\t\t\t\t\"incorrect\": \"\"\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"registration\": {\n\t\t\t\"heading\": {\n\t\t\t\t\"superAdmin\": \"\",\n\t\t\t\t\"user\": \"\"\n\t\t\t},\n\t\t\t\"subheadings\": {\n\t\t\t\t\"stepOne\": \"\",\n\t\t\t\t\"stepTwo\": \"\",\n\t\t\t\t\"stepThree\": \"\"\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\t\"superAdmin\": \"\",\n\t\t\t\t\"user\": \"\"\n\t\t\t},\n\t\t\t\"gettingStartedButton\": {\n\t\t\t\t\"superAdmin\": \"\",\n\t\t\t\t\"user\": \"\"\n\t\t\t},\n\t\t\t\"termsAndPolicies\": \"\",\n\t\t\t\"links\": {\n\t\t\t\t\"login\": \"\"\n\t\t\t},\n\t\t\t\"toasts\": {\n\t\t\t\t\"success\": \"\"\n\t\t\t}\n\t\t},\n\t\t\"forgotPassword\": {\n\t\t\t\"heading\": \"\",\n\t\t\t\"subheadings\": {\n\t\t\t\t\"stepOne\": \"\",\n\t\t\t\t\"stepTwo\": \"\",\n\t\t\t\t\"stepThree\": \"\",\n\t\t\t\t\"stepFour\": \"\"\n\t\t\t},\n\t\t\t\"buttons\": {\n\t\t\t\t\"openEmail\": \"\",\n\t\t\t\t\"resetPassword\": \"\"\n\t\t\t},\n\t\t\t\"imageAlts\": {\n\t\t\t\t\"passwordKey\": \"\",\n\t\t\t\t\"email\": \"\",\n\t\t\t\t\"lock\": \"\",\n\t\t\t\t\"passwordConfirm\": \"\"\n\t\t\t},\n\t\t\t\"links\": {\n\t\t\t\t\"login\": \"\",\n\t\t\t\t\"resend\": \"\"\n\t\t\t},\n\t\t\t\"toasts\": {\n\t\t\t\t\"sent\": \"\",\n\t\t\t\t\"emailNotFound\": \"\",\n\t\t\t\t\"redirect\": \"\",\n\t\t\t\t\"success\": \"\",\n\t\t\t\t\"error\": \"\"\n\t\t\t}\n\t\t}\n\t},\n\t\"errorPages\": {\n\t\t\"serverUnreachable\": {\n\t\t\t\"toasts\": {\n\t\t\t\t\"reconnected\": \"\",\n\t\t\t\t\"stillUnreachable\": \"\"\n\t\t\t},\n\t\t\t\"alertBox\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"retryButton\": {\n\t\t\t\t\"default\": \"\",\n\t\t\t\t\"processing\": \"\"\n\t\t\t}\n\t\t}\n\t},\n\t\"createNotifications\": {\n\t\t\"title\": \"\",\n\t\t\"nameSettings\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"nameLabel\": \"\",\n\t\t\t\"namePlaceholder\": \"\"\n\t\t},\n\t\t\"typeSettings\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"typeLabel\": \"\"\n\t\t},\n\t\t\"emailSettings\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"emailLabel\": \"\",\n\t\t\t\"emailPlaceholder\": \"\"\n\t\t},\n\t\t\"slackSettings\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"webhookLabel\": \"\",\n\t\t\t\"webhookPlaceholder\": \"\"\n\t\t},\n\t\t\"pagerdutySettings\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"integrationKeyLabel\": \"\",\n\t\t\t\"integrationKeyPlaceholder\": \"\"\n\t\t},\n\t\t\"discordSettings\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"webhookLabel\": \"\",\n\t\t\t\"webhookPlaceholder\": \"\"\n\t\t},\n\t\t\"webhookSettings\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"webhookLabel\": \"\",\n\t\t\t\"webhookPlaceholder\": \"\"\n\t\t}\n\t},\n\t\"notificationConfig\": {\n\t\t\"title\": \"\",\n\t\t\"description\": \"\"\n\t},\n\t\"monitorStatus\": {\n\t\t\"checkingEvery\": \"\",\n\t\t\"withCaptureAgent\": \"\",\n\t\t\"up\": \"\",\n\t\t\"down\": \"\",\n\t\t\"paused\": \"\"\n\t},\n\t\"advancedMatching\": \"\",\n\t\"sendTestNotifications\": \"\",\n\t\"testNotificationsDisabled\": \"\",\n\t\"selectAll\": \"\",\n\t\"showAdminLoginLink\": \"\",\n\t\"logsPage\": {\n\t\t\"title\": \"\",\n\t\t\"description\": \"\",\n\t\t\"tabs\": {\n\t\t\t\"queue\": \"\",\n\t\t\t\"logs\": \"\"\n\t\t},\n\t\t\"toast\": {\n\t\t\t\"fetchLogsSuccess\": \"\"\n\t\t},\n\t\t\"logLevelSelect\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"values\": {\n\t\t\t\t\"all\": \"\",\n\t\t\t\t\"info\": \"\",\n\t\t\t\t\"warn\": \"\",\n\t\t\t\t\"error\": \"\",\n\t\t\t\t\"debug\": \"\"\n\t\t\t}\n\t\t}\n\t},\n\t\"queuePage\": {\n\t\t\"title\": \"\",\n\t\t\"refreshButton\": \"\",\n\t\t\"flushButton\": \"\",\n\t\t\"jobTable\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"idHeader\": \"\",\n\t\t\t\"urlHeader\": \"\",\n\t\t\t\"typeHeader\": \"\",\n\t\t\t\"activeHeader\": \"\",\n\t\t\t\"lockedAtHeader\": \"\",\n\t\t\t\"runCountHeader\": \"\",\n\t\t\t\"failCountHeader\": \"\",\n\t\t\t\"lastRunHeader\": \"\",\n\t\t\t\"lastFinishedAtHeader\": \"\",\n\t\t\t\"lastRunTookHeader\": \"\"\n\t\t},\n\t\t\"metricsTable\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"metricHeader\": \"\",\n\t\t\t\"valueHeader\": \"\"\n\t\t},\n\t\t\"failedJobTable\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"monitorIdHeader\": \"\",\n\t\t\t\"monitorUrlHeader\": \"\",\n\t\t\t\"failCountHeader\": \"\",\n\t\t\t\"failedAtHeader\": \"\",\n\t\t\t\"failReasonHeader\": \"\"\n\t\t}\n\t},\n\t\"export\": {\n\t\t\"title\": \"\",\n\t\t\"success\": \"\",\n\t\t\"failed\": \"\"\n\t},\n\t\"monitorActions\": {\n\t\t\"title\": \"\",\n\t\t\"import\": \"\",\n\t\t\"export\": \"\"\n\t},\n\t\"settingsPage\": {\n\t\t\"aboutSettings\": {\n\t\t\t\"labelDevelopedBy\": \"\",\n\t\t\t\"labelVersion\": \"\",\n\t\t\t\"title\": \"\"\n\t\t},\n\t\t\"demoMonitorsSettings\": {\n\t\t\t\"buttonAddMonitors\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"title\": \"\"\n\t\t},\n\t\t\"emailSettings\": {\n\t\t\t\"buttonSendTestEmail\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"descriptionTransport\": \"\",\n\t\t\t\"labelAddress\": \"\",\n\t\t\t\"labelConnectionHost\": \"\",\n\t\t\t\"labelHost\": \"\",\n\t\t\t\"labelIgnoreTLS\": \"\",\n\t\t\t\"labelPassword\": \"\",\n\t\t\t\"labelPasswordSet\": \"\",\n\t\t\t\"labelPool\": \"\",\n\t\t\t\"labelPort\": \"\",\n\t\t\t\"labelRejectUnauthorized\": \"\",\n\t\t\t\"labelRequireTLS\": \"\",\n\t\t\t\"labelSecure\": \"\",\n\t\t\t\"labelTLSServername\": \"\",\n\t\t\t\"labelUser\": \"\",\n\t\t\t\"linkTransport\": \"\",\n\t\t\t\"placeholderUser\": \"\",\n\t\t\t\"title\": \"\"\n\t\t},\n\t\t\"pageSpeedSettings\": {\n\t\t\t\"description\": \"\",\n\t\t\t\"labelApiKeySet\": \"\",\n\t\t\t\"labelApiKey\": \"\",\n\t\t\t\"title\": \"\"\n\t\t},\n\t\t\"saveButtonLabel\": \"\",\n\t\t\"statsSettings\": {\n\t\t\t\"clearAllStatsButton\": \"\",\n\t\t\t\"clearAllStatsDescription\": \"\",\n\t\t\t\"clearAllStatsDialogConfirm\": \"\",\n\t\t\t\"clearAllStatsDialogDescription\": \"\",\n\t\t\t\"clearAllStatsDialogTitle\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"labelTTL\": \"\",\n\t\t\t\"labelTTLOptional\": \"\",\n\t\t\t\"title\": \"\"\n\t\t},\n\t\t\"systemResetSettings\": {\n\t\t\t\"buttonRemoveAllMonitors\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"dialogConfirm\": \"\",\n\t\t\t\"dialogDescription\": \"\",\n\t\t\t\"dialogTitle\": \"\",\n\t\t\t\"title\": \"\"\n\t\t},\n\t\t\"timezoneSettings\": {\n\t\t\t\"description\": \"\",\n\t\t\t\"label\": \"\",\n\t\t\t\"title\": \"\"\n\t\t},\n\t\t\"title\": \"\",\n\t\t\"uiSettings\": {\n\t\t\t\"description\": \"\",\n\t\t\t\"labelLanguage\": \"\",\n\t\t\t\"labelTheme\": \"\",\n\t\t\t\"title\": \"\"\n\t\t},\n\t\t\"urlSettings\": {\n\t\t\t\"description\": \"\",\n\t\t\t\"label\": \"\",\n\t\t\t\"selectDisabled\": \"\",\n\t\t\t\"selectEnabled\": \"\",\n\t\t\t\"title\": \"\"\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "client/src/locales/vi.json",
    "content": "{\n\t\"submit\": \"\",\n\t\"title\": \"\",\n\t\"distributedStatusHeaderText\": \"\",\n\t\"distributedStatusSubHeaderText\": \"\",\n\t\"settingsDisabled\": \"\",\n\t\"settingsSuccessSaved\": \"\",\n\t\"settingsFailedToSave\": \"\",\n\t\"settingsStatsCleared\": \"\",\n\t\"settingsFailedToClearStats\": \"\",\n\t\"settingsFailedToAddDemoMonitors\": \"\",\n\t\"settingsMonitorsDeleted\": \"\",\n\t\"settingsFailedToDeleteMonitors\": \"\",\n\t\"starPromptTitle\": \"\",\n\t\"starPromptDescription\": \"\",\n\t\"https\": \"\",\n\t\"http\": \"\",\n\t\"monitor\": \"\",\n\t\"aboutus\": \"\",\n\t\"now\": \"\",\n\t\"delete\": \"\",\n\t\"configure\": \"\",\n\t\"responseTime\": \"\",\n\t\"ms\": \"\",\n\t\"bar\": \"\",\n\t\"area\": \"\",\n\t\"country\": \"\",\n\t\"city\": \"\",\n\t\"response\": \"\",\n\t\"monitorStatusUp\": \"\",\n\t\"monitorStatusDown\": \"\",\n\t\"webhookSendSuccess\": \"\",\n\t\"webhookSendError\": \"\",\n\t\"webhookUnsupportedPlatform\": \"\",\n\t\"distributedRightCategoryTitle\": \"\",\n\t\"distributedStatusServerMonitors\": \"\",\n\t\"distributedStatusServerMonitorsDescription\": \"\",\n\t\"distributedUptimeCreateSelectURL\": \"\",\n\t\"distributedUptimeCreateChecks\": \"\",\n\t\"distributedUptimeCreateChecksDescription\": \"\",\n\t\"distributedUptimeCreateIncidentNotification\": \"\",\n\t\"distributedUptimeCreateIncidentDescription\": \"\",\n\t\"distributedUptimeCreateAdvancedSettings\": \"\",\n\t\"distributedUptimeDetailsNoMonitorHistory\": \"\",\n\t\"distributedUptimeDetailsStatusHeaderUptime\": \"\",\n\t\"distributedUptimeDetailsStatusHeaderLastUpdate\": \"\",\n\t\"notifications\": {\n\t\t\"enableNotifications\": \"\",\n\t\t\"testNotification\": \"\",\n\t\t\"addOrEditNotifications\": \"\",\n\t\t\"slack\": {\n\t\t\t\"label\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"webhookLabel\": \"\",\n\t\t\t\"webhookPlaceholder\": \"\",\n\t\t\t\"webhookRequired\": \"\"\n\t\t},\n\t\t\"discord\": {\n\t\t\t\"label\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"webhookLabel\": \"\",\n\t\t\t\"webhookPlaceholder\": \"\",\n\t\t\t\"webhookRequired\": \"\"\n\t\t},\n\t\t\"telegram\": {\n\t\t\t\"label\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"tokenLabel\": \"\",\n\t\t\t\"tokenPlaceholder\": \"\",\n\t\t\t\"chatIdLabel\": \"\",\n\t\t\t\"chatIdPlaceholder\": \"\",\n\t\t\t\"fieldsRequired\": \"\"\n\t\t},\n\t\t\"webhook\": {\n\t\t\t\"label\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"urlLabel\": \"\",\n\t\t\t\"urlPlaceholder\": \"\",\n\t\t\t\"urlRequired\": \"\"\n\t\t},\n\t\t\"testNotificationDevelop\": \"\",\n\t\t\"integrationButton\": \"\",\n\t\t\"testSuccess\": \"\",\n\t\t\"testFailed\": \"\",\n\t\t\"unsupportedType\": \"\",\n\t\t\"networkError\": \"\",\n\t\t\"fallback\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"checks\": [\"\"]\n\t\t},\n\t\t\"createButton\": \"\",\n\t\t\"createTitle\": \"\",\n\t\t\"create\": {\n\t\t\t\"success\": \"\",\n\t\t\t\"failed\": \"\"\n\t\t},\n\t\t\"fetch\": {\n\t\t\t\"success\": \"\",\n\t\t\t\"failed\": \"\"\n\t\t},\n\t\t\"delete\": {\n\t\t\t\"success\": \"\",\n\t\t\t\"failed\": \"\"\n\t\t},\n\t\t\"edit\": {\n\t\t\t\"success\": \"\",\n\t\t\t\"failed\": \"\"\n\t\t},\n\t\t\"test\": {\n\t\t\t\"success\": \"\",\n\t\t\t\"failed\": \"\"\n\t\t}\n\t},\n\t\"testLocale\": \"\",\n\t\"add\": \"\",\n\t\"monitors\": \"\",\n\t\"distributedUptimeStatusCreateStatusPage\": \"\",\n\t\"distributedUptimeStatusCreateStatusPageAccess\": \"\",\n\t\"distributedUptimeStatusCreateStatusPageReady\": \"\",\n\t\"distributedUptimeStatusBasicInfoHeader\": \"\",\n\t\"distributedUptimeStatusBasicInfoDescription\": \"\",\n\t\"distributedUptimeStatusLogoHeader\": \"\",\n\t\"distributedUptimeStatusLogoDescription\": \"\",\n\t\"distributedUptimeStatusLogoUploadButton\": \"\",\n\t\"distributedUptimeStatusStandardMonitorsHeader\": \"\",\n\t\"distributedUptimeStatusStandardMonitorsDescription\": \"\",\n\t\"distributedUptimeStatusCreateYour\": \"\",\n\t\"distributedUptimeStatusEditYour\": \"\",\n\t\"distributedUptimeStatusPublishedLabel\": \"\",\n\t\"distributedUptimeStatusCompanyNameLabel\": \"\",\n\t\"distributedUptimeStatusPageAddressLabel\": \"\",\n\t\"distributedUptimeStatus30Days\": \"\",\n\t\"distributedUptimeStatus60Days\": \"\",\n\t\"distributedUptimeStatus90Days\": \"\",\n\t\"distributedUptimeStatusPageNotSetUp\": \"\",\n\t\"distributedUptimeStatusContactAdmin\": \"\",\n\t\"distributedUptimeStatusPageNotPublic\": \"\",\n\t\"distributedUptimeStatusPageDeleteDialog\": \"\",\n\t\"distributedUptimeStatusPageDeleteConfirm\": \"\",\n\t\"distributedUptimeStatusPageDeleteDescription\": \"\",\n\t\"distributedUptimeStatusDevices\": \"\",\n\t\"distributedUptimeStatusUpt\": \"\",\n\t\"distributedUptimeStatusUptBurned\": \"\",\n\t\"distributedUptimeStatusUptLogo\": \"\",\n\t\"incidentsTableNoIncidents\": \"\",\n\t\"incidentsTablePaginationLabel\": \"\",\n\t\"incidentsTableMonitorName\": \"\",\n\t\"incidentsTableStatus\": \"\",\n\t\"incidentsTableDateTime\": \"\",\n\t\"incidentsTableStatusCode\": \"\",\n\t\"incidentsTableMessage\": \"\",\n\t\"incidentsOptionsHeader\": \"\",\n\t\"incidentsOptionsHeaderFilterBy\": \"\",\n\t\"incidentsOptionsHeaderFilterAll\": \"\",\n\t\"incidentsOptionsHeaderFilterDown\": \"\",\n\t\"incidentsOptionsHeaderFilterCannotResolve\": \"\",\n\t\"incidentsOptionsHeaderShow\": \"\",\n\t\"incidentsOptionsHeaderLastHour\": \"\",\n\t\"incidentsOptionsHeaderLastDay\": \"\",\n\t\"incidentsOptionsHeaderLastWeek\": \"\",\n\t\"incidentsOptionsPlaceholderAllServers\": \"\",\n\t\"infrastructureCreateYour\": \"\",\n\t\"infrastructureCreateGeneralSettingsDescription\": \"\",\n\t\"infrastructureServerRequirement\": \"\",\n\t\"infrastructureCustomizeAlerts\": \"\",\n\t\"infrastructureAlertNotificationDescription\": \"\",\n\t\"infrastructureCreateMonitor\": \"\",\n\t\"infrastructureProtocol\": \"\",\n\t\"infrastructureServerUrlLabel\": \"\",\n\t\"infrastructureDisplayNameLabel\": \"\",\n\t\"infrastructureAuthorizationSecretLabel\": \"\",\n\t\"gb\": \"\",\n\t\"mb\": \"\",\n\t\"mem\": \"\",\n\t\"memoryUsage\": \"\",\n\t\"cpu\": \"\",\n\t\"cpuUsage\": \"\",\n\t\"cpuTemperature\": \"\",\n\t\"diskUsage\": \"\",\n\t\"used\": \"\",\n\t\"total\": \"\",\n\t\"cores\": \"\",\n\t\"frequency\": \"\",\n\t\"status\": \"\",\n\t\"cpuPhysical\": \"\",\n\t\"cpuLogical\": \"\",\n\t\"cpuFrequency\": \"\",\n\t\"avgCpuTemperature\": \"\",\n\t\"memory\": \"\",\n\t\"disk\": \"\",\n\t\"uptime\": \"\",\n\t\"os\": \"\",\n\t\"host\": \"\",\n\t\"actions\": \"\",\n\t\"integrations\": \"\",\n\t\"integrationsPrism\": \"\",\n\t\"integrationsSlack\": \"\",\n\t\"integrationsSlackInfo\": \"\",\n\t\"integrationsDiscord\": \"\",\n\t\"integrationsDiscordInfo\": \"\",\n\t\"integrationsZapier\": \"\",\n\t\"integrationsZapierInfo\": \"\",\n\t\"commonSave\": \"\",\n\t\"createYour\": \"\",\n\t\"createMonitor\": \"\",\n\t\"pause\": \"\",\n\t\"resume\": \"\",\n\t\"editing\": \"\",\n\t\"url\": \"\",\n\t\"access\": \"\",\n\t\"timezone\": \"\",\n\t\"features\": \"\",\n\t\"administrator\": \"\",\n\t\"loginHere\": \"\",\n\t\"displayName\": \"\",\n\t\"urlMonitor\": \"\",\n\t\"portToMonitor\": \"\",\n\t\"websiteMonitoring\": \"\",\n\t\"websiteMonitoringDescription\": \"\",\n\t\"pingMonitoring\": \"\",\n\t\"pingMonitoringDescription\": \"\",\n\t\"dockerContainerMonitoring\": \"\",\n\t\"dockerContainerMonitoringDescription\": \"\",\n\t\"portMonitoring\": \"\",\n\t\"portMonitoringDescription\": \"\",\n\t\"createMaintenanceWindow\": \"\",\n\t\"createMaintenance\": \"\",\n\t\"editMaintenance\": \"\",\n\t\"maintenanceWindowName\": \"\",\n\t\"friendlyNameInput\": \"\",\n\t\"friendlyNamePlaceholder\": \"\",\n\t\"maintenanceRepeat\": \"\",\n\t\"maintenance\": \"\",\n\t\"duration\": \"\",\n\t\"addMonitors\": \"\",\n\t\"window\": \"\",\n\t\"cancel\": \"\",\n\t\"message\": \"\",\n\t\"low\": \"\",\n\t\"high\": \"\",\n\t\"statusCode\": \"\",\n\t\"date&Time\": \"\",\n\t\"type\": \"\",\n\t\"statusPageName\": \"\",\n\t\"publicURL\": \"\",\n\t\"repeat\": \"\",\n\t\"edit\": \"\",\n\t\"createA\": \"\",\n\t\"remove\": \"\",\n\t\"maintenanceWindowDescription\": \"\",\n\t\"startTime\": \"\",\n\t\"timeZoneInfo\": \"\",\n\t\"monitorsToApply\": \"\",\n\t\"nextWindow\": \"\",\n\t\"notFoundButton\": \"\",\n\t\"pageSpeedConfigureSettingsDescription\": \"\",\n\t\"monitorDisplayName\": \"\",\n\t\"whenNewIncident\": \"\",\n\t\"notifySMS\": \"\",\n\t\"notifyEmails\": \"\",\n\t\"seperateEmails\": \"\",\n\t\"checkFrequency\": \"\",\n\t\"chooseGame\": \"\",\n\t\"matchMethod\": \"\",\n\t\"expectedValue\": \"\",\n\t\"deleteDialogTitle\": \"\",\n\t\"deleteDialogDescription\": \"\",\n\t\"pageSpeedMonitor\": \"\",\n\t\"shown\": \"\",\n\t\"ago\": \"\",\n\t\"companyName\": \"\",\n\t\"pageSpeedDetailsPerformanceReport\": \"\",\n\t\"pageSpeedDetailsPerformanceReportCalculator\": \"\",\n\t\"checkingEvery\": \"\",\n\t\"statusPageCreateSettings\": \"\",\n\t\"basicInformation\": \"\",\n\t\"statusPageCreateBasicInfoDescription\": \"\",\n\t\"statusPageCreateSelectTimeZoneDescription\": \"\",\n\t\"statusPageCreateAppearanceDescription\": \"\",\n\t\"statusPageCreateSettingsCheckboxLabel\": \"\",\n\t\"statusPageCreateBasicInfoStatusPageAddress\": \"\",\n\t\"statusPageCreateTabsContent\": \"\",\n\t\"statusPageCreateTabsContentDescription\": \"\",\n\t\"statusPageCreateTabsContentFeaturesDescription\": \"\",\n\t\"showCharts\": \"\",\n\t\"showUptimePercentage\": \"\",\n\t\"removeLogo\": \"\",\n\t\"statusPageStatus\": \"\",\n\t\"statusPageStatusContactAdmin\": \"\",\n\t\"statusPageStatusNotPublic\": \"\",\n\t\"statusPageStatusNoPage\": \"\",\n\t\"statusPageStatusServiceStatus\": \"\",\n\t\"deleteStatusPage\": \"\",\n\t\"deleteStatusPageConfirm\": \"\",\n\t\"deleteStatusPageDescription\": \"\",\n\t\"uptimeCreate\": \"\",\n\t\"uptimeCreateJsonPath\": \"\",\n\t\"uptimeCreateJsonPathQuery\": \"\",\n\t\"maintenanceTableActionMenuDialogTitle\": \"\",\n\t\"infrastructureEditYour\": \"\",\n\t\"infrastructureEditMonitor\": \"\",\n\t\"infrastructureMonitorCreated\": \"\",\n\t\"infrastructureMonitorUpdated\": \"\",\n\t\"errorInvalidTypeId\": \"\",\n\t\"errorInvalidFieldId\": \"\",\n\t\"inviteNoTokenFound\": \"\",\n\t\"pageSpeedWarning\": \"\",\n\t\"pageSpeedLearnMoreLink\": \"\",\n\t\"pageSpeedAddApiKey\": \"\",\n\t\"update\": \"\",\n\t\"invalidFileFormat\": \"\",\n\t\"invalidFileSize\": \"\",\n\t\"ClickUpload\": \"\",\n\t\"DragandDrop\": \"\",\n\t\"MaxSize\": \"\",\n\t\"SupportedFormats\": \"\",\n\t\"FirstName\": \"\",\n\t\"LastName\": \"\",\n\t\"EmailDescriptionText\": \"\",\n\t\"YourPhoto\": \"\",\n\t\"PhotoDescriptionText\": \"\",\n\t\"save\": \"\",\n\t\"DeleteDescriptionText\": \"\",\n\t\"DeleteAccountWarning\": \"\",\n\t\"DeleteWarningTitle\": \"\",\n\t\"bulkImport\": {\n\t\t\"title\": \"\",\n\t\t\"selectFileTips\": \"\",\n\t\t\"selectFileDescription\": \"\",\n\t\t\"selectFile\": \"\",\n\t\t\"parsingFailed\": \"\",\n\t\t\"uploadSuccess\": \"\",\n\t\t\"validationFailed\": \"\",\n\t\t\"noFileSelected\": \"\",\n\t\t\"fallbackPage\": \"\"\n\t},\n\t\"DeleteAccountTitle\": \"\",\n\t\"DeleteAccountButton\": \"\",\n\t\"publicLink\": \"\",\n\t\"maskedPageSpeedKeyPlaceholder\": \"\",\n\t\"reset\": \"\",\n\t\"ignoreTLSError\": \"\",\n\t\"tlsErrorIgnored\": \"\",\n\t\"ignoreTLSErrorDescription\": \"\",\n\t\"createNew\": \"\",\n\t\"greeting\": {\n\t\t\"prepend\": \"\",\n\t\t\"append\": \"\",\n\t\t\"overview\": \"\"\n\t},\n\t\"roles\": {\n\t\t\"superAdmin\": \"\",\n\t\t\"admin\": \"\",\n\t\t\"teamMember\": \"\",\n\t\t\"demoUser\": \"\"\n\t},\n\t\"teamPanel\": {\n\t\t\"teamMembers\": \"\",\n\t\t\"filter\": {\n\t\t\t\"all\": \"\",\n\t\t\t\"member\": \"\"\n\t\t},\n\t\t\"inviteTeamMember\": \"\",\n\t\t\"inviteNewTeamMember\": \"\",\n\t\t\"inviteDescription\": \"\",\n\t\t\"email\": \"\",\n\t\t\"selectRole\": \"\",\n\t\t\"inviteLink\": \"\",\n\t\t\"cancel\": \"\",\n\t\t\"noMembers\": \"\",\n\t\t\"getToken\": \"\",\n\t\t\"emailToken\": \"\",\n\t\t\"table\": {\n\t\t\t\"name\": \"\",\n\t\t\t\"email\": \"\",\n\t\t\t\"role\": \"\",\n\t\t\t\"created\": \"\"\n\t\t}\n\t},\n\t\"monitorState\": {\n\t\t\"paused\": \"\",\n\t\t\"resumed\": \"\",\n\t\t\"active\": \"\"\n\t},\n\t\"menu\": {\n\t\t\"uptime\": \"\",\n\t\t\"pagespeed\": \"\",\n\t\t\"infrastructure\": \"\",\n\t\t\"incidents\": \"\",\n\t\t\"statusPages\": \"\",\n\t\t\"maintenance\": \"\",\n\t\t\"integrations\": \"\",\n\t\t\"settings\": \"\",\n\t\t\"support\": \"\",\n\t\t\"discussions\": \"\",\n\t\t\"docs\": \"\",\n\t\t\"changelog\": \"\",\n\t\t\"profile\": \"\",\n\t\t\"password\": \"\",\n\t\t\"team\": \"\",\n\t\t\"logOut\": \"\",\n\t\t\"notifications\": \"\",\n\t\t\"logs\": \"\"\n\t},\n\t\"settingsEmailUser\": \"\",\n\t\"state\": \"\",\n\t\"statusBreadCrumbsStatusPages\": \"\",\n\t\"statusBreadCrumbsDetails\": \"\",\n\t\"commonSaving\": \"\",\n\t\"navControls\": \"\",\n\t\"incidentsPageTitle\": \"\",\n\t\"passwordPanel\": {\n\t\t\"passwordChangedSuccess\": \"\",\n\t\t\"passwordInputIncorrect\": \"\",\n\t\t\"currentPassword\": \"\",\n\t\t\"enterCurrentPassword\": \"\",\n\t\t\"newPassword\": \"\",\n\t\t\"enterNewPassword\": \"\",\n\t\t\"confirmNewPassword\": \"\",\n\t\t\"passwordRequirements\": \"\",\n\t\t\"saving\": \"\"\n\t},\n\t\"emailSent\": \"\",\n\t\"failedToSendEmail\": \"\",\n\t\"settingsTestEmailSuccess\": \"\",\n\t\"settingsTestEmailFailed\": \"\",\n\t\"settingsTestEmailFailedWithReason\": \"\",\n\t\"settingsTestEmailUnknownError\": \"\",\n\t\"statusMsg\": {\n\t\t\"paused\": \"\",\n\t\t\"up\": \"\",\n\t\t\"down\": \"\",\n\t\t\"pending\": \"\"\n\t},\n\t\"uptimeGeneralInstructions\": {\n\t\t\"http\": \"\",\n\t\t\"ping\": \"\",\n\t\t\"docker\": \"\",\n\t\t\"port\": \"\",\n\t\t\"game\": \"\"\n\t},\n\t\"common\": {\n\t\t\"appName\": \"\",\n\t\t\"monitoringAgentName\": \"\",\n\t\t\"buttons\": {\n\t\t\t\"toggleTheme\": \"\"\n\t\t},\n\t\t\"toasts\": {\n\t\t\t\"networkError\": \"\",\n\t\t\t\"checkConnection\": \"\",\n\t\t\t\"unknownError\": \"\"\n\t\t}\n\t},\n\t\"auth\": {\n\t\t\"common\": {\n\t\t\t\"navigation\": {\n\t\t\t\t\"continue\": \"\",\n\t\t\t\t\"back\": \"\"\n\t\t\t},\n\t\t\t\"inputs\": {\n\t\t\t\t\"email\": {\n\t\t\t\t\t\"label\": \"\",\n\t\t\t\t\t\"placeholder\": \"\",\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"\",\n\t\t\t\t\t\t\"invalid\": \"\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"password\": {\n\t\t\t\t\t\"label\": \"\",\n\t\t\t\t\t\"rules\": {\n\t\t\t\t\t\t\"length\": {\n\t\t\t\t\t\t\t\"beginning\": \"\",\n\t\t\t\t\t\t\t\"highlighted\": \"\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"special\": {\n\t\t\t\t\t\t\t\"beginning\": \"\",\n\t\t\t\t\t\t\t\"highlighted\": \"\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"number\": {\n\t\t\t\t\t\t\t\"beginning\": \"\",\n\t\t\t\t\t\t\t\"highlighted\": \"\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"uppercase\": {\n\t\t\t\t\t\t\t\"beginning\": \"\",\n\t\t\t\t\t\t\t\"highlighted\": \"\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"lowercase\": {\n\t\t\t\t\t\t\t\"beginning\": \"\",\n\t\t\t\t\t\t\t\"highlighted\": \"\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"match\": {\n\t\t\t\t\t\t\t\"beginning\": \"\",\n\t\t\t\t\t\t\t\"highlighted\": \"\"\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"\",\n\t\t\t\t\t\t\"length\": \"\",\n\t\t\t\t\t\t\"uppercase\": \"\",\n\t\t\t\t\t\t\"lowercase\": \"\",\n\t\t\t\t\t\t\"number\": \"\",\n\t\t\t\t\t\t\"special\": \"\",\n\t\t\t\t\t\t\"incorrect\": \"\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"passwordConfirm\": {\n\t\t\t\t\t\"label\": \"\",\n\t\t\t\t\t\"placeholder\": \"\",\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"\",\n\t\t\t\t\t\t\"different\": \"\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"firstName\": {\n\t\t\t\t\t\"label\": \"\",\n\t\t\t\t\t\"placeholder\": \"\",\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"\",\n\t\t\t\t\t\t\"length\": \"\",\n\t\t\t\t\t\t\"pattern\": \"\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"lastName\": {\n\t\t\t\t\t\"label\": \"\",\n\t\t\t\t\t\"placeholder\": \"\",\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"\",\n\t\t\t\t\t\t\"length\": \"\",\n\t\t\t\t\t\t\"pattern\": \"\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"errors\": {\n\t\t\t\t\"validation\": \"\"\n\t\t\t},\n\t\t\t\"fields\": {\n\t\t\t\t\"password\": {\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"incorrect\": \"\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"login\": {\n\t\t\t\"heading\": \"\",\n\t\t\t\"subheadings\": {\n\t\t\t\t\"stepOne\": \"\",\n\t\t\t\t\"stepTwo\": \"\"\n\t\t\t},\n\t\t\t\"links\": {\n\t\t\t\t\"forgotPassword\": \"\",\n\t\t\t\t\"register\": \"\",\n\t\t\t\t\"forgotPasswordLink\": \"\",\n\t\t\t\t\"registerLink\": \"\"\n\t\t\t},\n\t\t\t\"toasts\": {\n\t\t\t\t\"success\": \"\",\n\t\t\t\t\"incorrectPassword\": \"\"\n\t\t\t},\n\t\t\t\"errors\": {\n\t\t\t\t\"password\": {\n\t\t\t\t\t\"incorrect\": \"\"\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"registration\": {\n\t\t\t\"heading\": {\n\t\t\t\t\"superAdmin\": \"\",\n\t\t\t\t\"user\": \"\"\n\t\t\t},\n\t\t\t\"subheadings\": {\n\t\t\t\t\"stepOne\": \"\",\n\t\t\t\t\"stepTwo\": \"\",\n\t\t\t\t\"stepThree\": \"\"\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\t\"superAdmin\": \"\",\n\t\t\t\t\"user\": \"\"\n\t\t\t},\n\t\t\t\"gettingStartedButton\": {\n\t\t\t\t\"superAdmin\": \"\",\n\t\t\t\t\"user\": \"\"\n\t\t\t},\n\t\t\t\"termsAndPolicies\": \"\",\n\t\t\t\"links\": {\n\t\t\t\t\"login\": \"\"\n\t\t\t},\n\t\t\t\"toasts\": {\n\t\t\t\t\"success\": \"\"\n\t\t\t}\n\t\t},\n\t\t\"forgotPassword\": {\n\t\t\t\"heading\": \"\",\n\t\t\t\"subheadings\": {\n\t\t\t\t\"stepOne\": \"\",\n\t\t\t\t\"stepTwo\": \"\",\n\t\t\t\t\"stepThree\": \"\",\n\t\t\t\t\"stepFour\": \"\"\n\t\t\t},\n\t\t\t\"buttons\": {\n\t\t\t\t\"openEmail\": \"\",\n\t\t\t\t\"resetPassword\": \"\"\n\t\t\t},\n\t\t\t\"imageAlts\": {\n\t\t\t\t\"passwordKey\": \"\",\n\t\t\t\t\"email\": \"\",\n\t\t\t\t\"lock\": \"\",\n\t\t\t\t\"passwordConfirm\": \"\"\n\t\t\t},\n\t\t\t\"links\": {\n\t\t\t\t\"login\": \"\",\n\t\t\t\t\"resend\": \"\"\n\t\t\t},\n\t\t\t\"toasts\": {\n\t\t\t\t\"sent\": \"\",\n\t\t\t\t\"emailNotFound\": \"\",\n\t\t\t\t\"redirect\": \"\",\n\t\t\t\t\"success\": \"\",\n\t\t\t\t\"error\": \"\"\n\t\t\t}\n\t\t}\n\t},\n\t\"errorPages\": {\n\t\t\"serverUnreachable\": {\n\t\t\t\"toasts\": {\n\t\t\t\t\"reconnected\": \"\",\n\t\t\t\t\"stillUnreachable\": \"\"\n\t\t\t},\n\t\t\t\"alertBox\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"retryButton\": {\n\t\t\t\t\"default\": \"\",\n\t\t\t\t\"processing\": \"\"\n\t\t\t}\n\t\t}\n\t},\n\t\"createNotifications\": {\n\t\t\"title\": \"\",\n\t\t\"nameSettings\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"nameLabel\": \"\",\n\t\t\t\"namePlaceholder\": \"\"\n\t\t},\n\t\t\"typeSettings\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"typeLabel\": \"\"\n\t\t},\n\t\t\"emailSettings\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"emailLabel\": \"\",\n\t\t\t\"emailPlaceholder\": \"\"\n\t\t},\n\t\t\"slackSettings\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"webhookLabel\": \"\",\n\t\t\t\"webhookPlaceholder\": \"\"\n\t\t},\n\t\t\"pagerdutySettings\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"integrationKeyLabel\": \"\",\n\t\t\t\"integrationKeyPlaceholder\": \"\"\n\t\t},\n\t\t\"discordSettings\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"webhookLabel\": \"\",\n\t\t\t\"webhookPlaceholder\": \"\"\n\t\t},\n\t\t\"webhookSettings\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"webhookLabel\": \"\",\n\t\t\t\"webhookPlaceholder\": \"\"\n\t\t}\n\t},\n\t\"notificationConfig\": {\n\t\t\"title\": \"\",\n\t\t\"description\": \"\"\n\t},\n\t\"monitorStatus\": {\n\t\t\"checkingEvery\": \"\",\n\t\t\"withCaptureAgent\": \"\",\n\t\t\"up\": \"\",\n\t\t\"down\": \"\",\n\t\t\"paused\": \"\"\n\t},\n\t\"advancedMatching\": \"\",\n\t\"sendTestNotifications\": \"\",\n\t\"testNotificationsDisabled\": \"\",\n\t\"selectAll\": \"\",\n\t\"showAdminLoginLink\": \"\",\n\t\"logsPage\": {\n\t\t\"title\": \"\",\n\t\t\"description\": \"\",\n\t\t\"tabs\": {\n\t\t\t\"queue\": \"\",\n\t\t\t\"logs\": \"\"\n\t\t},\n\t\t\"toast\": {\n\t\t\t\"fetchLogsSuccess\": \"\"\n\t\t},\n\t\t\"logLevelSelect\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"values\": {\n\t\t\t\t\"all\": \"\",\n\t\t\t\t\"info\": \"\",\n\t\t\t\t\"warn\": \"\",\n\t\t\t\t\"error\": \"\",\n\t\t\t\t\"debug\": \"\"\n\t\t\t}\n\t\t}\n\t},\n\t\"queuePage\": {\n\t\t\"title\": \"\",\n\t\t\"refreshButton\": \"\",\n\t\t\"flushButton\": \"\",\n\t\t\"jobTable\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"idHeader\": \"\",\n\t\t\t\"urlHeader\": \"\",\n\t\t\t\"typeHeader\": \"\",\n\t\t\t\"activeHeader\": \"\",\n\t\t\t\"lockedAtHeader\": \"\",\n\t\t\t\"runCountHeader\": \"\",\n\t\t\t\"failCountHeader\": \"\",\n\t\t\t\"lastRunHeader\": \"\",\n\t\t\t\"lastFinishedAtHeader\": \"\",\n\t\t\t\"lastRunTookHeader\": \"\"\n\t\t},\n\t\t\"metricsTable\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"metricHeader\": \"\",\n\t\t\t\"valueHeader\": \"\"\n\t\t},\n\t\t\"failedJobTable\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"monitorIdHeader\": \"\",\n\t\t\t\"monitorUrlHeader\": \"\",\n\t\t\t\"failCountHeader\": \"\",\n\t\t\t\"failedAtHeader\": \"\",\n\t\t\t\"failReasonHeader\": \"\"\n\t\t}\n\t},\n\t\"export\": {\n\t\t\"title\": \"\",\n\t\t\"success\": \"\",\n\t\t\"failed\": \"\"\n\t},\n\t\"monitorActions\": {\n\t\t\"title\": \"\",\n\t\t\"import\": \"\",\n\t\t\"export\": \"\"\n\t},\n\t\"settingsPage\": {\n\t\t\"aboutSettings\": {\n\t\t\t\"labelDevelopedBy\": \"\",\n\t\t\t\"labelVersion\": \"\",\n\t\t\t\"title\": \"\"\n\t\t},\n\t\t\"demoMonitorsSettings\": {\n\t\t\t\"buttonAddMonitors\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"title\": \"\"\n\t\t},\n\t\t\"emailSettings\": {\n\t\t\t\"buttonSendTestEmail\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"descriptionTransport\": \"\",\n\t\t\t\"labelAddress\": \"\",\n\t\t\t\"labelConnectionHost\": \"\",\n\t\t\t\"labelHost\": \"\",\n\t\t\t\"labelIgnoreTLS\": \"\",\n\t\t\t\"labelPassword\": \"\",\n\t\t\t\"labelPasswordSet\": \"\",\n\t\t\t\"labelPool\": \"\",\n\t\t\t\"labelPort\": \"\",\n\t\t\t\"labelRejectUnauthorized\": \"\",\n\t\t\t\"labelRequireTLS\": \"\",\n\t\t\t\"labelSecure\": \"\",\n\t\t\t\"labelTLSServername\": \"\",\n\t\t\t\"labelUser\": \"\",\n\t\t\t\"linkTransport\": \"\",\n\t\t\t\"placeholderUser\": \"\",\n\t\t\t\"title\": \"\"\n\t\t},\n\t\t\"pageSpeedSettings\": {\n\t\t\t\"description\": \"\",\n\t\t\t\"labelApiKeySet\": \"\",\n\t\t\t\"labelApiKey\": \"\",\n\t\t\t\"title\": \"\"\n\t\t},\n\t\t\"saveButtonLabel\": \"\",\n\t\t\"statsSettings\": {\n\t\t\t\"clearAllStatsButton\": \"\",\n\t\t\t\"clearAllStatsDescription\": \"\",\n\t\t\t\"clearAllStatsDialogConfirm\": \"\",\n\t\t\t\"clearAllStatsDialogDescription\": \"\",\n\t\t\t\"clearAllStatsDialogTitle\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"labelTTL\": \"\",\n\t\t\t\"labelTTLOptional\": \"\",\n\t\t\t\"title\": \"\"\n\t\t},\n\t\t\"systemResetSettings\": {\n\t\t\t\"buttonRemoveAllMonitors\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"dialogConfirm\": \"\",\n\t\t\t\"dialogDescription\": \"\",\n\t\t\t\"dialogTitle\": \"\",\n\t\t\t\"title\": \"\"\n\t\t},\n\t\t\"timezoneSettings\": {\n\t\t\t\"description\": \"\",\n\t\t\t\"label\": \"\",\n\t\t\t\"title\": \"\"\n\t\t},\n\t\t\"title\": \"\",\n\t\t\"uiSettings\": {\n\t\t\t\"description\": \"\",\n\t\t\t\"labelLanguage\": \"\",\n\t\t\t\"labelTheme\": \"\",\n\t\t\t\"title\": \"\"\n\t\t},\n\t\t\"urlSettings\": {\n\t\t\t\"description\": \"\",\n\t\t\t\"label\": \"\",\n\t\t\t\"selectDisabled\": \"\",\n\t\t\t\"selectEnabled\": \"\",\n\t\t\t\"title\": \"\"\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "client/src/locales/zh-CN.json",
    "content": "{\n\t\"submit\": \"提交\",\n\t\"title\": \"标题\",\n\t\"distributedStatusHeaderText\": \"实时、真实设备覆盖\",\n\t\"distributedStatusSubHeaderText\": \"在全球数百万设备的支持下，按全球区域、国家或城市查看系统性能\",\n\t\"settingsDisabled\": \"禁用\",\n\t\"settingsSuccessSaved\": \"设置保存成功\",\n\t\"settingsFailedToSave\": \"保存设置失败\",\n\t\"settingsStatsCleared\": \"统计数据已成功清除\",\n\t\"settingsFailedToClearStats\": \"清除统计数据失败\",\n\t\"settingsMonitorsDeleted\": \"已成功删除所有监视器\",\n\t\"settingsFailedToDeleteMonitors\": \"删除所有监视器失败\",\n\t\"starPromptTitle\": \"打星Checkmate\",\n\t\"starPromptDescription\": \"在 GitHub 上查看最新版本，并帮助社区发展壮大\",\n\t\"https\": \"HTTPS\",\n\t\"http\": \"HTTP\",\n\t\"monitor\": \"监控\",\n\t\"aboutus\": \"关于我们\",\n\t\"now\": \"现在\",\n\t\"delete\": \"删除\",\n\t\"configure\": \"配置\",\n\t\"responseTime\": \"响应时间\",\n\t\"ms\": \"毫秒\",\n\t\"bar\": \"条\",\n\t\"area\": \"区域\",\n\t\"country\": \"国家\",\n\t\"city\": \"城市\",\n\t\"response\": \"响应\",\n\t\"monitorStatusUp\": \"监控目标 {name} ({url}) 现在处于正常状态并正在响应\",\n\t\"monitorStatusDown\": \"监控目标 {name} ({url}) 已下线且无响应\",\n\t\"webhookSendSuccess\": \"Webhook通知发送成功\",\n\t\"webhookSendError\": \"向 {platform} 发送 Webhook 通知时出错\",\n\t\"webhookUnsupportedPlatform\": \"不支持的平台：{platform}\",\n\t\"distributedRightCategoryTitle\": \"监控\",\n\t\"distributedStatusServerMonitors\": \"服务器监控\",\n\t\"distributedStatusServerMonitorsDescription\": \"监控相关服务器的状态\",\n\t\"distributedUptimeCreateSelectURL\": \"在这里，您可以选择主机的URL以及监控类型。\",\n\t\"distributedUptimeCreateChecks\": \"分布式正常运行时间创建检查\",\n\t\"distributedUptimeCreateChecksDescription\": \"在添加站点之后，您随时可以增加或删除检查项。\",\n\t\"distributedUptimeCreateIncidentNotification\": \"事件通知\",\n\t\"distributedUptimeCreateIncidentDescription\": \"当发生事件时，通知用户。\",\n\t\"distributedUptimeCreateAdvancedSettings\": \"高级设置\",\n\t\"distributedUptimeDetailsNoMonitorHistory\": \"此监控器尚未有检查历史记录。\",\n\t\"distributedUptimeDetailsStatusHeaderUptime\": \"运行时间：\",\n\t\"distributedUptimeDetailsStatusHeaderLastUpdate\": \"最后更新于\",\n\t\"notifications\": {\n\t\t\"enableNotifications\": \"启用 {{platform}} 通知\",\n\t\t\"testNotification\": \"测试通知\",\n\t\t\"addOrEditNotifications\": \"添加或修改通知方式\",\n\t\t\"slack\": {\n\t\t\t\"label\": \"Slack\",\n\t\t\t\"description\": \"要启用 Slack 通知，请先创建一个 Slack 应用并启用传入的 Webhook。之后，只需在此处提供 Webhook URL 即可。\",\n\t\t\t\"webhookLabel\": \"Webhook 网址\",\n\t\t\t\"webhookPlaceholder\": \"https://hooks.slack.com/services/...\",\n\t\t\t\"webhookRequired\": \"需要 Slack Webhook URL\"\n\t\t},\n\t\t\"discord\": {\n\t\t\t\"label\": \"Discord\",\n\t\t\t\"description\": \"要通过 Discord 通知将数据从 Checkmate 发送到 Discord 频道，可以使用 Discord 的入站 WebHooks 功能。\",\n\t\t\t\"webhookLabel\": \"Discord 接收网址\",\n\t\t\t\"webhookPlaceholder\": \"https://discord.com/api/webhooks/...\",\n\t\t\t\"webhookRequired\": \"需要 Discord Webhook URL\"\n\t\t},\n\t\t\"telegram\": {\n\t\t\t\"label\": \"Telegram\",\n\t\t\t\"description\": \"要启用 Telegram 通知，请使用 BotFather创建一个 Telegram 机器人。然后，获取 API 令牌和聊天 ID 并在此处填写。\",\n\t\t\t\"tokenLabel\": \"你的机器人token\",\n\t\t\t\"tokenPlaceholder\": \"123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11\",\n\t\t\t\"chatIdLabel\": \"你的Chat ID\",\n\t\t\t\"chatIdPlaceholder\": \"-1001234567890\",\n\t\t\t\"fieldsRequired\": \"需要 Telegram 令牌和聊天 ID\"\n\t\t},\n\t\t\"webhook\": {\n\t\t\t\"label\": \"Webhooks\",\n\t\t\t\"description\": \"你可以设置自定义的 Webhook，以便在事件发生时接收通知。\",\n\t\t\t\"urlLabel\": \"Webhook URL\",\n\t\t\t\"urlPlaceholder\": \"https://your-server.com/webhook\",\n\t\t\t\"urlRequired\": \"Webhook URL 是必填项\"\n\t\t},\n\t\t\"testNotificationDevelop\": \"测试通知 2\",\n\t\t\"integrationButton\": \"通知集成\",\n\t\t\"testSuccess\": \"测试通知发送成功！\",\n\t\t\"testFailed\": \"测试通知发送失败\",\n\t\t\"unsupportedType\": \"不支持的通知类型\",\n\t\t\"networkError\": \"发生网络错误\",\n\t\t\"fallback\": {\n\t\t\t\"title\": \"通知通道用于：\",\n\t\t\t\"checks\": [\n\t\t\t\t\"提醒团队有关停机时间或性能问题\",\n\t\t\t\t\"让工程师知道事件发生时\",\n\t\t\t\t\"让管理员了解系统更改\"\n\t\t\t],\n\t\t\t\"actionButton\": \"让我们创建您的第一个通知渠道！\"\n\t\t},\n\t\t\"createButton\": \"创建通知渠道\",\n\t\t\"createTitle\": \"通知渠道\",\n\t\t\"create\": {\n\t\t\t\"success\": \"通知创建成功\",\n\t\t\t\"failed\": \"通知创建失败\"\n\t\t},\n\t\t\"fetch\": {\n\t\t\t\"success\": \"成功获取通知\",\n\t\t\t\"failed\": \"无法获取通知\"\n\t\t},\n\t\t\"delete\": {\n\t\t\t\"success\": \"通知已成功删除\",\n\t\t\t\"failed\": \"删除通知失败\"\n\t\t},\n\t\t\"edit\": {\n\t\t\t\"success\": \"通知已成功更新\",\n\t\t\t\"failed\": \"无法更新通知\"\n\t\t},\n\t\t\"test\": {\n\t\t\t\"success\": \"测试通知发送成功\",\n\t\t\t\"failed\": \"测试通知发送失败\"\n\t\t}\n\t},\n\t\"testLocale\": \"测试区域设置\",\n\t\"add\": \"添加\",\n\t\"monitors\": \"监视器\",\n\t\"distributedUptimeStatusCreateStatusPage\": \"状态页\",\n\t\"distributedUptimeStatusCreateStatusPageAccess\": \"访问\",\n\t\"distributedUptimeStatusCreateStatusPageReady\": \"如果状态页面准备就绪，您可以标记为已发布。\",\n\t\"distributedUptimeStatusBasicInfoHeader\": \"基础信息\",\n\t\"distributedUptimeStatusBasicInfoDescription\": \"定义公司名称和状态页指向的子域名。\",\n\t\"distributedUptimeStatusLogoHeader\": \"Logo\",\n\t\"distributedUptimeStatusLogoDescription\": \"为您的状态页面上传一个 Logo\",\n\t\"distributedUptimeStatusLogoUploadButton\": \"上传 Logo\",\n\t\"distributedUptimeStatusStandardMonitorsHeader\": \"标准监视器\",\n\t\"distributedUptimeStatusStandardMonitorsDescription\": \"将标准监视器附加到您的状态页面。\",\n\t\"distributedUptimeStatusCreateYour\": \"创建您的\",\n\t\"distributedUptimeStatusEditYour\": \"编辑您的\",\n\t\"distributedUptimeStatusPublishedLabel\": \"发布并公开可见\",\n\t\"distributedUptimeStatusCompanyNameLabel\": \"公司名称\",\n\t\"distributedUptimeStatusPageAddressLabel\": \"您的状态页面地址\",\n\t\"distributedUptimeStatus30Days\": \"30 天\",\n\t\"distributedUptimeStatus60Days\": \"60 天\",\n\t\"distributedUptimeStatus90Days\": \"90 天\",\n\t\"distributedUptimeStatusPageNotSetUp\": \"未设置状态页面。\",\n\t\"distributedUptimeStatusContactAdmin\": \"请联系您的管理员\",\n\t\"distributedUptimeStatusPageNotPublic\": \"此状态页面不公开。\",\n\t\"distributedUptimeStatusPageDeleteDialog\": \"你想删除这个状态页吗？\",\n\t\"distributedUptimeStatusPageDeleteConfirm\": \"确定，删除状态页\",\n\t\"distributedUptimeStatusPageDeleteDescription\": \"删除后将无法恢复您的状态页面。\",\n\t\"distributedUptimeStatusDevices\": \"设备\",\n\t\"distributedUptimeStatusUpt\": \"UPT\",\n\t\"distributedUptimeStatusUptBurned\": \"分布式正常运行时间状态运行已完成\",\n\t\"distributedUptimeStatusUptLogo\": \"分布式UptimeStatusUptLogo\",\n\t\"incidentsTableNoIncidents\": \"无事件记录\",\n\t\"incidentsTablePaginationLabel\": \"事件\",\n\t\"incidentsTableMonitorName\": \"监控名称\",\n\t\"incidentsTableStatus\": \"状态\",\n\t\"incidentsTableDateTime\": \"日期&时间\",\n\t\"incidentsTableStatusCode\": \"状态码\",\n\t\"incidentsTableMessage\": \"信息\",\n\t\"incidentsOptionsHeader\": \"事件:\",\n\t\"incidentsOptionsHeaderFilterBy\": \"筛选:\",\n\t\"incidentsOptionsHeaderFilterAll\": \"全部\",\n\t\"incidentsOptionsHeaderFilterDown\": \"离线\",\n\t\"incidentsOptionsHeaderFilterCannotResolve\": \"无法解析\",\n\t\"incidentsOptionsHeaderShow\": \"显示：\",\n\t\"incidentsOptionsHeaderLastHour\": \"过去一小时\",\n\t\"incidentsOptionsHeaderLastDay\": \"过去一天\",\n\t\"incidentsOptionsHeaderLastWeek\": \"过去一周\",\n\t\"incidentsOptionsPlaceholderAllServers\": \"所有服务器\",\n\t\"infrastructureCreateYour\": \"创建你的\",\n\t\"infrastructureCreateGeneralSettingsDescription\": \"在这里您可以选择主机的 URL，以及连接到服务器代理时使用的友好名称和授权密钥。\",\n\t\"infrastructureServerRequirement\": \"你正在监控的服务器必须运行在\",\n\t\"infrastructureCustomizeAlerts\": \"自定义告警\",\n\t\"infrastructureAlertNotificationDescription\": \"当阈值超过指定百分比时向用户(们)发送通知。\",\n\t\"infrastructureCreateMonitor\": \"创建基础设施监控\",\n\t\"infrastructureProtocol\": \"协议\",\n\t\"infrastructureServerUrlLabel\": \"服务器 URL\",\n\t\"infrastructureDisplayNameLabel\": \"显示名称\",\n\t\"infrastructureAuthorizationSecretLabel\": \"授权密钥\",\n\t\"gb\": \"GB\",\n\t\"mb\": \"MB\",\n\t\"mem\": \"内存\",\n\t\"memoryUsage\": \"内存使用率\",\n\t\"cpu\": \"CPU\",\n\t\"cpuUsage\": \"CPU 使用率\",\n\t\"cpuTemperature\": \"CPU 温度\",\n\t\"diskUsage\": \"硬盘使用率\",\n\t\"used\": \"已使用\",\n\t\"total\": \"总共\",\n\t\"cores\": \"核心\",\n\t\"frequency\": \"频率\",\n\t\"status\": \"状态\",\n\t\"cpuPhysical\": \"CPU（物理核心）\",\n\t\"cpuLogical\": \"CPU（逻辑核心）\",\n\t\"cpuFrequency\": \"CPU 频率\",\n\t\"avgCpuTemperature\": \"CPU 平均温度\",\n\t\"memory\": \"内存\",\n\t\"disk\": \"硬盘\",\n\t\"uptime\": \"运行时间\",\n\t\"os\": \"系统\",\n\t\"host\": \"主机\",\n\t\"actions\": \"动作\",\n\t\"integrations\": \"继承\",\n\t\"integrationsPrism\": \"将 Prism 连接到您喜欢的服务。\",\n\t\"integrationsSlack\": \"集成Slack\",\n\t\"integrationsSlackInfo\": \"集成SlackInfo\",\n\t\"integrationsDiscord\": \"集成Discord\",\n\t\"integrationsDiscordInfo\": \"集成Discord信息\",\n\t\"integrationsZapier\": \"集成Zapier\",\n\t\"integrationsZapierInfo\": \"集成ZapierInfo\",\n\t\"commonSave\": \"保存\",\n\t\"createYour\": \"创建你的\",\n\t\"createMonitor\": \"创建监控\",\n\t\"pause\": \"暂停\",\n\t\"resume\": \"恢复\",\n\t\"editing\": \"编辑中...\",\n\t\"url\": \"网址\",\n\t\"access\": \"访问\",\n\t\"timezone\": \"时区\",\n\t\"features\": \"特征\",\n\t\"administrator\": \"管理员？\",\n\t\"loginHere\": \"点击此处登录\",\n\t\"displayName\": \"显示名称\",\n\t\"urlMonitor\": \"监控的 URL\",\n\t\"portToMonitor\": \"监控端口\",\n\t\"websiteMonitoring\": \"网站监控\",\n\t\"websiteMonitoringDescription\": \"使用 HTTP（s）监控您的网站或 API 端点。\",\n\t\"pingMonitoring\": \"ping监控\",\n\t\"pingMonitoringDescription\": \"检查您的服务器是否可用。\",\n\t\"dockerContainerMonitoring\": \"Docker容器监控\",\n\t\"dockerContainerMonitoringDescription\": \"检查你的 Docker 容器是否正在运行。\",\n\t\"portMonitoring\": \"端口监控\",\n\t\"portMonitoringDescription\": \"检查你的端口是否已打开。\",\n\t\"createMaintenanceWindow\": \"创建维护窗口\",\n\t\"createMaintenance\": \"创建维护\",\n\t\"editMaintenance\": \"编辑维护\",\n\t\"maintenanceWindowName\": \"维护窗口名称\",\n\t\"friendlyNameInput\": \"友好名称\",\n\t\"friendlyNamePlaceholder\": \"维护时间于 __:__ ，持续 ___ 分钟\",\n\t\"maintenanceRepeat\": \"维护重复\",\n\t\"maintenance\": \"维护\",\n\t\"duration\": \"期间\",\n\t\"addMonitors\": \"添加监视器\",\n\t\"window\": \"窗口\",\n\t\"cancel\": \"取消\",\n\t\"message\": \"信息\",\n\t\"low\": \"低的\",\n\t\"high\": \"高的\",\n\t\"statusCode\": \"状态码\",\n\t\"date&Time\": \"日期&时间\",\n\t\"type\": \"类型\",\n\t\"statusPageName\": \"状态页名称\",\n\t\"publicURL\": \"公共 URL\",\n\t\"repeat\": \"重复\",\n\t\"edit\": \"编辑\",\n\t\"createA\": \"创建A\",\n\t\"remove\": \"移除\",\n\t\"maintenanceWindowDescription\": \"在维护时段内，所选监视器的所有监视都将暂停。不会执行任何网络检查，从而阻止触发任何状态更新或通知。您的显示器将冻结在其最后的已知状态，并且状态页面将显示维护指示器。维护时段结束后，监控会自动恢复，如果检测到问题，将触发警报。维护期不计入正常运行时间计算。\",\n\t\"startTime\": \"开始时间\",\n\t\"timeZoneInfo\": \"所有日期和时间均为 GMT+0 时区。\",\n\t\"monitorsToApply\": \"监控器应用\",\n\t\"nextWindow\": \"下一个窗口\",\n\t\"notFoundButton\": \"未找到按钮\",\n\t\"pageSpeedConfigureSettingsDescription\": \"您可以在此处选择主机的 URL 以及监视器类型。\",\n\t\"monitorDisplayName\": \"监视器显示名称\",\n\t\"whenNewIncident\": \"当新事件发生时\",\n\t\"notifySMS\": \"通过短信通知（即将推出）\",\n\t\"notifyEmails\": \"还通过电子邮件通知多个地址（即将推出）\",\n\t\"seperateEmails\": \"单独的电子邮件\",\n\t\"checkFrequency\": \"检查频率\",\n\t\"matchMethod\": \"match方法\",\n\t\"expectedValue\": \"预期值\",\n\t\"deleteDialogTitle\": \"确定要删除此监视器吗?\",\n\t\"deleteDialogDescription\": \"一旦删除，将无法检索此监视器。\",\n\t\"pageSpeedMonitor\": \"页面速度监控器\",\n\t\"shown\": \"显示\",\n\t\"ago\": \"前\",\n\t\"companyName\": \"公司名称\",\n\t\"pageSpeedDetailsPerformanceReport\": \"值是估计值，可能会有所不同。\",\n\t\"pageSpeedDetailsPerformanceReportCalculator\": \"页面速度详情性能报告计算器\",\n\t\"checkingEvery\": \"检查每一个\",\n\t\"statusPageCreateSettings\": \"如果您的状态页面已准备就绪，您可以将其标记为已发布。\",\n\t\"basicInformation\": \"基础信息\",\n\t\"statusPageCreateBasicInfoDescription\": \"定义公司名称和状态页面指向的子域。\",\n\t\"statusPageCreateSelectTimeZoneDescription\": \"选择状态页面的显示时区。\",\n\t\"statusPageCreateAppearanceDescription\": \"定义公共状态页面的默认外观。\",\n\t\"statusPageCreateSettingsCheckboxLabel\": \"已发布并向公众可见\",\n\t\"statusPageCreateBasicInfoStatusPageAddress\": \"您的状态页面地址\",\n\t\"statusPageCreateTabsContent\": \"状态页服务器\",\n\t\"statusPageCreateTabsContentDescription\": \"您可以将监视的任意数量的服务器添加到状态页面。您还可以重新排序它们以获得最佳观看体验。\",\n\t\"statusPageCreateTabsContentFeaturesDescription\": \"在状态页上显示更多详细信息\",\n\t\"showCharts\": \"显示图表\",\n\t\"showUptimePercentage\": \"显示正常运行时间百分比\",\n\t\"removeLogo\": \"移除Logo\",\n\t\"statusPageStatus\": \"未设置公开状态页面。\",\n\t\"statusPageStatusContactAdmin\": \"请联系您的管理员\",\n\t\"statusPageStatusNotPublic\": \"此状态页面不公开。\",\n\t\"statusPageStatusNoPage\": \"这里没有状态页面。\",\n\t\"statusPageStatusServiceStatus\": \"服务状态\",\n\t\"deleteStatusPage\": \"要删除此状态页面吗？\",\n\t\"deleteStatusPageConfirm\": \"是，删除状态页\",\n\t\"deleteStatusPageDescription\": \"一旦删除，您的状态页面将无法检索。\",\n\t\"uptimeCreate\": \"期望值用于与响应结果进行匹配，匹配确定状态。\",\n\t\"uptimeCreateJsonPath\": \"将根据响应 JSON 数据评估此表达式，并将结果用于与预期值进行匹配。看\",\n\t\"uptimeCreateJsonPathQuery\": \"查询语言文档。\",\n\t\"maintenanceTableActionMenuDialogTitle\": \"您真的想删除此维护窗口吗？\",\n\t\"infrastructureEditYour\": \"编辑您的\",\n\t\"infrastructureEditMonitor\": \"保存基础架构监视器\",\n\t\"infrastructureMonitorCreated\": \"基础设施监控创建成功！\",\n\t\"infrastructureMonitorUpdated\": \"基础设施监控更新成功！\",\n\t\"errorInvalidTypeId\": \"提供的通知类型无效\",\n\t\"errorInvalidFieldId\": \"提供的字段 ID 无效\",\n\t\"inviteNoTokenFound\": \"未找到邀请令牌\",\n\t\"pageSpeedWarning\": \"警告：您尚未添加 Google PageSpeed API 密钥。没有它，PageSpeed 监视器将无法运行。\",\n\t\"pageSpeedLearnMoreLink\": \"点击这里\",\n\t\"pageSpeedAddApiKey\": \"以添加您的 API 密钥。\",\n\t\"update\": \"更新\",\n\t\"invalidFileFormat\": \"不支持的文件格式！\",\n\t\"invalidFileSize\": \"文件太大了！\",\n\t\"ClickUpload\": \"点击上传\",\n\t\"DragandDrop\": \"拖放\",\n\t\"MaxSize\": \"最大尺寸\",\n\t\"SupportedFormats\": \"支持的格式\",\n\t\"FirstName\": \"名\",\n\t\"LastName\": \"姓\",\n\t\"EmailDescriptionText\": \"这是您当前的电子邮件地址 - 无法更改。\",\n\t\"YourPhoto\": \"个人资料照片\",\n\t\"PhotoDescriptionText\": \"这张照片将显示在您的个人资料页面中。\",\n\t\"save\": \"保存\",\n\t\"DeleteDescriptionText\": \"这将从服务器中删除帐户和所有关联数据。这是不可逆的。\",\n\t\"DeleteAccountWarning\": \"删除您的帐户意味着您将无法再次登录，并且您的所有数据都将被删除。这是不可逆的。\",\n\t\"DeleteWarningTitle\": \"真的删除这个帐户？\",\n\t\"bulkImport\": {\n\t\t\"title\": \"批量导入\",\n\t\t\"selectFileTips\": \"选择要上传的 CSV 文件\",\n\t\t\"selectFileDescription\": \"您可以下载我们的<template>模板</template>或<sample>示例</sample>\",\n\t\t\"selectFile\": \"选择文件\",\n\t\t\"parsingFailed\": \"解析失败\",\n\t\t\"uploadSuccess\": \"监视器创建成功！\",\n\t\t\"validationFailed\": \"验证失败\",\n\t\t\"noFileSelected\": \"未选择文件\",\n\t\t\"fallbackPage\": \"导入文件以批量上传服务器列表\",\n\t\t\"invalidFileType\": \"文件类型无效\",\n\t\t\"uploadFailed\": \"上传失败\"\n\t},\n\t\"DeleteAccountTitle\": \"删除账户\",\n\t\"DeleteAccountButton\": \"删除帐户\",\n\t\"publicLink\": \"公共链接\",\n\t\"maskedPageSpeedKeyPlaceholder\": \"*************************************\",\n\t\"reset\": \"重置\",\n\t\"ignoreTLSError\": \"忽略 TLS/SSL 错误\",\n\t\"tlsErrorIgnored\": \"已忽略 TLS/SSL 错误\",\n\t\"ignoreTLSErrorDescription\": \"忽略 TLS/SSL 错误并继续检查网站可用性\",\n\t\"createNew\": \"新建\",\n\t\"greeting\": {\n\t\t\"prepend\": \"你好\",\n\t\t\"append\": \"下午时间，尽情发挥！\",\n\t\t\"overview\": \"以下是您的 {{type}} 监视器的概述。\"\n\t},\n\t\"roles\": {\n\t\t\"superAdmin\": \"超级管理员\",\n\t\t\"admin\": \"管理\",\n\t\t\"teamMember\": \"团队成员\",\n\t\t\"demoUser\": \"演示用户\"\n\t},\n\t\"teamPanel\": {\n\t\t\"teamMembers\": \"团队成员\",\n\t\t\"filter\": {\n\t\t\t\"all\": \"全部\",\n\t\t\t\"member\": \"成员\"\n\t\t},\n\t\t\"inviteTeamMember\": \"邀请新团队成员\",\n\t\t\"inviteNewTeamMember\": \"邀请新团队成员\",\n\t\t\"inviteDescription\": \"当您添加新的团队成员时，他们将可以访问所有监视器。\",\n\t\t\"email\": \"电子邮件\",\n\t\t\"selectRole\": \"选择角色\",\n\t\t\"inviteLink\": \"邀请链接\",\n\t\t\"cancel\": \"取消\",\n\t\t\"noMembers\": \"没有具有此角色的团队成员\",\n\t\t\"getToken\": \"获取Token\",\n\t\t\"emailToken\": \"电子邮件令牌\",\n\t\t\"table\": {\n\t\t\t\"name\": \"名字\",\n\t\t\t\"email\": \"邮箱\",\n\t\t\t\"role\": \"角色\",\n\t\t\t\"created\": \"创建\"\n\t\t},\n\t\t\"addTeamMember\": {\n\t\t\t\"addMemberMenu\": \"添加团队成员\",\n\t\t\t\"title\": \"注册新团队成员\",\n\t\t\t\"description\": \"创建一个新用户并与他们共享凭据。此方法使成员能够立即访问所有监视器。\",\n\t\t\t\"addButton\": \"添加成员\"\n\t\t},\n\t\t\"register\": \"注册团队成员\",\n\t\t\"registerToast\": {\n\t\t\t\"success\": \"用户创建，安全地与成员共享凭据。\",\n\t\t\t\"dbUserExists\": \"用户已存在。\",\n\t\t\t\"unknownError\": \"发生未知错误。\"\n\t\t},\n\t\t\"registerTeamMember\": {\n\t\t\t\"title\": \"注册团队成员\",\n\t\t\t\"auth\": {\n\t\t\t\t\"common\": {\n\t\t\t\t\t\"inputs\": {\n\t\t\t\t\t\t\"firstName\": {\n\t\t\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\t\t\"empty\": \"请输入姓名\",\n\t\t\t\t\t\t\t\t\"pattern\": \"名称只能包含字母、空格、撇号或连字符\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"lastName\": {\n\t\t\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\t\t\"empty\": \"请输入姓氏\",\n\t\t\t\t\t\t\t\t\"pattern\": \"姓氏只能包含字母、空格、撇号或连字符\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"email\": {\n\t\t\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\t\t\"empty\": \"要继续，请输入电子邮件地址\",\n\t\t\t\t\t\t\t\t\"invalid\": \"请重新检查输入的电子邮件地址的有效性\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"role\": {\n\t\t\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\t\t\"empty\": \"角色是必需的\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"role\": \"角色\",\n\t\t\"changeTeamPassword\": {\n\t\t\t\"changePasswordMenu\": \"\",\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"success\": \"\"\n\t\t}\n\t},\n\t\"monitorState\": {\n\t\t\"paused\": \"暂停\",\n\t\t\"resumed\": \"恢复\",\n\t\t\"active\": \"已激活\"\n\t},\n\t\"menu\": {\n\t\t\"uptime\": \"上线时间\",\n\t\t\"pagespeed\": \"页面速度\",\n\t\t\"infrastructure\": \"基础设施\",\n\t\t\"incidents\": \"事件\",\n\t\t\"statusPages\": \"状态页\",\n\t\t\"maintenance\": \"维护\",\n\t\t\"integrations\": \"集成\",\n\t\t\"settings\": \"设置\",\n\t\t\"support\": \"支持\",\n\t\t\"discussions\": \"讨论\",\n\t\t\"docs\": \"文档\",\n\t\t\"changelog\": \"变更日志\",\n\t\t\"profile\": \"用户配置\",\n\t\t\"password\": \"密码\",\n\t\t\"team\": \"团队\",\n\t\t\"logOut\": \"登出\",\n\t\t\"notifications\": \"通知\",\n\t\t\"logs\": \"日志\"\n\t},\n\t\"settingsEmailUser\": \"电子邮件用户 - 用于身份验证的用户名，如果指定，则覆盖电子邮件地址\",\n\t\"state\": \"状态\",\n\t\"statusBreadCrumbsStatusPages\": \"状态页\",\n\t\"statusBreadCrumbsDetails\": \"详情\",\n\t\"commonSaving\": \"保存中...\",\n\t\"navControls\": \"控制\",\n\t\"incidentsPageTitle\": \"事件页面标题\",\n\t\"passwordPanel\": {\n\t\t\"passwordChangedSuccess\": \"您的密码已成功更改。\",\n\t\t\"passwordInputIncorrect\": \"您的密码输入错误。\",\n\t\t\"currentPassword\": \"当前密码\",\n\t\t\"enterCurrentPassword\": \"输入当前密码\",\n\t\t\"newPassword\": \"新密码\",\n\t\t\"enterNewPassword\": \"输入新密码\",\n\t\t\"confirmNewPassword\": \"确认新密码\",\n\t\t\"passwordRequirements\": \"新密码必须至少包含 8 个字符，并且必须至少包含一个大写字母、一个小写字母、一个数字和一个特殊字符。\",\n\t\t\"saving\": \"保存...\"\n\t},\n\t\"emailSent\": \"电子邮件已发送\",\n\t\"failedToSendEmail\": \"电子邮件发送失败\",\n\t\"settingsTestEmailSuccess\": \"设置测试电子邮件成功\",\n\t\"settingsTestEmailFailed\": \"发送测试电子邮件失败\",\n\t\"settingsTestEmailFailedWithReason\": \"发送测试电子邮件失败： {{reason}}\",\n\t\"settingsTestEmailUnknownError\": \"未知错误\",\n\t\"statusMsg\": {\n\t\t\"paused\": \"监视已暂停。\",\n\t\t\"up\": \"您的网站已上线。\",\n\t\t\"down\": \"您的网站已下线。\",\n\t\t\"pending\": \"等待中...\"\n\t},\n\t\"uptimeGeneralInstructions\": {\n\t\t\"http\": \"输入要监控的 URL 或 IP（例如.. https://example.com/ or 192.168.1.100）并添加仪表板上显示的清晰显示名称。\",\n\t\t\"ping\": \"输入要 ping 的 IP 地址或主机名（例如.. 192.168.1.100 或 example.com），并添加显示在仪表板上的清晰显示名称。\",\n\t\t\"docker\": \"码输入 Docker 容器名称或 ID。您可以使用容器名称（例如.. my-app）或容器 ID（完整的 64 字符 ID 或短 ID）。\",\n\t\t\"port\": \"输入服务器的 URL 或 IP、端口号和仪表板上显示的清晰显示名称。\",\n\t\t\"game\": \"输入要 ping 的 IP 地址或主机名和端口号（例如.. 192.168.1.100 或 example.com）并选择游戏类型。\",\n\t\t\"https\": \"\"\n\t},\n\t\"common\": {\n\t\t\"appName\": \"Checkmate\",\n\t\t\"monitoringAgentName\": \"捕获\",\n\t\t\"buttons\": {\n\t\t\t\"toggleTheme\": \"切换主题明&暗\"\n\t\t},\n\t\t\"toasts\": {\n\t\t\t\"networkError\": \"网络错误\",\n\t\t\t\"checkConnection\": \"请检查你的网络连接\",\n\t\t\t\"unknownError\": \"未知错误\"\n\t\t}\n\t},\n\t\"auth\": {\n\t\t\"common\": {\n\t\t\t\"navigation\": {\n\t\t\t\t\"continue\": \"继续\",\n\t\t\t\t\"back\": \"返回\"\n\t\t\t},\n\t\t\t\"inputs\": {\n\t\t\t\t\"email\": {\n\t\t\t\t\t\"label\": \"电子邮件\",\n\t\t\t\t\t\"placeholder\": \"jordan.ellis@domain.com\",\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"要继续，请输入您的电子邮件地址\",\n\t\t\t\t\t\t\"invalid\": \"请重新检查输入的电子邮件地址的有效性\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"password\": {\n\t\t\t\t\t\"label\": \"密码\",\n\t\t\t\t\t\"rules\": {\n\t\t\t\t\t\t\"length\": {\n\t\t\t\t\t\t\t\"beginning\": \"必须至少\",\n\t\t\t\t\t\t\t\"highlighted\": \"8 个字符长\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"special\": {\n\t\t\t\t\t\t\t\"beginning\": \"必须至少包含\",\n\t\t\t\t\t\t\t\"highlighted\": \"一个特殊字符\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"number\": {\n\t\t\t\t\t\t\t\"beginning\": \"必须至少包含\",\n\t\t\t\t\t\t\t\"highlighted\": \"一个数字\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"uppercase\": {\n\t\t\t\t\t\t\t\"beginning\": \"必须至少包含\",\n\t\t\t\t\t\t\t\"highlighted\": \"一个大写字母\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"lowercase\": {\n\t\t\t\t\t\t\t\"beginning\": \"必须至少包含\",\n\t\t\t\t\t\t\t\"highlighted\": \"一个小写字母\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"match\": {\n\t\t\t\t\t\t\t\"beginning\": \"密码\",\n\t\t\t\t\t\t\t\"highlighted\": \"必须匹配\"\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"请输入您的密码\",\n\t\t\t\t\t\t\"length\": \"密码长度必须至少为 8 个字符\",\n\t\t\t\t\t\t\"uppercase\": \"密码必须至少包含 1 个大写字母\",\n\t\t\t\t\t\t\"lowercase\": \"密码必须至少包含 1 个小写字母\",\n\t\t\t\t\t\t\"number\": \"密码必须至少包含 1 个数字\",\n\t\t\t\t\t\t\"special\": \"密码必须至少包含 1 个特殊字符\",\n\t\t\t\t\t\t\"incorrect\": \"您提供的密码与我们的记录不符\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"passwordConfirm\": {\n\t\t\t\t\t\"label\": \"确认密码\",\n\t\t\t\t\t\"placeholder\": \"重新输入密码以确认\",\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"请再次输入您的密码以进行确认（有助于解决拼写错误）\",\n\t\t\t\t\t\t\"different\": \"输入的密码不匹配，因此其中一个密码可能输入错误\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"firstName\": {\n\t\t\t\t\t\"label\": \"名字\",\n\t\t\t\t\t\"placeholder\": \"Jordan\",\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"请输入您的姓名\",\n\t\t\t\t\t\t\"length\": \"姓名必须少于 50 个字符\",\n\t\t\t\t\t\t\"pattern\": \"名称只能包含字母、空格、撇号或连字符\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"lastName\": {\n\t\t\t\t\t\"label\": \"姓\",\n\t\t\t\t\t\"placeholder\": \"Ellis\",\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"请输入您的姓氏\",\n\t\t\t\t\t\t\"length\": \"姓氏必须少于 50 个字符\",\n\t\t\t\t\t\t\"pattern\": \"姓氏只能包含字母、空格、撇号或连字符\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"errors\": {\n\t\t\t\t\"validation\": \"验证数据时出错。\"\n\t\t\t},\n\t\t\t\"fields\": {\n\t\t\t\t\"password\": {\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"incorrect\": \"您提供的密码与我们的记录不符\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"role\": {\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"min\": \"必须至少设置一个角色\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"login\": {\n\t\t\t\"heading\": \"登录以继续\",\n\t\t\t\"subheadings\": {\n\t\t\t\t\"stepOne\": \"输入您的电子邮件\",\n\t\t\t\t\"stepTwo\": \"输入您的密码\"\n\t\t\t},\n\t\t\t\"links\": {\n\t\t\t\t\"forgotPassword\": \"忘记密码？\",\n\t\t\t\t\"register\": \"没有帐户？\",\n\t\t\t\t\"forgotPasswordLink\": \"重置密码\",\n\t\t\t\t\"registerLink\": \"注册链接\"\n\t\t\t},\n\t\t\t\"toasts\": {\n\t\t\t\t\"success\": \"欢迎回来！您已成功登录。\",\n\t\t\t\t\"incorrectPassword\": \"密码错误\"\n\t\t\t},\n\t\t\t\"errors\": {\n\t\t\t\t\"password\": {\n\t\t\t\t\t\"incorrect\": \"您提供的密码与我们的记录不符\"\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"welcome\": \"欢迎回到 Checkmate！\"\n\t\t},\n\t\t\"registration\": {\n\t\t\t\"heading\": {\n\t\t\t\t\"superAdmin\": \"创建超级管理员\",\n\t\t\t\t\"user\": \"注册\"\n\t\t\t},\n\t\t\t\"subheadings\": {\n\t\t\t\t\"stepOne\": \"输入您的个人详细信息\",\n\t\t\t\t\"stepTwo\": \"输入您的电子邮件\",\n\t\t\t\t\"stepThree\": \"创建密码\"\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\t\"superAdmin\": \"创建超级用户帐户以开始使用\",\n\t\t\t\t\"user\": \"注册为用户并请求超级管理员访问您的监视器\"\n\t\t\t},\n\t\t\t\"gettingStartedButton\": {\n\t\t\t\t\"superAdmin\": \"创建超级管理员帐户\",\n\t\t\t\t\"user\": \"注册普通用户\"\n\t\t\t},\n\t\t\t\"termsAndPolicies\": \"创建帐户即表示您同意我们的<a1>服务条款</a1>和<a2>隐私政策 </a2>。\",\n\t\t\t\"links\": {\n\t\t\t\t\"login\": \"已拥有帐号？ <a>登录</a>\"\n\t\t\t},\n\t\t\t\"toasts\": {\n\t\t\t\t\"success\": \"欢迎！您的账号已成功创建。\"\n\t\t\t},\n\t\t\t\"welcome\": \"欢迎来到Checkmate！\"\n\t\t},\n\t\t\"forgotPassword\": {\n\t\t\t\"heading\": \"忘记密码？\",\n\t\t\t\"subheadings\": {\n\t\t\t\t\"stepOne\": \"不用担心，我们会向您发送重置说明。\",\n\t\t\t\t\"stepTwo\": \"我们已发送密码重置链接到 <email/>\",\n\t\t\t\t\"stepThree\": \"您的新密码必须与以前使用的密码不同。\",\n\t\t\t\t\"stepFour\": \"您的密码已成功重置。点击下方登录。\"\n\t\t\t},\n\t\t\t\"buttons\": {\n\t\t\t\t\"openEmail\": \"打开电子邮件应用\",\n\t\t\t\t\"resetPassword\": \"重置密码\"\n\t\t\t},\n\t\t\t\"imageAlts\": {\n\t\t\t\t\"passwordKey\": \"密码图标\",\n\t\t\t\t\"email\": \"电子邮件图标\",\n\t\t\t\t\"lock\": \"锁定图标\",\n\t\t\t\t\"passwordConfirm\": \"密码确认图标\"\n\t\t\t},\n\t\t\t\"links\": {\n\t\t\t\t\"login\": \"返回到<a>登录</a>\",\n\t\t\t\t\"resend\": \"没有收到电子邮件？<a> 点击重新发送</a>\"\n\t\t\t},\n\t\t\t\"toasts\": {\n\t\t\t\t\"sent\": \"指令发送至 <email/>.\",\n\t\t\t\t\"emailNotFound\": \"未找到电子邮件。\",\n\t\t\t\t\"redirect\": \"将在<seconds/>秒后重定向...\",\n\t\t\t\t\"success\": \"您的密码已成功重置。\",\n\t\t\t\t\"error\": \"无法重置密码。请稍后重试或联系支持人员。\"\n\t\t\t}\n\t\t}\n\t},\n\t\"errorPages\": {\n\t\t\"serverUnreachable\": {\n\t\t\t\"toasts\": {\n\t\t\t\t\"reconnected\": \"已成功重新连接到服务器。\",\n\t\t\t\t\"stillUnreachable\": \"服务器仍然无法访问。请稍后重试。\"\n\t\t\t},\n\t\t\t\"alertBox\": \"服务器连接错误\",\n\t\t\t\"description\": \"我们无法连接到服务器。如果问题仍然存在，请检查您的互联网连接或验证您的部署配置。\",\n\t\t\t\"retryButton\": {\n\t\t\t\t\"default\": \"尝试重连\",\n\t\t\t\t\"processing\": \"连接中...\"\n\t\t\t}\n\t\t}\n\t},\n\t\"createNotifications\": {\n\t\t\"title\": \"创建通知通道\",\n\t\t\"nameSettings\": {\n\t\t\t\"title\": \"名字\",\n\t\t\t\"description\": \"集成的描述性名称。\",\n\t\t\t\"nameLabel\": \"名字\",\n\t\t\t\"namePlaceholder\": \"例如.. Slack 通知\"\n\t\t},\n\t\t\"typeSettings\": {\n\t\t\t\"title\": \"类型\",\n\t\t\t\"description\": \"选择要创建的通知通道类型。\",\n\t\t\t\"typeLabel\": \"类型\"\n\t\t},\n\t\t\"emailSettings\": {\n\t\t\t\"title\": \"邮箱\",\n\t\t\t\"description\": \"目标电子邮件地址。\",\n\t\t\t\"emailLabel\": \"电子邮件地址\",\n\t\t\t\"emailPlaceholder\": \"例如.. john@example.com\"\n\t\t},\n\t\t\"slackSettings\": {\n\t\t\t\"title\": \"Slack\",\n\t\t\t\"description\": \"在此处配置您的 Slack Webhook\",\n\t\t\t\"webhookLabel\": \"Slack webhook 网址\",\n\t\t\t\"webhookPlaceholder\": \"https://hooks.slack.com/services/...\"\n\t\t},\n\t\t\"pagerdutySettings\": {\n\t\t\t\"title\": \"PagerDuty\",\n\t\t\t\"description\": \"在此处配置您的 PagerDuty 集成\",\n\t\t\t\"integrationKeyLabel\": \"集成密钥\",\n\t\t\t\"integrationKeyPlaceholder\": \"1234567890\"\n\t\t},\n\t\t\"discordSettings\": {\n\t\t\t\"title\": \"Discord\",\n\t\t\t\"description\": \"在此处配置您的 Discord Webhook\",\n\t\t\t\"webhookLabel\": \"Discord Webhook 网址\",\n\t\t\t\"webhookPlaceholder\": \"https://your-server.com/webhook\"\n\t\t},\n\t\t\"webhookSettings\": {\n\t\t\t\"title\": \"Webhook\",\n\t\t\t\"description\": \"在此处配置 Webhook\",\n\t\t\t\"webhookLabel\": \"Webhook网址\",\n\t\t\t\"webhookPlaceholder\": \"https://your-server.com/webhook\"\n\t\t},\n\t\t\"testNotification\": \"测试通知\",\n\t\t\"dialogDeleteTitle\": \"你确认要删除此通知吗？\",\n\t\t\"dialogDeleteConfirm\": \"删除\"\n\t},\n\t\"notificationConfig\": {\n\t\t\"title\": \"通知\",\n\t\t\"description\": \"选择要使用的通知渠道\"\n\t},\n\t\"monitorStatus\": {\n\t\t\"checkingEvery\": \"每隔 {{interval}} 检查一次\",\n\t\t\"withCaptureAgent\": \"使用 Capture 代理 {{version}}\",\n\t\t\"up\": \"在线\",\n\t\t\"down\": \"离线\",\n\t\t\"paused\": \"暂停\"\n\t},\n\t\"advancedMatching\": \"高级匹配\",\n\t\"sendTestNotifications\": \"发送测试通知\",\n\t\"selectAll\": \"全选\",\n\t\"showAdminLoginLink\": \"显示“管理员？在此处登录“状态页面上的链接\",\n\t\"logsPage\": {\n\t\t\"title\": \"日志\",\n\t\t\"description\": \"系统日志 - 最后 1000 行\",\n\t\t\"tabs\": {\n\t\t\t\"queue\": \"作业队列\",\n\t\t\t\"logs\": \"服务器日志\",\n\t\t\t\"diagnostics\": \"诊断\"\n\t\t},\n\t\t\"toast\": {\n\t\t\t\"fetchLogsSuccess\": \"日志获取成功\"\n\t\t},\n\t\t\"logLevelSelect\": {\n\t\t\t\"title\": \"日志等级\",\n\t\t\t\"values\": {\n\t\t\t\t\"all\": \"全部\",\n\t\t\t\t\"info\": \"信息\",\n\t\t\t\t\"warn\": \"警告\",\n\t\t\t\t\"error\": \"错误\",\n\t\t\t\t\"debug\": \"调试\"\n\t\t\t}\n\t\t}\n\t},\n\t\"queuePage\": {\n\t\t\"title\": \"队列\",\n\t\t\"refreshButton\": \"刷新\",\n\t\t\"flushButton\": \"刷新队列\",\n\t\t\"jobTable\": {\n\t\t\t\"title\": \"当前在队列中的作业\",\n\t\t\t\"idHeader\": \"监视器 ID\",\n\t\t\t\"urlHeader\": \"网址\",\n\t\t\t\"typeHeader\": \"类型\",\n\t\t\t\"activeHeader\": \"有效\",\n\t\t\t\"lockedAtHeader\": \"锁定在\",\n\t\t\t\"runCountHeader\": \"运行计数\",\n\t\t\t\"failCountHeader\": \"失败计数\",\n\t\t\t\"lastRunHeader\": \"上次运行时间\",\n\t\t\t\"lastFinishedAtHeader\": \"最后完成时间\",\n\t\t\t\"lastRunTookHeader\": \"上次运行花费了\",\n\t\t\t\"intervalHeader\": \"间隔\"\n\t\t},\n\t\t\"metricsTable\": {\n\t\t\t\"title\": \"队列指标\",\n\t\t\t\"metricHeader\": \"度量\",\n\t\t\t\"valueHeader\": \"值\"\n\t\t},\n\t\t\"failedJobTable\": {\n\t\t\t\"title\": \"失败的作业\",\n\t\t\t\"monitorIdHeader\": \"监视器ID\",\n\t\t\t\"monitorUrlHeader\": \"监控网址\",\n\t\t\t\"failCountHeader\": \"失败计数\",\n\t\t\t\"failedAtHeader\": \"上次失败时于\",\n\t\t\t\"failReasonHeader\": \"失败原因\"\n\t\t}\n\t},\n\t\"export\": {\n\t\t\"title\": \"导出监视器\",\n\t\t\"success\": \"监视器导出成功！\",\n\t\t\"failed\": \"导出监视器失败\"\n\t},\n\t\"monitorActions\": {\n\t\t\"title\": \"导出/导入\",\n\t\t\"import\": \"导入监视器\",\n\t\t\"export\": \"导出监视器\",\n\t\t\"deleteSuccess\": \"监视项删除成功\",\n\t\t\"deleteFailed\": \"删除监视项失败\",\n\t\t\"details\": \"详情\"\n\t},\n\t\"settingsPage\": {\n\t\t\"aboutSettings\": {\n\t\t\t\"labelDevelopedBy\": \"由 Bluewave Labs 开发\",\n\t\t\t\"labelVersion\": \"版本\",\n\t\t\t\"title\": \"关于\"\n\t\t},\n\t\t\"demoMonitorsSettings\": {\n\t\t\t\"buttonAddMonitors\": \"添加演示监视器\",\n\t\t\t\"description\": \"添加示例监视器以进行演示。\",\n\t\t\t\"title\": \"示例监视器\"\n\t\t},\n\t\t\"emailSettings\": {\n\t\t\t\"buttonSendTestEmail\": \"发送测试电子邮件\",\n\t\t\t\"description\": \"配置系统的电子邮件设置。这用于发送通知和警报。\",\n\t\t\t\"descriptionTransport\": \"这将为 NodeMailer 构建 SMTP 传输\",\n\t\t\t\"labelAddress\": \"电子邮件地址 - 用于身份验证\",\n\t\t\t\"labelConnectionHost\": \"电子邮件连接主机 - 要在 HELO/EHLO 问候语中使用的主机名\",\n\t\t\t\"labelHost\": \"电子邮件主机 - 要连接到的主机名或 IP 地址\",\n\t\t\t\"labelIgnoreTLS\": \"禁用 STARTTLS：即使服务器支持 TLS，也不要使用 TLS\",\n\t\t\t\"labelPassword\": \"电子邮件密码 - 身份验证密码\",\n\t\t\t\"labelPasswordSet\": \"已设置密码。单击重置以更改它。\",\n\t\t\t\"labelPool\": \"启用连接池：重用现有连接以提高性能\",\n\t\t\t\"labelPort\": \"电子邮件端口 - 要连接的端口\",\n\t\t\t\"labelRejectUnauthorized\": \"拒绝无效证书：拒绝具有自签名或不受信任的证书的连接\",\n\t\t\t\"labelRequireTLS\": \"强制 STARTTLS：需要 TLS 升级，如果不支持则失败\",\n\t\t\t\"labelSecure\": \"使用 SSL（推荐）：使用 SSL/TLS 加密连接\",\n\t\t\t\"labelTLSServername\": \"TLS 服务器名称 - 当主机是 IP 时，用于 TLS 验证的可选主机名\",\n\t\t\t\"labelUser\": \"电子邮件用户 - 用于身份验证的用户名，如果指定，则覆盖电子邮件地址\",\n\t\t\t\"linkTransport\": \"在此处查看规格\",\n\t\t\t\"placeholderUser\": \"如果不需要，请留空\",\n\t\t\t\"title\": \"电子邮件\",\n\t\t\t\"toastEmailRequiredFieldsError\": \"需要输入电子邮件地址、主机、端口和密码\"\n\t\t},\n\t\t\"pageSpeedSettings\": {\n\t\t\t\"description\": \"输入您的 Google PageSpeed API 密钥以启用 Google PageSpeed 监控。单击重置以更新密钥。\",\n\t\t\t\"labelApiKeySet\": \"API 密钥已设置。单击重置以更改它。\",\n\t\t\t\"labelApiKey\": \"ageSpeed API 密钥\",\n\t\t\t\"title\": \"Google PageSpeed API 密钥\"\n\t\t},\n\t\t\"saveButtonLabel\": \"保存\",\n\t\t\"statsSettings\": {\n\t\t\t\"clearAllStatsButton\": \"清除所有统计\",\n\t\t\t\"clearAllStatsDescription\": \"清除所有统计数据。这是不可逆转的。\",\n\t\t\t\"clearAllStatsDialogConfirm\": \"是的，清除所有统计数据\",\n\t\t\t\"clearAllStatsDialogDescription\": \"一旦删除，监控历史记录和统计信息将无法检索。\",\n\t\t\t\"clearAllStatsDialogTitle\": \"你想清除所有的统计数据吗？\",\n\t\t\t\"description\": \"定义要保留历史数据的时间。您还可以清除所有现有数据。\",\n\t\t\t\"labelTTL\": \"要保留监控历史记录的天数。\",\n\t\t\t\"labelTTLOptional\": \"0 表示无限\",\n\t\t\t\"title\": \"查看历史记录\"\n\t\t},\n\t\t\"systemResetSettings\": {\n\t\t\t\"buttonRemoveAllMonitors\": \"移除所有监视项\",\n\t\t\t\"description\": \"从系统中移除所有监视项。\",\n\t\t\t\"dialogConfirm\": \"确定，移除所有监视项\",\n\t\t\t\"dialogDescription\": \"移除后，无法恢复这些监视项。\",\n\t\t\t\"dialogTitle\": \"你想移除所有的监视项吗？\",\n\t\t\t\"title\": \"系统复位\"\n\t\t},\n\t\t\"timezoneSettings\": {\n\t\t\t\"description\": \"选择用于在整个应用程序中显示日期和时间时区。\",\n\t\t\t\"label\": \"显示时区\",\n\t\t\t\"title\": \"显示时区\"\n\t\t},\n\t\t\"title\": \"设置\",\n\t\t\"uiSettings\": {\n\t\t\t\"description\": \"在亮色和暗色模式之间切换，或更改用户界面语言。\",\n\t\t\t\"labelLanguage\": \"语言\",\n\t\t\t\"labelTheme\": \"主题模式\",\n\t\t\t\"title\": \"外观\"\n\t\t},\n\t\t\"urlSettings\": {\n\t\t\t\"description\": \"在公共状态页面上显示监控的 IP 地址或 URL。如果禁用，则仅显示监控名称以保护敏感信息。\",\n\t\t\t\"label\": \"在状态页面显示 IP/URL\",\n\t\t\t\"selectDisabled\": \"禁用\",\n\t\t\t\"selectEnabled\": \"启用\",\n\t\t\t\"title\": \"在状态页面上监控 IP/URL\"\n\t\t},\n\t\t\"globalThresholds\": {\n\t\t\t\"title\": \"全局阈值\",\n\t\t\t\"description\": \"配置 CPU、内存、磁盘和温度阈值。如果提供了阈值，则会自动启用监控。\"\n\t\t}\n\t},\n\t\"statusPageCreate\": {\n\t\t\"buttonSave\": \"保存\"\n\t},\n\t\"incidentsOptionsHeaderFilterResolved\": \"已解决\",\n\t\"settingsSave\": \"保存\",\n\t\"statusPageCreateAppearanceTitle\": \"外观\",\n\t\"confirmPassword\": \"确认密码\",\n\t\"monitorHooks\": {\n\t\t\"failureAddDemoMonitors\": \"未能添加示例监视器\",\n\t\t\"successAddDemoMonitors\": \"成功添加示例监视器\"\n\t},\n\t\"settingsAppearance\": \"外观\",\n\t\"settingsDisplayTimezone\": \"显示时区\",\n\t\"settingsGeneralSettings\": \"常规设置\",\n\t\"incidentsOptionsHeaderTotalIncidents\": \"事件总数\",\n\t\"statusPage\": {\n\t\t\"deleteSuccess\": \"状态页面已成功删除\",\n\t\t\"deleteFailed\": \"删除状态页面失败\",\n\t\t\"createSuccess\": \"状态页创建成功\",\n\t\t\"updateSuccess\": \"状态页更新成功\",\n\t\t\"generalSettings\": \"常规设置\",\n\t\t\"contents\": \"内容\",\n\t\t\"fallback\": {\n\t\t\t\"checks\": [\n\t\t\t\t\"实时监控和显示服务的运行状况\",\n\t\t\t\t\"跟踪多个服务并共享其状态\",\n\t\t\t\t\"让用户了解中断和性能\"\n\t\t\t],\n\t\t\t\"title\": \"状态页用于：\",\n\t\t\t\"actionButton\": \"让我们创建你的第一个状态页！\"\n\t\t}\n\t},\n\t\"testNotificationsDisabled\": \"此监视器没有通知设置。您需要通过单击‘配置’按钮来添加一个\",\n\t\"incidentsTableResolvedAt\": \"解决于\",\n\t\"incidentsTableActionResolve\": \"解决\",\n\t\"checkHooks\": {\n\t\t\"failureResolveOne\": \"未能解决事件。\",\n\t\t\"failureResolveAll\": \"未能解决所有事件。\",\n\t\t\"failureResolveMonitor\": \"故障排除监控事件失败。\"\n\t},\n\t\"checkFormError\": \"请检查表单中的错误。\",\n\t\"diagnosticsPage\": {\n\t\t\"diagnosticDescription\": \"系统诊断\",\n\t\t\"statsDescription\": \"系统统计数据\",\n\t\t\"gauges\": {\n\t\t\t\"heapAllocationTitle\": \"堆分配\",\n\t\t\t\"heapAllocationSubtitle\": \"% 的可用内存占用率\",\n\t\t\t\"heapUsageTitle\": \"堆使用情况\",\n\t\t\t\"heapUsageSubtitle\": \"% 的可用内存占用率\",\n\t\t\t\"heapUtilizationTitle\": \"堆利用率\",\n\t\t\t\"heapUtilizationSubtitle\": \"% 的分配百分比\",\n\t\t\t\"instantCpuUsageTitle\": \"当前 CPU 使用率\",\n\t\t\t\"instantCpuUsageSubtitle\": \"% 的1秒CPU占用率\"\n\t\t},\n\t\t\"stats\": {\n\t\t\t\"eventLoopDelayTitle\": \"事件循环延迟\",\n\t\t\t\"uptimeTitle\": \"运行时间\",\n\t\t\t\"usedHeapSizeTitle\": \"已用堆内存大小\",\n\t\t\t\"totalHeapSizeTitle\": \"总堆大小\",\n\t\t\t\"osMemoryLimitTitle\": \"系统内存限制\"\n\t\t}\n\t},\n\t\"pageSpeedLighthouseAPI\": \"使用 Lighthouse PageSpeed API 监控您的网站\",\n\t\"time\": {\n\t\t\"threeMinutes\": \"3 分钟\",\n\t\t\"fiveMinutes\": \"5 分钟\",\n\t\t\"tenMinutes\": \"10 分钟\",\n\t\t\"twentyMinutes\": \"20 分钟\",\n\t\t\"oneHour\": \"1 小时\",\n\t\t\"oneDay\": \"1 天\",\n\t\t\"oneWeek\": \"1 周\",\n\t\t\"fourMinutes\": \"4 分钟\",\n\t\t\"oneMinute\": \"1 分钟\",\n\t\t\"twoMinutes\": \"2 分钟\",\n\t\t\"fifteenSeconds\": \"15 秒\",\n\t\t\"thirtySeconds\": \"30 秒\"\n\t},\n\t\"general\": {\n\t\t\"noOptionsFound\": \"{{unit}} 未找到\"\n\t},\n\t\"infrastructureMonitor\": {\n\t\t\"fallback\": {\n\t\t\t\"checks\": [\n\t\t\t\t\"追踪服务器性能表现\",\n\t\t\t\t\"识别瓶颈并优化资源利用率\",\n\t\t\t\t\"通过实时监控保障系统可靠性\"\n\t\t\t],\n\t\t\t\"title\": \"基础设施监视器用于：\",\n\t\t\t\"actionButton\": \"让我们创建你的第一个基础设施视器！\"\n\t\t}\n\t},\n\t\"maintenanceWindow\": {\n\t\t\"fallback\": {\n\t\t\t\"checks\": [\"标记维护时段\", \"消除所有误解\", \"停止在维护窗口内发送警报\"],\n\t\t\t\"title\": \"维护时段用于：\",\n\t\t\t\"actionButton\": \"让我们创建您的第一个维护时段！\"\n\t\t}\n\t},\n\t\"pageSpeed\": {\n\t\t\"fallback\": {\n\t\t\t\"checks\": [\"报告页面的用户体验\", \"帮助分析网页速度\", \"就如何改进页面提出建议\"],\n\t\t\t\"title\": \"PageSpeed 监视器用于：\",\n\t\t\t\"actionButton\": \"让我们创建您的第一个 PageSpeed 监视器！\"\n\t\t}\n\t},\n\t\"uptimeMonitor\": {\n\t\t\"fallback\": {\n\t\t\t\"checks\": [\n\t\t\t\t\"检测网站或服务器是否在线及响应正常\",\n\t\t\t\t\"向团队发送停机或性能问题警报\",\n\t\t\t\t\"监控 HTTP 端点、Ping 测试、容器及端口状态\",\n\t\t\t\t\"追踪历史运行时长与可靠性趋势\"\n\t\t\t],\n\t\t\t\"title\": \"正常运行时间监视器用于：\",\n\t\t\t\"actionButton\": \"让我们创建您的第一个正常运行时间监视器！\"\n\t\t}\n\t},\n\t\"editUserPage\": {\n\t\t\"form\": {\n\t\t\t\"email\": \"电子邮件\",\n\t\t\t\"firstName\": \"名\",\n\t\t\t\"lastName\": \"姓氏\",\n\t\t\t\"role\": \"角色\",\n\t\t\t\"save\": \"保存\"\n\t\t},\n\t\t\"table\": {\n\t\t\t\"actionHeader\": \"操作\",\n\t\t\t\"roleHeader\": \"角色\"\n\t\t},\n\t\t\"title\": \"编辑用户\",\n\t\t\"toast\": {\n\t\t\t\"successUserUpdate\": \"用户更新成功\",\n\t\t\t\"validationErrors\": \"验证错误\"\n\t\t}\n\t},\n\t\"incidentsPageActionResolveMonitor\": \"解决监控事件\",\n\t\"incidentsPageActionResolveAll\": \"解决所有事件\",\n\t\"matchMethodOptions\": {\n\t\t\"equal\": \"相等\",\n\t\t\"equalPlaceholder\": \"成功\",\n\t\t\"include\": \"包含\",\n\t\t\"includePlaceholder\": \"OK\",\n\t\t\"regex\": \"正则表达式\",\n\t\t\"regexPlaceholder\": \"^(success|ok)$\",\n\t\t\"text\": \"匹配方法\"\n\t},\n\t\"monitorType\": {\n\t\t\"docker\": {\n\t\t\t\"label\": \"容器 ID\",\n\t\t\t\"namePlaceholder\": \"我的容器\",\n\t\t\t\"placeholder\": \"我的应用程序或 abcd1234\"\n\t\t},\n\t\t\"http\": {\n\t\t\t\"label\": \"要监控的 URL\",\n\t\t\t\"namePlaceholder\": \"Google\",\n\t\t\t\"placeholder\": \"google.com\"\n\t\t},\n\t\t\"ping\": {\n\t\t\t\"label\": \"要监控的 IP 地址\",\n\t\t\t\"namePlaceholder\": \"Google\",\n\t\t\t\"placeholder\": \"1.1.1.1\"\n\t\t},\n\t\t\"port\": {\n\t\t\t\"label\": \"要监控的 URL\",\n\t\t\t\"namePlaceholder\": \"localhost:5173\",\n\t\t\t\"placeholder\": \"localhost\"\n\t\t},\n\t\t\"game\": {\n\t\t\t\"label\": \"丢包监控网址\",\n\t\t\t\"namePlaceholder\": \"localhost:5173\",\n\t\t\t\"placeholder\": \"localhost\"\n\t\t}\n\t},\n\t\"uptimeAdvancedMatching\": {\n\t\t\"jsonPath\": \"JSON 路径\"\n\t},\n\t\"bytesPerSecond\": \"每秒字节数\",\n\t\"bytesReceived\": \"已接收字节数\",\n\t\"bytesSent\": \"已发送字节数\",\n\t\"chooseGame\": \"选择游戏\",\n\t\"createMonitorPage\": {\n\t\t\"incidentConfigDescription\": \"滑动窗口用于确定监视器何时发生故障。仅当滑动窗口中的检查百分比满足指定值时，监视器的状态才会改变。\",\n\t\t\"incidentConfigStatusWindowLabel\": \"在滑动窗口中应包含多少次检测？\",\n\t\t\"incidentConfigStatusWindowThresholdLabel\": \"在监视器状态改变之前，滑动窗口中的检查失败/成功的百分比是多少？\",\n\t\t\"incidentConfigTitle\": \"事件\",\n\t\t\"incidentConfigDescriptionV2\": \"\",\n\t\t\"incidentConfigStatusCheckNumber\": \"\",\n\t\t\"intervalTitle\": \"\",\n\t\t\"intervalDescription\": \"\"\n\t},\n\t\"dataRate\": \"数据速率\",\n\t\"dataReceived\": \"已接收数据\",\n\t\"dataSent\": \"已发送数据\",\n\t\"details\": \"详情\",\n\t\"drops\": \"丢包\",\n\t\"errors\": \"错误\",\n\t\"errorsIn\": \"错误于\",\n\t\"errorsOut\": \"错误输出\",\n\t\"gameServerMonitoring\": \"游戏服务器监视\",\n\t\"gameServerMonitoringDescription\": \"检查你的游戏服务器是否正在运行\",\n\t\"network\": \"网络\",\n\t\"networkDrops\": \"网络丢包\",\n\t\"networkErrors\": \"网络错误\",\n\t\"networkInterface\": \"网络接口\",\n\t\"noNetworkStatsAvailable\": \"没有可用的网络统计数据。\",\n\t\"packetsPerSecond\": \"每秒数据包数\",\n\t\"packetsReceived\": \"已接收数据包\",\n\t\"packetsReceivedRate\": \"数据包接收率\",\n\t\"packetsSent\": \"已发送数据包\",\n\t\"rate\": \"速度\",\n\t\"selectInterface\": \"选择接口\",\n\t\"v1\": {\n\t\t\"infrastructure\": {\n\t\t\t\"disk_selection_title\": \"磁盘选择\",\n\t\t\t\"disk_selection_info\": \"目前没有检测到磁盘。\",\n\t\t\t\"disk_selection_description\": \"选择您要监控的特定磁盘。\"\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "client/src/locales/zh-TW.json",
    "content": "{\n\t\"submit\": \"提交\",\n\t\"title\": \"名稱\",\n\t\"distributedStatusHeaderText\": \"實時、真實設備覆蓋\",\n\t\"distributedStatusSubHeaderText\": \"由全球數百萬個設備提供支持，您可以按全球區域、國家或城市查看系統效能\",\n\t\"settingsDisabled\": \"已停用\",\n\t\"settingsSuccessSaved\": \"設定已成功儲存\",\n\t\"settingsFailedToSave\": \"無法儲存設定\",\n\t\"settingsStatsCleared\": \"統計數據已成功清除\",\n\t\"settingsFailedToClearStats\": \"無法清除統計數據\",\n\t\"settingsMonitorsDeleted\": \"已成功刪除所有監視器\",\n\t\"settingsFailedToDeleteMonitors\": \"無法刪除所有監視器\",\n\t\"starPromptTitle\": \"星標Checkmate\",\n\t\"starPromptDescription\": \"查看最新版本發布及在 GitHub 上幫助社區成長\",\n\t\"https\": \"HTTPS\",\n\t\"http\": \"HTTP\",\n\t\"monitor\": \"監控\",\n\t\"aboutus\": \"關於我們\",\n\t\"now\": \"現在\",\n\t\"delete\": \"刪除\",\n\t\"configure\": \"設定\",\n\t\"responseTime\": \"回應時間\",\n\t\"ms\": \"毫秒\",\n\t\"bar\": \"條\",\n\t\"area\": \"區域\",\n\t\"country\": \"國家\",\n\t\"city\": \"城市\",\n\t\"response\": \"回應\",\n\t\"monitorStatusUp\": \"\",\n\t\"monitorStatusDown\": \"\",\n\t\"webhookSendSuccess\": \"Webhook 通知發送成功\",\n\t\"webhookSendError\": \"\",\n\t\"webhookUnsupportedPlatform\": \"不支援的平台: {platform}\",\n\t\"distributedRightCategoryTitle\": \"監控\",\n\t\"distributedStatusServerMonitors\": \"伺服器監控\",\n\t\"distributedStatusServerMonitorsDescription\": \"監控相關伺服器狀態\",\n\t\"distributedUptimeCreateSelectURL\": \"你可以在這裡選擇主機的 URL，同時選擇監視器類型。\",\n\t\"distributedUptimeCreateChecks\": \"要執行的檢查項目\",\n\t\"distributedUptimeCreateChecksDescription\": \"你可以在新增網站後，隨時新增或移除檢查項目。\",\n\t\"distributedUptimeCreateIncidentNotification\": \"事故通知\",\n\t\"distributedUptimeCreateIncidentDescription\": \"事故發生時，向用戶發送通知。\",\n\t\"distributedUptimeCreateAdvancedSettings\": \"進階設定\",\n\t\"distributedUptimeDetailsNoMonitorHistory\": \"此監控尚無檢查記錄。\",\n\t\"distributedUptimeDetailsStatusHeaderUptime\": \"正常運行時間:\",\n\t\"distributedUptimeDetailsStatusHeaderLastUpdate\": \"最後更新\",\n\t\"notifications\": {\n\t\t\"enableNotifications\": \"\",\n\t\t\"testNotification\": \"測試通知\",\n\t\t\"addOrEditNotifications\": \"新增或編輯通知\",\n\t\t\"slack\": {\n\t\t\t\"label\": \"Slack\",\n\t\t\t\"description\": \"要啟用 Slack 通知，請建立一個 Slack 應用程式並啟用傳入 Webhook。完成後，請在此提供 Webhook URL 即可。\",\n\t\t\t\"webhookLabel\": \"Webhook URL\",\n\t\t\t\"webhookPlaceholder\": \"https://hooks.slack.com/services/...\",\n\t\t\t\"webhookRequired\": \"Slack webhook URL is required\"\n\t\t},\n\t\t\"discord\": {\n\t\t\t\"label\": \"Discord\",\n\t\t\t\"description\": \"\",\n\t\t\t\"webhookLabel\": \"Discord Webhook URL\",\n\t\t\t\"webhookPlaceholder\": \"https://discord.com/api/webhooks/...\",\n\t\t\t\"webhookRequired\": \"\"\n\t\t},\n\t\t\"telegram\": {\n\t\t\t\"label\": \"Telegram\",\n\t\t\t\"description\": \"要啟用 Telegram 通知，請使用 BotFather 用於創建和管理 Telegram 的官方機器來建立一個 Telegram 機器人。接著，取得 API 金鑰和聊天室 ID，並在此處填寫。\",\n\t\t\t\"tokenLabel\": \"你的機器人金鑰\",\n\t\t\t\"tokenPlaceholder\": \"123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11\",\n\t\t\t\"chatIdLabel\": \"你的聊天 ID\",\n\t\t\t\"chatIdPlaceholder\": \"-1001234567890\",\n\t\t\t\"fieldsRequired\": \"\"\n\t\t},\n\t\t\"webhook\": {\n\t\t\t\"label\": \"Webhooks\",\n\t\t\t\"description\": \"你可以設定自訂 webhook，在事件發生時接收通知。\",\n\t\t\t\"urlLabel\": \"Webhook URL\",\n\t\t\t\"urlPlaceholder\": \"https://your-server.com/webhook\",\n\t\t\t\"urlRequired\": \"\"\n\t\t},\n\t\t\"testNotificationDevelop\": \"測試通知 2\",\n\t\t\"integrationButton\": \"\",\n\t\t\"testSuccess\": \"\",\n\t\t\"testFailed\": \"\",\n\t\t\"unsupportedType\": \"\",\n\t\t\"networkError\": \"\",\n\t\t\"fallback\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"checks\": [\n\t\t\t\t\"提醒團隊有關停機或性能問題\",\n\t\t\t\t\"讓工程師知道事件發生時的情況\",\n\t\t\t\t\"讓管理員了解系統變更情況\"\n\t\t\t],\n\t\t\t\"actionButton\": \"讓我們建立您的第一個通知頻道！\"\n\t\t},\n\t\t\"createButton\": \"\",\n\t\t\"createTitle\": \"\",\n\t\t\"create\": {\n\t\t\t\"success\": \"\",\n\t\t\t\"failed\": \"\"\n\t\t},\n\t\t\"fetch\": {\n\t\t\t\"success\": \"\",\n\t\t\t\"failed\": \"\"\n\t\t},\n\t\t\"delete\": {\n\t\t\t\"success\": \"\",\n\t\t\t\"failed\": \"\"\n\t\t},\n\t\t\"edit\": {\n\t\t\t\"success\": \"\",\n\t\t\t\"failed\": \"\"\n\t\t},\n\t\t\"test\": {\n\t\t\t\"success\": \"\",\n\t\t\t\"failed\": \"\"\n\t\t}\n\t},\n\t\"testLocale\": \"測試語言環境\",\n\t\"add\": \"新增\",\n\t\"monitors\": \"\",\n\t\"distributedUptimeStatusCreateStatusPage\": \"\",\n\t\"distributedUptimeStatusCreateStatusPageAccess\": \"\",\n\t\"distributedUptimeStatusCreateStatusPageReady\": \"\",\n\t\"distributedUptimeStatusBasicInfoHeader\": \"基本資料\",\n\t\"distributedUptimeStatusBasicInfoDescription\": \"\",\n\t\"distributedUptimeStatusLogoHeader\": \"標誌\",\n\t\"distributedUptimeStatusLogoDescription\": \"\",\n\t\"distributedUptimeStatusLogoUploadButton\": \"上傳標誌\",\n\t\"distributedUptimeStatusStandardMonitorsHeader\": \"\",\n\t\"distributedUptimeStatusStandardMonitorsDescription\": \"\",\n\t\"distributedUptimeStatusCreateYour\": \"\",\n\t\"distributedUptimeStatusEditYour\": \"\",\n\t\"distributedUptimeStatusPublishedLabel\": \"\",\n\t\"distributedUptimeStatusCompanyNameLabel\": \"公司名稱\",\n\t\"distributedUptimeStatusPageAddressLabel\": \"\",\n\t\"distributedUptimeStatus30Days\": \"30日\",\n\t\"distributedUptimeStatus60Days\": \"60日\",\n\t\"distributedUptimeStatus90Days\": \"90日\",\n\t\"distributedUptimeStatusPageNotSetUp\": \"\",\n\t\"distributedUptimeStatusContactAdmin\": \"\",\n\t\"distributedUptimeStatusPageNotPublic\": \"\",\n\t\"distributedUptimeStatusPageDeleteDialog\": \"\",\n\t\"distributedUptimeStatusPageDeleteConfirm\": \"\",\n\t\"distributedUptimeStatusPageDeleteDescription\": \"\",\n\t\"distributedUptimeStatusDevices\": \"設備\",\n\t\"distributedUptimeStatusUpt\": \"UPT\",\n\t\"distributedUptimeStatusUptBurned\": \"\",\n\t\"distributedUptimeStatusUptLogo\": \"\",\n\t\"incidentsTableNoIncidents\": \"\",\n\t\"incidentsTablePaginationLabel\": \"\",\n\t\"incidentsTableMonitorName\": \"\",\n\t\"incidentsTableStatus\": \"\",\n\t\"incidentsTableDateTime\": \"\",\n\t\"incidentsTableStatusCode\": \"\",\n\t\"incidentsTableMessage\": \"\",\n\t\"incidentsOptionsHeader\": \"\",\n\t\"incidentsOptionsHeaderFilterBy\": \"\",\n\t\"incidentsOptionsHeaderFilterAll\": \"\",\n\t\"incidentsOptionsHeaderFilterDown\": \"\",\n\t\"incidentsOptionsHeaderFilterCannotResolve\": \"\",\n\t\"incidentsOptionsHeaderShow\": \"\",\n\t\"incidentsOptionsHeaderLastHour\": \"\",\n\t\"incidentsOptionsHeaderLastDay\": \"\",\n\t\"incidentsOptionsHeaderLastWeek\": \"\",\n\t\"incidentsOptionsPlaceholderAllServers\": \"\",\n\t\"infrastructureCreateYour\": \"\",\n\t\"infrastructureCreateGeneralSettingsDescription\": \"\",\n\t\"infrastructureServerRequirement\": \"\",\n\t\"infrastructureCustomizeAlerts\": \"\",\n\t\"infrastructureAlertNotificationDescription\": \"\",\n\t\"infrastructureCreateMonitor\": \"\",\n\t\"infrastructureProtocol\": \"\",\n\t\"infrastructureServerUrlLabel\": \"\",\n\t\"infrastructureDisplayNameLabel\": \"\",\n\t\"infrastructureAuthorizationSecretLabel\": \"\",\n\t\"gb\": \"GB\",\n\t\"mb\": \"MB\",\n\t\"mem\": \"Mem\",\n\t\"memoryUsage\": \"\",\n\t\"cpu\": \"CPU\",\n\t\"cpuUsage\": \"CPU 使用量\",\n\t\"cpuTemperature\": \"CPU 溫度\",\n\t\"diskUsage\": \"\",\n\t\"used\": \"\",\n\t\"total\": \"\",\n\t\"cores\": \"核\",\n\t\"frequency\": \"\",\n\t\"status\": \"\",\n\t\"cpuPhysical\": \"CPU (實體核心)\",\n\t\"cpuLogical\": \"CPU (邏輯核心)\",\n\t\"cpuFrequency\": \"CPU 頻率\",\n\t\"avgCpuTemperature\": \"平均 CPU 溫度\",\n\t\"memory\": \"\",\n\t\"disk\": \"\",\n\t\"uptime\": \"\",\n\t\"os\": \"OS\",\n\t\"host\": \"\",\n\t\"actions\": \"行動\",\n\t\"integrations\": \"\",\n\t\"integrationsPrism\": \"\",\n\t\"integrationsSlack\": \"Slack\",\n\t\"integrationsSlackInfo\": \"\",\n\t\"integrationsDiscord\": \"\",\n\t\"integrationsDiscordInfo\": \"\",\n\t\"integrationsZapier\": \"\",\n\t\"integrationsZapierInfo\": \"\",\n\t\"commonSave\": \"儲存\",\n\t\"createYour\": \"\",\n\t\"createMonitor\": \"\",\n\t\"pause\": \"\",\n\t\"resume\": \"\",\n\t\"editing\": \"\",\n\t\"url\": \"UR:\",\n\t\"access\": \"存取\",\n\t\"timezone\": \"時區\",\n\t\"features\": \"\",\n\t\"administrator\": \"系統管理員?\",\n\t\"loginHere\": \"\",\n\t\"displayName\": \"\",\n\t\"urlMonitor\": \"\",\n\t\"portToMonitor\": \"\",\n\t\"websiteMonitoring\": \"網站監控\",\n\t\"websiteMonitoringDescription\": \"\",\n\t\"pingMonitoring\": \"\",\n\t\"pingMonitoringDescription\": \"\",\n\t\"dockerContainerMonitoring\": \"\",\n\t\"dockerContainerMonitoringDescription\": \"\",\n\t\"portMonitoring\": \"\",\n\t\"portMonitoringDescription\": \"\",\n\t\"createMaintenanceWindow\": \"\",\n\t\"createMaintenance\": \"\",\n\t\"editMaintenance\": \"\",\n\t\"maintenanceWindowName\": \"\",\n\t\"friendlyNameInput\": \"\",\n\t\"friendlyNamePlaceholder\": \"\",\n\t\"maintenanceRepeat\": \"\",\n\t\"maintenance\": \"\",\n\t\"duration\": \"\",\n\t\"addMonitors\": \"新增監視器\",\n\t\"window\": \"\",\n\t\"cancel\": \"取消\",\n\t\"message\": \"\",\n\t\"low\": \"低\",\n\t\"high\": \"高\",\n\t\"statusCode\": \"\",\n\t\"date&Time\": \"日期與時間\",\n\t\"type\": \"類型\",\n\t\"statusPageName\": \"\",\n\t\"publicURL\": \"\",\n\t\"repeat\": \"\",\n\t\"edit\": \"\",\n\t\"createA\": \"\",\n\t\"remove\": \"\",\n\t\"maintenanceWindowDescription\": \"\",\n\t\"startTime\": \"\",\n\t\"timeZoneInfo\": \"\",\n\t\"monitorsToApply\": \"\",\n\t\"nextWindow\": \"\",\n\t\"notFoundButton\": \"\",\n\t\"pageSpeedConfigureSettingsDescription\": \"\",\n\t\"monitorDisplayName\": \"\",\n\t\"whenNewIncident\": \"\",\n\t\"notifySMS\": \"\",\n\t\"notifyEmails\": \"\",\n\t\"seperateEmails\": \"\",\n\t\"checkFrequency\": \"檢查頻率\",\n\t\"matchMethod\": \"\",\n\t\"expectedValue\": \"\",\n\t\"deleteDialogTitle\": \"您確定要刪除此監視器嗎？\",\n\t\"deleteDialogDescription\": \"一旦刪除，該監視器無法恢復。\",\n\t\"pageSpeedMonitor\": \"\",\n\t\"shown\": \"\",\n\t\"ago\": \"\",\n\t\"companyName\": \"公司名稱\",\n\t\"pageSpeedDetailsPerformanceReport\": \"\",\n\t\"pageSpeedDetailsPerformanceReportCalculator\": \"\",\n\t\"checkingEvery\": \"\",\n\t\"statusPageCreateSettings\": \"\",\n\t\"basicInformation\": \"基本資料\",\n\t\"statusPageCreateBasicInfoDescription\": \"\",\n\t\"statusPageCreateSelectTimeZoneDescription\": \"\",\n\t\"statusPageCreateAppearanceDescription\": \"\",\n\t\"statusPageCreateSettingsCheckboxLabel\": \"\",\n\t\"statusPageCreateBasicInfoStatusPageAddress\": \"\",\n\t\"statusPageCreateTabsContent\": \"\",\n\t\"statusPageCreateTabsContentDescription\": \"\",\n\t\"statusPageCreateTabsContentFeaturesDescription\": \"\",\n\t\"showCharts\": \"\",\n\t\"showUptimePercentage\": \"\",\n\t\"removeLogo\": \"\",\n\t\"statusPageStatus\": \"\",\n\t\"statusPageStatusContactAdmin\": \"\",\n\t\"statusPageStatusNotPublic\": \"\",\n\t\"statusPageStatusNoPage\": \"\",\n\t\"statusPageStatusServiceStatus\": \"\",\n\t\"deleteStatusPage\": \"\",\n\t\"deleteStatusPageConfirm\": \"\",\n\t\"deleteStatusPageDescription\": \"\",\n\t\"uptimeCreate\": \"\",\n\t\"uptimeCreateJsonPath\": \"\",\n\t\"uptimeCreateJsonPathQuery\": \"\",\n\t\"maintenanceTableActionMenuDialogTitle\": \"\",\n\t\"infrastructureEditYour\": \"\",\n\t\"infrastructureEditMonitor\": \"\",\n\t\"infrastructureMonitorCreated\": \"\",\n\t\"infrastructureMonitorUpdated\": \"\",\n\t\"errorInvalidTypeId\": \"\",\n\t\"errorInvalidFieldId\": \"\",\n\t\"inviteNoTokenFound\": \"\",\n\t\"pageSpeedWarning\": \"\",\n\t\"pageSpeedLearnMoreLink\": \"\",\n\t\"pageSpeedAddApiKey\": \"\",\n\t\"update\": \"更新\",\n\t\"invalidFileFormat\": \"\",\n\t\"invalidFileSize\": \"\",\n\t\"ClickUpload\": \"點擊上傳\",\n\t\"DragandDrop\": \"\",\n\t\"MaxSize\": \"\",\n\t\"SupportedFormats\": \"\",\n\t\"FirstName\": \"\",\n\t\"LastName\": \"\",\n\t\"EmailDescriptionText\": \"\",\n\t\"YourPhoto\": \"頭像\",\n\t\"PhotoDescriptionText\": \"\",\n\t\"save\": \"\",\n\t\"DeleteDescriptionText\": \"這將刪除帳號以及所有相關的伺服器資料，此操作不可逆轉。\",\n\t\"DeleteAccountWarning\": \"刪除您的帳號表示您將無法再次登入，且所有資料都會被移除。此操作不可逆轉。\",\n\t\"DeleteWarningTitle\": \"\",\n\t\"bulkImport\": {\n\t\t\"title\": \"批量匯入\",\n\t\t\"selectFileTips\": \"\",\n\t\t\"selectFileDescription\": \"\",\n\t\t\"selectFile\": \"\",\n\t\t\"parsingFailed\": \"\",\n\t\t\"uploadSuccess\": \"\",\n\t\t\"validationFailed\": \"\",\n\t\t\"noFileSelected\": \"\",\n\t\t\"fallbackPage\": \"\",\n\t\t\"invalidFileType\": \"\",\n\t\t\"uploadFailed\": \"\"\n\t},\n\t\"DeleteAccountTitle\": \"刪除帳戶\",\n\t\"DeleteAccountButton\": \"刪除帳戶\",\n\t\"publicLink\": \"\",\n\t\"maskedPageSpeedKeyPlaceholder\": \"\",\n\t\"reset\": \"\",\n\t\"ignoreTLSError\": \"\",\n\t\"tlsErrorIgnored\": \"\",\n\t\"ignoreTLSErrorDescription\": \"\",\n\t\"createNew\": \"\",\n\t\"greeting\": {\n\t\t\"prepend\": \"\",\n\t\t\"append\": \"\",\n\t\t\"overview\": \"\"\n\t},\n\t\"roles\": {\n\t\t\"superAdmin\": \"\",\n\t\t\"admin\": \"管理員\",\n\t\t\"teamMember\": \"\",\n\t\t\"demoUser\": \"示範用戶\"\n\t},\n\t\"teamPanel\": {\n\t\t\"teamMembers\": \"\",\n\t\t\"filter\": {\n\t\t\t\"all\": \"全部\",\n\t\t\t\"member\": \"\"\n\t\t},\n\t\t\"inviteTeamMember\": \"\",\n\t\t\"inviteNewTeamMember\": \"\",\n\t\t\"inviteDescription\": \"\",\n\t\t\"email\": \"\",\n\t\t\"selectRole\": \"\",\n\t\t\"inviteLink\": \"\",\n\t\t\"cancel\": \"取消\",\n\t\t\"noMembers\": \"\",\n\t\t\"getToken\": \"\",\n\t\t\"emailToken\": \"\",\n\t\t\"table\": {\n\t\t\t\"name\": \"\",\n\t\t\t\"email\": \"\",\n\t\t\t\"role\": \"\",\n\t\t\t\"created\": \"\"\n\t\t},\n\t\t\"addTeamMember\": {\n\t\t\t\"addMemberMenu\": \"\",\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"addButton\": \"\"\n\t\t},\n\t\t\"register\": \"\",\n\t\t\"registerToast\": {\n\t\t\t\"success\": \"\",\n\t\t\t\"dbUserExists\": \"\",\n\t\t\t\"unknownError\": \"\"\n\t\t},\n\t\t\"registerTeamMember\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"auth\": {\n\t\t\t\t\"common\": {\n\t\t\t\t\t\"inputs\": {\n\t\t\t\t\t\t\"firstName\": {\n\t\t\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\t\t\"empty\": \"\",\n\t\t\t\t\t\t\t\t\"pattern\": \"\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"lastName\": {\n\t\t\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\t\t\"empty\": \"\",\n\t\t\t\t\t\t\t\t\"pattern\": \"\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"email\": {\n\t\t\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\t\t\"empty\": \"\",\n\t\t\t\t\t\t\t\t\"invalid\": \"\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"role\": {\n\t\t\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\t\t\"empty\": \"\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"role\": \"\",\n\t\t\"changeTeamPassword\": {\n\t\t\t\"changePasswordMenu\": \"\",\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"success\": \"\"\n\t\t}\n\t},\n\t\"monitorState\": {\n\t\t\"paused\": \"\",\n\t\t\"resumed\": \"\",\n\t\t\"active\": \"啟用中\"\n\t},\n\t\"menu\": {\n\t\t\"uptime\": \"\",\n\t\t\"pagespeed\": \"\",\n\t\t\"infrastructure\": \"\",\n\t\t\"incidents\": \"\",\n\t\t\"statusPages\": \"\",\n\t\t\"maintenance\": \"\",\n\t\t\"integrations\": \"\",\n\t\t\"settings\": \"\",\n\t\t\"support\": \"\",\n\t\t\"discussions\": \"\",\n\t\t\"docs\": \"\",\n\t\t\"changelog\": \"版本變更記錄\",\n\t\t\"profile\": \"\",\n\t\t\"password\": \"\",\n\t\t\"team\": \"\",\n\t\t\"logOut\": \"\",\n\t\t\"notifications\": \"\",\n\t\t\"logs\": \"\"\n\t},\n\t\"settingsEmailUser\": \"\",\n\t\"state\": \"\",\n\t\"statusBreadCrumbsStatusPages\": \"\",\n\t\"statusBreadCrumbsDetails\": \"\",\n\t\"commonSaving\": \"儲存中...\",\n\t\"navControls\": \"\",\n\t\"incidentsPageTitle\": \"\",\n\t\"passwordPanel\": {\n\t\t\"passwordChangedSuccess\": \"\",\n\t\t\"passwordInputIncorrect\": \"\",\n\t\t\"currentPassword\": \"當前密碼\",\n\t\t\"enterCurrentPassword\": \"\",\n\t\t\"newPassword\": \"\",\n\t\t\"enterNewPassword\": \"\",\n\t\t\"confirmNewPassword\": \"確認新密碼\",\n\t\t\"passwordRequirements\": \"\",\n\t\t\"saving\": \"\"\n\t},\n\t\"emailSent\": \"\",\n\t\"failedToSendEmail\": \"\",\n\t\"settingsTestEmailSuccess\": \"\",\n\t\"settingsTestEmailFailed\": \"\",\n\t\"settingsTestEmailFailedWithReason\": \"\",\n\t\"settingsTestEmailUnknownError\": \"\",\n\t\"statusMsg\": {\n\t\t\"paused\": \"\",\n\t\t\"up\": \"\",\n\t\t\"down\": \"\",\n\t\t\"pending\": \"\"\n\t},\n\t\"uptimeGeneralInstructions\": {\n\t\t\"http\": \"\",\n\t\t\"ping\": \"\",\n\t\t\"docker\": \"\",\n\t\t\"port\": \"\",\n\t\t\"game\": \"\",\n\t\t\"https\": \"\"\n\t},\n\t\"common\": {\n\t\t\"appName\": \"Checkmate\",\n\t\t\"monitoringAgentName\": \"\",\n\t\t\"buttons\": {\n\t\t\t\"toggleTheme\": \"\"\n\t\t},\n\t\t\"toasts\": {\n\t\t\t\"networkError\": \"\",\n\t\t\t\"checkConnection\": \"請檢查您的連線\",\n\t\t\t\"unknownError\": \"\"\n\t\t}\n\t},\n\t\"auth\": {\n\t\t\"common\": {\n\t\t\t\"navigation\": {\n\t\t\t\t\"continue\": \"繼續\",\n\t\t\t\t\"back\": \"返回\"\n\t\t\t},\n\t\t\t\"inputs\": {\n\t\t\t\t\"email\": {\n\t\t\t\t\t\"label\": \"\",\n\t\t\t\t\t\"placeholder\": \"\",\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"\",\n\t\t\t\t\t\t\"invalid\": \"\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"password\": {\n\t\t\t\t\t\"label\": \"\",\n\t\t\t\t\t\"rules\": {\n\t\t\t\t\t\t\"length\": {\n\t\t\t\t\t\t\t\"beginning\": \"必須至少\",\n\t\t\t\t\t\t\t\"highlighted\": \"\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"special\": {\n\t\t\t\t\t\t\t\"beginning\": \"必須至少包含\",\n\t\t\t\t\t\t\t\"highlighted\": \"\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"number\": {\n\t\t\t\t\t\t\t\"beginning\": \"必須至少包含\",\n\t\t\t\t\t\t\t\"highlighted\": \"\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"uppercase\": {\n\t\t\t\t\t\t\t\"beginning\": \"必須至少包含\",\n\t\t\t\t\t\t\t\"highlighted\": \"\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"lowercase\": {\n\t\t\t\t\t\t\t\"beginning\": \"必須至少包含\",\n\t\t\t\t\t\t\t\"highlighted\": \"\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"match\": {\n\t\t\t\t\t\t\t\"beginning\": \"\",\n\t\t\t\t\t\t\t\"highlighted\": \"\"\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"\",\n\t\t\t\t\t\t\"length\": \"\",\n\t\t\t\t\t\t\"uppercase\": \"\",\n\t\t\t\t\t\t\"lowercase\": \"\",\n\t\t\t\t\t\t\"number\": \"\",\n\t\t\t\t\t\t\"special\": \"\",\n\t\t\t\t\t\t\"incorrect\": \"\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"passwordConfirm\": {\n\t\t\t\t\t\"label\": \"\",\n\t\t\t\t\t\"placeholder\": \"\",\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"\",\n\t\t\t\t\t\t\"different\": \"\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"firstName\": {\n\t\t\t\t\t\"label\": \"\",\n\t\t\t\t\t\"placeholder\": \"\",\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"\",\n\t\t\t\t\t\t\"length\": \"\",\n\t\t\t\t\t\t\"pattern\": \"\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"lastName\": {\n\t\t\t\t\t\"label\": \"\",\n\t\t\t\t\t\"placeholder\": \"\",\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"empty\": \"\",\n\t\t\t\t\t\t\"length\": \"\",\n\t\t\t\t\t\t\"pattern\": \"\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"errors\": {\n\t\t\t\t\"validation\": \"\"\n\t\t\t},\n\t\t\t\"fields\": {\n\t\t\t\t\"password\": {\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"incorrect\": \"\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"role\": {\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"min\": \"\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"login\": {\n\t\t\t\"heading\": \"\",\n\t\t\t\"subheadings\": {\n\t\t\t\t\"stepOne\": \"\",\n\t\t\t\t\"stepTwo\": \"\"\n\t\t\t},\n\t\t\t\"links\": {\n\t\t\t\t\"forgotPassword\": \"\",\n\t\t\t\t\"register\": \"\",\n\t\t\t\t\"forgotPasswordLink\": \"\",\n\t\t\t\t\"registerLink\": \"\"\n\t\t\t},\n\t\t\t\"toasts\": {\n\t\t\t\t\"success\": \"歡迎回來！您已成功登入。\",\n\t\t\t\t\"incorrectPassword\": \"\"\n\t\t\t},\n\t\t\t\"errors\": {\n\t\t\t\t\"password\": {\n\t\t\t\t\t\"incorrect\": \"\"\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"welcome\": \"\"\n\t\t},\n\t\t\"registration\": {\n\t\t\t\"heading\": {\n\t\t\t\t\"superAdmin\": \"\",\n\t\t\t\t\"user\": \"\"\n\t\t\t},\n\t\t\t\"subheadings\": {\n\t\t\t\t\"stepOne\": \"\",\n\t\t\t\t\"stepTwo\": \"\",\n\t\t\t\t\"stepThree\": \"\"\n\t\t\t},\n\t\t\t\"description\": {\n\t\t\t\t\"superAdmin\": \"\",\n\t\t\t\t\"user\": \"\"\n\t\t\t},\n\t\t\t\"gettingStartedButton\": {\n\t\t\t\t\"superAdmin\": \"\",\n\t\t\t\t\"user\": \"\"\n\t\t\t},\n\t\t\t\"termsAndPolicies\": \"\",\n\t\t\t\"links\": {\n\t\t\t\t\"login\": \"\"\n\t\t\t},\n\t\t\t\"toasts\": {\n\t\t\t\t\"success\": \"歡迎！您的帳號已成功建立。\"\n\t\t\t},\n\t\t\t\"welcome\": \"\"\n\t\t},\n\t\t\"forgotPassword\": {\n\t\t\t\"heading\": \"\",\n\t\t\t\"subheadings\": {\n\t\t\t\t\"stepOne\": \"\",\n\t\t\t\t\"stepTwo\": \"\",\n\t\t\t\t\"stepThree\": \"\",\n\t\t\t\t\"stepFour\": \"\"\n\t\t\t},\n\t\t\t\"buttons\": {\n\t\t\t\t\"openEmail\": \"\",\n\t\t\t\t\"resetPassword\": \"\"\n\t\t\t},\n\t\t\t\"imageAlts\": {\n\t\t\t\t\"passwordKey\": \"\",\n\t\t\t\t\"email\": \"\",\n\t\t\t\t\"lock\": \"\",\n\t\t\t\t\"passwordConfirm\": \"\"\n\t\t\t},\n\t\t\t\"links\": {\n\t\t\t\t\"login\": \"\",\n\t\t\t\t\"resend\": \"\"\n\t\t\t},\n\t\t\t\"toasts\": {\n\t\t\t\t\"sent\": \"\",\n\t\t\t\t\"emailNotFound\": \"\",\n\t\t\t\t\"redirect\": \"\",\n\t\t\t\t\"success\": \"您的密碼已成功重設。\",\n\t\t\t\t\"error\": \"\"\n\t\t\t}\n\t\t}\n\t},\n\t\"errorPages\": {\n\t\t\"serverUnreachable\": {\n\t\t\t\"toasts\": {\n\t\t\t\t\"reconnected\": \"\",\n\t\t\t\t\"stillUnreachable\": \"\"\n\t\t\t},\n\t\t\t\"alertBox\": \"伺服器連線錯誤\",\n\t\t\t\"description\": \"我們無法連接到伺服器。請檢查您的網路連線，若問題持續，請確認您的部署設定是否正確。\",\n\t\t\t\"retryButton\": {\n\t\t\t\t\"default\": \"重新嘗試連線\",\n\t\t\t\t\"processing\": \"\"\n\t\t\t}\n\t\t}\n\t},\n\t\"createNotifications\": {\n\t\t\"title\": \"\",\n\t\t\"nameSettings\": {\n\t\t\t\"title\": \"姓名\",\n\t\t\t\"description\": \"為您的整合設定描述名稱。\",\n\t\t\t\"nameLabel\": \"\",\n\t\t\t\"namePlaceholder\": \"\"\n\t\t},\n\t\t\"typeSettings\": {\n\t\t\t\"title\": \"類型\",\n\t\t\t\"description\": \"請選擇您想要建立的通知頻道類型。\",\n\t\t\t\"typeLabel\": \"類型\"\n\t\t},\n\t\t\"emailSettings\": {\n\t\t\t\"title\": \"電郵\",\n\t\t\t\"description\": \"目的地電子郵件位址。\",\n\t\t\t\"emailLabel\": \"\",\n\t\t\t\"emailPlaceholder\": \"\"\n\t\t},\n\t\t\"slackSettings\": {\n\t\t\t\"title\": \"Slack\",\n\t\t\t\"description\": \"在此配置您的 Slack webhook\",\n\t\t\t\"webhookLabel\": \"\",\n\t\t\t\"webhookPlaceholder\": \"\"\n\t\t},\n\t\t\"pagerdutySettings\": {\n\t\t\t\"title\": \"PagerDuty\",\n\t\t\t\"description\": \"在此配置您的 PagerDuty 整合\",\n\t\t\t\"integrationKeyLabel\": \"\",\n\t\t\t\"integrationKeyPlaceholder\": \"\"\n\t\t},\n\t\t\"discordSettings\": {\n\t\t\t\"title\": \"Discord\",\n\t\t\t\"description\": \"在此配置您的 Discord webhook\",\n\t\t\t\"webhookLabel\": \"\",\n\t\t\t\"webhookPlaceholder\": \"\"\n\t\t},\n\t\t\"webhookSettings\": {\n\t\t\t\"title\": \"Webhook\",\n\t\t\t\"description\": \"\",\n\t\t\t\"webhookLabel\": \"\",\n\t\t\t\"webhookPlaceholder\": \"\"\n\t\t},\n\t\t\"testNotification\": \"\",\n\t\t\"dialogDeleteTitle\": \"\",\n\t\t\"dialogDeleteConfirm\": \"\"\n\t},\n\t\"notificationConfig\": {\n\t\t\"title\": \"通知\",\n\t\t\"description\": \"請選擇您想要使用的通知頻道\"\n\t},\n\t\"monitorStatus\": {\n\t\t\"checkingEvery\": \"\",\n\t\t\"withCaptureAgent\": \"\",\n\t\t\"up\": \"\",\n\t\t\"down\": \"\",\n\t\t\"paused\": \"\"\n\t},\n\t\"advancedMatching\": \"進階匹配\",\n\t\"sendTestNotifications\": \"\",\n\t\"selectAll\": \"\",\n\t\"showAdminLoginLink\": \"\",\n\t\"logsPage\": {\n\t\t\"title\": \"\",\n\t\t\"description\": \"\",\n\t\t\"tabs\": {\n\t\t\t\"queue\": \"\",\n\t\t\t\"logs\": \"\",\n\t\t\t\"diagnostics\": \"\"\n\t\t},\n\t\t\"toast\": {\n\t\t\t\"fetchLogsSuccess\": \"\"\n\t\t},\n\t\t\"logLevelSelect\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"values\": {\n\t\t\t\t\"all\": \"全部\",\n\t\t\t\t\"info\": \"\",\n\t\t\t\t\"warn\": \"\",\n\t\t\t\t\"error\": \"\",\n\t\t\t\t\"debug\": \"除錯\"\n\t\t\t}\n\t\t}\n\t},\n\t\"queuePage\": {\n\t\t\"title\": \"\",\n\t\t\"refreshButton\": \"\",\n\t\t\"flushButton\": \"\",\n\t\t\"jobTable\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"idHeader\": \"\",\n\t\t\t\"urlHeader\": \"\",\n\t\t\t\"typeHeader\": \"類型\",\n\t\t\t\"activeHeader\": \"啟用中\",\n\t\t\t\"lockedAtHeader\": \"\",\n\t\t\t\"runCountHeader\": \"\",\n\t\t\t\"failCountHeader\": \"\",\n\t\t\t\"lastRunHeader\": \"\",\n\t\t\t\"lastFinishedAtHeader\": \"\",\n\t\t\t\"lastRunTookHeader\": \"\",\n\t\t\t\"intervalHeader\": \"\"\n\t\t},\n\t\t\"metricsTable\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"metricHeader\": \"\",\n\t\t\t\"valueHeader\": \"\"\n\t\t},\n\t\t\"failedJobTable\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"monitorIdHeader\": \"\",\n\t\t\t\"monitorUrlHeader\": \"\",\n\t\t\t\"failCountHeader\": \"\",\n\t\t\t\"failedAtHeader\": \"\",\n\t\t\t\"failReasonHeader\": \"\"\n\t\t}\n\t},\n\t\"export\": {\n\t\t\"title\": \"\",\n\t\t\"success\": \"\",\n\t\t\"failed\": \"\"\n\t},\n\t\"monitorActions\": {\n\t\t\"title\": \"\",\n\t\t\"import\": \"\",\n\t\t\"export\": \"\",\n\t\t\"deleteSuccess\": \"\",\n\t\t\"deleteFailed\": \"\",\n\t\t\"details\": \"\"\n\t},\n\t\"settingsPage\": {\n\t\t\"aboutSettings\": {\n\t\t\t\"labelDevelopedBy\": \"\",\n\t\t\t\"labelVersion\": \"\",\n\t\t\t\"title\": \"關於\"\n\t\t},\n\t\t\"demoMonitorsSettings\": {\n\t\t\t\"buttonAddMonitors\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"title\": \"\"\n\t\t},\n\t\t\"emailSettings\": {\n\t\t\t\"buttonSendTestEmail\": \"發送測試電子郵件\",\n\t\t\t\"description\": \"\",\n\t\t\t\"descriptionTransport\": \"\",\n\t\t\t\"labelAddress\": \"\",\n\t\t\t\"labelConnectionHost\": \"\",\n\t\t\t\"labelHost\": \"\",\n\t\t\t\"labelIgnoreTLS\": \"\",\n\t\t\t\"labelPassword\": \"\",\n\t\t\t\"labelPasswordSet\": \"\",\n\t\t\t\"labelPool\": \"\",\n\t\t\t\"labelPort\": \"\",\n\t\t\t\"labelRejectUnauthorized\": \"\",\n\t\t\t\"labelRequireTLS\": \"\",\n\t\t\t\"labelSecure\": \"\",\n\t\t\t\"labelTLSServername\": \"\",\n\t\t\t\"labelUser\": \"\",\n\t\t\t\"linkTransport\": \"\",\n\t\t\t\"placeholderUser\": \"\",\n\t\t\t\"title\": \"電郵\",\n\t\t\t\"toastEmailRequiredFieldsError\": \"\"\n\t\t},\n\t\t\"pageSpeedSettings\": {\n\t\t\t\"description\": \"\",\n\t\t\t\"labelApiKeySet\": \"\",\n\t\t\t\"labelApiKey\": \"\",\n\t\t\t\"title\": \"Google PageSpeed API 金鑰\"\n\t\t},\n\t\t\"saveButtonLabel\": \"\",\n\t\t\"statsSettings\": {\n\t\t\t\"clearAllStatsButton\": \"清除所有統計數據\",\n\t\t\t\"clearAllStatsDescription\": \"清除所有統計數據，此操作不可逆轉。\",\n\t\t\t\"clearAllStatsDialogConfirm\": \"是，請清除所有統計數據\",\n\t\t\t\"clearAllStatsDialogDescription\": \"一旦刪除，監控歷史和統計數據將無法復原。\",\n\t\t\t\"clearAllStatsDialogTitle\": \"您是否要清除所有統計數據？\",\n\t\t\t\"description\": \"\",\n\t\t\t\"labelTTL\": \"\",\n\t\t\t\"labelTTLOptional\": \"0 表示無限\",\n\t\t\t\"title\": \"\"\n\t\t},\n\t\t\"systemResetSettings\": {\n\t\t\t\"buttonRemoveAllMonitors\": \"\",\n\t\t\t\"description\": \"\",\n\t\t\t\"dialogConfirm\": \"\",\n\t\t\t\"dialogDescription\": \"\",\n\t\t\t\"dialogTitle\": \"\",\n\t\t\t\"title\": \"系統重設\"\n\t\t},\n\t\t\"timezoneSettings\": {\n\t\t\t\"description\": \"\",\n\t\t\t\"label\": \"\",\n\t\t\t\"title\": \"顯示時區\"\n\t\t},\n\t\t\"title\": \"設定\",\n\t\t\"uiSettings\": {\n\t\t\t\"description\": \"\",\n\t\t\t\"labelLanguage\": \"\",\n\t\t\t\"labelTheme\": \"\",\n\t\t\t\"title\": \"外觀\"\n\t\t},\n\t\t\"urlSettings\": {\n\t\t\t\"description\": \"\",\n\t\t\t\"label\": \"\",\n\t\t\t\"selectDisabled\": \"\",\n\t\t\t\"selectEnabled\": \"\",\n\t\t\t\"title\": \"\"\n\t\t},\n\t\t\"globalThresholds\": {\n\t\t\t\"title\": \"\",\n\t\t\t\"description\": \"\"\n\t\t}\n\t},\n\t\"statusPageCreate\": {\n\t\t\"buttonSave\": \"儲存\"\n\t},\n\t\"incidentsOptionsHeaderFilterResolved\": \"\",\n\t\"settingsSave\": \"\",\n\t\"statusPageCreateAppearanceTitle\": \"\",\n\t\"confirmPassword\": \"確認密碼\",\n\t\"monitorHooks\": {\n\t\t\"failureAddDemoMonitors\": \"\",\n\t\t\"successAddDemoMonitors\": \"\"\n\t},\n\t\"settingsAppearance\": \"\",\n\t\"settingsDisplayTimezone\": \"\",\n\t\"settingsGeneralSettings\": \"\",\n\t\"incidentsOptionsHeaderTotalIncidents\": \"\",\n\t\"statusPage\": {\n\t\t\"deleteSuccess\": \"\",\n\t\t\"deleteFailed\": \"刪除狀態頁面失敗\",\n\t\t\"createSuccess\": \"\",\n\t\t\"updateSuccess\": \"\",\n\t\t\"generalSettings\": \"\",\n\t\t\"contents\": \"內容\",\n\t\t\"fallback\": {\n\t\t\t\"checks\": [\"\"],\n\t\t\t\"title\": \"\",\n\t\t\t\"actionButton\": \"讓我們建立您的第一個狀態頁面！\"\n\t\t}\n\t},\n\t\"testNotificationsDisabled\": \"\",\n\t\"incidentsTableResolvedAt\": \"\",\n\t\"incidentsTableActionResolve\": \"\",\n\t\"checkHooks\": {\n\t\t\"failureResolveOne\": \"\",\n\t\t\"failureResolveAll\": \"\",\n\t\t\"failureResolveMonitor\": \"\"\n\t},\n\t\"checkFormError\": \"\",\n\t\"diagnosticsPage\": {\n\t\t\"diagnosticDescription\": \"\",\n\t\t\"statsDescription\": \"\",\n\t\t\"gauges\": {\n\t\t\t\"heapAllocationTitle\": \"\",\n\t\t\t\"heapAllocationSubtitle\": \"\",\n\t\t\t\"heapUsageTitle\": \"\",\n\t\t\t\"heapUsageSubtitle\": \"\",\n\t\t\t\"heapUtilizationTitle\": \"\",\n\t\t\t\"heapUtilizationSubtitle\": \"\",\n\t\t\t\"instantCpuUsageTitle\": \"\",\n\t\t\t\"instantCpuUsageSubtitle\": \"\"\n\t\t},\n\t\t\"stats\": {\n\t\t\t\"eventLoopDelayTitle\": \"\",\n\t\t\t\"uptimeTitle\": \"\",\n\t\t\t\"usedHeapSizeTitle\": \"\",\n\t\t\t\"totalHeapSizeTitle\": \"\",\n\t\t\t\"osMemoryLimitTitle\": \"\"\n\t\t}\n\t},\n\t\"pageSpeedLighthouseAPI\": \"\",\n\t\"time\": {\n\t\t\"threeMinutes\": \"3分鐘\",\n\t\t\"fiveMinutes\": \"5分鐘\",\n\t\t\"tenMinutes\": \"10分鐘\",\n\t\t\"twentyMinutes\": \"20分鐘\",\n\t\t\"oneHour\": \"1小時\",\n\t\t\"oneDay\": \"1日\",\n\t\t\"oneWeek\": \"1星期\",\n\t\t\"fourMinutes\": \"\",\n\t\t\"oneMinute\": \"\",\n\t\t\"twoMinutes\": \"\",\n\t\t\"fifteenSeconds\": \"\",\n\t\t\"thirtySeconds\": \"\"\n\t},\n\t\"general\": {\n\t\t\"noOptionsFound\": \"\"\n\t},\n\t\"infrastructureMonitor\": {\n\t\t\"fallback\": {\n\t\t\t\"checks\": [\"追蹤伺服器的效能\", \"識別瓶頸並優化資源使用\", \"透過即時監控確保可靠性\"],\n\t\t\t\"title\": \"\",\n\t\t\t\"actionButton\": \"讓我們建立您的第一個基礎設施監視器！\"\n\t\t}\n\t},\n\t\"maintenanceWindow\": {\n\t\t\"fallback\": {\n\t\t\t\"checks\": [\"標記您的維護期間\", \"消除任何誤解\", \"在維護時段停止發送警報\"],\n\t\t\t\"title\": \"\",\n\t\t\t\"actionButton\": \"讓我們建立您的第一個維護時段！\"\n\t\t}\n\t},\n\t\"pageSpeed\": {\n\t\t\"fallback\": {\n\t\t\t\"checks\": [\"\"],\n\t\t\t\"title\": \"\",\n\t\t\t\"actionButton\": \"讓我們建立您的第一個 PageSpeed 監視器！\"\n\t\t}\n\t},\n\t\"uptimeMonitor\": {\n\t\t\"fallback\": {\n\t\t\t\"checks\": [\"\"],\n\t\t\t\"title\": \"\",\n\t\t\t\"actionButton\": \"讓我們建立您的第一個正常運行時間監視器！\"\n\t\t}\n\t},\n\t\"editUserPage\": {\n\t\t\"form\": {\n\t\t\t\"email\": \"電郵\",\n\t\t\t\"firstName\": \"名\",\n\t\t\t\"lastName\": \"姓\",\n\t\t\t\"role\": \"角色\",\n\t\t\t\"save\": \"儲存\"\n\t\t},\n\t\t\"table\": {\n\t\t\t\"actionHeader\": \"行動\",\n\t\t\t\"roleHeader\": \"角色\"\n\t\t},\n\t\t\"title\": \"編輯用戶\",\n\t\t\"toast\": {\n\t\t\t\"successUserUpdate\": \"\",\n\t\t\t\"validationErrors\": \"\"\n\t\t}\n\t},\n\t\"incidentsPageActionResolveMonitor\": \"解決監視器事故\",\n\t\"incidentsPageActionResolveAll\": \"解決所有事故\",\n\t\"matchMethodOptions\": {\n\t\t\"equal\": \"\",\n\t\t\"equalPlaceholder\": \"\",\n\t\t\"include\": \"\",\n\t\t\"includePlaceholder\": \"\",\n\t\t\"regex\": \"\",\n\t\t\"regexPlaceholder\": \"\",\n\t\t\"text\": \"\"\n\t},\n\t\"monitorType\": {\n\t\t\"docker\": {\n\t\t\t\"label\": \"\",\n\t\t\t\"namePlaceholder\": \"\",\n\t\t\t\"placeholder\": \"\"\n\t\t},\n\t\t\"http\": {\n\t\t\t\"label\": \"\",\n\t\t\t\"namePlaceholder\": \"\",\n\t\t\t\"placeholder\": \"\"\n\t\t},\n\t\t\"ping\": {\n\t\t\t\"label\": \"\",\n\t\t\t\"namePlaceholder\": \"\",\n\t\t\t\"placeholder\": \"\"\n\t\t},\n\t\t\"port\": {\n\t\t\t\"label\": \"\",\n\t\t\t\"namePlaceholder\": \"\",\n\t\t\t\"placeholder\": \"\"\n\t\t},\n\t\t\"game\": {\n\t\t\t\"label\": \"\",\n\t\t\t\"namePlaceholder\": \"\",\n\t\t\t\"placeholder\": \"\"\n\t\t}\n\t},\n\t\"uptimeAdvancedMatching\": {\n\t\t\"jsonPath\": \"\"\n\t},\n\t\"bytesPerSecond\": \"\",\n\t\"bytesReceived\": \"\",\n\t\"bytesSent\": \"\",\n\t\"chooseGame\": \"\",\n\t\"createMonitorPage\": {\n\t\t\"incidentConfigDescription\": \"\",\n\t\t\"incidentConfigStatusWindowLabel\": \"\",\n\t\t\"incidentConfigStatusWindowThresholdLabel\": \"\",\n\t\t\"incidentConfigTitle\": \"\",\n\t\t\"incidentConfigDescriptionV2\": \"\",\n\t\t\"incidentConfigStatusCheckNumber\": \"\",\n\t\t\"intervalTitle\": \"\",\n\t\t\"intervalDescription\": \"\"\n\t},\n\t\"dataRate\": \"\",\n\t\"dataReceived\": \"\",\n\t\"dataSent\": \"\",\n\t\"details\": \"\",\n\t\"drops\": \"\",\n\t\"errors\": \"\",\n\t\"errorsIn\": \"\",\n\t\"errorsOut\": \"\",\n\t\"gameServerMonitoring\": \"\",\n\t\"gameServerMonitoringDescription\": \"\",\n\t\"network\": \"\",\n\t\"networkDrops\": \"\",\n\t\"networkErrors\": \"\",\n\t\"networkInterface\": \"\",\n\t\"noNetworkStatsAvailable\": \"\",\n\t\"packetsPerSecond\": \"\",\n\t\"packetsReceived\": \"\",\n\t\"packetsReceivedRate\": \"\",\n\t\"packetsSent\": \"\",\n\t\"rate\": \"\",\n\t\"selectInterface\": \"\"\n}\n"
  },
  {
    "path": "client/src/main.tsx",
    "content": "import ReactDOM from \"react-dom/client\";\nimport App from \"./App.jsx\";\nimport \"./index.css\";\nimport { BrowserRouter as Router } from \"react-router-dom\";\nimport { Provider } from \"react-redux\";\nimport { persistor, store } from \"@/store.js\";\nimport { PersistGate } from \"redux-persist/integration/react\";\nimport I18nLoader from \"./Components/i18nLoader/index.js\";\nimport { initApiClient } from \"./Utils/ApiClient.js\";\n\ninitApiClient(store);\n\nReactDOM.createRoot(document.getElementById(\"root\")!).render(\n\t<Provider store={store}>\n\t\t<PersistGate\n\t\t\tloading={null}\n\t\t\tpersistor={persistor}\n\t\t>\n\t\t\t<I18nLoader />\n\t\t\t<Router>\n\t\t\t\t<App />\n\t\t\t</Router>\n\t\t</PersistGate>\n\t</Provider>\n);\n"
  },
  {
    "path": "client/src/store.ts",
    "content": "import { configureStore, combineReducers } from \"@reduxjs/toolkit\";\nimport authReducer from \"@/Features/Auth/authSlice\";\nimport uiReducer from \"@/Features/UI/uiSlice\";\nimport storage from \"redux-persist/lib/storage\";\nimport {\n\tpersistReducer,\n\tpersistStore,\n\tcreateTransform,\n\tPERSIST,\n\tREHYDRATE,\n} from \"redux-persist\";\n\nconst authTransform = createTransform(\n\t(inboundState: Record<string, unknown>) => {\n\t\tconst { profileImage, ...rest } = inboundState;\n\t\treturn rest;\n\t},\n\tundefined,\n\t{ whitelist: [\"auth\"] }\n);\n\nconst persistConfig = {\n\tkey: \"root\",\n\tstorage,\n\twhitelist: [\"auth\", \"ui\"],\n\ttransforms: [authTransform],\n};\n\nconst rootReducer = combineReducers({\n\tauth: authReducer,\n\tui: uiReducer,\n});\n\n// @ts-expect-error - redux-persist types don't align perfectly with redux-toolkit\nconst persistedReducer = persistReducer(persistConfig, rootReducer);\n\nexport const store = configureStore({\n\treducer: persistedReducer,\n\tmiddleware: (getDefaultMiddleware) =>\n\t\tgetDefaultMiddleware({\n\t\t\tserializableCheck: {\n\t\t\t\tignoredActions: [PERSIST, REHYDRATE, \"persist/REGISTER\"],\n\t\t\t},\n\t\t}),\n});\n\nexport type RootState = ReturnType<typeof rootReducer>;\nexport type AppDispatch = typeof store.dispatch;\n\nexport const persistor = persistStore(store);\nexport default store;\n"
  },
  {
    "path": "client/tsconfig.app.json",
    "content": "{\n\t\"compilerOptions\": {\n\t\t\"tsBuildInfoFile\": \"./node_modules/.tmp/tsconfig.app.tsbuildinfo\",\n\t\t\"target\": \"ES2022\",\n\t\t\"useDefineForClassFields\": true,\n\t\t\"lib\": [\"ES2022\", \"DOM\", \"DOM.Iterable\"],\n\t\t\"module\": \"ESNext\",\n\t\t\"skipLibCheck\": true,\n\n\t\t/* Bundler mode */\n\t\t\"moduleResolution\": \"bundler\",\n\t\t\"allowImportingTsExtensions\": true,\n\t\t\"verbatimModuleSyntax\": true,\n\t\t\"moduleDetection\": \"force\",\n\t\t\"noEmit\": true,\n\t\t\"jsx\": \"react-jsx\",\n\n\t\t/* Linting */\n\t\t\"strict\": true,\n\t\t\"noUnusedLocals\": true,\n\t\t\"noUnusedParameters\": true,\n\t\t\"erasableSyntaxOnly\": true,\n\t\t\"noFallthroughCasesInSwitch\": true,\n\t\t\"noUncheckedSideEffectImports\": true,\n\t\t\"paths\": {\n\t\t\t\"@/*\": [\"./src/*\"]\n\t\t},\n\t\t\"allowJs\": true,\n\t\t\"checkJs\": false\n\t},\n\t\"include\": [\"src\"]\n}\n"
  },
  {
    "path": "client/tsconfig.json",
    "content": "{\n\t\"files\": [],\n\t\"references\": [{ \"path\": \"./tsconfig.app.json\" }, { \"path\": \"./tsconfig.node.json\" }],\n\t\"compilerOptions\": {\n\t\t\"types\": [\"node\"],\n\t\t\"module\": \"ESNext\",\n\t\t\"moduleResolution\": \"Bundler\",\n\t\t\"skipLibCheck\": true,\n\t\t\"paths\": {\n\t\t\t\"@/*\": [\"./src/*\"]\n\t\t},\n\t\t\"allowJs\": true,\n\t\t\"checkJs\": false\n\t}\n}\n"
  },
  {
    "path": "client/tsconfig.node.json",
    "content": "{\n\t\"compilerOptions\": {\n\t\t\"tsBuildInfoFile\": \"./node_modules/.tmp/tsconfig.node.tsbuildinfo\",\n\t\t\"target\": \"ES2023\",\n\t\t\"lib\": [\"ES2023\"],\n\t\t\"module\": \"ESNext\",\n\t\t\"skipLibCheck\": true,\n\n\t\t/* Bundler mode */\n\t\t\"moduleResolution\": \"bundler\",\n\t\t\"allowImportingTsExtensions\": true,\n\t\t\"verbatimModuleSyntax\": true,\n\t\t\"moduleDetection\": \"force\",\n\t\t\"noEmit\": true,\n\n\t\t/* Linting */\n\t\t\"strict\": true,\n\t\t\"noUnusedLocals\": true,\n\t\t\"noUnusedParameters\": true,\n\t\t\"erasableSyntaxOnly\": true,\n\t\t\"noFallthroughCasesInSwitch\": true,\n\t\t\"noUncheckedSideEffectImports\": true,\n\t\t\"allowJs\": true,\n\t\t\"checkJs\": false\n\t},\n\t\"include\": [\"vite.config.ts\"]\n}\n"
  },
  {
    "path": "client/tsconfig.tsbuildinfo",
    "content": "{\"root\":[\"./vite.config.ts\",\"./dist/assets/index-BtHE-Ph5.js\",\"./src/App.jsx\",\"./src/main.jsx\",\"./src/store.js\",\"./src/Components/LanguageSelector.jsx\",\"./src/Components/ActionsMenu/index.jsx\",\"./src/Components/Alert/index.jsx\",\"./src/Components/Animated/PulseDot.jsx\",\"./src/Components/ArrowLeft/index.jsx\",\"./src/Components/ArrowRight/index.jsx\",\"./src/Components/Avatar/index.jsx\",\"./src/Components/Breadcrumbs/index.jsx\",\"./src/Components/Buttons/RoundGradientButton.jsx\",\"./src/Components/Charts/AreaChart/index.jsx\",\"./src/Components/Charts/BarChart/index.jsx\",\"./src/Components/Charts/ChartBox/EmptyView.jsx\",\"./src/Components/Charts/ChartBox/index.jsx\",\"./src/Components/Charts/CustomGauge/index.jsx\",\"./src/Components/Charts/DePINStatusPageBarChart/index.jsx\",\"./src/Components/Charts/LegendBox/index.jsx\",\"./src/Components/Charts/MonitorDetailsAreaChart/index.jsx\",\"./src/Components/Charts/StatusPageBarChart/index.jsx\",\"./src/Components/Charts/Utils/chartUtilFunctions.js\",\"./src/Components/Charts/Utils/chartUtils.jsx\",\"./src/Components/Charts/Utils/gradientUtils.jsx\",\"./src/Components/Check/Check.jsx\",\"./src/Components/CircularCount/index.jsx\",\"./src/Components/Common/AppBar.jsx\",\"./src/Components/Common/Footer.jsx\",\"./src/Components/ConfigBox/index.jsx\",\"./src/Components/ConfigRow/index.jsx\",\"./src/Components/Dialog/genericDialog.jsx\",\"./src/Components/Dialog/index.jsx\",\"./src/Components/Dot/index.jsx\",\"./src/Components/Fallback/FallBackActionButtons.jsx\",\"./src/Components/Fallback/FallbackBackground.jsx\",\"./src/Components/Fallback/FallbackCheckList.jsx\",\"./src/Components/Fallback/FallbackContainer.jsx\",\"./src/Components/Fallback/FallbackPageSpeedWarning.jsx\",\"./src/Components/Fallback/FallbackTitle.jsx\",\"./src/Components/Fallback/index.jsx\",\"./src/Components/FilterHeader/index.jsx\",\"./src/Components/GenericFallback/NetworkError.jsx\",\"./src/Components/GenericFallback/index.jsx\",\"./src/Components/HOC/withAdminCheck.jsx\",\"./src/Components/Heading/index.jsx\",\"./src/Components/Host/index.jsx\",\"./src/Components/HttpStatusLabel/index.jsx\",\"./src/Components/I18nLoader/index.jsx\",\"./src/Components/IconBox/index.jsx\",\"./src/Components/Image/index.jsx\",\"./src/Components/InfoBox/index.jsx\",\"./src/Components/Inputs/Checkbox/index.jsx\",\"./src/Components/Inputs/ColorPicker/index.jsx\",\"./src/Components/Inputs/FieldWrapper/index.jsx\",\"./src/Components/Inputs/ImageUpload/index.jsx\",\"./src/Components/Inputs/Radio/index.jsx\",\"./src/Components/Inputs/Search/index.jsx\",\"./src/Components/Inputs/Select/index.jsx\",\"./src/Components/Inputs/TextInput/index.jsx\",\"./src/Components/Inputs/TextInput/indexV2.tsx\",\"./src/Components/Inputs/TextInput/Adornments/index.jsx\",\"./src/Components/Label/index.jsx\",\"./src/Components/Layouts/AppLayout/index.jsx\",\"./src/Components/Layouts/HomeLayout/index.jsx\",\"./src/Components/Link/index.jsx\",\"./src/Components/MonitorActions/index.jsx\",\"./src/Components/MonitorCountHeader/index.jsx\",\"./src/Components/MonitorCountHeader/skeleton.jsx\",\"./src/Components/MonitorCreateHeader/index.jsx\",\"./src/Components/MonitorCreateHeader/skeleton.jsx\",\"./src/Components/MonitorDetailsControlHeader/index.jsx\",\"./src/Components/MonitorDetailsControlHeader/skeleton.jsx\",\"./src/Components/MonitorDetailsControlHeader/status.jsx\",\"./src/Components/MonitorTimeFrameHeader/index.jsx\",\"./src/Components/MonitorTimeFrameHeader/skeleton.jsx\",\"./src/Components/NotificationConfig/index.jsx\",\"./src/Components/NotificationIntegrationModal/Components/NotificationIntegrationModal.jsx\",\"./src/Components/NotificationIntegrationModal/Components/TabComponent.jsx\",\"./src/Components/NotificationIntegrationModal/Components/TabPanel.jsx\",\"./src/Components/NotificationIntegrationModal/Hooks/useNotification.js\",\"./src/Components/PageStateWrapper/index.jsx\",\"./src/Components/ProgressBars/index.jsx\",\"./src/Components/ProgressStepper/index.jsx\",\"./src/Components/ProtectedRoute/index.jsx\",\"./src/Components/RoleProtectedRoute/index.jsx\",\"./src/Components/ShareComponent/index.jsx\",\"./src/Components/Sidebar/index.jsx\",\"./src/Components/Sidebar/components/authFooter.jsx\",\"./src/Components/Sidebar/components/collapseButton.jsx\",\"./src/Components/Sidebar/components/logo.jsx\",\"./src/Components/Sidebar/components/navItem.jsx\",\"./src/Components/Skeletons/FullPage/index.jsx\",\"./src/Components/StandardContainer/index.jsx\",\"./src/Components/StarPrompt/index.jsx\",\"./src/Components/StatBox/index.jsx\",\"./src/Components/StatusBoxes/index.jsx\",\"./src/Components/StatusBoxes/skeleton.jsx\",\"./src/Components/Subheader/index.jsx\",\"./src/Components/Tab/index.jsx\",\"./src/Components/Table/TableUtils.js\",\"./src/Components/Table/index.jsx\",\"./src/Components/Table/skeleton.jsx\",\"./src/Components/Table/TablePagination/index.jsx\",\"./src/Components/Table/TablePagination/Actions/index.jsx\",\"./src/Components/TextLink/index.jsx\",\"./src/Components/ThemeSwitch/SunAndMoonIcon.jsx\",\"./src/Components/ThemeSwitch/index.jsx\",\"./src/Components/Toast/body.jsx\",\"./src/Components/Toast/index.jsx\",\"./src/Components/WalletProvider/index.jsx\",\"./src/Features/Auth/authSlice.js\",\"./src/Features/UI/uiSlice.js\",\"./src/Hooks/v1/checkHooks.js\",\"./src/Hooks/v1/inviteHooks.js\",\"./src/Hooks/v1/logHooks.js\",\"./src/Hooks/v1/monitorHooks.js\",\"./src/Hooks/v1/settingsHooks.js\",\"./src/Hooks/v1/useIsAdmin.js\",\"./src/Hooks/v1/useMonitorUtils.js\",\"./src/Hooks/v1/useNotifications.js\",\"./src/Hooks/v1/useSendTestEmail.js\",\"./src/Hooks/v1/userHooks.js\",\"./src/Hooks/v2/UseApi.tsx\",\"./src/Pages/v1/ServerUnreachable.jsx\",\"./src/Pages/v1/About/index.jsx\",\"./src/Pages/v1/Account/index.jsx\",\"./src/Pages/v1/Account/EditUser/index.jsx\",\"./src/Pages/v1/Account/EditUser/hooks/editUser.js\",\"./src/Pages/v1/Account/components/PasswordPanel.jsx\",\"./src/Pages/v1/Account/components/ProfilePanel.jsx\",\"./src/Pages/v1/Account/components/TeamPanel.jsx\",\"./src/Pages/v1/Account/components/AddMemberMenu/index.jsx\",\"./src/Pages/v1/Account/components/AddTeamMember/index.jsx\",\"./src/Pages/v1/Account/components/AddTeamMember/hooks/useAddTeamMember.jsx\",\"./src/Pages/v1/Account/components/RoleTable/index.jsx\",\"./src/Pages/v1/Auth/CheckEmail.jsx\",\"./src/Pages/v1/Auth/ForgotPassword.jsx\",\"./src/Pages/v1/Auth/NewPasswordConfirmed.jsx\",\"./src/Pages/v1/Auth/SetNewPassword.jsx\",\"./src/Pages/v1/Auth/Login/index.jsx\",\"./src/Pages/v1/Auth/Login/hooks/useLoadingSubmit.jsx\",\"./src/Pages/v1/Auth/Login/hooks/useLoginForm.jsx\",\"./src/Pages/v1/Auth/Login/hooks/useLoginSubmit.jsx\",\"./src/Pages/v1/Auth/Login/hooks/useValidateLoginForm.jsx\",\"./src/Pages/v1/Auth/Register/index.jsx\",\"./src/Pages/v1/Auth/components/AuthHeader.jsx\",\"./src/Pages/v1/Auth/components/AuthPageWrapper.jsx\",\"./src/Pages/v1/Auth/components/PasswordTooltip.jsx\",\"./src/Pages/v1/Auth/hooks/usePasswordFeedback.jsx\",\"./src/Pages/v1/Auth/hooks/useValidatePassword.jsx\",\"./src/Pages/v1/Incidents/index.jsx\",\"./src/Pages/v1/Incidents/Components/IncidentTable/index.jsx\",\"./src/Pages/v1/Incidents/Components/OptionsHeader/index.jsx\",\"./src/Pages/v1/Incidents/Components/OptionsHeader/skeleton.jsx\",\"./src/Pages/v1/Incidents/Components/StatusBoxes/StatusBox.jsx\",\"./src/Pages/v1/Incidents/Components/StatusBoxes/index.jsx\",\"./src/Pages/v1/Incidents/Components/StatusBoxes/skeleton.jsx\",\"./src/Pages/v1/Infrastructure/Create/index.jsx\",\"./src/Pages/v1/Infrastructure/Create/Components/CustomAlertsSection.jsx\",\"./src/Pages/v1/Infrastructure/Create/Components/MonitorActionButtons.jsx\",\"./src/Pages/v1/Infrastructure/Create/Components/MonitorStatusHeader.jsx\",\"./src/Pages/v1/Infrastructure/Create/Components/CustomThreshold/index.jsx\",\"./src/Pages/v1/Infrastructure/Create/hooks/useInfrastructureMonitorForm.jsx\",\"./src/Pages/v1/Infrastructure/Create/hooks/useInfrastructureSubmit.jsx\",\"./src/Pages/v1/Infrastructure/Create/hooks/useValidateInfrastructureForm.jsx\",\"./src/Pages/v1/Infrastructure/Details/index.jsx\",\"./src/Pages/v1/Infrastructure/Details/Components/AreaChartBoxes/InfraAreaChart.jsx\",\"./src/Pages/v1/Infrastructure/Details/Components/AreaChartBoxes/index.jsx\",\"./src/Pages/v1/Infrastructure/Details/Components/AreaChartBoxes/skeleton.jsx\",\"./src/Pages/v1/Infrastructure/Details/Components/BaseContainer/index.jsx\",\"./src/Pages/v1/Infrastructure/Details/Components/GaugeBoxes/Gauge.jsx\",\"./src/Pages/v1/Infrastructure/Details/Components/GaugeBoxes/index.jsx\",\"./src/Pages/v1/Infrastructure/Details/Components/GaugeBoxes/skeleton.jsx\",\"./src/Pages/v1/Infrastructure/Details/Components/NetworkStats/NetworkCharts.jsx\",\"./src/Pages/v1/Infrastructure/Details/Components/NetworkStats/NetworkStatBoxes.jsx\",\"./src/Pages/v1/Infrastructure/Details/Components/NetworkStats/index.jsx\",\"./src/Pages/v1/Infrastructure/Details/Components/NetworkStats/skeleton.jsx\",\"./src/Pages/v1/Infrastructure/Details/Components/StatusBoxes/index.jsx\",\"./src/Pages/v1/Infrastructure/Details/Hooks/useHardwareUtils.jsx\",\"./src/Pages/v1/Infrastructure/Monitors/index.jsx\",\"./src/Pages/v1/Infrastructure/Monitors/Components/Filters/index.jsx\",\"./src/Pages/v1/Infrastructure/Monitors/Components/MonitorsTable/index.jsx\",\"./src/Pages/v1/Infrastructure/Monitors/Components/MonitorsTableMenu/index.jsx\",\"./src/Pages/v1/Integrations/index.jsx\",\"./src/Pages/v1/Logs/index.jsx\",\"./src/Pages/v1/Logs/Diagnostics/index.jsx\",\"./src/Pages/v1/Logs/Diagnostics/components/gauges/index.jsx\",\"./src/Pages/v1/Logs/Diagnostics/components/stats/index.jsx\",\"./src/Pages/v1/Logs/Diagnostics/utils/utils.js\",\"./src/Pages/v1/Logs/Logs/index.jsx\",\"./src/Pages/v1/Logs/Queue/index.jsx\",\"./src/Pages/v1/Logs/Queue/components/FailedJobTable/index.jsx\",\"./src/Pages/v1/Logs/Queue/components/JobTable/index.jsx\",\"./src/Pages/v1/Logs/Queue/components/Metrics/index.jsx\",\"./src/Pages/v1/Logs/Queue/components/MetricsTable/index.jsx\",\"./src/Pages/v1/Maintenance/index.jsx\",\"./src/Pages/v1/Maintenance/CreateMaintenance/index.jsx\",\"./src/Pages/v1/Maintenance/CreateMaintenance/Components/ConfigSelect/index.jsx\",\"./src/Pages/v1/Maintenance/CreateMaintenance/Components/MonitorList/index.jsx\",\"./src/Pages/v1/Maintenance/CreateMaintenance/Components/MonitorsConfig/index.jsx\",\"./src/Pages/v1/Maintenance/CreateMaintenance/hooks/useMaintenanceActions.jsx\",\"./src/Pages/v1/Maintenance/CreateMaintenance/hooks/useMaintenanceData.jsx\",\"./src/Pages/v1/Maintenance/MaintenanceTable/index.jsx\",\"./src/Pages/v1/Maintenance/MaintenanceTable/ActionsMenu/index.jsx\",\"./src/Pages/v1/NotFound/index.jsx\",\"./src/Pages/v1/Notifications/index.jsx\",\"./src/Pages/v1/Notifications/utils.js\",\"./src/Pages/v1/Notifications/components/ActionMenu.jsx\",\"./src/Pages/v1/Notifications/create/index.jsx\",\"./src/Pages/v1/PageSpeed/Create/index.jsx\",\"./src/Pages/v1/PageSpeed/Create/skeleton.jsx\",\"./src/Pages/v1/PageSpeed/Details/index.jsx\",\"./src/Pages/v1/PageSpeed/Details/Components/Charts/AreaChart.jsx\",\"./src/Pages/v1/PageSpeed/Details/Components/Charts/AreaChartLegend.jsx\",\"./src/Pages/v1/PageSpeed/Details/Components/Charts/PieChart.jsx\",\"./src/Pages/v1/PageSpeed/Details/Components/Charts/PieChartLegend.jsx\",\"./src/Pages/v1/PageSpeed/Details/Components/PageSpeedAreaChart/index.jsx\",\"./src/Pages/v1/PageSpeed/Details/Components/PageSpeedAreaChart/skeleton.jsx\",\"./src/Pages/v1/PageSpeed/Details/Components/PageSpeedStatusBoxes/index.jsx\",\"./src/Pages/v1/PageSpeed/Details/Components/PerformanceReport/index.jsx\",\"./src/Pages/v1/PageSpeed/Details/Components/PerformanceReport/skeleton.jsx\",\"./src/Pages/v1/PageSpeed/Monitors/index.jsx\",\"./src/Pages/v1/PageSpeed/Monitors/Components/Card/index.jsx\",\"./src/Pages/v1/PageSpeed/Monitors/Components/MonitorGrid/index.jsx\",\"./src/Pages/v1/Settings/SettingsAbout.jsx\",\"./src/Pages/v1/Settings/SettingsDemoMonitors.jsx\",\"./src/Pages/v1/Settings/SettingsEmail.jsx\",\"./src/Pages/v1/Settings/SettingsGlobalThresholds.jsx\",\"./src/Pages/v1/Settings/SettingsPagespeed.jsx\",\"./src/Pages/v1/Settings/SettingsStats.jsx\",\"./src/Pages/v1/Settings/SettingsTimeZone.jsx\",\"./src/Pages/v1/Settings/SettingsUI.jsx\",\"./src/Pages/v1/Settings/SettingsURL.jsx\",\"./src/Pages/v1/Settings/index.jsx\",\"./src/Pages/v1/StatusPage/Create/index.jsx\",\"./src/Pages/v1/StatusPage/Create/Components/MonitorList/index.jsx\",\"./src/Pages/v1/StatusPage/Create/Components/Progress/index.jsx\",\"./src/Pages/v1/StatusPage/Create/Components/Skeleton/index.jsx\",\"./src/Pages/v1/StatusPage/Create/Components/Tabs/ConfigStack.jsx\",\"./src/Pages/v1/StatusPage/Create/Components/Tabs/Content.jsx\",\"./src/Pages/v1/StatusPage/Create/Components/Tabs/Settings.jsx\",\"./src/Pages/v1/StatusPage/Create/Components/Tabs/index.jsx\",\"./src/Pages/v1/StatusPage/Create/Hooks/useCreateStatusPage.jsx\",\"./src/Pages/v1/StatusPage/Create/Hooks/useMonitorsFetch.jsx\",\"./src/Pages/v1/StatusPage/Status/index.jsx\",\"./src/Pages/v1/StatusPage/Status/Components/AdminLink/index.jsx\",\"./src/Pages/v1/StatusPage/Status/Components/ControlsHeader/index.jsx\",\"./src/Pages/v1/StatusPage/Status/Components/MonitorsList/index.jsx\",\"./src/Pages/v1/StatusPage/Status/Components/Skeleton/index.jsx\",\"./src/Pages/v1/StatusPage/Status/Components/StatusBar/index.jsx\",\"./src/Pages/v1/StatusPage/Status/Hooks/useStatusPageDelete.jsx\",\"./src/Pages/v1/StatusPage/Status/Hooks/useStatusPageFetch.jsx\",\"./src/Pages/v1/StatusPage/StatusPages/index.jsx\",\"./src/Pages/v1/StatusPage/StatusPages/Components/StatusPagesTable/index.jsx\",\"./src/Pages/v1/StatusPage/StatusPages/Hooks/useStatusPagesFetch.jsx\",\"./src/Pages/v1/Uptime/BulkImport/Upload.jsx\",\"./src/Pages/v1/Uptime/BulkImport/index.jsx\",\"./src/Pages/v1/Uptime/Create/index.jsx\",\"./src/Pages/v1/Uptime/Create/skeleton.jsx\",\"./src/Pages/v1/Uptime/Details/index.jsx\",\"./src/Pages/v1/Uptime/Details/Components/ChartBoxes/index.jsx\",\"./src/Pages/v1/Uptime/Details/Components/ChartBoxes/skeleton.jsx\",\"./src/Pages/v1/Uptime/Details/Components/Charts/CustomLabels.jsx\",\"./src/Pages/v1/Uptime/Details/Components/Charts/DownBarChart.jsx\",\"./src/Pages/v1/Uptime/Details/Components/Charts/ResponseGaugeChart.jsx\",\"./src/Pages/v1/Uptime/Details/Components/Charts/ResponseTimeChart.jsx\",\"./src/Pages/v1/Uptime/Details/Components/Charts/ResponseTimeChartSkeleton.jsx\",\"./src/Pages/v1/Uptime/Details/Components/Charts/UpBarChart.jsx\",\"./src/Pages/v1/Uptime/Details/Components/ResponseTable/index.jsx\",\"./src/Pages/v1/Uptime/Details/Components/ResponseTable/skeleton.jsx\",\"./src/Pages/v1/Uptime/Details/Components/UptimeStatusBoxes/index.jsx\",\"./src/Pages/v1/Uptime/Details/Hooks/useCertificateFetch.jsx\",\"./src/Pages/v1/Uptime/Monitors/index.jsx\",\"./src/Pages/v1/Uptime/Monitors/Components/Filter/index.jsx\",\"./src/Pages/v1/Uptime/Monitors/Components/LoadingSpinner/index.jsx\",\"./src/Pages/v1/Uptime/Monitors/Components/SearchComponent/index.jsx\",\"./src/Pages/v1/Uptime/Monitors/Components/Skeleton/index.jsx\",\"./src/Pages/v1/Uptime/Monitors/Components/StatusBoxes/index.jsx\",\"./src/Pages/v1/Uptime/Monitors/Components/StatusBoxes/skeleton.jsx\",\"./src/Pages/v1/Uptime/Monitors/Components/StatusBoxes/statusBox.jsx\",\"./src/Pages/v1/Uptime/Monitors/Components/UptimeDataTable/index.jsx\",\"./src/Pages/v1/Uptime/Monitors/Hooks/useDebounce.jsx\",\"./src/Pages/v2/Auth/Login.tsx\",\"./src/Routes/index.jsx\",\"./src/Utils/ApiClient.ts\",\"./src/Utils/Logger.js\",\"./src/Utils/NetworkService.js\",\"./src/Utils/NetworkServiceProvider.jsx\",\"./src/Utils/debounce.jsx\",\"./src/Utils/fileUtils.js\",\"./src/Utils/greeting.jsx\",\"./src/Utils/i18n.js\",\"./src/Utils/monitorUtils.js\",\"./src/Utils/roleUtils.js\",\"./src/Utils/stringUtils.js\",\"./src/Utils/timeUtils.js\",\"./src/Utils/toastUtils.jsx\",\"./src/Utils/utils.js\",\"./src/Utils/Theme/constants.js\",\"./src/Utils/Theme/darkTheme.js\",\"./src/Utils/Theme/extractColorObject.js\",\"./src/Utils/Theme/globalTheme.js\",\"./src/Utils/Theme/lightTheme.js\",\"./src/Utils/Theme/v2/palette.ts\",\"./src/Utils/Theme/v2/theme.ts\",\"./src/Validation/error.js\",\"./src/Validation/validation.js\",\"./src/types/env.d.ts\",\"./src/types/mui.d.ts\"],\"errors\":true,\"version\":\"5.9.2\"}"
  },
  {
    "path": "client/vite.config.ts",
    "content": "import { defineConfig } from \"vite\";\nimport react from \"@vitejs/plugin-react\";\nimport svgr from \"vite-plugin-svgr\";\nimport path from \"path\";\nimport { fileURLToPath } from \"url\";\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\nexport default defineConfig(({}) => {\n\tlet version = \"3.5.1\";\n\n\treturn {\n\t\tbase: \"/\",\n\t\tplugins: [svgr(), react()],\n\t\tserver: {\n\t\t\thost: true,\n\t\t},\n\t\tresolve: {\n\t\t\talias: {\n\t\t\t\t\"@\": path.resolve(__dirname, \"src\"),\n\t\t\t},\n\t\t},\n\t\toptimizeDeps: {\n\t\t\tinclude: [\"@mui/material/Tooltip\", \"@emotion/styled\"],\n\t\t},\n\t\tdefine: {\n\t\t\t__APP_VERSION__: JSON.stringify(version),\n\t\t},\n\t};\n});\n"
  },
  {
    "path": "docker/.gitignore",
    "content": "*.sh\n!quickstart.sh\n!build_images.sh\ndev/mongo/data/*\ndev/redis/data/*\ndist/mongo/data/*\ndist/redis/data/*\nprod/mongo/data/*\nprod/redis/data/*\ndist/docker-compose-test.yaml\n/dist-mono/mongo/data/*\n/dist-mono/redis/data/*\n/dist-arm/mongo/data/*\n*.env\n\n# Custom CA certificates and keys (should not be committed)\ndev/certs/*\n!dev/certs/.gitkeep\n\n# Certificate artifacts\n*.key\n*.csr\n*.srl\n*.log\n"
  },
  {
    "path": "docker/coolify/build_images.sh",
    "content": "#!/bin/bash\n# Change directory to root Server directory for correct Docker Context\ncd \"$(dirname \"$0\")\"\ncd ../../../\n\n# Define an array of services and their Dockerfiles\ndeclare -A services=(\n  [\"bluewaveuptime/uptime_client\"]=\"./server/docker/dist/client.Dockerfile\"\n  [\"bluewaveuptime/uptime_database_mongo\"]=\"./server/docker/dist/mongoDB.Dockerfile\"\n  [\"bluewaveuptime/uptime_redis\"]=\"./server/docker/dist/redis.Dockerfile\"\n  [\"bluewaveuptime/uptime_server\"]=\"./server/docker/dist/server.Dockerfile\"\n)\n\n# Loop through each service and build the corresponding image\nfor service in \"${!services[@]}\"; do\n  docker build -f \"${services[$service]}\" -t \"$service\" .\n  \n  # Check if the build succeeded\n  if [ $? -ne 0 ]; then\n    echo \"Error building $service image. Exiting...\"\n    exit 1\n  fi\ndone\n\necho \"All images built successfully\"\n"
  },
  {
    "path": "docker/coolify/client.Dockerfile",
    "content": "FROM node:20-slim AS build\n\nENV NODE_OPTIONS=\"--max-old-space-size=4096\"\n\nWORKDIR /app\n\nCOPY ./client/package*.json ./\n\nRUN npm install\n\nCOPY ./client .\n\nRUN npm run build\n\nFROM nginx:1.27.1-alpine\n\nCOPY ./server/docker/dist/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf\nCOPY --from=build /app/dist /usr/share/nginx/html\nCOPY --from=build /app/env.sh /docker-entrypoint.d/env.sh\nRUN chmod +x /docker-entrypoint.d/env.sh\n\nCMD [\"nginx\", \"-g\", \"daemon off;\"]\n"
  },
  {
    "path": "docker/coolify/mongoDB.Dockerfile",
    "content": "FROM mongo\nEXPOSE 27017\nCMD [\"mongod\"]\n"
  },
  {
    "path": "docker/coolify/nginx/conf.d/default.conf",
    "content": "server {\n    listen       80;\n    listen  [::]:80;\n\n    server_name checkmate-demo.bluewavelabs.ca;\n    server_tokens off;\n\n    location /.well-known/acme-challenge/ {\n        root /var/www/certbot;\n    }\n\n    location / {\n        root   /usr/share/nginx/html;\n        index  index.html index.htm;\n        try_files $uri $uri/ /index.html;\n    }\n    \n    location /api/ {\n        proxy_pass http://server:5000/api/;\n        proxy_http_version 1.1;\n        proxy_set_header Host $host;\n        proxy_set_header X-Real-IP $remote_addr;\n        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n        proxy_set_header X-Forwarded-Proto $scheme;\n    }\n\n    location /api-docs/ {\n        proxy_pass http://server:5000/api-docs/;\n        proxy_http_version 1.1;\n        proxy_set_header Host $host;\n        proxy_set_header X-Real-IP $remote_addr;\n        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n        proxy_set_header X-Forwarded-Proto $scheme;\n    }\n}"
  },
  {
    "path": "docker/coolify/redis.Dockerfile",
    "content": "FROM redis\nEXPOSE 6379"
  },
  {
    "path": "docker/coolify/server.Dockerfile",
    "content": "FROM node:20-slim\n\n# Install ping\nRUN apt-get update \\\n    && apt-get install -y iputils-ping \\\n    && rm -rf /var/lib/apt/lists/*\n\nWORKDIR /app\n\nCOPY ../../package*.json ./\n\nRUN npm install\n\nCOPY ../../ ./\n\nRUN npm run build\n\nEXPOSE 5000\n\nCMD [\"node\", \"dist/index.js\"]\n"
  },
  {
    "path": "docker/dev/build_images.sh",
    "content": "#!/bin/bash\n\n# Change directory to root Server directory for correct Docker Context\ncd \"$(dirname \"$0\")\"\ncd ../..\n\n# Define service names and their corresponding Dockerfiles in parallel arrays\nservices=(\"uptime_client\" \"uptime_mongo\" \"uptime_server\")\ndockerfiles=(\n  \"./docker/dev/client.Dockerfile\"\n  \"./docker/dev/mongoDB.Dockerfile\"\n  \"./docker/dev/server.Dockerfile\"\n)\n\n# Loop through each service and build the corresponding image\nfor i in \"${!services[@]}\"; do\n  service=\"${services[$i]}\"\n  dockerfile=\"${dockerfiles[$i]}\"\n  \n  docker build -f \"$dockerfile\" -t \"$service\" .\n  \n  # Check if the build succeeded\n  if [ $? -ne 0 ]; then\n    echo \"Error building $service image. Exiting...\"\n    exit 1\n  fi\ndone\n\necho \"All images built successfully\""
  },
  {
    "path": "docker/dev/certs/.gitkeep",
    "content": ""
  },
  {
    "path": "docker/dev/client.Dockerfile",
    "content": "FROM node:20-slim AS build\n\nENV NODE_OPTIONS=\"--max-old-space-size=4096\"\n\nWORKDIR /app\n\nCOPY ./client/package*.json ./\n\nRUN npm install\n\nCOPY ./client ./\n\nRUN npm run build\n\nFROM nginx:1.27.1-alpine\n\nCOPY --from=build /app/dist /usr/share/nginx/html\nCOPY --from=build /app/env.sh /docker-entrypoint.d/env.sh\nRUN chmod +x /docker-entrypoint.d/env.sh\nCMD [\"nginx\", \"-g\", \"daemon off;\"]"
  },
  {
    "path": "docker/dev/docker-compose.custom-ca-example.yaml",
    "content": "# Dev/Test only: Not required in production\n# Example Docker Compose configuration for custom CA trust\n# This file demonstrates how to configure Checkmate to trust custom CAs\n# \n# Usage: docker-compose -f docker-compose.yaml -f docker-compose.custom-ca-example.yaml up\n\nservices:\n  server:\n    image: uptime_server:latest\n    restart: always\n    ports:\n      - \"52345:52345\"\n    env_file:\n      - server.env\n    environment:\n      # Mount your custom CA certificate\n      NODE_EXTRA_CA_CERTS: /certs/custom-ca.pem\n    volumes:\n      # Mount the certs directory (read-only for security)\n      - ./certs:/certs:ro\n    depends_on:\n      - redis\n      - mongodb\n    # Optional: Add healthcheck to ensure the server starts properly\n    healthcheck:\n      test: [\"CMD\", \"wget\", \"--no-verbose\", \"--tries=1\", \"--spider\", \"http://localhost:52345/api/v1/health\"]\n      interval: 30s\n      timeout: 10s\n      retries: 3\n      start_period: 40s\n"
  },
  {
    "path": "docker/dev/docker-compose.yaml",
    "content": "services:\n  client:\n    image: uptime_client:latest\n    restart: always\n    ports:\n      - \"80:80\"\n    environment:\n      UPTIME_APP_API_BASE_URL: \"http://localhost:52345/api/v1\"\n      UPTIME_APP_CLIENT_HOST: \"http://localhost\"\n    volumes:\n      - ./nginx/conf.d:/etc/nginx/conf.d/\n    depends_on:\n      - server\n  server:\n    image: uptime_server:latest\n    restart: always\n    ports:\n      - \"52345:52345\"\n    env_file:\n      - server.env\n    depends_on:\n      - mongodb\n  mongodb:\n    image: uptime_mongo:latest\n    restart: always\n    command: [\"mongod\", \"--quiet\", \"--bind_ip_all\"]\n    volumes:\n      - ./mongo/data:/data/db\n    healthcheck:\n      test: [\"CMD\", \"mongosh\", \"--eval\", \"db.adminCommand('ping')\", \"--quiet\"]\n      interval: 5s\n      timeout: 30s\n      start_period: 0s\n      start_interval: 1s\n      retries: 30\n"
  },
  {
    "path": "docker/dev/mongoDB.Dockerfile",
    "content": "FROM mongo\nEXPOSE 27017\nCMD [\"mongod\"]\n"
  },
  {
    "path": "docker/dev/nginx/conf.d/default.conf",
    "content": "server {\n    listen 80 default_server;\n    listen [::]:80 default_server;\n\n    server_name localhost;      # Set server name to localhost\n    server_tokens off;\n\n    location / {\n        root   /usr/share/nginx/html;\n        index  index.html index.htm;\n        try_files $uri $uri/ /index.html;\n    }\n    \n    # location /api/ {\n    #     proxy_pass http://server:52345/api/;\n    #     proxy_http_version 1.1;\n    #     proxy_set_header Host $host;\n    #     proxy_set_header X-Real-IP $remote_addr;\n    #     proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n    #     proxy_set_header X-Forwarded-Proto $scheme;\n    #     proxy_set_header Connection '';\n    #     chunked_transfer_encoding off;\n    #     proxy_buffering off;\n    #     proxy_cache off;\n    # }\n\n    # location /api-docs/ {\n    #     proxy_pass http://server:52345/api-docs/;\n    #     proxy_http_version 1.1;\n    #     proxy_set_header Host $host;\n    #     proxy_set_header X-Real-IP $remote_addr;\n    #     proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n    #     proxy_set_header X-Forwarded-Proto $scheme;\n    # }\n}"
  },
  {
    "path": "docker/dev/nginx-test/docker-compose.nginx-test.yaml",
    "content": "# Dev/Test only: Not required in production\n# Docker Compose configuration for nginx test service\n\nservices:\n  nginx-test:\n    image: nginx:alpine\n    ports:\n      - \"8443:443\"\n    volumes:\n      - ../certs/host-int-cert.pem:/etc/nginx/certs/server.crt:ro\n      - ../certs/host-int-key.pem:/etc/nginx/certs/server.key:ro\n      - ./nginx.conf:/etc/nginx/nginx.conf:ro\n    restart: unless-stopped\n"
  },
  {
    "path": "docker/dev/nginx-test/nginx.conf",
    "content": "# Dev/Test only: Not required in production\n# Nginx configuration for testing custom CA trust functionality\n\nevents {}\nhttp {\n    server {\n        listen              443 ssl;\n        ssl_certificate     /etc/nginx/certs/server.crt;\n        ssl_certificate_key /etc/nginx/certs/server.key;\n        location / { \n            return 200 \"hello from tls\\n\"; \n        }\n    }\n}\n"
  },
  {
    "path": "docker/dev/server.Dockerfile",
    "content": "FROM node:20-slim\n\n# Install ping\nRUN apt-get update \\\n    && apt-get install -y iputils-ping \\\n    && rm -rf /var/lib/apt/lists/*\n\nWORKDIR /app\n\nCOPY ./server/package*.json ./\n\nRUN npm install\n\nCOPY ./server/ ./\n\nRUN npm run build\n\nEXPOSE 52345\n\nCMD [\"node\", \"dist/index.js\"]"
  },
  {
    "path": "docker/dist/build_images.sh",
    "content": "#!/bin/bash\n# Change directory to root Server directory for correct Docker Context\ncd \"$(dirname \"$0\")\"\ncd ../../\n\n# Define an array of services and their Dockerfiles\ndeclare -A services=(\n  [\"bluewaveuptime/uptime_client\"]=\"./docker/dist/client.Dockerfile\"\n  [\"bluewaveuptime/uptime_database_mongo\"]=\"./docker/dist/mongoDB.Dockerfile\"\n  [\"bluewaveuptime/uptime_server\"]=\"./docker/dist/server.Dockerfile\"\n)\n\nfor service in \"${!services[@]}\"; do\n  docker build \\\n    -f \"${services[$service]}\" \\\n    -t \"$service\" \\\n    .\n\n  if [ $? -ne 0 ]; then\n    echo \"Error building $service image. Exiting...\"\n    exit 1\n  fi\ndone\n\necho \"All images built successfully\"\n"
  },
  {
    "path": "docker/dist/client.Dockerfile",
    "content": "FROM node:20-slim AS build\n\nENV NODE_OPTIONS=\"--max-old-space-size=4096\"\n\nWORKDIR /app\n\nCOPY ./client/package*.json ./\n\nRUN npm install\n\nCOPY ./client .\n\nRUN npm run build\n\nFROM nginx:1.27.1-alpine\n\nCOPY ./docker/dist/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf\nCOPY --from=build /app/dist /usr/share/nginx/html\nCOPY --from=build /app/env.sh /docker-entrypoint.d/env.sh\nRUN chmod +x /docker-entrypoint.d/env.sh\n\nCMD [\"nginx\", \"-g\", \"daemon off;\"]\n"
  },
  {
    "path": "docker/dist/docker-compose.yaml",
    "content": "services:\n  client:\n    image: ghcr.io/bluewave-labs/checkmate-client:latest\n    restart: always\n    environment:\n      UPTIME_APP_API_BASE_URL: \"http://localhost:52345/api/v1\"\n      UPTIME_APP_CLIENT_HOST: \"http://localhost\"\n    ports:\n      - \"80:80\"\n      - \"443:443\"\n    depends_on:\n      - server\n  server:\n    image: ghcr.io/bluewave-labs/checkmate-backend:latest\n    restart: always\n    ports:\n      - \"52345:52345\"\n    depends_on:\n      - mongodb\n    environment:\n      - DB_CONNECTION_STRING=mongodb://mongodb:27017/uptime_db\n      - CLIENT_HOST=http://localhost\n      - JWT_SECRET=my_secret\n    # volumes:\n    # - /var/run/docker.sock:/var/run/docker.sock:ro\n  mongodb:\n    image: ghcr.io/bluewave-labs/checkmate-mongo:latest\n    restart: always\n    volumes:\n      - ./mongo/data:/data/db\n    command: [\"mongod\", \"--quiet\", \"--bind_ip_all\"]\n    healthcheck:\n      test: [\"CMD\", \"mongosh\", \"--eval\", \"db.adminCommand('ping')\", \"--quiet\"]\n      interval: 5s\n      timeout: 30s\n      start_period: 0s\n      start_interval: 1s\n      retries: 30\n"
  },
  {
    "path": "docker/dist/mongoDB.Dockerfile",
    "content": "FROM mongo\nEXPOSE 27017\nCMD [\"mongod\"]\n"
  },
  {
    "path": "docker/dist/nginx/conf.d/default.conf",
    "content": "server {\n    listen       80;\n    listen  [::]:80;\n\n    server_name checkmate-demo.bluewavelabs.ca;\n    server_tokens off;\n\n    location /.well-known/acme-challenge/ {\n        root /var/www/certbot;\n    }\n\n    location / {\n        root   /usr/share/nginx/html;\n        index  index.html index.htm;\n        try_files $uri $uri/ /index.html;\n    }\n    \n    # location /api/ {\n    #     proxy_pass http://server:5000/api/;\n    #     proxy_http_version 1.1;\n    #     proxy_set_header Host $host;\n    #     proxy_set_header X-Real-IP $remote_addr;\n    #     proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n    #     proxy_set_header X-Forwarded-Proto $scheme;\n    # }\n\n    location /api-docs/ {\n        proxy_pass http://server:5000/api-docs/;\n        proxy_http_version 1.1;\n        proxy_set_header Host $host;\n        proxy_set_header X-Real-IP $remote_addr;\n        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n        proxy_set_header X-Forwarded-Proto $scheme;\n    }\n}"
  },
  {
    "path": "docker/dist/server.Dockerfile",
    "content": "FROM node:20-slim\n\n# Install ping\nRUN apt-get update \\\n    && apt-get install -y iputils-ping \\\n    && rm -rf /var/lib/apt/lists/*\n\nWORKDIR /app\n\nCOPY ./server/package*.json ./\n\nRUN npm install\n\nCOPY ./server/ ./\n\nRUN npm run build\n\nEXPOSE 52345\n\nCMD [\"node\", \"dist/index.js\"]"
  },
  {
    "path": "docker/dist-arm/build_images.sh",
    "content": "#!/bin/bash\n\nset -e  # Exit on error\n\n# Change directory to root Server directory for correct Docker Context\ncd \"$(dirname \"$0\")\"\ncd ../..\n\n# Ensure buildx builder exists and is used\nif ! docker buildx inspect mybuilder &>/dev/null; then\n  docker buildx create --name mybuilder --use\nelse\n  docker buildx use mybuilder\nfi\n\n# Define service names and Dockerfiles\nservices=(\"mono_server_arm\")\ndockerfiles=(\n  \"./docker/dist-arm/server.Dockerfile\"\n)\n\n# Static image name for GitHub Container Registry (GHCR)\nimage=\"ghcr.io/bluewave-labs/checkmate:backend-dist-multi-arch\"\nplatforms=\"linux/amd64,linux/arm64\"\nrepo_url=\"https://github.com/bluewave-labs/checkmate\"\n\n# Loop through each service and build\nfor i in \"${!services[@]}\"; do\n  service=\"${services[$i]}\"\n  dockerfile=\"${dockerfiles[$i]}\"\n\n  echo \"🚀 Building multi-arch image for $service...\"\n  docker buildx build \\\n    --platform \"$platforms\" \\\n    -f \"$dockerfile\" \\\n    -t \"$image\" \\\n    --label \"org.opencontainers.image.source=$repo_url\" \\\n    --push \\\n    .\n\n  echo \"✅ $image pushed for platforms: $platforms\"\ndone\n\necho \"🎉 All multi-arch images built and pushed successfully\"\n"
  },
  {
    "path": "docker/dist-arm/docker-compose.yaml",
    "content": "services:\n  server:\n    image: ghcr.io/bluewave-labs/checkmate-backend-mono-multiarch:latest\n    restart: always\n    pull_policy: always\n    ports:\n      - \"52345:52345\"\n    environment:\n      - UPTIME_APP_API_BASE_URL=http://localhost:52345/api/v1\n      - UPTIME_APP_CLIENT_HOST=http://localhost\n      - DB_CONNECTION_STRING=mongodb://mongodb:27017/uptime_db\n      - REDIS_URL=redis://redis:6379\n      - CLIENT_HOST=http://localhost\n      - JWT_SECRET=my_secret\n    depends_on:\n      - mongodb\n  mongodb:\n    image: mongo:6.0\n    restart: always\n    command: [\"mongod\", \"--quiet\", \"--bind_ip_all\"]\n    ports:\n      - \"27017:27017\"\n    volumes:\n      - ./mongo/data:/data/db\n    healthcheck:\n      test: [\"CMD\", \"mongosh\", \"--eval\", \"db.runCommand({ ping: 1 })\", \"--quiet\"]\n      interval: 5s\n      timeout: 30s\n      start_period: 0s\n      start_interval: 1s\n      retries: 30\n"
  },
  {
    "path": "docker/dist-arm/server.Dockerfile",
    "content": "# ---------------------\n# Frontend build stage\n# ---------------------\nFROM node:20-slim AS frontend-build\n\n\n\nWORKDIR /app/client\n\nCOPY client/package.json ./\n\nRUN npm install\n\nRUN npm install esbuild@0.25.5 --build-from-source\n\nCOPY client ./\n\nRUN npm run build\n\n# ---------------------\n# Backend stage\n# ---------------------\nFROM node:20-slim AS backend\n\n# Install ping\nRUN apt-get update \\\n    && apt-get install -y iputils-ping \\\n    && rm -rf /var/lib/apt/lists/*\n\nWORKDIR /app/server\n\nCOPY server/package.json ./\n\nRUN npm install\n\nCOPY server ./\n\nRUN chmod +x ./scripts/inject-vars.sh\n\nRUN npm run build\n\nCOPY --from=frontend-build /app/client/dist ./public\n\nEXPOSE 52345\n\nCMD [\"sh\", \"-c\", \"./scripts/inject-vars.sh && node ./dist/index.js\"]\n"
  },
  {
    "path": "docker/dist-mono/build_images.sh",
    "content": "#!/bin/bash\n\n# Change directory to root Server directory for correct Docker Context\ncd \"$(dirname \"$0\")\"\ncd ../..\n\n# Define service names and their corresponding Dockerfiles in parallel arrays\nservices=(\"mono_mongo\"  \"mono_server\")\ndockerfiles=(\n  \"./docker/dist-mono/mongoDB.Dockerfile\"\n  \"./docker/dist-mono/server.Dockerfile\"\n)\n\n# Loop through each service and build the corresponding image\nfor i in \"${!services[@]}\"; do\n  service=\"${services[$i]}\"\n  dockerfile=\"${dockerfiles[$i]}\"\n  \n  docker build -f \"$dockerfile\" -t \"$service\" .\n  \n  # Check if the build succeeded\n  if [ $? -ne 0 ]; then\n    echo \"Error building $service image. Exiting...\"\n    exit 1\n  fi\ndone\n\necho \"All images built successfully\""
  },
  {
    "path": "docker/dist-mono/docker-compose-local.yaml",
    "content": "services:\n  server:\n    image: mono_server\n    restart: always\n    ports:\n      - \"52345:52345\"\n    environment:\n      - UPTIME_APP_API_BASE_URL=http://localhost:52345/api/v1\n      - UPTIME_APP_CLIENT_HOST=http://localhost\n      - DB_CONNECTION_STRING=mongodb://mongodb:27017/uptime_db\n      - CLIENT_HOST=http://localhost\n      - JWT_SECRET=my_secret\n    depends_on:\n      - mongodb\n  mongodb:\n    image: mono_mongo\n    restart: always\n    command: [\"mongod\", \"--quiet\", \"--bind_ip_all\"]\n    volumes:\n      - ./mongo/data:/data/db\n    healthcheck:\n      test: [\"CMD\", \"mongosh\", \"--eval\", \"db.adminCommand('ping')\", \"--quiet\"]\n      interval: 5s\n      timeout: 30s\n      start_period: 0s\n      start_interval: 1s\n      retries: 30\n"
  },
  {
    "path": "docker/dist-mono/docker-compose.yaml",
    "content": "services:\n  server:\n    image: ghcr.io/bluewave-labs/checkmate-backend-mono:latest\n    pull_policy: always\n    restart: always\n    ports:\n      - \"52345:52345\"\n    environment:\n      - UPTIME_APP_API_BASE_URL=http://localhost:52345/api/v1\n      - UPTIME_APP_CLIENT_HOST=http://localhost\n      - DB_CONNECTION_STRING=mongodb://mongodb:27017/uptime_db\n      - CLIENT_HOST=http://localhost\n      - JWT_SECRET=my_secret\n    depends_on:\n      - mongodb\n  mongodb:\n    image: ghcr.io/bluewave-labs/checkmate-mongo:latest\n    restart: always\n    command: [\"mongod\", \"--quiet\", \"--bind_ip_all\"]\n    volumes:\n      - ./mongo/data:/data/db\n    healthcheck:\n      test: [\"CMD\", \"mongosh\", \"--eval\", \"db.adminCommand('ping')\", \"--quiet\"]\n      interval: 5s\n      timeout: 30s\n      start_period: 0s\n      start_interval: 1s\n      retries: 30\n"
  },
  {
    "path": "docker/dist-mono/mongoDB.Dockerfile",
    "content": "FROM mongo\nEXPOSE 27017\nCMD [\"mongod\"]\n"
  },
  {
    "path": "docker/dist-mono/server.Dockerfile",
    "content": "FROM node:20-slim AS frontend-build\n\nWORKDIR /app/client\n\nCOPY client/package*.json ./\nRUN npm install\n\nCOPY client ./\nRUN npm run build\n\nFROM node:20-slim AS app\n\n# Install ping\nRUN apt-get update \\\n    && apt-get install -y iputils-ping \\\n    && rm -rf /var/lib/apt/lists/*\n\nWORKDIR /app/server\n\nCOPY server ./\n\n\nRUN npm install\n\nRUN npm run build\n\nCOPY --from=frontend-build /app/client/dist ./public\n\nRUN chmod +x ./scripts/inject-vars.sh\n\nEXPOSE 52345\n\nCMD ./scripts/inject-vars.sh && node ./dist/index.js\n"
  },
  {
    "path": "docker/prod/build_images.sh",
    "content": "#!/bin/bash\n\n# Change directory to root directory for correct Docker Context\ncd \"$(dirname \"$0\")\"\ncd ../../\n\n# Define an array of services and their Dockerfiles\ndeclare -A services=(\n  [\"uptime_client\"]=\"./docker/prod/client.Dockerfile\"\n  [\"uptime_database_mongo\"]=\"./docker/prod/mongoDB.Dockerfile\"\n  [\"uptime_server\"]=\"./docker/prod/server.Dockerfile\"\n)\n\n# Loop through each service and build the corresponding image\nfor service in \"${!services[@]}\"; do\n  docker build -f \"${services[$service]}\" -t \"$service\" .\n  \n  # Check if the build succeeded\n  if [ $? -ne 0 ]; then\n    echo \"Error building $service image. Exiting...\"\n    exit 1\n  fi\ndone\n\necho \"All images built successfully\""
  },
  {
    "path": "docker/prod/certbot-compose.yaml",
    "content": "version: \"3\"\n\nservices:\n  webserver:\n    image: nginx:latest\n    ports:\n      - 80:80\n      - 443:443\n    restart: always\n    volumes:\n      - ./nginx/conf.d/:/etc/nginx/conf.d/:ro\n      - ./certbot/www/:/var/www/certbot/:ro\n  certbot:\n    image: certbot/certbot:latest\n    volumes:\n      - ./certbot/www/:/var/www/certbot/:rw\n      - ./certbot/conf/:/etc/letsencrypt/:rw\n    depends_on:\n      - webserver\n"
  },
  {
    "path": "docker/prod/client.Dockerfile",
    "content": "FROM node:20-slim AS build\n\nENV NODE_OPTIONS=\"--max-old-space-size=4096\"\n\nWORKDIR /app\n\nCOPY ./client/package*.json ./\n\nRUN npm install\n\nCOPY ./client .\n\nRUN npm run build\n\nFROM nginx:1.27.1-alpine\n\nCOPY --from=build /app/dist /usr/share/nginx/html\nCOPY --from=build /app/env.sh /docker-entrypoint.d/env.sh\nRUN chmod +x /docker-entrypoint.d/env.sh\nCMD [\"nginx\", \"-g\", \"daemon off;\"]"
  },
  {
    "path": "docker/prod/docker-compose.yaml",
    "content": "services:\n  client:\n    image: ghcr.io/bluewave-labs/checkmate:frontend-demo\n    restart: always\n    environment:\n      UPTIME_APP_API_BASE_URL: \"https://checkmate-demo.bluewavelabs.ca/api/v1\"\n      UPTIME_APP_CLIENT_HOST: \"https://checkmate-demo.bluewavelabs.ca\"\n    ports:\n      - \"80:80\"\n      - \"443:443\"\n    depends_on:\n      - server\n    volumes:\n      - ./nginx/conf.d:/etc/nginx/conf.d/:ro\n      - ./certbot/www:/var/www/certbot/:ro\n      - ./certbot/conf/:/etc/nginx/ssl/:ro\n\n  certbot:\n    image: certbot/certbot:latest\n    restart: always\n    volumes:\n      - ./certbot/www/:/var/www/certbot/:rw\n      - ./certbot/conf/:/etc/letsencrypt/:rw\n    entrypoint: \"/bin/sh -c 'trap exit TERM; while :; do certbot renew --webroot -w /var/www/certbot; sleep 12h & wait $${!}; done;'\"\n\n  server:\n    image: ghcr.io/bluewave-labs/checkmate:backend-demo\n    restart: always\n    ports:\n      - \"52345:52345\"\n    env_file:\n      - server.env\n    depends_on:\n      - mongodb\n    volumes:\n      - /var/run/docker.sock:/var/run/docker.sock:ro\n  mongodb:\n    image: ghcr.io/bluewave-labs/checkmate:mongo-demo\n    restart: always\n    command: [\"mongod\", \"--quiet\", \"--bind_ip_all\"]\n    volumes:\n      - ./mongo/data:/data/db\n    env_file:\n      - mongo.env\n    healthcheck:\n      test: [\"CMD\", \"mongosh\", \"--eval\", \"db.adminCommand('ping')\", \"--quiet\"]\n      interval: 5s\n      timeout: 30s\n      start_period: 0s\n      start_interval: 1s\n      retries: 30\n  capture:\n    image: ghcr.io/bluewave-labs/capture:latest\n    container_name: capture\n    restart: unless-stopped\n    ports:\n      - \"59232:59232\"\n    environment:\n      - API_SECRET=my_secret\n      - GIN_MODE=release\n    volumes:\n      - /etc/os-release:/etc/os-release:ro\n"
  },
  {
    "path": "docker/prod/mongoDB.Dockerfile",
    "content": "FROM mongo\nEXPOSE 27017\nCMD [\"mongod\"]\n"
  },
  {
    "path": "docker/prod/nginx/conf.d/cerbot",
    "content": "server {\n    listen 80;\n    listen [::]:80;\n\n    server_name checkmate-demo.bluewavelabs.ca www.checkmate-demo.bluewavelabs.ca;\n    server_tokens off;\n\n    location /.well-known/acme-challenge/ {\n        root /var/www/certbot;\n    }\n\n    location / {\n        return 301 https://[domain-name]$request_uri;\n    }\n}\n"
  },
  {
    "path": "docker/prod/nginx/conf.d/default.conf",
    "content": "server {\n    listen       80;\n    listen  [::]:80;\n\n    server_name checkmate-demo.bluewavelabs.ca;\n    server_tokens off;\n\n    location /.well-known/acme-challenge/ {\n        root /var/www/certbot;\n    }\n\n    location / {\n        root   /usr/share/nginx/html;\n        index  index.html index.htm;\n        try_files $uri $uri/ /index.html;\n    }\n    \n    location /api/ {\n        proxy_pass http://server:52345/api/;\n        proxy_http_version 1.1;\n        proxy_set_header Host $host;\n        proxy_set_header X-Real-IP $remote_addr;\n        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n        proxy_set_header X-Forwarded-Proto $scheme;\n    }\n\n    location /api-docs/ {\n        proxy_pass http://server:52345/api-docs/;\n        proxy_http_version 1.1;\n        proxy_set_header Host $host;\n        proxy_set_header X-Real-IP $remote_addr;\n        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n        proxy_set_header X-Forwarded-Proto $scheme;\n    }\n}\n\nserver {\n    listen 443 default_server ssl http2;\n    listen [::]:443 ssl http2;\n\n    server_name checkmate-demo.bluewavelabs.ca;\n\n    ssl_certificate /etc/nginx/ssl/live/checkmate-demo.bluewavelabs.ca/fullchain.pem;\n    ssl_certificate_key /etc/nginx/ssl/live/checkmate-demo.bluewavelabs.ca/privkey.pem;\n    \n    location / {\n        root   /usr/share/nginx/html;\n        index  index.html index.htm;\n        try_files $uri $uri/ /index.html;\n    }\n\n    location /api/ {\n        proxy_pass http://server:52345/api/;\n        proxy_http_version 1.1;\n        proxy_set_header Host $host;\n        proxy_set_header X-Real-IP $remote_addr;\n        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n        proxy_set_header X-Forwarded-Proto $scheme;\n    }\n\n    location /api-docs/ {\n        proxy_pass http://server:52345/api-docs/;\n        proxy_http_version 1.1;\n        proxy_set_header Host $host;\n        proxy_set_header X-Real-IP $remote_addr;\n        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n        proxy_set_header X-Forwarded-Proto $scheme;\n    }\n}\n"
  },
  {
    "path": "docker/prod/server.Dockerfile",
    "content": "FROM node:20-slim\n\n# Install ping\nRUN apt-get update \\\n    && apt-get install -y iputils-ping \\\n    && rm -rf /var/lib/apt/lists/*\n\nENV NODE_OPTIONS=\"--max-old-space-size=2048\"\n\nWORKDIR /app\n\nCOPY ./server/package*.json ./\n\nRUN npm install\n\nCOPY ./server ./\n\nRUN npm run build\n\nEXPOSE 52345\n\nCMD [\"node\", \"dist/index.js\"]"
  },
  {
    "path": "docker/staging/build_images.sh",
    "content": "#!/bin/bash\n\n# Change directory to root directory for correct Docker Context\ncd \"$(dirname \"$0\")\"\ncd ../../\n\n# Define an array of services and their Dockerfiles\ndeclare -A services=(\n  [\"uptime_client\"]=\"./docker/staging/client.Dockerfile\"\n  [\"uptime_database_mongo\"]=\"./docker/staging/mongoDB.Dockerfile\"\n  [\"uptime_server\"]=\"./docker/staging/server.Dockerfile\"\n)\n\n# Loop through each service and build the corresponding image\nfor service in \"${!services[@]}\"; do\n  docker build -f \"${services[$service]}\" -t \"$service\" .\n  \n  # Check if the build succeeded\n  if [ $? -ne 0 ]; then\n    echo \"Error building $service image. Exiting...\"\n    exit 1\n  fi\ndone\n\necho \"All images built successfully\""
  },
  {
    "path": "docker/staging/cerbot-compose.yaml",
    "content": "version: \"3\"\n\nservices:\n  webserver:\n    image: nginx:latest\n    ports:\n      - 80:80\n      - 443:443\n    restart: always\n    volumes:\n      - ./nginx/conf.d/:/etc/nginx/conf.d/:ro\n      - ./certbot/www/:/var/www/certbot/:ro\n  certbot:\n    image: certbot/certbot:latest\n    volumes:\n      - ./certbot/www/:/var/www/certbot/:rw\n      - ./certbot/conf/:/etc/letsencrypt/:rw\n    depends_on:\n      - webserver\n"
  },
  {
    "path": "docker/staging/client.Dockerfile",
    "content": "FROM node:20-slim AS build\n\nENV NODE_OPTIONS=\"--max-old-space-size=4096\"\n\nWORKDIR /app\n\nCOPY ./client/package*.json ./\n\nRUN npm install\n\nCOPY ./client ./\n\nRUN npm run build\n\nFROM nginx:1.27.1-alpine\n\nCOPY --from=build /app/dist /usr/share/nginx/html\nCOPY --from=build /app/env.sh /docker-entrypoint.d/env.sh\nRUN chmod +x /docker-entrypoint.d/env.sh\nCMD [\"nginx\", \"-g\", \"daemon off;\"]"
  },
  {
    "path": "docker/staging/docker-compose.yaml",
    "content": "services:\n  client:\n    image: ghcr.io/bluewave-labs/checkmate:frontend-staging\n    restart: always\n    environment:\n      UPTIME_APP_API_BASE_URL: \"https://checkmate-test.bluewavelabs.ca/api/v1\"\n      UPTIME_APP_CLIENT_HOST: \"https://checkmate-test.bluewavelabs.ca\"\n    ports:\n      - \"80:80\"\n      - \"443:443\"\n    depends_on:\n      - server\n    volumes:\n      - ./nginx/conf.d:/etc/nginx/conf.d/:ro\n      - ./certbot/www:/var/www/certbot/:ro\n      - ./certbot/conf/:/etc/nginx/ssl/:ro\n\n  certbot:\n    image: certbot/certbot:latest\n    restart: always\n    volumes:\n      - ./certbot/www/:/var/www/certbot/:rw\n      - ./certbot/conf/:/etc/letsencrypt/:rw\n    entrypoint: \"/bin/sh -c 'trap exit TERM; while :; do certbot renew --webroot -w /var/www/certbot; sleep 12h & wait $${!}; done;'\"\n\n  server:\n    image: ghcr.io/bluewave-labs/checkmate:backend-staging\n    restart: always\n    ports:\n      - \"52345:52345\"\n    env_file:\n      - server.env\n    depends_on:\n      - mongodb\n  mongodb:\n    image: ghcr.io/bluewave-labs/checkmate:mongo-staging\n    restart: always\n    command: [\"mongod\", \"--quiet\", \"--bind_ip_all\"]\n    ports:\n      - \"27017:27017\"\n    volumes:\n      - ./mongo/data:/data/db\n    env_file:\n      - mongo.env\n    healthcheck:\n      test: [\"CMD\", \"mongosh\", \"--eval\", \"db.adminCommand('ping')\", \"--quiet\"]\n      interval: 5s\n      timeout: 30s\n      start_period: 0s\n      start_interval: 1s\n      retries: 30\n  capture:\n    image: ghcr.io/bluewave-labs/capture:latest\n    container_name: capture\n    restart: unless-stopped\n    ports:\n      - \"59232:59232\"\n    environment:\n      - API_SECRET=my_secret\n      - GIN_MODE=release\n    volumes:\n      - /etc/os-release:/etc/os-release:ro\n"
  },
  {
    "path": "docker/staging/mongoDB.Dockerfile",
    "content": "FROM mongo\nEXPOSE 27017\nCMD [\"mongod\"]\n"
  },
  {
    "path": "docker/staging/nginx/conf.d/certbot",
    "content": "server {\n    listen 80;\n    listen [::]:80;\n\n    server_name checkmate-test.bluewavelabs.ca www.checkmate-test.bluewavelabs.ca;\n    server_tokens off;\n\n    location /.well-known/acme-challenge/ {\n        root /var/www/certbot;\n    }\n\n    location / {\n        return 301 https://[domain-name]$request_uri;\n    }\n}\n"
  },
  {
    "path": "docker/staging/nginx/conf.d/default.conf",
    "content": "server {\n    listen       80;\n    listen  [::]:80;\n\n    server_name checkmate-test.bluewavelabs.ca;\n    server_tokens off;\n\n    location /.well-known/acme-challenge/ {\n        root /var/www/certbot;\n    }\n\n    location / {\n        root   /usr/share/nginx/html;\n        index  index.html index.htm;\n        try_files $uri $uri/ /index.html;\n    }\n    \n    location /api/ {\n        proxy_pass http://server:52345/api/;\n        proxy_http_version 1.1;\n        proxy_set_header Host $host;\n        proxy_set_header X-Real-IP $remote_addr;\n        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n        proxy_set_header X-Forwarded-Proto $scheme;\n        proxy_set_header Connection '';\n        chunked_transfer_encoding off;\n        proxy_buffering off;\n        proxy_cache off;\n    }\n\n    location /api-docs/ {\n        proxy_pass http://server:52345/api-docs/;\n        proxy_http_version 1.1;\n        proxy_set_header Host $host;\n        proxy_set_header X-Real-IP $remote_addr;\n        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n        proxy_set_header X-Forwarded-Proto $scheme;\n    }\n}\n\nserver {\n    listen 443 default_server ssl http2;\n    listen [::]:443 ssl http2;\n\n    server_name checkmate-test.bluewavelabs.ca;\n\n    ssl_certificate /etc/nginx/ssl/live/checkmate-test.bluewavelabs.ca/fullchain.pem;\n    ssl_certificate_key /etc/nginx/ssl/live/checkmate-test.bluewavelabs.ca/privkey.pem;\n    \n    location / {\n        root   /usr/share/nginx/html;\n        index  index.html index.htm;\n        try_files $uri $uri/ /index.html;\n    }\n\n    location /api/ {\n        proxy_pass http://server:52345/api/;\n        proxy_http_version 1.1;\n        proxy_set_header Host $host;\n        proxy_set_header X-Real-IP $remote_addr;\n        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n        proxy_set_header X-Forwarded-Proto $scheme;\n        proxy_set_header Connection '';\n        chunked_transfer_encoding off;\n        proxy_buffering off;\n        proxy_cache off;\n    }\n\n    location /api-docs/ {\n        proxy_pass http://server:52345/api-docs/;\n        proxy_http_version 1.1;\n        proxy_set_header Host $host;\n        proxy_set_header X-Real-IP $remote_addr;\n        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n        proxy_set_header X-Forwarded-Proto $scheme;\n    }\n}\n"
  },
  {
    "path": "docker/staging/server.Dockerfile",
    "content": "FROM node:20-slim\n\n# Install ping\nRUN apt-get update \\\n    && apt-get install -y iputils-ping \\\n    && rm -rf /var/lib/apt/lists/*\n\nENV NODE_OPTIONS=\"--max-old-space-size=2048\"\n\nWORKDIR /app\n\nCOPY ./server/package*.json ./\n\nRUN npm install\n\nCOPY ./server ./\n\nRUN npm run build\n\nEXPOSE 52345\n\nCMD [\"node\", \"dist/index.js\"]"
  },
  {
    "path": "docs/README.md",
    "content": "# Checkmate Documentation\n\nWelcome to the Checkmate documentation. This directory contains guides and references for various aspects of Checkmate deployment and configuration.\n\n## Available Documentation\n\n### Deployment & Configuration\n- **[Custom CA Trust Guide](./custom-ca-trust.md)** - Configure Checkmate to trust custom Certificate Authorities\n- **[Custom CA Quick Reference](./custom-ca-quick-reference.md)** - Quick setup guide for custom CA trust\n\n## Docker Configuration\n\n### Custom CA Trust\nIf you need to monitor internal HTTPS endpoints with certificates from private Certificate Authorities (like Smallstep), see our custom CA trust documentation:\n\n- **Full Guide**: [Custom CA Trust Guide](./custom-ca-trust.md)\n- **Quick Reference**: [Custom CA Quick Reference](./custom-ca-quick-reference.md)\n\n### Example Configurations\nThe `docker/dev/` directory contains example configurations:\n- `docker-compose.custom-ca-example.yaml` - Example Docker Compose with custom CA\n- `server-custom-ca.Dockerfile` - Example Dockerfile for OS-level CA trust\n- `export-smallstep-ca.sh` - Helper script for Smallstep CA export\n\n## Contributing to Documentation\n\nIf you find issues or want to improve the documentation:\n\n1. Check existing issues and discussions\n2. Submit a pull request with your changes\n3. Follow the same markdown formatting style\n4. Include practical examples and code snippets\n\n## Getting Help\n\n- [GitHub Discussions](https://github.com/bluewave-labs/checkmate/discussions)\n- [Discord Channel](https://discord.gg/NAb6H3UTjK)\n- [Documentation Portal](https://docs.checkmate.so/)\n"
  },
  {
    "path": "docs/custom-ca-quick-reference.md",
    "content": "# Custom CA Trust - Quick Reference\n\n## Fast Setup (Node-level)\n\n1. **Export your CA certificate:**\n   ```bash\n   # For Smallstep\n   step certificate inspect --format pem step-ca/root_ca.crt > docker/dev/certs/custom-ca.pem\n   ```\n\n2. **Use the provided example override:**\n   ```bash\n   docker-compose -f docker-compose.yaml -f docker-compose.custom-ca-example.yaml up -d\n   ```\n\n3. **Or manually update docker-compose.yaml:**\n   ```yaml\n   services:\n     server:\n       environment:\n         NODE_EXTRA_CA_CERTS: /certs/custom-ca.pem\n       volumes:\n         - ./certs:/certs:ro\n   ```\n\n## Alternative Setup (OS-level)\n\n1. **Use custom Dockerfile:**\n   ```bash\n   docker-compose -f docker-compose.yaml -f docker-compose.custom-ca.yaml up\n   ```\n\n## File Structure\n```\ndocker/dev/\n├── docker-compose.yaml\n├── docker-compose.custom-ca-example.yaml  # Example config\n├── certs/\n│   ├── README.md\n│   └── custom-ca.pem                     # Your CA certificate\n└── export-smallstep-ca.sh                # Helper script\n```\n\n## Environment Variables\n- `NODE_EXTRA_CA_CERTS=/certs/custom-ca.pem` - Node.js trust\n- Mount `./certs:/certs:ro` - Volume mount\n\n## Security\n- ✅ Only trust CAs you control\n- ✅ Use read-only volume mounts\n- ✅ Keep certificates out of version control\n- ❌ Never trust untrusted CAs\n\n## Troubleshooting\n- Check container logs: `docker-compose logs server`\n- Verify certificate: `docker exec -it <container> ls -la /certs/`\n- Test connection: `docker exec -it <container> wget --ca-certificate=/certs/custom-ca.pem https://your-internal-site.com`\n\n## Full Documentation\nSee [Custom CA Trust Guide](./custom-ca-trust.md) for detailed instructions.\n"
  },
  {
    "path": "docs/custom-ca-trust.md",
    "content": "# Custom Certificate Authority Trust\n\nThis guide explains how to configure Checkmate to trust custom Certificate Authorities (CAs) when running in Docker, particularly useful for internal/private CAs like Smallstep.\n\n## Understanding Certificate Authorities\n\nCertificate Authorities (CAs) are entities that issue and manage digital certificates. While public CAs (like Let's Encrypt, DigiCert) are trusted by default in most systems, private or internal CAs (like those issued by Smallstep, internal PKI systems) require explicit trust configuration.\n\nWhen Checkmate monitors HTTPS endpoints with certificates from private CAs, it may show them as \"DOWN\" due to certificate validation failures, even if the service is actually accessible.\n\n## Node-level Trust Approach\n\nThe simplest approach is to mount your custom CA certificate and configure Node.js to trust it using the `NODE_EXTRA_CA_CERTS` environment variable.\n\n### Docker Compose Configuration\n\nAdd a volume mount for your CA certificate and set the environment variable:\n\n```yaml\nservices:\n  server:\n    image: uptime_server:latest\n    restart: always\n    ports:\n      - \"52345:52345\"\n    env_file:\n      - server.env\n    environment:\n      NODE_EXTRA_CA_CERTS: /certs/custom-ca.pem\n    volumes:\n      - ./certs:/certs:ro\n    depends_on:\n      - redis\n      - mongodb\n```\n\n### Directory Structure\n\nCreate a `certs` directory in your Docker Compose project root:\n\n```\ndocker/dev/\n├── docker-compose.yaml\n├── certs/\n│   └── custom-ca.pem\n└── ...\n```\n\n## OS-level Trust Approach (Debian-based)\n\nFor more comprehensive trust configuration, you can create a derived Dockerfile that installs your CA at the OS level.\n\n### Custom Dockerfile\n\nCreate `docker/dev/server-custom-ca.Dockerfile`:\n\n```dockerfile\nFROM node:20-alpine\n\n# Install ca-certificates for Alpine\nRUN apk add --no-cache ca-certificates\n\nWORKDIR /app\n\nCOPY ./server/package*.json ./\n\nRUN npm install\n\nCOPY ./server/ ./\n\n# Copy your custom CA certificate\nCOPY ./certs/custom-ca.crt /usr/local/share/ca-certificates/\n\n# Update CA certificates\nRUN update-ca-certificates\n\nEXPOSE 52345\n\nCMD [\"node\", \"src/index.js\"]\n```\n\n### Docker Compose Override\n\nCreate `docker/dev/docker-compose.custom-ca.yaml`:\n\n```yaml\nservices:\n  server:\n    build:\n      context: .\n      dockerfile: server-custom-ca.Dockerfile\n    restart: always\n    ports:\n      - \"52345:52345\"\n    env_file:\n      - server.env\n    depends_on:\n      - redis\n      - mongodb\n```\n\nRun with: `docker-compose -f docker-compose.yaml -f docker-compose.custom-ca.yaml up`\n\n## Alpine Linux Considerations\n\nSince Checkmate uses Alpine Linux as the base image, you need to install the `ca-certificates` package:\n\n```dockerfile\n# Install ca-certificates for Alpine\nRUN apk add --no-cache ca-certificates\n\n# Copy and update CA certificates\nCOPY ./certs/custom-ca.crt /usr/local/share/ca-certificates/\nRUN update-ca-certificates\n```\n\n## Smallstep CA Configuration\n\nIf you're using Smallstep as your internal CA, you can export the root CA certificate:\n\n### Export Smallstep Root CA\n\n```bash\n# Export the root CA certificate\nstep certificate inspect --format pem step-ca/root_ca.crt > custom-ca.pem\n\n# Or if you have the CA URL configured\nstep certificate inspect --format pem $(step path)/certs/root_ca.crt > custom-ca.pem\n```\n\n### Using the Exported Certificate\n\n1. Copy the exported `custom-ca.pem` to your `docker/dev/certs/` directory\n2. Use either the Node-level or OS-level approach above\n3. Restart your Checkmate server container\n\n## Security Considerations\n\n⚠️ **Important Security Warning**: Only trust CAs that you control or explicitly trust. Adding untrusted CAs can compromise the security of your monitoring system.\n\n- **Private CAs**: Only trust CAs from your organization's PKI infrastructure\n- **Self-signed certificates**: Consider using proper CA infrastructure instead\n- **Certificate validation**: Ensure your CA certificates are valid and not expired\n- **Access control**: Limit access to the CA certificate files in production\n\n## Troubleshooting\n\n### Verify CA Trust\n\nTest if your CA is trusted by the container:\n\n```bash\n# Enter the running container\ndocker exec -it <container_name> sh\n\n# Check if the CA is in the trust store\nls -la /usr/local/share/ca-certificates/\ncat /etc/ssl/certs/ca-certificates.crt | grep -A 5 -B 5 \"YOUR_CA_NAME\"\n```\n\n### Common Issues\n\n1. **Permission denied**: Ensure the CA certificate file has proper read permissions\n2. **Certificate format**: Use PEM format (.pem, .crt) for best compatibility\n3. **Container restart**: Always restart the container after adding new CA certificates\n4. **Path issues**: Verify the certificate path in your volume mounts\n\n## Example: Complete Working Setup\n\nHere's a complete example for a Smallstep CA setup. This demonstrates both the baseline failure (expected) and the custom CA success:\n\n### Baseline Test (Should Fail)\n1. **Start Checkmate without custom CA trust:**\n   ```bash\n   cd docker/dev\n   docker-compose up -d\n   ```\n\n2. **Test connection to internal HTTPS endpoint:**\n   ```bash\n   # This should fail with TLS error (unknown CA)\n   docker-compose exec server node -e \"\n     const https = require('https');\n     https.get('https://your-internal-site.com', res => {\n       console.log('STATUS:', res.statusCode);\n     }).on('error', e => {\n       console.error('ERR:', e.message);\n     });\n   \"\n   ```\n   **Expected result**: TLS error due to unknown CA\n\n### Custom CA Test (Should Succeed)\n1. **Export Smallstep Root CA:**\n   ```bash\n   step certificate inspect --format pem step-ca/root_ca.crt > docker/dev/certs/smallstep-root-ca.pem\n   ```\n\n2. **Update docker-compose.yaml with custom CA trust:**\n   ```yaml\n   services:\n     server:\n       environment:\n         NODE_EXTRA_CA_CERTS: /certs/smallstep-root-ca.pem\n       volumes:\n         - ./certs:/certs:ro\n   ```\n\n3. **Restart with custom CA:**\n   ```bash\n   docker-compose down\n   docker-compose -f docker-compose.yaml -f docker-compose.custom-ca-example.yaml up -d\n   ```\n\n4. **Test the same connection:**\n   ```bash\n   # This should now succeed\n   docker-compose exec server node -e \"\n     const https = require('https');\n     https.get('https://your-internal-site.com', res => {\n       console.log('STATUS:', res.statusCode);\n     }).on('error', e => {\n       console.error('ERR:', e.message);\n     });\n   \"\n   ```\n   **Expected result**: HTTP 200 OK\n\n### Verification\n- **Baseline**: TLS failure proves default behavior (unknown CA)\n- **Custom CA**: TLS success proves custom CA trust is working\n- **Both tests must pass** to confirm the feature works correctly\n\nYour Checkmate server should now trust certificates issued by your Smallstep CA, allowing you to monitor internal HTTPS endpoints without disabling SSL validation.\n"
  },
  {
    "path": "docs/infrastructure-disk-selection.md",
    "content": "# Infrastructure Monitoring - Disk Selection\n\nThis guide explains how to use the selective disk monitoring feature in Checkmate's infrastructure monitoring.\n\n## Overview\n\nBy default, Checkmate monitors all detected disks on your server. The disk selection feature allows you to choose specific disks/mountpoints to monitor, giving you more control over what gets tracked and displayed.\n\n## Prerequisites\n\n- Checkmate server running with [Capture agent](https://github.com/bluewave-labs/capture) installed on target server\n- An existing infrastructure monitor already created and configured\n- At least one disk detected by the Capture agent\n\n## Using Disk Selection\n\n### Accessing the Feature\n\n1. Navigate to your Infrastructure monitors page\n2. Click on an existing infrastructure monitor to view details\n3. Click the \"Configure\" or \"Edit\" button\n4. Scroll down to the **Disk Selection** section\n\n> **Note:** The disk selection feature is only available when editing existing monitors that have already detected disks.\n\n### Selecting Disks to Monitor\n\n1. **View Available Disks**: The system automatically detects all disks/mountpoints from your server\n2. **Select Disks**: Check the boxes next to the disks you want to monitor\n3. **Apply Changes**: Click \"Save\" to update your monitor configuration\n\n### Understanding Disk Identifiers\n\nDisks are identified by their mountpoint or device name:\n- **Mountpoint**: `/` (root), `/home`, `/var`, etc.\n- **Device**: `/dev/sda1`, `/dev/nvme0n1p1`, etc.\n\n### Behavior\n\n- **All disks selected**: Shows all detected disks in gauges and charts\n- **Specific disks selected**: Only shows selected disks in the monitoring interface\n- **No disks detected**: Displays \"No disk detected for the moment\" message\n\n## What Gets Filtered\n\nWhen you select specific disks, the following elements are filtered:\n\n- **Disk Usage Gauges**: Only selected disks appear in the dashboard\n- **Disk Usage Charts**: Time-series charts show only selected disks\n- **Monitor Table**: Summary view reflects only selected disk usage\n\n## Example Use Cases\n\n- **Server with multiple drives**: Monitor only critical system disks, ignore temporary storage\n- **Database servers**: Focus monitoring on database partition while ignoring logs partition\n- **Web servers**: Monitor web content disk separately from system disk\n- **Development environments**: Track only project-specific mountpoints\n\n## Troubleshooting\n\n### No Disks Appearing\n- Verify the Capture agent is running on the target server\n- Check that the agent has proper permissions to read disk information\n- Ensure the monitor has been running long enough to collect at least one check\n\n### Missing Disk Information\n- Some disks may not be accessible to the Capture agent due to permissions\n- Virtual or network-mounted disks may not appear in the list\n- Check the Capture agent logs for any disk detection errors\n\n## Related Documentation\n\n- [Infrastructure Monitoring Setup](https://docs.checkmate.so/checkmate-2.1)\n- [Capture Agent Installation](https://github.com/bluewave-labs/capture)"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"checkmate\",\n  \"version\": \"1.0.0\",\n  \"description\": \"<p align=center> <a href=\\\"https://trendshift.io/repositories/12443\\\" target=\\\"_blank\\\"><img src=\\\"https://trendshift.io/api/badge/repositories/12443\\\" alt=\\\"bluewave-labs%2Fcheckmate | Trendshift\\\" style=\\\"width: 250px; height: 55px;\\\" width=\\\"250\\\" height=\\\"55\\\"/></a></p>\",\n  \"main\": \"index.js\",\n  \"directories\": {\n    \"doc\": \"docs\"\n  },\n  \"scripts\": {\n    \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\",\n    \"prepare\": \"husky\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/bluewave-labs/Checkmate.git\"\n  },\n  \"keywords\": [],\n  \"author\": \"\",\n  \"license\": \"ISC\",\n  \"type\": \"commonjs\",\n  \"bugs\": {\n    \"url\": \"https://github.com/bluewave-labs/Checkmate/issues\"\n  },\n  \"homepage\": \"https://github.com/bluewave-labs/Checkmate#readme\",\n  \"devDependencies\": {\n    \"husky\": \"^9.1.7\"\n  }\n}\n"
  },
  {
    "path": "scripts/flatten-locales.js",
    "content": "#!/usr/bin/env node\n\nconst fs = require(\"fs\");\nconst path = require(\"path\");\n\nfunction flattenKeys(obj, prefix = \"\", result = []) {\n  for (const key in obj) {\n    if (obj.hasOwnProperty(key)) {\n      const newKey = prefix ? `${prefix}.${key}` : key;\n\n      if (\n        typeof obj[key] === \"object\" &&\n        obj[key] !== null &&\n        !Array.isArray(obj[key])\n      ) {\n        flattenKeys(obj[key], newKey, result);\n      } else {\n        result.push(newKey);\n      }\n    }\n  }\n  return result;\n}\n\n// Paths\nconst localesDir = path.join(__dirname, \"../client/src/locales\");\nconst inputPath = path.join(localesDir, \"en.json\");\nconst outputPath = path.join(localesDir, \"keys.json\");\n\ntry {\n  const jsonContent = fs.readFileSync(inputPath, \"utf8\");\n  const jsonData = JSON.parse(jsonContent);\n\n  const flattenedKeys = flattenKeys(jsonData);\n  flattenedKeys.sort();\n\n  fs.writeFileSync(outputPath, JSON.stringify(flattenedKeys, null, 2), \"utf8\");\n\n  console.log(`Keys written to: ${outputPath}`);\n} catch (error) {\n  console.error(error.message);\n  process.exit(1);\n}\n"
  },
  {
    "path": "server/.dockerignore",
    "content": "./docker"
  },
  {
    "path": "server/.github/pull_request_template.md",
    "content": "**(Please remove this line only before submitting your PR. Ensure that all relevant items are checked before submission.)**\n\n## Describe your changes\n\nBriefly describe the changes you made and their purpose.\n\n## Write your issue number after \"Fixes \"\n\nFixes #123\n\n## Please ensure all items are checked off before requesting a review. \"Checked off\" means you need to add an \"x\" character between brackets so they turn into checkmarks.\n\n- [ ] (Do not skip this or your PR will be closed) I deployed the application locally.\n- [ ] (Do not skip this or your PR will be closed) I have performed a self-review and testing of my code.\n- [ ] I have included the issue # in the PR.\n- [ ] I have added i18n support to visible strings (instead of `<div>Add</div>`, use):\n\n```Javascript\nconst { t } = useTranslation();\n<div>{t('add')}</div>\n```\n\n- [ ] The issue I am working on is assigned to me.\n- [ ] I didn't use any hardcoded values (otherwise it will not scale, and will make it difficult to maintain consistency across the application).\n- [ ] My PR is granular and targeted to one specific feature.\n"
  },
  {
    "path": "server/.github/workflows/staging-deploy.yml",
    "content": "name: Staging deploy\n\non:\n  push:\n    branches: [\"develop\"]\n\njobs:\n  docker-build-and-push:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v4\n\n      - name: Log in to GitHub Container Registry\n        uses: docker/login-action@v3\n        with:\n          registry: ghcr.io\n          username: ${{ github.actor }}\n          password: ${{ secrets.GITHUB_TOKEN }}\n\n      - name: Build Server Docker image\n        run: |\n          docker build \\\n            -t ghcr.io/bluewave-labs/checkmate-backend:staging \\\n            -f ./docker/staging/server.Dockerfile \\\n            --label org.opencontainers.image.source=https://github.com/bluewave-labs/checkmate-backend \\\n            .\n\n      - name: Push Server Docker image\n        run: docker push ghcr.io/bluewave-labs/checkmate-backend:staging\n\n      - name: Build Mongo Docker image\n        run: |\n          docker build \\\n            -t ghcr.io/bluewave-labs/checkmate-mongo:staging \\\n            -f ./docker/staging/mongoDB.Dockerfile \\\n            --label org.opencontainers.image.source=https://github.com/bluewave-labs/checkmate-backend \\\n            .\n\n      - name: Push MongoDB Docker image\n        run: docker push ghcr.io/bluewave-labs/checkmate-mongo:staging\n\n      - name: Build Redis Docker image\n        run: |\n          docker build \\\n            -t ghcr.io/bluewave-labs/checkmate-redis:staging \\\n            -f ./docker/staging/redis.Dockerfile \\\n            --label org.opencontainers.image.source=https://github.com/bluewave-labs/checkmate-backend \\\n            .\n\n      - name: Push Redis Docker image\n        run: docker push ghcr.io/bluewave-labs/checkmate-redis:staging\n\n  deploy-to-staging:\n    needs: docker-build-and-push\n    runs-on: ubuntu-latest\n    steps:\n      - name: SSH into server and restart container using Docker Compose\n        uses: appleboy/ssh-action@v1.0.0\n        with:\n          host: ${{ secrets.STAGING_SERVER_HOST }}\n          username: ${{ secrets.STAGING_SERVER_USER }}\n          key: ${{ secrets.STAGING_SERVER_SSH_KEY }}\n          script: |\n            cd checkmate/server/docker/staging\n            docker compose down\n            docker compose pull\n            docker compose up -d\n"
  },
  {
    "path": "server/.gitignore",
    "content": "node_modules\n.env\n*.log\n*.sh\n!scripts/inject-vars.sh\n.nyc_output\ncoverage\n.clinic\nnode_modules\n.vscode/*\npublic\ndist"
  },
  {
    "path": "server/.mocharc.cjs",
    "content": "module.exports = {\n\trequire: [\"esm\", \"chai/register-expect.js\"], // Include Chai's \"expect\" interface globally\n\tspec: \"tests/**/*.test.js\", // Specify test files\n\ttimeout: 5000, // Set test-case timeout in milliseconds\n\trecursive: true, // Include subdirectories\n\treporter: \"spec\", // Use the \"spec\" reporter\n\texit: true, // Force Mocha to quit after tests complete\n};\n"
  },
  {
    "path": "server/.nycrc",
    "content": "{\n\t\"all\": true,\n\t\"include\": [\"controllers/*.js\", \"utils/*.js\", \"service/*.js\", \"db/mongo/modules/*.js\"],\n\t\"exclude\": [\"**/*.test.js\"],\n\t\"reporter\": [\"html\", \"text\", \"lcov\"],\n\t\"sourceMap\": false,\n\t\"instrument\": true\n}\n"
  },
  {
    "path": "server/.prettierrc",
    "content": "{\n\t\"printWidth\": 150,\n\t\"useTabs\": true,\n\t\"tabWidth\": 2,\n\t\"singleQuote\": false,\n\t\"bracketSpacing\": true,\n\t\"proseWrap\": \"preserve\",\n\t\"bracketSameLine\": false,\n\t\"singleAttributePerLine\": true,\n\t\"semi\": true,\n\t\"jsxSingleQuote\": false,\n\t\"quoteProps\": \"as-needed\",\n\t\"arrowParens\": \"always\",\n\t\"trailingComma\": \"es5\",\n\t\"htmlWhitespaceSensitivity\": \"css\"\n}\n"
  },
  {
    "path": "server/LICENSE",
    "content": "                    GNU AFFERO GENERAL PUBLIC LICENSE\n                       Version 3, 19 November 2007\n\n Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n                            Preamble\n\n  The GNU Affero General Public License is a free, copyleft license for\nsoftware and other kinds of works, specifically designed to ensure\ncooperation with the community in the case of network server software.\n\n  The licenses for most software and other practical works are designed\nto take away your freedom to share and change the works.  By contrast,\nour General Public Licenses are intended to guarantee your freedom to\nshare and change all versions of a program--to make sure it remains free\nsoftware for all its users.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthem if you wish), that you receive source code or can get it if you\nwant it, that you can change the software or use pieces of it in new\nfree programs, and that you know you can do these things.\n\n  Developers that use our General Public Licenses protect your rights\nwith two steps: (1) assert copyright on the software, and (2) offer\nyou this License which gives you legal permission to copy, distribute\nand/or modify the software.\n\n  A secondary benefit of defending all users' freedom is that\nimprovements made in alternate versions of the program, if they\nreceive widespread use, become available for other developers to\nincorporate.  Many developers of free software are heartened and\nencouraged by the resulting cooperation.  However, in the case of\nsoftware used on network servers, this result may fail to come about.\nThe GNU General Public License permits making a modified version and\nletting the public access it on a server without ever releasing its\nsource code to the public.\n\n  The GNU Affero General Public License is designed specifically to\nensure that, in such cases, the modified source code becomes available\nto the community.  It requires the operator of a network server to\nprovide the source code of the modified version running there to the\nusers of that server.  Therefore, public use of a modified version, on\na publicly accessible server, gives the public access to the source\ncode of the modified version.\n\n  An older license, called the Affero General Public License and\npublished by Affero, was designed to accomplish similar goals.  This is\na different license, not a version of the Affero GPL, but Affero has\nreleased a new version of the Affero GPL which permits relicensing under\nthis license.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\n                       TERMS AND CONDITIONS\n\n  0. Definitions.\n\n  \"This License\" refers to version 3 of the GNU Affero General Public License.\n\n  \"Copyright\" also means copyright-like laws that apply to other kinds of\nworks, such as semiconductor masks.\n\n  \"The Program\" refers to any copyrightable work licensed under this\nLicense.  Each licensee is addressed as \"you\".  \"Licensees\" and\n\"recipients\" may be individuals or organizations.\n\n  To \"modify\" a work means to copy from or adapt all or part of the work\nin a fashion requiring copyright permission, other than the making of an\nexact copy.  The resulting work is called a \"modified version\" of the\nearlier work or a work \"based on\" the earlier work.\n\n  A \"covered work\" means either the unmodified Program or a work based\non the Program.\n\n  To \"propagate\" a work means to do anything with it that, without\npermission, would make you directly or secondarily liable for\ninfringement under applicable copyright law, except executing it on a\ncomputer or modifying a private copy.  Propagation includes copying,\ndistribution (with or without modification), making available to the\npublic, and in some countries other activities as well.\n\n  To \"convey\" a work means any kind of propagation that enables other\nparties to make or receive copies.  Mere interaction with a user through\na computer network, with no transfer of a copy, is not conveying.\n\n  An interactive user interface displays \"Appropriate Legal Notices\"\nto the extent that it includes a convenient and prominently visible\nfeature that (1) displays an appropriate copyright notice, and (2)\ntells the user that there is no warranty for the work (except to the\nextent that warranties are provided), that licensees may convey the\nwork under this License, and how to view a copy of this License.  If\nthe interface presents a list of user commands or options, such as a\nmenu, a prominent item in the list meets this criterion.\n\n  1. Source Code.\n\n  The \"source code\" for a work means the preferred form of the work\nfor making modifications to it.  \"Object code\" means any non-source\nform of a work.\n\n  A \"Standard Interface\" means an interface that either is an official\nstandard defined by a recognized standards body, or, in the case of\ninterfaces specified for a particular programming language, one that\nis widely used among developers working in that language.\n\n  The \"System Libraries\" of an executable work include anything, other\nthan the work as a whole, that (a) is included in the normal form of\npackaging a Major Component, but which is not part of that Major\nComponent, and (b) serves only to enable use of the work with that\nMajor Component, or to implement a Standard Interface for which an\nimplementation is available to the public in source code form.  A\n\"Major Component\", in this context, means a major essential component\n(kernel, window system, and so on) of the specific operating system\n(if any) on which the executable work runs, or a compiler used to\nproduce the work, or an object code interpreter used to run it.\n\n  The \"Corresponding Source\" for a work in object code form means all\nthe source code needed to generate, install, and (for an executable\nwork) run the object code and to modify the work, including scripts to\ncontrol those activities.  However, it does not include the work's\nSystem Libraries, or general-purpose tools or generally available free\nprograms which are used unmodified in performing those activities but\nwhich are not part of the work.  For example, Corresponding Source\nincludes interface definition files associated with source files for\nthe work, and the source code for shared libraries and dynamically\nlinked subprograms that the work is specifically designed to require,\nsuch as by intimate data communication or control flow between those\nsubprograms and other parts of the work.\n\n  The Corresponding Source need not include anything that users\ncan regenerate automatically from other parts of the Corresponding\nSource.\n\n  The Corresponding Source for a work in source code form is that\nsame work.\n\n  2. Basic Permissions.\n\n  All rights granted under this License are granted for the term of\ncopyright on the Program, and are irrevocable provided the stated\nconditions are met.  This License explicitly affirms your unlimited\npermission to run the unmodified Program.  The output from running a\ncovered work is covered by this License only if the output, given its\ncontent, constitutes a covered work.  This License acknowledges your\nrights of fair use or other equivalent, as provided by copyright law.\n\n  You may make, run and propagate covered works that you do not\nconvey, without conditions so long as your license otherwise remains\nin force.  You may convey covered works to others for the sole purpose\nof having them make modifications exclusively for you, or provide you\nwith facilities for running those works, provided that you comply with\nthe terms of this License in conveying all material for which you do\nnot control copyright.  Those thus making or running the covered works\nfor you must do so exclusively on your behalf, under your direction\nand control, on terms that prohibit them from making any copies of\nyour copyrighted material outside their relationship with you.\n\n  Conveying under any other circumstances is permitted solely under\nthe conditions stated below.  Sublicensing is not allowed; section 10\nmakes it unnecessary.\n\n  3. Protecting Users' Legal Rights From Anti-Circumvention Law.\n\n  No covered work shall be deemed part of an effective technological\nmeasure under any applicable law fulfilling obligations under article\n11 of the WIPO copyright treaty adopted on 20 December 1996, or\nsimilar laws prohibiting or restricting circumvention of such\nmeasures.\n\n  When you convey a covered work, you waive any legal power to forbid\ncircumvention of technological measures to the extent such circumvention\nis effected by exercising rights under this License with respect to\nthe covered work, and you disclaim any intention to limit operation or\nmodification of the work as a means of enforcing, against the work's\nusers, your or third parties' legal rights to forbid circumvention of\ntechnological measures.\n\n  4. Conveying Verbatim Copies.\n\n  You may convey verbatim copies of the Program's source code as you\nreceive it, in any medium, provided that you conspicuously and\nappropriately publish on each copy an appropriate copyright notice;\nkeep intact all notices stating that this License and any\nnon-permissive terms added in accord with section 7 apply to the code;\nkeep intact all notices of the absence of any warranty; and give all\nrecipients a copy of this License along with the Program.\n\n  You may charge any price or no price for each copy that you convey,\nand you may offer support or warranty protection for a fee.\n\n  5. Conveying Modified Source Versions.\n\n  You may convey a work based on the Program, or the modifications to\nproduce it from the Program, in the form of source code under the\nterms of section 4, provided that you also meet all of these conditions:\n\n    a) The work must carry prominent notices stating that you modified\n    it, and giving a relevant date.\n\n    b) The work must carry prominent notices stating that it is\n    released under this License and any conditions added under section\n    7.  This requirement modifies the requirement in section 4 to\n    \"keep intact all notices\".\n\n    c) You must license the entire work, as a whole, under this\n    License to anyone who comes into possession of a copy.  This\n    License will therefore apply, along with any applicable section 7\n    additional terms, to the whole of the work, and all its parts,\n    regardless of how they are packaged.  This License gives no\n    permission to license the work in any other way, but it does not\n    invalidate such permission if you have separately received it.\n\n    d) If the work has interactive user interfaces, each must display\n    Appropriate Legal Notices; however, if the Program has interactive\n    interfaces that do not display Appropriate Legal Notices, your\n    work need not make them do so.\n\n  A compilation of a covered work with other separate and independent\nworks, which are not by their nature extensions of the covered work,\nand which are not combined with it such as to form a larger program,\nin or on a volume of a storage or distribution medium, is called an\n\"aggregate\" if the compilation and its resulting copyright are not\nused to limit the access or legal rights of the compilation's users\nbeyond what the individual works permit.  Inclusion of a covered work\nin an aggregate does not cause this License to apply to the other\nparts of the aggregate.\n\n  6. Conveying Non-Source Forms.\n\n  You may convey a covered work in object code form under the terms\nof sections 4 and 5, provided that you also convey the\nmachine-readable Corresponding Source under the terms of this License,\nin one of these ways:\n\n    a) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by the\n    Corresponding Source fixed on a durable physical medium\n    customarily used for software interchange.\n\n    b) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by a\n    written offer, valid for at least three years and valid for as\n    long as you offer spare parts or customer support for that product\n    model, to give anyone who possesses the object code either (1) a\n    copy of the Corresponding Source for all the software in the\n    product that is covered by this License, on a durable physical\n    medium customarily used for software interchange, for a price no\n    more than your reasonable cost of physically performing this\n    conveying of source, or (2) access to copy the\n    Corresponding Source from a network server at no charge.\n\n    c) Convey individual copies of the object code with a copy of the\n    written offer to provide the Corresponding Source.  This\n    alternative is allowed only occasionally and noncommercially, and\n    only if you received the object code with such an offer, in accord\n    with subsection 6b.\n\n    d) Convey the object code by offering access from a designated\n    place (gratis or for a charge), and offer equivalent access to the\n    Corresponding Source in the same way through the same place at no\n    further charge.  You need not require recipients to copy the\n    Corresponding Source along with the object code.  If the place to\n    copy the object code is a network server, the Corresponding Source\n    may be on a different server (operated by you or a third party)\n    that supports equivalent copying facilities, provided you maintain\n    clear directions next to the object code saying where to find the\n    Corresponding Source.  Regardless of what server hosts the\n    Corresponding Source, you remain obligated to ensure that it is\n    available for as long as needed to satisfy these requirements.\n\n    e) Convey the object code using peer-to-peer transmission, provided\n    you inform other peers where the object code and Corresponding\n    Source of the work are being offered to the general public at no\n    charge under subsection 6d.\n\n  A separable portion of the object code, whose source code is excluded\nfrom the Corresponding Source as a System Library, need not be\nincluded in conveying the object code work.\n\n  A \"User Product\" is either (1) a \"consumer product\", which means any\ntangible personal property which is normally used for personal, family,\nor household purposes, or (2) anything designed or sold for incorporation\ninto a dwelling.  In determining whether a product is a consumer product,\ndoubtful cases shall be resolved in favor of coverage.  For a particular\nproduct received by a particular user, \"normally used\" refers to a\ntypical or common use of that class of product, regardless of the status\nof the particular user or of the way in which the particular user\nactually uses, or expects or is expected to use, the product.  A product\nis a consumer product regardless of whether the product has substantial\ncommercial, industrial or non-consumer uses, unless such uses represent\nthe only significant mode of use of the product.\n\n  \"Installation Information\" for a User Product means any methods,\nprocedures, authorization keys, or other information required to install\nand execute modified versions of a covered work in that User Product from\na modified version of its Corresponding Source.  The information must\nsuffice to ensure that the continued functioning of the modified object\ncode is in no case prevented or interfered with solely because\nmodification has been made.\n\n  If you convey an object code work under this section in, or with, or\nspecifically for use in, a User Product, and the conveying occurs as\npart of a transaction in which the right of possession and use of the\nUser Product is transferred to the recipient in perpetuity or for a\nfixed term (regardless of how the transaction is characterized), the\nCorresponding Source conveyed under this section must be accompanied\nby the Installation Information.  But this requirement does not apply\nif neither you nor any third party retains the ability to install\nmodified object code on the User Product (for example, the work has\nbeen installed in ROM).\n\n  The requirement to provide Installation Information does not include a\nrequirement to continue to provide support service, warranty, or updates\nfor a work that has been modified or installed by the recipient, or for\nthe User Product in which it has been modified or installed.  Access to a\nnetwork may be denied when the modification itself materially and\nadversely affects the operation of the network or violates the rules and\nprotocols for communication across the network.\n\n  Corresponding Source conveyed, and Installation Information provided,\nin accord with this section must be in a format that is publicly\ndocumented (and with an implementation available to the public in\nsource code form), and must require no special password or key for\nunpacking, reading or copying.\n\n  7. Additional Terms.\n\n  \"Additional permissions\" are terms that supplement the terms of this\nLicense by making exceptions from one or more of its conditions.\nAdditional permissions that are applicable to the entire Program shall\nbe treated as though they were included in this License, to the extent\nthat they are valid under applicable law.  If additional permissions\napply only to part of the Program, that part may be used separately\nunder those permissions, but the entire Program remains governed by\nthis License without regard to the additional permissions.\n\n  When you convey a copy of a covered work, you may at your option\nremove any additional permissions from that copy, or from any part of\nit.  (Additional permissions may be written to require their own\nremoval in certain cases when you modify the work.)  You may place\nadditional permissions on material, added by you to a covered work,\nfor which you have or can give appropriate copyright permission.\n\n  Notwithstanding any other provision of this License, for material you\nadd to a covered work, you may (if authorized by the copyright holders of\nthat material) supplement the terms of this License with terms:\n\n    a) Disclaiming warranty or limiting liability differently from the\n    terms of sections 15 and 16 of this License; or\n\n    b) Requiring preservation of specified reasonable legal notices or\n    author attributions in that material or in the Appropriate Legal\n    Notices displayed by works containing it; or\n\n    c) Prohibiting misrepresentation of the origin of that material, or\n    requiring that modified versions of such material be marked in\n    reasonable ways as different from the original version; or\n\n    d) Limiting the use for publicity purposes of names of licensors or\n    authors of the material; or\n\n    e) Declining to grant rights under trademark law for use of some\n    trade names, trademarks, or service marks; or\n\n    f) Requiring indemnification of licensors and authors of that\n    material by anyone who conveys the material (or modified versions of\n    it) with contractual assumptions of liability to the recipient, for\n    any liability that these contractual assumptions directly impose on\n    those licensors and authors.\n\n  All other non-permissive additional terms are considered \"further\nrestrictions\" within the meaning of section 10.  If the Program as you\nreceived it, or any part of it, contains a notice stating that it is\ngoverned by this License along with a term that is a further\nrestriction, you may remove that term.  If a license document contains\na further restriction but permits relicensing or conveying under this\nLicense, you may add to a covered work material governed by the terms\nof that license document, provided that the further restriction does\nnot survive such relicensing or conveying.\n\n  If you add terms to a covered work in accord with this section, you\nmust place, in the relevant source files, a statement of the\nadditional terms that apply to those files, or a notice indicating\nwhere to find the applicable terms.\n\n  Additional terms, permissive or non-permissive, may be stated in the\nform of a separately written license, or stated as exceptions;\nthe above requirements apply either way.\n\n  8. Termination.\n\n  You may not propagate or modify a covered work except as expressly\nprovided under this License.  Any attempt otherwise to propagate or\nmodify it is void, and will automatically terminate your rights under\nthis License (including any patent licenses granted under the third\nparagraph of section 11).\n\n  However, if you cease all violation of this License, then your\nlicense from a particular copyright holder is reinstated (a)\nprovisionally, unless and until the copyright holder explicitly and\nfinally terminates your license, and (b) permanently, if the copyright\nholder fails to notify you of the violation by some reasonable means\nprior to 60 days after the cessation.\n\n  Moreover, your license from a particular copyright holder is\nreinstated permanently if the copyright holder notifies you of the\nviolation by some reasonable means, this is the first time you have\nreceived notice of violation of this License (for any work) from that\ncopyright holder, and you cure the violation prior to 30 days after\nyour receipt of the notice.\n\n  Termination of your rights under this section does not terminate the\nlicenses of parties who have received copies or rights from you under\nthis License.  If your rights have been terminated and not permanently\nreinstated, you do not qualify to receive new licenses for the same\nmaterial under section 10.\n\n  9. Acceptance Not Required for Having Copies.\n\n  You are not required to accept this License in order to receive or\nrun a copy of the Program.  Ancillary propagation of a covered work\noccurring solely as a consequence of using peer-to-peer transmission\nto receive a copy likewise does not require acceptance.  However,\nnothing other than this License grants you permission to propagate or\nmodify any covered work.  These actions infringe copyright if you do\nnot accept this License.  Therefore, by modifying or propagating a\ncovered work, you indicate your acceptance of this License to do so.\n\n  10. Automatic Licensing of Downstream Recipients.\n\n  Each time you convey a covered work, the recipient automatically\nreceives a license from the original licensors, to run, modify and\npropagate that work, subject to this License.  You are not responsible\nfor enforcing compliance by third parties with this License.\n\n  An \"entity transaction\" is a transaction transferring control of an\norganization, or substantially all assets of one, or subdividing an\norganization, or merging organizations.  If propagation of a covered\nwork results from an entity transaction, each party to that\ntransaction who receives a copy of the work also receives whatever\nlicenses to the work the party's predecessor in interest had or could\ngive under the previous paragraph, plus a right to possession of the\nCorresponding Source of the work from the predecessor in interest, if\nthe predecessor has it or can get it with reasonable efforts.\n\n  You may not impose any further restrictions on the exercise of the\nrights granted or affirmed under this License.  For example, you may\nnot impose a license fee, royalty, or other charge for exercise of\nrights granted under this License, and you may not initiate litigation\n(including a cross-claim or counterclaim in a lawsuit) alleging that\nany patent claim is infringed by making, using, selling, offering for\nsale, or importing the Program or any portion of it.\n\n  11. Patents.\n\n  A \"contributor\" is a copyright holder who authorizes use under this\nLicense of the Program or a work on which the Program is based.  The\nwork thus licensed is called the contributor's \"contributor version\".\n\n  A contributor's \"essential patent claims\" are all patent claims\nowned or controlled by the contributor, whether already acquired or\nhereafter acquired, that would be infringed by some manner, permitted\nby this License, of making, using, or selling its contributor version,\nbut do not include claims that would be infringed only as a\nconsequence of further modification of the contributor version.  For\npurposes of this definition, \"control\" includes the right to grant\npatent sublicenses in a manner consistent with the requirements of\nthis License.\n\n  Each contributor grants you a non-exclusive, worldwide, royalty-free\npatent license under the contributor's essential patent claims, to\nmake, use, sell, offer for sale, import and otherwise run, modify and\npropagate the contents of its contributor version.\n\n  In the following three paragraphs, a \"patent license\" is any express\nagreement or commitment, however denominated, not to enforce a patent\n(such as an express permission to practice a patent or covenant not to\nsue for patent infringement).  To \"grant\" such a patent license to a\nparty means to make such an agreement or commitment not to enforce a\npatent against the party.\n\n  If you convey a covered work, knowingly relying on a patent license,\nand the Corresponding Source of the work is not available for anyone\nto copy, free of charge and under the terms of this License, through a\npublicly available network server or other readily accessible means,\nthen you must either (1) cause the Corresponding Source to be so\navailable, or (2) arrange to deprive yourself of the benefit of the\npatent license for this particular work, or (3) arrange, in a manner\nconsistent with the requirements of this License, to extend the patent\nlicense to downstream recipients.  \"Knowingly relying\" means you have\nactual knowledge that, but for the patent license, your conveying the\ncovered work in a country, or your recipient's use of the covered work\nin a country, would infringe one or more identifiable patents in that\ncountry that you have reason to believe are valid.\n\n  If, pursuant to or in connection with a single transaction or\narrangement, you convey, or propagate by procuring conveyance of, a\ncovered work, and grant a patent license to some of the parties\nreceiving the covered work authorizing them to use, propagate, modify\nor convey a specific copy of the covered work, then the patent license\nyou grant is automatically extended to all recipients of the covered\nwork and works based on it.\n\n  A patent license is \"discriminatory\" if it does not include within\nthe scope of its coverage, prohibits the exercise of, or is\nconditioned on the non-exercise of one or more of the rights that are\nspecifically granted under this License.  You may not convey a covered\nwork if you are a party to an arrangement with a third party that is\nin the business of distributing software, under which you make payment\nto the third party based on the extent of your activity of conveying\nthe work, and under which the third party grants, to any of the\nparties who would receive the covered work from you, a discriminatory\npatent license (a) in connection with copies of the covered work\nconveyed by you (or copies made from those copies), or (b) primarily\nfor and in connection with specific products or compilations that\ncontain the covered work, unless you entered into that arrangement,\nor that patent license was granted, prior to 28 March 2007.\n\n  Nothing in this License shall be construed as excluding or limiting\nany implied license or other defenses to infringement that may\notherwise be available to you under applicable patent law.\n\n  12. No Surrender of Others' Freedom.\n\n  If conditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot convey a\ncovered work so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you may\nnot convey it at all.  For example, if you agree to terms that obligate you\nto collect a royalty for further conveying from those to whom you convey\nthe Program, the only way you could satisfy both those terms and this\nLicense would be to refrain entirely from conveying the Program.\n\n  13. Remote Network Interaction; Use with the GNU General Public License.\n\n  Notwithstanding any other provision of this License, if you modify the\nProgram, your modified version must prominently offer all users\ninteracting with it remotely through a computer network (if your version\nsupports such interaction) an opportunity to receive the Corresponding\nSource of your version by providing access to the Corresponding Source\nfrom a network server at no charge, through some standard or customary\nmeans of facilitating copying of software.  This Corresponding Source\nshall include the Corresponding Source for any work covered by version 3\nof the GNU General Public License that is incorporated pursuant to the\nfollowing paragraph.\n\n  Notwithstanding any other provision of this License, you have\npermission to link or combine any covered work with a work licensed\nunder version 3 of the GNU General Public License into a single\ncombined work, and to convey the resulting work.  The terms of this\nLicense will continue to apply to the part which is the covered work,\nbut the work with which it is combined will remain governed by version\n3 of the GNU General Public License.\n\n  14. Revised Versions of this License.\n\n  The Free Software Foundation may publish revised and/or new versions of\nthe GNU Affero General Public License from time to time.  Such new versions\nwill be similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\n  Each version is given a distinguishing version number.  If the\nProgram specifies that a certain numbered version of the GNU Affero General\nPublic License \"or any later version\" applies to it, you have the\noption of following the terms and conditions either of that numbered\nversion or of any later version published by the Free Software\nFoundation.  If the Program does not specify a version number of the\nGNU Affero General Public License, you may choose any version ever published\nby the Free Software Foundation.\n\n  If the Program specifies that a proxy can decide which future\nversions of the GNU Affero General Public License can be used, that proxy's\npublic statement of acceptance of a version permanently authorizes you\nto choose that version for the Program.\n\n  Later license versions may give you additional or different\npermissions.  However, no additional obligations are imposed on any\nauthor or copyright holder as a result of your choosing to follow a\nlater version.\n\n  15. Disclaimer of Warranty.\n\n  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY\nAPPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT\nHOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY\nOF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,\nTHE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM\nIS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF\nALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n  16. Limitation of Liability.\n\n  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS\nTHE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY\nGENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE\nUSE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF\nDATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD\nPARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),\nEVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF\nSUCH DAMAGES.\n\n  17. Interpretation of Sections 15 and 16.\n\n  If the disclaimer of warranty and limitation of liability provided\nabove cannot be given local legal effect according to their terms,\nreviewing courts shall apply local law that most closely approximates\nan absolute waiver of all civil liability in connection with the\nProgram, unless a warranty or assumption of liability accompanies a\ncopy of the Program in return for a fee.\n\n                     END OF TERMS AND CONDITIONS\n\n            How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nstate the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the program's name and a brief idea of what it does.>\n    Copyright (C) 2025  BlueWave Labs\n\n    This program is free software: you can redistribute it and/or modify\n    it under the terms of the GNU Affero General Public License as published\n    by the Free Software Foundation, either version 3 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU Affero General Public License for more details.\n\n    You should have received a copy of the GNU Affero General Public License\n    along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nAlso add information on how to contact you by electronic and paper mail.\n\n  If your software can interact with users remotely through a computer\nnetwork, you should also make sure that it provides a way for users to\nget its source.  For example, if your program is a web application, its\ninterface could display a \"Source\" link that leads users to an archive\nof the code.  There are many ways you could offer source, and different\nsolutions will be better for different programs; see section 13 for the\nspecific requirements.\n\n  You should also get your employer (if you work as a programmer) or school,\nif any, to sign a \"copyright disclaimer\" for the program, if necessary.\nFor more information on this, and how to apply and follow the GNU AGPL, see\n<https://www.gnu.org/licenses/>.\n"
  },
  {
    "path": "server/README.md",
    "content": "<h1 align=\"center\"><a href=\"https://bluewavelabs.ca\" target=\"_blank\">Checkmate backend</a></h1>\n\n<p align=\"center\"><strong>The backend service for Checkmate, an open source uptime and infrastructure monitoring application</strong></p>\n\nThis directory contains the **backend** of Checkmate, which handles data processing, storage, and API services for the Checkmate monitoring tool. The backend is responsible for managing uptime checks, handling real-time alerts, and storing historical monitoring data.\n\nCheckmate's backend is designed to be lightweight and scalable, ensuring reliable performance even with a high number of active monitors.\n\n## Installation & documentation\n\nFor setup instructions, configuration details, and deployment guidelines, please visit our official documentation at [docs.checkmate.so](https://docs.checkmate.so).\n\n## Related repositories\n\n- [Capture Agent](https://github.com/bluewave-labs/capture) (Optional, provides additional server insights)\n"
  },
  {
    "path": "server/eslint.config.js",
    "content": "import globals from \"globals\";\nimport pluginJs from \"@eslint/js\";\nimport mochaPlugin from \"eslint-plugin-mocha\";\nimport tseslint from \"typescript-eslint\";\n\n/*\nPlease do not forget to look at the latest eslint configurations and rules.\nESlint v9 configuration is different than v8.\n\"https://eslint.org/docs/latest/use/configure/\"\n*/\n\n/** @type {import('eslint').Linter.Config[]} */\nexport default [\n\t{\n\t\tignores: [\"dist/**\", \"node_modules/**\", \"coverage/**\", \"test/**\"],\n\t},\n\t{\n\t\tlanguageOptions: {\n\t\t\tglobals: {\n\t\t\t\t...globals.node, // Add Node.js globals\n\t\t\t\t...globals.chai, // Add Chai globals\n\t\t\t},\n\t\t\tecmaVersion: 2023,\n\t\t\tsourceType: \"module\",\n\t\t},\n\t},\n\tpluginJs.configs.recommended, // Core JS rules\n\t...tseslint.configs.recommended, // TypeScript recommended rules\n\tmochaPlugin.configs.flat.recommended, // Mocha rules\n\t{\n\t\tfiles: [\"**/*.ts\", \"**/*.tsx\"],\n\t\tlanguageOptions: {\n\t\t\tparser: tseslint.parser,\n\t\t\tparserOptions: {\n\t\t\t\tprojectService: {\n\t\t\t\t\tallowDefaultProject: [\"jest.config.ts\"],\n\t\t\t\t},\n\t\t\t\ttsconfigRootDir: import.meta.dirname,\n\t\t\t},\n\t\t},\n\t\trules: {\n\t\t\t\"@typescript-eslint/no-unused-vars\": [\"error\", { argsIgnorePattern: \"^_\" }], // Ignore unused variables that start with '_'\n\t\t\t\"@typescript-eslint/no-explicit-any\": \"warn\", // Warn on 'any' types\n\t\t\t\"mocha/max-top-level-suites\": \"warn\", // Warn if there are too many top-level suites instead of failing\n\t\t},\n\t},\n];\n"
  },
  {
    "path": "server/jest.config.ts",
    "content": "import type { Config } from \"jest\";\n\nconst config: Config = {\n\trootDir: \".\",\n\ttestEnvironment: \"node\",\n\textensionsToTreatAsEsm: [\".ts\"],\n\ttransform: {\n\t\t\"^.+\\\\.(t|j)sx?$\": [\"ts-jest\", { useESM: true, tsconfig: \"./tsconfig.jest.json\" }],\n\t},\n\tmoduleNameMapper: {\n\t\t\"^@/validation/(.*)\\\\.js$\": \"<rootDir>/src/validation/$1.js\",\n\t\t\"^@/utils/(AppError)\\\\.js$\": \"<rootDir>/src/utils/$1.ts\",\n\t\t\"^@/utils/(.*)\\\\.js$\": \"<rootDir>/src/utils/$1.js\",\n\t\t\"^@/(.*)\\\\.ts$\": \"<rootDir>/src/$1.ts\",\n\t\t\"^@/(.*)\\\\.js$\": \"<rootDir>/src/$1.ts\",\n\t\t\"^@/(.*)$\": \"<rootDir>/src/$1\",\n\t},\n\ttestMatch: [\"<rootDir>/test/**/*.test.ts\"],\n\tsetupFilesAfterEnv: [],\n\tcollectCoverageFrom: [\"src/**/*.ts\"],\n\tcoveragePathIgnorePatterns: [\"/node_modules/\", \"/test/\"],\n\tclearMocks: true,\n};\n\nexport default config;\n"
  },
  {
    "path": "server/nodemon.json",
    "content": "{\n\t\"ignore\": [\"node_modules/*\"],\n\t\"watch\": [\"src/**/*.ts\", \"src/**/*.js\", \"*.json\"],\n\t\"ext\": \"ts,js,json\"\n}\n"
  },
  {
    "path": "server/openapi.json",
    "content": "{\n\t\"openapi\": \"3.1.0\",\n\t\"info\": {\n\t\t\"title\": \"Checkmate API\",\n\t\t\"summary\": \"Checkmate OpenAPI Specifications\",\n\t\t\"description\": \"Checkmate is an open source monitoring tool used to track the operational status and performance of servers and websites. It regularly checks whether a server/website is accessible and performs optimally, providing real-time alerts and reports on the monitored services' availability, downtime, and response time.\",\n\t\t\"contact\": {\n\t\t\t\"name\": \"API Support\",\n\t\t\t\"url\": \"mailto:support@bluewavelabs.ca\",\n\t\t\t\"email\": \"support@bluewavelabs.ca\"\n\t\t},\n\t\t\"license\": {\n\t\t\t\"name\": \"AGPLv3\",\n\t\t\t\"url\": \"https://github.com/bluewave-labs/checkmate/tree/HEAD/LICENSE\"\n\t\t},\n\t\t\"version\": \"2.3\"\n\t},\n\t\"servers\": [\n\t\t{\n\t\t\t\"url\": \"http://localhost:{PORT}/{API_PATH}\",\n\t\t\t\"description\": \"Local Development Server\",\n\t\t\t\"variables\": {\n\t\t\t\t\"PORT\": {\n\t\t\t\t\t\"default\": \"52345\"\n\t\t\t\t},\n\t\t\t\t\"API_PATH\": {\n\t\t\t\t\t\"default\": \"api/v1\"\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"url\": \"https://checkmate-demo.bluewavelabs.ca/{API_PATH}\",\n\t\t\t\"description\": \"Checkmate Demo Server\",\n\t\t\t\"variables\": {\n\t\t\t\t\"API_PATH\": {\n\t\t\t\t\t\"default\": \"api/v1\"\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t],\n\t\"tags\": [\n\t\t{\n\t\t\t\"name\": \"auth\",\n\t\t\t\"description\": \"Authentication and user management\"\n\t\t},\n\t\t{\n\t\t\t\"name\": \"invite\",\n\t\t\t\"description\": \"Team invitation management\"\n\t\t},\n\t\t{\n\t\t\t\"name\": \"monitors\",\n\t\t\t\"description\": \"Monitor management (uptime, page speed, hardware)\"\n\t\t},\n\t\t{\n\t\t\t\"name\": \"checks\",\n\t\t\t\"description\": \"Monitor check results and history\"\n\t\t},\n\t\t{\n\t\t\t\"name\": \"maintenance-window\",\n\t\t\t\"description\": \"Scheduled maintenance windows\"\n\t\t},\n\t\t{\n\t\t\t\"name\": \"queue\",\n\t\t\t\"description\": \"Job queue management\"\n\t\t},\n\t\t{\n\t\t\t\"name\": \"status-page\",\n\t\t\t\"description\": \"Public status page management\"\n\t\t},\n\t\t{\n\t\t\t\"name\": \"settings\",\n\t\t\t\"description\": \"Application configuration settings\"\n\t\t},\n\t\t{\n\t\t\t\"name\": \"logs\",\n\t\t\t\"description\": \"Application logs and diagnostics\"\n\t\t},\n\t\t{\n\t\t\t\"name\": \"notifications\",\n\t\t\t\"description\": \"Notification integrations (email, slack, discord, etc.)\"\n\t\t},\n\t\t{\n\t\t\t\"name\": \"diagnostic\",\n\t\t\t\"description\": \"System health and performance diagnostics\"\n\t\t},\n\t\t{\n\t\t\t\"name\": \"incidents\",\n\t\t\t\"description\": \"Incident management and resolution\"\n\t\t}\n\t],\n\t\"paths\": {\n\t\t\"/auth/register\": {\n\t\t\t\"post\": {\n\t\t\t\t\"tags\": [\"auth\"],\n\t\t\t\t\"summary\": \"Register new user\",\n\t\t\t\t\"description\": \"Register a new user account with profile information\",\n\t\t\t\t\"requestBody\": {\n\t\t\t\t\t\"required\": true,\n\t\t\t\t\t\"content\": {\n\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\t\"$ref\": \"#/components/schemas/RegisterRequest\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"description\": \"User registered successfully\",\n\t\t\t\t\t\t\"content\": {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\t\t\"$ref\": \"#/components/schemas/AuthResponse\"\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"422\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/ValidationError\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"/auth/login\": {\n\t\t\t\"post\": {\n\t\t\t\t\"tags\": [\"auth\"],\n\t\t\t\t\"summary\": \"User login\",\n\t\t\t\t\"description\": \"Authenticate user with email and password\",\n\t\t\t\t\"requestBody\": {\n\t\t\t\t\t\"required\": true,\n\t\t\t\t\t\"content\": {\n\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\t\"$ref\": \"#/components/schemas/LoginRequest\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"description\": \"Login successful\",\n\t\t\t\t\t\t\"content\": {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\t\t\"$ref\": \"#/components/schemas/AuthResponse\"\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"401\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Unauthorized\"\n\t\t\t\t\t},\n\t\t\t\t\t\"422\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/ValidationError\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"/auth/user/{userId}\": {\n\t\t\t\"put\": {\n\t\t\t\t\"tags\": [\"auth\"],\n\t\t\t\t\"summary\": \"Update user profile\",\n\t\t\t\t\"description\": \"Update user information including profile image\",\n\t\t\t\t\"parameters\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"name\": \"userId\",\n\t\t\t\t\t\t\"in\": \"path\",\n\t\t\t\t\t\t\"required\": true,\n\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"requestBody\": {\n\t\t\t\t\t\"required\": true,\n\t\t\t\t\t\"content\": {\n\t\t\t\t\t\t\"multipart/form-data\": {\n\t\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\t\"$ref\": \"#/components/schemas/UserUpdateRequest\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Success\"\n\t\t\t\t\t},\n\t\t\t\t\t\"422\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/ValidationError\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t},\n\t\t\t\"delete\": {\n\t\t\t\t\"tags\": [\"auth\"],\n\t\t\t\t\"summary\": \"Delete user account\",\n\t\t\t\t\"description\": \"Permanently delete user account and associated data\",\n\t\t\t\t\"parameters\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"name\": \"userId\",\n\t\t\t\t\t\t\"in\": \"path\",\n\t\t\t\t\t\t\"required\": true,\n\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Success\"\n\t\t\t\t\t},\n\t\t\t\t\t\"404\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/NotFound\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t\"/auth/users\": {\n\t\t\t\"get\": {\n\t\t\t\t\"tags\": [\"auth\"],\n\t\t\t\t\"summary\": \"Get all users\",\n\t\t\t\t\"description\": \"Retrieve all users (admin/superadmin only)\",\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"description\": \"Users retrieved successfully\",\n\t\t\t\t\t\t\"content\": {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\t\t\"allOf\": [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"$ref\": \"#/components/schemas/SuccessResponse\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"object\",\n\t\t\t\t\t\t\t\t\t\t\t\"properties\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\"data\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"type\": \"array\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"items\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"$ref\": \"#/components/schemas/User\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"403\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Forbidden\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t\"/auth/users/superadmin\": {\n\t\t\t\"get\": {\n\t\t\t\t\"tags\": [\"auth\"],\n\t\t\t\t\"summary\": \"Check superadmin exists\",\n\t\t\t\t\"description\": \"Check if a superadmin account exists in the system\",\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"description\": \"Check completed\",\n\t\t\t\t\t\t\"content\": {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\t\t\"allOf\": [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"$ref\": \"#/components/schemas/SuccessResponse\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"object\",\n\t\t\t\t\t\t\t\t\t\t\t\"properties\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\"data\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"type\": \"object\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"properties\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"exists\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"type\": \"boolean\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"/auth/recovery/request\": {\n\t\t\t\"post\": {\n\t\t\t\t\"tags\": [\"auth\"],\n\t\t\t\t\"summary\": \"Request password reset\",\n\t\t\t\t\"description\": \"Send password reset email to user\",\n\t\t\t\t\"requestBody\": {\n\t\t\t\t\t\"required\": true,\n\t\t\t\t\t\"content\": {\n\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\t\"type\": \"object\",\n\t\t\t\t\t\t\t\t\"required\": [\"email\"],\n\t\t\t\t\t\t\t\t\"properties\": {\n\t\t\t\t\t\t\t\t\t\"email\": {\n\t\t\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\t\t\"format\": \"email\",\n\t\t\t\t\t\t\t\t\t\t\"description\": \"User email address\"\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Success\"\n\t\t\t\t\t},\n\t\t\t\t\t\"404\": {\n\t\t\t\t\t\t\"description\": \"User not found\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"/auth/recovery/validate\": {\n\t\t\t\"post\": {\n\t\t\t\t\"tags\": [\"auth\"],\n\t\t\t\t\"summary\": \"Validate recovery token\",\n\t\t\t\t\"description\": \"Validate password reset token\",\n\t\t\t\t\"requestBody\": {\n\t\t\t\t\t\"required\": true,\n\t\t\t\t\t\"content\": {\n\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\t\"type\": \"object\",\n\t\t\t\t\t\t\t\t\"required\": [\"recoveryToken\"],\n\t\t\t\t\t\t\t\t\"properties\": {\n\t\t\t\t\t\t\t\t\t\"recoveryToken\": {\n\t\t\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\t\t\"description\": \"Password reset token\"\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Success\"\n\t\t\t\t\t},\n\t\t\t\t\t\"400\": {\n\t\t\t\t\t\t\"description\": \"Invalid or expired token\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"/auth/recovery/reset\": {\n\t\t\t\"post\": {\n\t\t\t\t\"tags\": [\"auth\"],\n\t\t\t\t\"summary\": \"Reset password\",\n\t\t\t\t\"description\": \"Reset user password with recovery token\",\n\t\t\t\t\"requestBody\": {\n\t\t\t\t\t\"required\": true,\n\t\t\t\t\t\"content\": {\n\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\t\"type\": \"object\",\n\t\t\t\t\t\t\t\t\"required\": [\"recoveryToken\", \"password\"],\n\t\t\t\t\t\t\t\t\"properties\": {\n\t\t\t\t\t\t\t\t\t\"recoveryToken\": {\n\t\t\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\t\t\"description\": \"Password reset token\"\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\"password\": {\n\t\t\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\t\t\"format\": \"password\",\n\t\t\t\t\t\t\t\t\t\t\"description\": \"New password\"\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Success\"\n\t\t\t\t\t},\n\t\t\t\t\t\"400\": {\n\t\t\t\t\t\t\"description\": \"Invalid token or password requirements not met\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"/monitors\": {\n\t\t\t\"post\": {\n\t\t\t\t\"tags\": [\"monitors\"],\n\t\t\t\t\"summary\": \"Create monitor\",\n\t\t\t\t\"description\": \"Create a new monitoring endpoint\",\n\t\t\t\t\"requestBody\": {\n\t\t\t\t\t\"required\": true,\n\t\t\t\t\t\"content\": {\n\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\t\"$ref\": \"#/components/schemas/CreateMonitorRequest\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"201\": {\n\t\t\t\t\t\t\"description\": \"Monitor created successfully\",\n\t\t\t\t\t\t\"content\": {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\t\t\"allOf\": [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"$ref\": \"#/components/schemas/SuccessResponse\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"object\",\n\t\t\t\t\t\t\t\t\t\t\t\"properties\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\"data\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"$ref\": \"#/components/schemas/Monitor\"\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"422\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/ValidationError\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t},\n\t\t\t\"delete\": {\n\t\t\t\t\"tags\": [\"monitors\"],\n\t\t\t\t\"summary\": \"Delete all monitors\",\n\t\t\t\t\"description\": \"Delete all monitors (superadmin only)\",\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Success\"\n\t\t\t\t\t},\n\t\t\t\t\t\"403\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Forbidden\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t\"/monitors/team\": {\n\t\t\t\"get\": {\n\t\t\t\t\"tags\": [\"monitors\"],\n\t\t\t\t\"summary\": \"Get monitors by team\",\n\t\t\t\t\"description\": \"Get monitors filtered by team with optional parameters\",\n\t\t\t\t\"parameters\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"name\": \"type\",\n\t\t\t\t\t\t\"in\": \"query\",\n\t\t\t\t\t\t\"description\": \"Filter by monitor type\",\n\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\"oneOf\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\t\"enum\": [\"http\", \"ping\", \"pagespeed\", \"docker\", \"hardware\", \"port\", \"game\", \"grpc\", \"websocket\"]\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"type\": \"array\",\n\t\t\t\t\t\t\t\t\t\"items\": {\n\t\t\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\t\t\"enum\": [\"http\", \"ping\", \"pagespeed\", \"docker\", \"hardware\", \"port\", \"game\", \"grpc\", \"websocket\"]\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"name\": \"filter\",\n\t\t\t\t\t\t\"in\": \"query\",\n\t\t\t\t\t\t\"description\": \"Search filter value\",\n\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"description\": \"Team monitors retrieved successfully\",\n\t\t\t\t\t\t\"content\": {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\t\t\"allOf\": [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"$ref\": \"#/components/schemas/SuccessResponse\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"object\",\n\t\t\t\t\t\t\t\t\t\t\t\"properties\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\"data\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"type\": \"object\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"properties\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"monitors\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"type\": \"array\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"items\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"$ref\": \"#/components/schemas/Monitor\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"totalCount\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"type\": \"integer\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t\"/monitors/team/with-checks\": {\n\t\t\t\"get\": {\n\t\t\t\t\"tags\": [\"monitors\"],\n\t\t\t\t\"summary\": \"Get monitors with recent checks\",\n\t\t\t\t\"description\": \"Get team monitors with their most recent check results\",\n\t\t\t\t\"parameters\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"name\": \"limit\",\n\t\t\t\t\t\t\"in\": \"query\",\n\t\t\t\t\t\t\"description\": \"Number of recent checks to include per monitor\",\n\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\"type\": \"integer\",\n\t\t\t\t\t\t\t\"minimum\": 1,\n\t\t\t\t\t\t\t\"maximum\": 50,\n\t\t\t\t\t\t\t\"default\": 10\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"description\": \"Monitors with checks retrieved successfully\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t\"/monitors/team/groups\": {\n\t\t\t\"get\": {\n\t\t\t\t\"tags\": [\"monitors\"],\n\t\t\t\t\"summary\": \"Get monitor groups by team\",\n\t\t\t\t\"description\": \"Get all monitor groups for the authenticated user's team\",\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"description\": \"Monitor groups retrieved successfully\",\n\t\t\t\t\t\t\"content\": {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\t\t\"type\": \"object\",\n\t\t\t\t\t\t\t\t\t\"properties\": {\n\t\t\t\t\t\t\t\t\t\t\"success\": {\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"boolean\",\n\t\t\t\t\t\t\t\t\t\t\t\"example\": true\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\"msg\": {\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\t\t\t\"example\": \"Monitor groups retrieved successfully\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\"data\": {\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"array\",\n\t\t\t\t\t\t\t\t\t\t\t\"items\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\"type\": \"object\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"properties\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"_id\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"name\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"monitors\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"type\": \"array\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"items\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"401\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Unauthorized\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t\"/monitors/{monitorId}\": {\n\t\t\t\"get\": {\n\t\t\t\t\"tags\": [\"monitors\"],\n\t\t\t\t\"summary\": \"Get monitor by ID\",\n\t\t\t\t\"description\": \"Retrieve a specific monitor by its ID\",\n\t\t\t\t\"parameters\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"name\": \"monitorId\",\n\t\t\t\t\t\t\"in\": \"path\",\n\t\t\t\t\t\t\"required\": true,\n\t\t\t\t\t\t\"description\": \"Monitor ID\",\n\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"description\": \"Monitor retrieved successfully\",\n\t\t\t\t\t\t\"content\": {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\t\t\"allOf\": [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"$ref\": \"#/components/schemas/SuccessResponse\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"object\",\n\t\t\t\t\t\t\t\t\t\t\t\"properties\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\"data\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"$ref\": \"#/components/schemas/Monitor\"\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"404\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/NotFound\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t},\n\t\t\t\"patch\": {\n\t\t\t\t\"tags\": [\"monitors\"],\n\t\t\t\t\"summary\": \"Update monitor\",\n\t\t\t\t\"description\": \"Update an existing monitor\",\n\t\t\t\t\"parameters\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"name\": \"monitorId\",\n\t\t\t\t\t\t\"in\": \"path\",\n\t\t\t\t\t\t\"required\": true,\n\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"requestBody\": {\n\t\t\t\t\t\"required\": true,\n\t\t\t\t\t\"content\": {\n\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\t\"$ref\": \"#/components/schemas/UpdateMonitorRequest\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Success\"\n\t\t\t\t\t},\n\t\t\t\t\t\"404\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/NotFound\"\n\t\t\t\t\t},\n\t\t\t\t\t\"422\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/ValidationError\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t},\n\t\t\t\"delete\": {\n\t\t\t\t\"tags\": [\"monitors\"],\n\t\t\t\t\"summary\": \"Delete monitor\",\n\t\t\t\t\"description\": \"Delete a specific monitor\",\n\t\t\t\t\"parameters\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"name\": \"monitorId\",\n\t\t\t\t\t\t\"in\": \"path\",\n\t\t\t\t\t\t\"required\": true,\n\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Success\"\n\t\t\t\t\t},\n\t\t\t\t\t\"404\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/NotFound\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t\"/monitors/uptime/details/{monitorId}\": {\n\t\t\t\"get\": {\n\t\t\t\t\"tags\": [\"monitors\"],\n\t\t\t\t\"summary\": \"Get uptime details\",\n\t\t\t\t\"description\": \"Get detailed uptime statistics for a monitor\",\n\t\t\t\t\"parameters\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"name\": \"monitorId\",\n\t\t\t\t\t\t\"in\": \"path\",\n\t\t\t\t\t\t\"required\": true,\n\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"description\": \"Uptime details retrieved successfully\"\n\t\t\t\t\t},\n\t\t\t\t\t\"404\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/NotFound\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t\"/monitors/hardware/details/{monitorId}\": {\n\t\t\t\"get\": {\n\t\t\t\t\"tags\": [\"monitors\"],\n\t\t\t\t\"summary\": \"Get hardware monitoring details\",\n\t\t\t\t\"description\": \"Get hardware performance metrics for a monitor\",\n\t\t\t\t\"parameters\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"name\": \"monitorId\",\n\t\t\t\t\t\t\"in\": \"path\",\n\t\t\t\t\t\t\"required\": true,\n\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"description\": \"Hardware details retrieved successfully\"\n\t\t\t\t\t},\n\t\t\t\t\t\"404\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/NotFound\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t\"/monitors/pause/{monitorId}\": {\n\t\t\t\"post\": {\n\t\t\t\t\"tags\": [\"monitors\"],\n\t\t\t\t\"summary\": \"Pause/unpause monitor\",\n\t\t\t\t\"description\": \"Toggle monitor active status\",\n\t\t\t\t\"parameters\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"name\": \"monitorId\",\n\t\t\t\t\t\t\"in\": \"path\",\n\t\t\t\t\t\t\"required\": true,\n\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Success\"\n\t\t\t\t\t},\n\t\t\t\t\t\"404\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/NotFound\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t\"/monitors/pagespeed/details/{monitorId}\": {\n\t\t\t\"get\": {\n\t\t\t\t\"tags\": [\"monitors\"],\n\t\t\t\t\"summary\": \"Get PageSpeed monitor details\",\n\t\t\t\t\"description\": \"Get detailed PageSpeed monitoring data including performance metrics and Core Web Vitals\",\n\t\t\t\t\"parameters\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"name\": \"monitorId\",\n\t\t\t\t\t\t\"in\": \"path\",\n\t\t\t\t\t\t\"required\": true,\n\t\t\t\t\t\t\"description\": \"The PageSpeed monitor ID\",\n\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"name\": \"sortOrder\",\n\t\t\t\t\t\t\"in\": \"query\",\n\t\t\t\t\t\t\"description\": \"Sort order for results\",\n\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\"enum\": [\"asc\", \"desc\"],\n\t\t\t\t\t\t\t\"default\": \"desc\"\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"name\": \"limit\",\n\t\t\t\t\t\t\"in\": \"query\",\n\t\t\t\t\t\t\"description\": \"Number of results to return\",\n\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\"type\": \"integer\",\n\t\t\t\t\t\t\t\"default\": 50\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"description\": \"PageSpeed details retrieved successfully\",\n\t\t\t\t\t\t\"content\": {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\t\t\"type\": \"object\",\n\t\t\t\t\t\t\t\t\t\"properties\": {\n\t\t\t\t\t\t\t\t\t\t\"success\": {\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"boolean\",\n\t\t\t\t\t\t\t\t\t\t\t\"example\": true\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\"msg\": {\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\t\t\t\"example\": \"PageSpeed details retrieved successfully\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\"data\": {\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"object\",\n\t\t\t\t\t\t\t\t\t\t\t\"properties\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\"monitor\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"$ref\": \"#/components/schemas/Monitor\"\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\"checks\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"type\": \"array\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"items\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"$ref\": \"#/components/schemas/Check\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"401\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Unauthorized\"\n\t\t\t\t\t},\n\t\t\t\t\t\"404\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/NotFound\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t\"/monitors/certificate/{monitorId}\": {\n\t\t\t\"get\": {\n\t\t\t\t\"tags\": [\"monitors\"],\n\t\t\t\t\"summary\": \"Get SSL certificate info\",\n\t\t\t\t\"description\": \"Get SSL certificate information for a monitor\",\n\t\t\t\t\"parameters\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"name\": \"monitorId\",\n\t\t\t\t\t\t\"in\": \"path\",\n\t\t\t\t\t\t\"required\": true,\n\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"description\": \"Certificate information retrieved successfully\"\n\t\t\t\t\t},\n\t\t\t\t\t\"404\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/NotFound\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t\"/monitors/demo\": {\n\t\t\t\"post\": {\n\t\t\t\t\"tags\": [\"monitors\"],\n\t\t\t\t\"summary\": \"Add demo monitors\",\n\t\t\t\t\"description\": \"Add preconfigured demo monitors for testing\",\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Success\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t\"/monitors/export/json\": {\n\t\t\t\"get\": {\n\t\t\t\t\"tags\": [\"monitors\"],\n\t\t\t\t\"summary\": \"Export monitors to JSON\",\n\t\t\t\t\"description\": \"Export all monitors to JSON format (admin/superadmin only)\",\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"description\": \"JSON file generated successfully\",\n\t\t\t\t\t\t\"content\": {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\t\t\"type\": \"object\",\n\t\t\t\t\t\t\t\t\t\"properties\": {\n\t\t\t\t\t\t\t\t\t\t\"success\": {\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"boolean\",\n\t\t\t\t\t\t\t\t\t\t\t\"example\": true\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\"msg\": {\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\t\t\t\"example\": \"Monitors exported successfully\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\"data\": {\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"array\",\n\t\t\t\t\t\t\t\t\t\t\t\"items\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\"$ref\": \"#/components/schemas/Monitor\"\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"401\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Unauthorized\"\n\t\t\t\t\t},\n\t\t\t\t\t\"403\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Forbidden\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t\"/monitors/bulk\": {\n\t\t\t\"post\": {\n\t\t\t\t\"tags\": [\"monitors\"],\n\t\t\t\t\"summary\": \"Bulk import monitors\",\n\t\t\t\t\"description\": \"Import monitors from CSV file\",\n\t\t\t\t\"requestBody\": {\n\t\t\t\t\t\"required\": true,\n\t\t\t\t\t\"content\": {\n\t\t\t\t\t\t\"multipart/form-data\": {\n\t\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\t\"type\": \"object\",\n\t\t\t\t\t\t\t\t\"properties\": {\n\t\t\t\t\t\t\t\t\t\"csvFile\": {\n\t\t\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\t\t\"format\": \"binary\",\n\t\t\t\t\t\t\t\t\t\t\"description\": \"CSV file containing monitor data\"\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"description\": \"Monitors imported successfully\"\n\t\t\t\t\t},\n\t\t\t\t\t\"422\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/ValidationError\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t\"/monitors/test-email\": {\n\t\t\t\"post\": {\n\t\t\t\t\"tags\": [\"monitors\"],\n\t\t\t\t\"summary\": \"Send test email\",\n\t\t\t\t\"description\": \"Send a test email notification\",\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Success\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t\"/settings\": {\n\t\t\t\"get\": {\n\t\t\t\t\"tags\": [\"settings\"],\n\t\t\t\t\"summary\": \"Get application settings\",\n\t\t\t\t\"description\": \"Retrieve current application configuration\",\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"description\": \"Settings retrieved successfully\",\n\t\t\t\t\t\t\"content\": {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\t\t\"allOf\": [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"$ref\": \"#/components/schemas/SuccessResponse\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"object\",\n\t\t\t\t\t\t\t\t\t\t\t\"properties\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\"data\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"$ref\": \"#/components/schemas/AppSettings\"\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t},\n\t\t\t\"put\": {\n\t\t\t\t\"tags\": [\"settings\"],\n\t\t\t\t\"summary\": \"Update application settings\",\n\t\t\t\t\"description\": \"Update application configuration (admin/superadmin only)\",\n\t\t\t\t\"requestBody\": {\n\t\t\t\t\t\"required\": true,\n\t\t\t\t\t\"content\": {\n\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\t\"$ref\": \"#/components/schemas/AppSettings\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Success\"\n\t\t\t\t\t},\n\t\t\t\t\t\"403\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Forbidden\"\n\t\t\t\t\t},\n\t\t\t\t\t\"422\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/ValidationError\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t\"/settings/test-email\": {\n\t\t\t\"post\": {\n\t\t\t\t\"tags\": [\"settings\"],\n\t\t\t\t\"summary\": \"Send test email\",\n\t\t\t\t\"description\": \"Send test email to verify email configuration\",\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Success\"\n\t\t\t\t\t},\n\t\t\t\t\t\"403\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Forbidden\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t\"/notifications\": {\n\t\t\t\"post\": {\n\t\t\t\t\"tags\": [\"notifications\"],\n\t\t\t\t\"summary\": \"Create notification\",\n\t\t\t\t\"description\": \"Create a new notification integration\",\n\t\t\t\t\"requestBody\": {\n\t\t\t\t\t\"required\": true,\n\t\t\t\t\t\"content\": {\n\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\t\"$ref\": \"#/components/schemas/CreateNotificationRequest\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"201\": {\n\t\t\t\t\t\t\"description\": \"Notification created successfully\"\n\t\t\t\t\t},\n\t\t\t\t\t\"422\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/ValidationError\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t\"/notifications/team\": {\n\t\t\t\"get\": {\n\t\t\t\t\"tags\": [\"notifications\"],\n\t\t\t\t\"summary\": \"Get team notifications\",\n\t\t\t\t\"description\": \"Get all notification configurations for the team\",\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"description\": \"Notifications retrieved successfully\",\n\t\t\t\t\t\t\"content\": {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\t\t\"allOf\": [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"$ref\": \"#/components/schemas/SuccessResponse\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"object\",\n\t\t\t\t\t\t\t\t\t\t\t\"properties\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\"data\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"type\": \"array\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"items\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"$ref\": \"#/components/schemas/Notification\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t\"/notifications/{id}\": {\n\t\t\t\"get\": {\n\t\t\t\t\"tags\": [\"notifications\"],\n\t\t\t\t\"summary\": \"Get notification by ID\",\n\t\t\t\t\"description\": \"Retrieve a specific notification configuration\",\n\t\t\t\t\"parameters\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"name\": \"id\",\n\t\t\t\t\t\t\"in\": \"path\",\n\t\t\t\t\t\t\"required\": true,\n\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"description\": \"Notification retrieved successfully\"\n\t\t\t\t\t},\n\t\t\t\t\t\"404\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/NotFound\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t},\n\t\t\t\"put\": {\n\t\t\t\t\"tags\": [\"notifications\"],\n\t\t\t\t\"summary\": \"Update notification\",\n\t\t\t\t\"description\": \"Update an existing notification configuration\",\n\t\t\t\t\"parameters\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"name\": \"id\",\n\t\t\t\t\t\t\"in\": \"path\",\n\t\t\t\t\t\t\"required\": true,\n\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"requestBody\": {\n\t\t\t\t\t\"required\": true,\n\t\t\t\t\t\"content\": {\n\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\t\"$ref\": \"#/components/schemas/CreateNotificationRequest\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Success\"\n\t\t\t\t\t},\n\t\t\t\t\t\"404\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/NotFound\"\n\t\t\t\t\t},\n\t\t\t\t\t\"422\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/ValidationError\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t},\n\t\t\t\"delete\": {\n\t\t\t\t\"tags\": [\"notifications\"],\n\t\t\t\t\"summary\": \"Delete notification\",\n\t\t\t\t\"description\": \"Delete a notification configuration\",\n\t\t\t\t\"parameters\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"name\": \"id\",\n\t\t\t\t\t\t\"in\": \"path\",\n\t\t\t\t\t\t\"required\": true,\n\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Success\"\n\t\t\t\t\t},\n\t\t\t\t\t\"404\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/NotFound\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t\"/notifications/test\": {\n\t\t\t\"post\": {\n\t\t\t\t\"tags\": [\"notifications\"],\n\t\t\t\t\"summary\": \"Test notification\",\n\t\t\t\t\"description\": \"Send a test notification to verify configuration\",\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Success\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t\"/notifications/test/all\": {\n\t\t\t\"post\": {\n\t\t\t\t\"tags\": [\"notifications\"],\n\t\t\t\t\"summary\": \"Test all notifications\",\n\t\t\t\t\"description\": \"Send test notifications to all configured integrations\",\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Success\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t\"/logs\": {\n\t\t\t\"get\": {\n\t\t\t\t\"tags\": [\"logs\"],\n\t\t\t\t\"summary\": \"Get application logs\",\n\t\t\t\t\"description\": \"Retrieve application logs (admin/superadmin only)\",\n\t\t\t\t\"parameters\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"name\": \"level\",\n\t\t\t\t\t\t\"in\": \"query\",\n\t\t\t\t\t\t\"description\": \"Log level filter\",\n\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\"enum\": [\"error\", \"warn\", \"info\", \"debug\"]\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"name\": \"limit\",\n\t\t\t\t\t\t\"in\": \"query\",\n\t\t\t\t\t\t\"description\": \"Number of log entries to return\",\n\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\"type\": \"integer\",\n\t\t\t\t\t\t\t\"minimum\": 1,\n\t\t\t\t\t\t\t\"maximum\": 1000,\n\t\t\t\t\t\t\t\"default\": 100\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"description\": \"Logs retrieved successfully\"\n\t\t\t\t\t},\n\t\t\t\t\t\"403\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Forbidden\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t\"/diagnostic/system\": {\n\t\t\t\"get\": {\n\t\t\t\t\"tags\": [\"diagnostic\"],\n\t\t\t\t\"summary\": \"Get system diagnostics\",\n\t\t\t\t\"description\": \"Get system health and performance metrics (admin/superadmin only)\",\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"description\": \"System diagnostics retrieved successfully\",\n\t\t\t\t\t\t\"content\": {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\t\t\"allOf\": [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"$ref\": \"#/components/schemas/SuccessResponse\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"object\",\n\t\t\t\t\t\t\t\t\t\t\t\"properties\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\"data\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"$ref\": \"#/components/schemas/SystemDiagnostics\"\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"403\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Forbidden\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t\"/auth/user\": {\n\t\t\t\"put\": {\n\t\t\t\t\"tags\": [\"auth\"],\n\t\t\t\t\"summary\": \"Update current user profile\",\n\t\t\t\t\"description\": \"Update authenticated user's profile information\",\n\t\t\t\t\"requestBody\": {\n\t\t\t\t\t\"required\": true,\n\t\t\t\t\t\"content\": {\n\t\t\t\t\t\t\"multipart/form-data\": {\n\t\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\t\"$ref\": \"#/components/schemas/UserUpdateRequest\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Success\"\n\t\t\t\t\t},\n\t\t\t\t\t\"422\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/ValidationError\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t},\n\t\t\t\"delete\": {\n\t\t\t\t\"tags\": [\"auth\"],\n\t\t\t\t\"summary\": \"Delete current user account\",\n\t\t\t\t\"description\": \"Delete authenticated user's account and associated data\",\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Success\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t\"/auth/users/{userId}\": {\n\t\t\t\"get\": {\n\t\t\t\t\"tags\": [\"auth\"],\n\t\t\t\t\"summary\": \"Get user by ID\",\n\t\t\t\t\"description\": \"Get a specific user by ID (superadmin only)\",\n\t\t\t\t\"parameters\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"name\": \"userId\",\n\t\t\t\t\t\t\"in\": \"path\",\n\t\t\t\t\t\t\"required\": true,\n\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"description\": \"User retrieved successfully\",\n\t\t\t\t\t\t\"content\": {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\t\t\"allOf\": [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"$ref\": \"#/components/schemas/SuccessResponse\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"object\",\n\t\t\t\t\t\t\t\t\t\t\t\"properties\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\"data\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"$ref\": \"#/components/schemas/User\"\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"404\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/NotFound\"\n\t\t\t\t\t},\n\t\t\t\t\t\"403\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Forbidden\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t},\n\t\t\t\"put\": {\n\t\t\t\t\"tags\": [\"auth\"],\n\t\t\t\t\"summary\": \"Update user by ID\",\n\t\t\t\t\"description\": \"Update a specific user by ID (superadmin only)\",\n\t\t\t\t\"parameters\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"name\": \"userId\",\n\t\t\t\t\t\t\"in\": \"path\",\n\t\t\t\t\t\t\"required\": true,\n\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"requestBody\": {\n\t\t\t\t\t\"required\": true,\n\t\t\t\t\t\"content\": {\n\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\t\"$ref\": \"#/components/schemas/UserUpdateRequest\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Success\"\n\t\t\t\t\t},\n\t\t\t\t\t\"404\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/NotFound\"\n\t\t\t\t\t},\n\t\t\t\t\t\"403\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Forbidden\"\n\t\t\t\t\t},\n\t\t\t\t\t\"422\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/ValidationError\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t\"/auth/users/{userId}/password\": {\n\t\t\t\"put\": {\n\t\t\t\t\"tags\": [\"auth\"],\n\t\t\t\t\"summary\": \"Update user password by ID\",\n\t\t\t\t\"description\": \"Update a specific user's password by ID (superadmin only)\",\n\t\t\t\t\"parameters\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"name\": \"userId\",\n\t\t\t\t\t\t\"in\": \"path\",\n\t\t\t\t\t\t\"required\": true,\n\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"requestBody\": {\n\t\t\t\t\t\"required\": true,\n\t\t\t\t\t\"content\": {\n\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\t\"type\": \"object\",\n\t\t\t\t\t\t\t\t\"required\": [\"password\"],\n\t\t\t\t\t\t\t\t\"properties\": {\n\t\t\t\t\t\t\t\t\t\"password\": {\n\t\t\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\t\t\"format\": \"password\",\n\t\t\t\t\t\t\t\t\t\t\"minLength\": 8,\n\t\t\t\t\t\t\t\t\t\t\"description\": \"New password for the user\"\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Success\"\n\t\t\t\t\t},\n\t\t\t\t\t\"404\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/NotFound\"\n\t\t\t\t\t},\n\t\t\t\t\t\"403\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Forbidden\"\n\t\t\t\t\t},\n\t\t\t\t\t\"422\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/ValidationError\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t\"/invite\": {\n\t\t\t\"post\": {\n\t\t\t\t\"tags\": [\"invite\"],\n\t\t\t\t\"summary\": \"Create invite token\",\n\t\t\t\t\"description\": \"Create a new invitation token\",\n\t\t\t\t\"requestBody\": {\n\t\t\t\t\t\"required\": true,\n\t\t\t\t\t\"content\": {\n\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\t\"type\": \"object\",\n\t\t\t\t\t\t\t\t\"required\": [\"email\", \"role\"],\n\t\t\t\t\t\t\t\t\"properties\": {\n\t\t\t\t\t\t\t\t\t\"email\": {\n\t\t\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\t\t\"format\": \"email\"\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\"role\": {\n\t\t\t\t\t\t\t\t\t\t\"type\": \"array\",\n\t\t\t\t\t\t\t\t\t\t\"items\": {\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\t\t\t\"enum\": [\"user\", \"admin\"]\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"201\": {\n\t\t\t\t\t\t\"description\": \"Invite token created successfully\"\n\t\t\t\t\t},\n\t\t\t\t\t\"403\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Forbidden\"\n\t\t\t\t\t},\n\t\t\t\t\t\"422\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/ValidationError\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t\"/invite/send\": {\n\t\t\t\"post\": {\n\t\t\t\t\"tags\": [\"invite\"],\n\t\t\t\t\"summary\": \"Send invitation email\",\n\t\t\t\t\"description\": \"Send invitation email to user\",\n\t\t\t\t\"requestBody\": {\n\t\t\t\t\t\"required\": true,\n\t\t\t\t\t\"content\": {\n\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\t\"type\": \"object\",\n\t\t\t\t\t\t\t\t\"required\": [\"email\"],\n\t\t\t\t\t\t\t\t\"properties\": {\n\t\t\t\t\t\t\t\t\t\"email\": {\n\t\t\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\t\t\"format\": \"email\"\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Success\"\n\t\t\t\t\t},\n\t\t\t\t\t\"403\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Forbidden\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t\"/invite/verify\": {\n\t\t\t\"post\": {\n\t\t\t\t\"tags\": [\"invite\"],\n\t\t\t\t\"summary\": \"Verify invitation token\",\n\t\t\t\t\"description\": \"Verify an invitation token\",\n\t\t\t\t\"requestBody\": {\n\t\t\t\t\t\"required\": true,\n\t\t\t\t\t\"content\": {\n\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\t\"type\": \"object\",\n\t\t\t\t\t\t\t\t\"required\": [\"token\"],\n\t\t\t\t\t\t\t\t\"properties\": {\n\t\t\t\t\t\t\t\t\t\"token\": {\n\t\t\t\t\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Success\"\n\t\t\t\t\t},\n\t\t\t\t\t\"400\": {\n\t\t\t\t\t\t\"description\": \"Invalid or expired token\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"/checks/{monitorId}\": {\n\t\t\t\"get\": {\n\t\t\t\t\"tags\": [\"checks\"],\n\t\t\t\t\"summary\": \"Get checks by monitor\",\n\t\t\t\t\"description\": \"Get all checks for a specific monitor\",\n\t\t\t\t\"parameters\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"name\": \"monitorId\",\n\t\t\t\t\t\t\"in\": \"path\",\n\t\t\t\t\t\t\"required\": true,\n\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"description\": \"Checks retrieved successfully\"\n\t\t\t\t\t},\n\t\t\t\t\t\"404\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/NotFound\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t},\n\t\t\t\"delete\": {\n\t\t\t\t\"tags\": [\"checks\"],\n\t\t\t\t\"summary\": \"Delete checks by monitor\",\n\t\t\t\t\"description\": \"Delete all checks for a specific monitor\",\n\t\t\t\t\"parameters\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"name\": \"monitorId\",\n\t\t\t\t\t\t\"in\": \"path\",\n\t\t\t\t\t\t\"required\": true,\n\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Success\"\n\t\t\t\t\t},\n\t\t\t\t\t\"404\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/NotFound\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t\"/checks/team\": {\n\t\t\t\"get\": {\n\t\t\t\t\"tags\": [\"checks\"],\n\t\t\t\t\"summary\": \"Get checks by team\",\n\t\t\t\t\"description\": \"Get all checks for team monitors\",\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"description\": \"Team checks retrieved successfully\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t},\n\t\t\t\"delete\": {\n\t\t\t\t\"tags\": [\"checks\"],\n\t\t\t\t\"summary\": \"Delete team checks\",\n\t\t\t\t\"description\": \"Delete all checks for team (admin/superadmin only)\",\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Success\"\n\t\t\t\t\t},\n\t\t\t\t\t\"403\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Forbidden\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t\"/checks/team/summary\": {\n\t\t\t\"get\": {\n\t\t\t\t\"tags\": [\"checks\"],\n\t\t\t\t\"summary\": \"Get team checks summary\",\n\t\t\t\t\"description\": \"Get summary statistics for team checks\",\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"description\": \"Team checks summary retrieved successfully\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t\"/checks/team/ttl\": {\n\t\t\t\"put\": {\n\t\t\t\t\"tags\": [\"checks\"],\n\t\t\t\t\"summary\": \"Update checks TTL\",\n\t\t\t\t\"description\": \"Update time-to-live for checks (admin/superadmin only)\",\n\t\t\t\t\"requestBody\": {\n\t\t\t\t\t\"required\": true,\n\t\t\t\t\t\"content\": {\n\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\t\"type\": \"object\",\n\t\t\t\t\t\t\t\t\"required\": [\"ttl\"],\n\t\t\t\t\t\t\t\t\"properties\": {\n\t\t\t\t\t\t\t\t\t\"ttl\": {\n\t\t\t\t\t\t\t\t\t\t\"type\": \"integer\",\n\t\t\t\t\t\t\t\t\t\t\"minimum\": 1,\n\t\t\t\t\t\t\t\t\t\t\"description\": \"Time to live in days\"\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Success\"\n\t\t\t\t\t},\n\t\t\t\t\t\"403\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Forbidden\"\n\t\t\t\t\t},\n\t\t\t\t\t\"422\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/ValidationError\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t\"/checks/check/{checkId}\": {\n\t\t\t\"put\": {\n\t\t\t\t\"tags\": [\"checks\"],\n\t\t\t\t\"summary\": \"Acknowledge check\",\n\t\t\t\t\"description\": \"Acknowledge a specific check\",\n\t\t\t\t\"parameters\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"name\": \"checkId\",\n\t\t\t\t\t\t\"in\": \"path\",\n\t\t\t\t\t\t\"required\": true,\n\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"requestBody\": {\n\t\t\t\t\t\"content\": {\n\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\t\"type\": \"object\",\n\t\t\t\t\t\t\t\t\"properties\": {\n\t\t\t\t\t\t\t\t\t\"ack\": {\n\t\t\t\t\t\t\t\t\t\t\"type\": \"boolean\",\n\t\t\t\t\t\t\t\t\t\t\"description\": \"Acknowledgement status\"\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Success\"\n\t\t\t\t\t},\n\t\t\t\t\t\"404\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/NotFound\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t\"/checks/{action}\": {\n\t\t\t\"put\": {\n\t\t\t\t\"tags\": [\"checks\"],\n\t\t\t\t\"summary\": \"Acknowledge all checks for all monitors\",\n\t\t\t\t\"description\": \"Acknowledge all checks across all monitors for the team\",\n\t\t\t\t\"parameters\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"name\": \"action\",\n\t\t\t\t\t\t\"in\": \"path\",\n\t\t\t\t\t\t\"required\": true,\n\t\t\t\t\t\t\"description\": \"Action to perform (e.g., 'ack')\",\n\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\"enum\": [\"ack\"]\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"requestBody\": {\n\t\t\t\t\t\"required\": true,\n\t\t\t\t\t\"content\": {\n\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\t\"type\": \"object\",\n\t\t\t\t\t\t\t\t\"required\": [\"ack\"],\n\t\t\t\t\t\t\t\t\"properties\": {\n\t\t\t\t\t\t\t\t\t\"ack\": {\n\t\t\t\t\t\t\t\t\t\t\"type\": \"boolean\",\n\t\t\t\t\t\t\t\t\t\t\"description\": \"Acknowledgement status to set\"\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"description\": \"Checks acknowledged successfully\",\n\t\t\t\t\t\t\"content\": {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\t\t\"type\": \"object\",\n\t\t\t\t\t\t\t\t\t\"properties\": {\n\t\t\t\t\t\t\t\t\t\t\"success\": {\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"boolean\",\n\t\t\t\t\t\t\t\t\t\t\t\"example\": true\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\"msg\": {\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\t\t\t\"example\": \"All checks acknowledged successfully\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\"data\": {\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"object\",\n\t\t\t\t\t\t\t\t\t\t\t\"description\": \"Updated checks information\"\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"401\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Unauthorized\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t\"/checks/{action}/{monitorId}\": {\n\t\t\t\"put\": {\n\t\t\t\t\"tags\": [\"checks\"],\n\t\t\t\t\"summary\": \"Acknowledge all checks for a specific monitor\",\n\t\t\t\t\"description\": \"Acknowledge all checks for a specific monitor\",\n\t\t\t\t\"parameters\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"name\": \"action\",\n\t\t\t\t\t\t\"in\": \"path\",\n\t\t\t\t\t\t\"required\": true,\n\t\t\t\t\t\t\"description\": \"Action to perform (e.g., 'ack')\",\n\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\"enum\": [\"ack\"]\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"name\": \"monitorId\",\n\t\t\t\t\t\t\"in\": \"path\",\n\t\t\t\t\t\t\"required\": true,\n\t\t\t\t\t\t\"description\": \"Monitor ID to acknowledge checks for\",\n\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"requestBody\": {\n\t\t\t\t\t\"required\": true,\n\t\t\t\t\t\"content\": {\n\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\t\"type\": \"object\",\n\t\t\t\t\t\t\t\t\"required\": [\"ack\"],\n\t\t\t\t\t\t\t\t\"properties\": {\n\t\t\t\t\t\t\t\t\t\"ack\": {\n\t\t\t\t\t\t\t\t\t\t\"type\": \"boolean\",\n\t\t\t\t\t\t\t\t\t\t\"description\": \"Acknowledgement status to set\"\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"description\": \"Checks acknowledged successfully\",\n\t\t\t\t\t\t\"content\": {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\t\t\"type\": \"object\",\n\t\t\t\t\t\t\t\t\t\"properties\": {\n\t\t\t\t\t\t\t\t\t\t\"success\": {\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"boolean\",\n\t\t\t\t\t\t\t\t\t\t\t\"example\": true\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\"msg\": {\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\t\t\t\"example\": \"All checks acknowledged successfully\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\"data\": {\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"object\",\n\t\t\t\t\t\t\t\t\t\t\t\"description\": \"Updated checks information\"\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"401\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Unauthorized\"\n\t\t\t\t\t},\n\t\t\t\t\t\"404\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/NotFound\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t\"/maintenance-window\": {\n\t\t\t\"post\": {\n\t\t\t\t\"tags\": [\"maintenance-window\"],\n\t\t\t\t\"summary\": \"Create maintenance window\",\n\t\t\t\t\"description\": \"Create a new maintenance window\",\n\t\t\t\t\"requestBody\": {\n\t\t\t\t\t\"required\": true,\n\t\t\t\t\t\"content\": {\n\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\t\"type\": \"object\",\n\t\t\t\t\t\t\t\t\"required\": [\"name\", \"startTime\", \"endTime\"],\n\t\t\t\t\t\t\t\t\"properties\": {\n\t\t\t\t\t\t\t\t\t\"name\": {\n\t\t\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\t\t\"maxLength\": 100\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\"description\": {\n\t\t\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\t\t\"maxLength\": 500\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\"startTime\": {\n\t\t\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\t\t\"format\": \"date-time\"\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\"endTime\": {\n\t\t\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\t\t\"format\": \"date-time\"\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\"monitors\": {\n\t\t\t\t\t\t\t\t\t\t\"type\": \"array\",\n\t\t\t\t\t\t\t\t\t\t\"items\": {\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"201\": {\n\t\t\t\t\t\t\"description\": \"Maintenance window created successfully\"\n\t\t\t\t\t},\n\t\t\t\t\t\"422\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/ValidationError\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t\"/maintenance-window/team\": {\n\t\t\t\"get\": {\n\t\t\t\t\"tags\": [\"maintenance-window\"],\n\t\t\t\t\"summary\": \"Get team maintenance windows\",\n\t\t\t\t\"description\": \"Get all maintenance windows for the team\",\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"description\": \"Maintenance windows retrieved successfully\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t\"/maintenance-window/monitor/{monitorId}\": {\n\t\t\t\"get\": {\n\t\t\t\t\"tags\": [\"maintenance-window\"],\n\t\t\t\t\"summary\": \"Get maintenance windows by monitor\",\n\t\t\t\t\"description\": \"Get all maintenance windows for a specific monitor\",\n\t\t\t\t\"parameters\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"name\": \"monitorId\",\n\t\t\t\t\t\t\"in\": \"path\",\n\t\t\t\t\t\t\"required\": true,\n\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"description\": \"Monitor maintenance windows retrieved successfully\"\n\t\t\t\t\t},\n\t\t\t\t\t\"404\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/NotFound\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t\"/maintenance-window/{id}\": {\n\t\t\t\"get\": {\n\t\t\t\t\"tags\": [\"maintenance-window\"],\n\t\t\t\t\"summary\": \"Get maintenance window by ID\",\n\t\t\t\t\"description\": \"Get a specific maintenance window\",\n\t\t\t\t\"parameters\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"name\": \"id\",\n\t\t\t\t\t\t\"in\": \"path\",\n\t\t\t\t\t\t\"required\": true,\n\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"description\": \"Maintenance window retrieved successfully\"\n\t\t\t\t\t},\n\t\t\t\t\t\"404\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/NotFound\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t},\n\t\t\t\"put\": {\n\t\t\t\t\"tags\": [\"maintenance-window\"],\n\t\t\t\t\"summary\": \"Update maintenance window\",\n\t\t\t\t\"description\": \"Update an existing maintenance window\",\n\t\t\t\t\"parameters\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"name\": \"id\",\n\t\t\t\t\t\t\"in\": \"path\",\n\t\t\t\t\t\t\"required\": true,\n\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"requestBody\": {\n\t\t\t\t\t\"required\": true,\n\t\t\t\t\t\"content\": {\n\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\t\"type\": \"object\",\n\t\t\t\t\t\t\t\t\"properties\": {\n\t\t\t\t\t\t\t\t\t\"name\": {\n\t\t\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\t\t\"maxLength\": 100\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\"description\": {\n\t\t\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\t\t\"maxLength\": 500\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\"startTime\": {\n\t\t\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\t\t\"format\": \"date-time\"\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\"endTime\": {\n\t\t\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\t\t\"format\": \"date-time\"\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\"monitors\": {\n\t\t\t\t\t\t\t\t\t\t\"type\": \"array\",\n\t\t\t\t\t\t\t\t\t\t\"items\": {\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Success\"\n\t\t\t\t\t},\n\t\t\t\t\t\"404\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/NotFound\"\n\t\t\t\t\t},\n\t\t\t\t\t\"422\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/ValidationError\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t},\n\t\t\t\"delete\": {\n\t\t\t\t\"tags\": [\"maintenance-window\"],\n\t\t\t\t\"summary\": \"Delete maintenance window\",\n\t\t\t\t\"description\": \"Delete a specific maintenance window\",\n\t\t\t\t\"parameters\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"name\": \"id\",\n\t\t\t\t\t\t\"in\": \"path\",\n\t\t\t\t\t\t\"required\": true,\n\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Success\"\n\t\t\t\t\t},\n\t\t\t\t\t\"404\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/NotFound\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t\"/queue/jobs\": {\n\t\t\t\"get\": {\n\t\t\t\t\"tags\": [\"queue\"],\n\t\t\t\t\"summary\": \"Get queue jobs\",\n\t\t\t\t\"description\": \"Retrieve all jobs in the queue (admin/superadmin only)\",\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"description\": \"Queue jobs retrieved successfully\",\n\t\t\t\t\t\t\"content\": {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\t\t\"type\": \"object\",\n\t\t\t\t\t\t\t\t\t\"properties\": {\n\t\t\t\t\t\t\t\t\t\t\"success\": {\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"boolean\",\n\t\t\t\t\t\t\t\t\t\t\t\"example\": true\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\"msg\": {\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\t\t\t\"example\": \"Queue jobs fetched successfully\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\"data\": {\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"array\",\n\t\t\t\t\t\t\t\t\t\t\t\"items\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\"$ref\": \"#/components/schemas/QueueJob\"\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"401\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Unauthorized\"\n\t\t\t\t\t},\n\t\t\t\t\t\"403\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Forbidden\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t},\n\t\t\t\"post\": {\n\t\t\t\t\"tags\": [\"queue\"],\n\t\t\t\t\"summary\": \"Add job to queue\",\n\t\t\t\t\"description\": \"Add a new job to the queue (admin/superadmin only)\",\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"description\": \"Job added successfully\",\n\t\t\t\t\t\t\"content\": {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\t\t\"type\": \"object\",\n\t\t\t\t\t\t\t\t\t\"properties\": {\n\t\t\t\t\t\t\t\t\t\t\"success\": {\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"boolean\",\n\t\t\t\t\t\t\t\t\t\t\t\"example\": true\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\"msg\": {\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\t\t\t\"example\": \"Job added to queue successfully\"\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"401\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Unauthorized\"\n\t\t\t\t\t},\n\t\t\t\t\t\"403\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Forbidden\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t\"/queue/metrics\": {\n\t\t\t\"get\": {\n\t\t\t\t\"tags\": [\"queue\"],\n\t\t\t\t\"summary\": \"Get queue metrics\",\n\t\t\t\t\"description\": \"Retrieve queue metrics (admin/superadmin only)\",\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"description\": \"Queue metrics retrieved successfully\",\n\t\t\t\t\t\t\"content\": {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\t\t\"type\": \"object\",\n\t\t\t\t\t\t\t\t\t\"properties\": {\n\t\t\t\t\t\t\t\t\t\t\"success\": {\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"boolean\",\n\t\t\t\t\t\t\t\t\t\t\t\"example\": true\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\"msg\": {\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\t\t\t\"example\": \"Queue metrics fetched successfully\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\"data\": {\n\t\t\t\t\t\t\t\t\t\t\t\"$ref\": \"#/components/schemas/QueueMetrics\"\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"401\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Unauthorized\"\n\t\t\t\t\t},\n\t\t\t\t\t\"403\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Forbidden\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t\"/queue/health\": {\n\t\t\t\"get\": {\n\t\t\t\t\"tags\": [\"queue\"],\n\t\t\t\t\"summary\": \"Check queue health\",\n\t\t\t\t\"description\": \"Check the health status of the job queue (admin/superadmin only)\",\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"description\": \"Queue health status retrieved successfully\"\n\t\t\t\t\t},\n\t\t\t\t\t\"403\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Forbidden\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t\"/queue/all-metrics\": {\n\t\t\t\"get\": {\n\t\t\t\t\"tags\": [\"queue\"],\n\t\t\t\t\"summary\": \"Get all queue metrics\",\n\t\t\t\t\"description\": \"Get comprehensive queue metrics (admin/superadmin only)\",\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"description\": \"All queue metrics retrieved successfully\"\n\t\t\t\t\t},\n\t\t\t\t\t\"403\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Forbidden\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t\"/queue/flush\": {\n\t\t\t\"post\": {\n\t\t\t\t\"tags\": [\"queue\"],\n\t\t\t\t\"summary\": \"Flush queue\",\n\t\t\t\t\"description\": \"Clear all jobs from the queue (admin/superadmin only)\",\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Success\"\n\t\t\t\t\t},\n\t\t\t\t\t\"403\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Forbidden\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t\"/monitors/games\": {\n\t\t\t\"get\": {\n\t\t\t\t\"tags\": [\"monitors\"],\n\t\t\t\t\"summary\": \"Get game server list\",\n\t\t\t\t\"description\": \"Get available game servers for monitoring\",\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"description\": \"Game servers retrieved successfully\",\n\t\t\t\t\t\t\"content\": {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\t\t\"allOf\": [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"$ref\": \"#/components/schemas/SuccessResponse\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"object\",\n\t\t\t\t\t\t\t\t\t\t\t\"properties\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\"data\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"type\": \"array\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"items\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"type\": \"object\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"properties\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"id\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"name\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t\"/status-page\": {\n\t\t\t\"get\": {\n\t\t\t\t\"tags\": [\"status-page\"],\n\t\t\t\t\"summary\": \"Get status page\",\n\t\t\t\t\"description\": \"Get default status page information\",\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Success\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"post\": {\n\t\t\t\t\"tags\": [\"status-page\"],\n\t\t\t\t\"summary\": \"Create status page\",\n\t\t\t\t\"description\": \"Create a new status page with optional logo upload\",\n\t\t\t\t\"requestBody\": {\n\t\t\t\t\t\"content\": {\n\t\t\t\t\t\t\"multipart/form-data\": {\n\t\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\t\"type\": \"object\",\n\t\t\t\t\t\t\t\t\"properties\": {\n\t\t\t\t\t\t\t\t\t\"logo\": {\n\t\t\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\t\t\"format\": \"binary\",\n\t\t\t\t\t\t\t\t\t\t\"description\": \"Logo file for the status page\"\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\"title\": {\n\t\t\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\t\t\"description\": \"Status page title\"\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\"description\": {\n\t\t\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\t\t\"description\": \"Status page description\"\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\"url\": {\n\t\t\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\t\t\"description\": \"Custom URL for the status page\"\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"201\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Success\"\n\t\t\t\t\t},\n\t\t\t\t\t\"400\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/BadRequest\"\n\t\t\t\t\t},\n\t\t\t\t\t\"401\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Unauthorized\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t},\n\t\t\t\"put\": {\n\t\t\t\t\"tags\": [\"status-page\"],\n\t\t\t\t\"summary\": \"Update status page\",\n\t\t\t\t\"description\": \"Update an existing status page with optional logo upload\",\n\t\t\t\t\"requestBody\": {\n\t\t\t\t\t\"content\": {\n\t\t\t\t\t\t\"multipart/form-data\": {\n\t\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\t\"type\": \"object\",\n\t\t\t\t\t\t\t\t\"properties\": {\n\t\t\t\t\t\t\t\t\t\"logo\": {\n\t\t\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\t\t\"format\": \"binary\",\n\t\t\t\t\t\t\t\t\t\t\"description\": \"Logo file for the status page\"\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\"title\": {\n\t\t\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\t\t\"description\": \"Status page title\"\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\"description\": {\n\t\t\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\t\t\"description\": \"Status page description\"\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\"url\": {\n\t\t\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\t\t\"description\": \"Custom URL for the status page\"\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Success\"\n\t\t\t\t\t},\n\t\t\t\t\t\"400\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/BadRequest\"\n\t\t\t\t\t},\n\t\t\t\t\t\"401\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Unauthorized\"\n\t\t\t\t\t},\n\t\t\t\t\t\"404\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/NotFound\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t\"/status-page/team\": {\n\t\t\t\"get\": {\n\t\t\t\t\"tags\": [\"status-page\"],\n\t\t\t\t\"summary\": \"Get status pages by team\",\n\t\t\t\t\"description\": \"Get all status pages for the authenticated user's team\",\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Success\"\n\t\t\t\t\t},\n\t\t\t\t\t\"401\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Unauthorized\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t\"/status-page/{url}\": {\n\t\t\t\"get\": {\n\t\t\t\t\"tags\": [\"status-page\"],\n\t\t\t\t\"summary\": \"Get status page by URL\",\n\t\t\t\t\"description\": \"Get a specific status page by its custom URL\",\n\t\t\t\t\"parameters\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"name\": \"url\",\n\t\t\t\t\t\t\"in\": \"path\",\n\t\t\t\t\t\t\"required\": true,\n\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"description\": \"Custom URL of the status page\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Success\"\n\t\t\t\t\t},\n\t\t\t\t\t\"404\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/NotFound\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"delete\": {\n\t\t\t\t\"tags\": [\"status-page\"],\n\t\t\t\t\"summary\": \"Delete status page\",\n\t\t\t\t\"description\": \"Delete a status page by its custom URL\",\n\t\t\t\t\"parameters\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"name\": \"url\",\n\t\t\t\t\t\t\"in\": \"path\",\n\t\t\t\t\t\t\"required\": true,\n\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"description\": \"Custom URL of the status page (supports wildcards)\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Success\"\n\t\t\t\t\t},\n\t\t\t\t\t\"401\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Unauthorized\"\n\t\t\t\t\t},\n\t\t\t\t\t\"404\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/NotFound\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t\"/incidents/team\": {\n\t\t\t\"get\": {\n\t\t\t\t\"tags\": [\"incidents\"],\n\t\t\t\t\"summary\": \"Get incidents by team\",\n\t\t\t\t\"description\": \"Retrieve all incidents for the authenticated user's team with optional filtering\",\n\t\t\t\t\"parameters\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"name\": \"status\",\n\t\t\t\t\t\t\"in\": \"query\",\n\t\t\t\t\t\t\"description\": \"Filter by incident status (true = ongoing, false = resolved)\",\n\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\"type\": \"boolean\"\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"name\": \"monitorId\",\n\t\t\t\t\t\t\"in\": \"query\",\n\t\t\t\t\t\t\"description\": \"Filter by monitor ID\",\n\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"name\": \"page\",\n\t\t\t\t\t\t\"in\": \"query\",\n\t\t\t\t\t\t\"description\": \"Page number for pagination\",\n\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\"type\": \"integer\",\n\t\t\t\t\t\t\t\"default\": 1\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"name\": \"limit\",\n\t\t\t\t\t\t\"in\": \"query\",\n\t\t\t\t\t\t\"description\": \"Number of items per page\",\n\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\"type\": \"integer\",\n\t\t\t\t\t\t\t\"default\": 10\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"name\": \"sortOrder\",\n\t\t\t\t\t\t\"in\": \"query\",\n\t\t\t\t\t\t\"description\": \"Sort order for results\",\n\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\"enum\": [\"asc\", \"desc\"],\n\t\t\t\t\t\t\t\"default\": \"desc\"\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"description\": \"Incidents retrieved successfully\",\n\t\t\t\t\t\t\"content\": {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\t\t\"type\": \"object\",\n\t\t\t\t\t\t\t\t\t\"properties\": {\n\t\t\t\t\t\t\t\t\t\t\"success\": {\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"boolean\",\n\t\t\t\t\t\t\t\t\t\t\t\"example\": true\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\"msg\": {\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\t\t\t\"example\": \"Incidents retrieved successfully\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\"data\": {\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"array\",\n\t\t\t\t\t\t\t\t\t\t\t\"items\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\"$ref\": \"#/components/schemas/Incident\"\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"401\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Unauthorized\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t\"/incidents/team/summary\": {\n\t\t\t\"get\": {\n\t\t\t\t\"tags\": [\"incidents\"],\n\t\t\t\t\"summary\": \"Get incident summary\",\n\t\t\t\t\"description\": \"Retrieve a summary of incidents for the authenticated user's team\",\n\t\t\t\t\"parameters\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"name\": \"dateRange\",\n\t\t\t\t\t\t\"in\": \"query\",\n\t\t\t\t\t\t\"description\": \"Date range for summary\",\n\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\"enum\": [\"day\", \"week\", \"month\"],\n\t\t\t\t\t\t\t\"default\": \"week\"\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"description\": \"Incident summary retrieved successfully\",\n\t\t\t\t\t\t\"content\": {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\t\t\"type\": \"object\",\n\t\t\t\t\t\t\t\t\t\"properties\": {\n\t\t\t\t\t\t\t\t\t\t\"success\": {\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"boolean\",\n\t\t\t\t\t\t\t\t\t\t\t\"example\": true\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\"msg\": {\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\t\t\t\"example\": \"Incident summary retrieved successfully\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\"data\": {\n\t\t\t\t\t\t\t\t\t\t\t\"$ref\": \"#/components/schemas/IncidentSummary\"\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"401\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Unauthorized\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t\"/incidents/{incidentId}\": {\n\t\t\t\"get\": {\n\t\t\t\t\"tags\": [\"incidents\"],\n\t\t\t\t\"summary\": \"Get incident by ID\",\n\t\t\t\t\"description\": \"Retrieve a specific incident by its ID\",\n\t\t\t\t\"parameters\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"name\": \"incidentId\",\n\t\t\t\t\t\t\"in\": \"path\",\n\t\t\t\t\t\t\"required\": true,\n\t\t\t\t\t\t\"description\": \"The incident ID\",\n\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"description\": \"Incident retrieved successfully\",\n\t\t\t\t\t\t\"content\": {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\t\t\"type\": \"object\",\n\t\t\t\t\t\t\t\t\t\"properties\": {\n\t\t\t\t\t\t\t\t\t\t\"success\": {\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"boolean\",\n\t\t\t\t\t\t\t\t\t\t\t\"example\": true\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\"msg\": {\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\t\t\t\"example\": \"Incident retrieved successfully\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\"data\": {\n\t\t\t\t\t\t\t\t\t\t\t\"$ref\": \"#/components/schemas/Incident\"\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"401\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Unauthorized\"\n\t\t\t\t\t},\n\t\t\t\t\t\"404\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/NotFound\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t\"/incidents/{incidentId}/resolve\": {\n\t\t\t\"put\": {\n\t\t\t\t\"tags\": [\"incidents\"],\n\t\t\t\t\"summary\": \"Resolve incident manually\",\n\t\t\t\t\"description\": \"Manually resolve an ongoing incident. Requires admin or superadmin role.\",\n\t\t\t\t\"parameters\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"name\": \"incidentId\",\n\t\t\t\t\t\t\"in\": \"path\",\n\t\t\t\t\t\t\"required\": true,\n\t\t\t\t\t\t\"description\": \"The incident ID to resolve\",\n\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"requestBody\": {\n\t\t\t\t\t\"content\": {\n\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\t\"type\": \"object\",\n\t\t\t\t\t\t\t\t\"properties\": {\n\t\t\t\t\t\t\t\t\t\"comment\": {\n\t\t\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\t\t\"description\": \"Optional comment about the resolution\",\n\t\t\t\t\t\t\t\t\t\t\"example\": \"Issue resolved by restarting the service\"\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"responses\": {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\"description\": \"Incident resolved successfully\",\n\t\t\t\t\t\t\"content\": {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\t\t\"type\": \"object\",\n\t\t\t\t\t\t\t\t\t\"properties\": {\n\t\t\t\t\t\t\t\t\t\t\"success\": {\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"boolean\",\n\t\t\t\t\t\t\t\t\t\t\t\"example\": true\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\"msg\": {\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\t\t\t\"example\": \"Incident resolved successfully\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\"data\": {\n\t\t\t\t\t\t\t\t\t\t\t\"$ref\": \"#/components/schemas/Incident\"\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"401\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Unauthorized\"\n\t\t\t\t\t},\n\t\t\t\t\t\"403\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/Forbidden\"\n\t\t\t\t\t},\n\t\t\t\t\t\"404\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/NotFound\"\n\t\t\t\t\t},\n\t\t\t\t\t\"500\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/responses/InternalServerError\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"security\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"bearerAuth\": []\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t}\n\t},\n\t\"components\": {\n\t\t\"securitySchemes\": {\n\t\t\t\"bearerAuth\": {\n\t\t\t\t\"type\": \"http\",\n\t\t\t\t\"scheme\": \"bearer\",\n\t\t\t\t\"bearerFormat\": \"JWT\",\n\t\t\t\t\"description\": \"JWT token obtained from login endpoint\"\n\t\t\t}\n\t\t},\n\t\t\"responses\": {\n\t\t\t\"Success\": {\n\t\t\t\t\"description\": \"Operation successful\",\n\t\t\t\t\"content\": {\n\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\"$ref\": \"#/components/schemas/SuccessResponse\"\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"NotFound\": {\n\t\t\t\t\"description\": \"Resource not found\",\n\t\t\t\t\"content\": {\n\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\"$ref\": \"#/components/schemas/ErrorResponse\"\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"ValidationError\": {\n\t\t\t\t\"description\": \"Validation failed\",\n\t\t\t\t\"content\": {\n\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\"$ref\": \"#/components/schemas/ErrorResponse\"\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"Unauthorized\": {\n\t\t\t\t\"description\": \"Authentication required or token invalid\",\n\t\t\t\t\"content\": {\n\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\"$ref\": \"#/components/schemas/ErrorResponse\"\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"Forbidden\": {\n\t\t\t\t\"description\": \"Insufficient permissions\",\n\t\t\t\t\"content\": {\n\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\"$ref\": \"#/components/schemas/ErrorResponse\"\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"BadRequest\": {\n\t\t\t\t\"description\": \"Invalid request parameters\",\n\t\t\t\t\"content\": {\n\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\"$ref\": \"#/components/schemas/ErrorResponse\"\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"InternalServerError\": {\n\t\t\t\t\"description\": \"Internal server error\",\n\t\t\t\t\"content\": {\n\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\"schema\": {\n\t\t\t\t\t\t\t\"$ref\": \"#/components/schemas/ErrorResponse\"\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t\"schemas\": {\n\t\t\t\"SuccessResponse\": {\n\t\t\t\t\"type\": \"object\",\n\t\t\t\t\"required\": [\"success\", \"msg\"],\n\t\t\t\t\"properties\": {\n\t\t\t\t\t\"success\": {\n\t\t\t\t\t\t\"type\": \"boolean\",\n\t\t\t\t\t\t\"example\": true\n\t\t\t\t\t},\n\t\t\t\t\t\"msg\": {\n\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\"example\": \"Operation completed successfully\"\n\t\t\t\t\t},\n\t\t\t\t\t\"data\": {\n\t\t\t\t\t\t\"type\": \"object\",\n\t\t\t\t\t\t\"description\": \"Response payload (varies by endpoint)\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"ErrorResponse\": {\n\t\t\t\t\"type\": \"object\",\n\t\t\t\t\"required\": [\"success\", \"msg\"],\n\t\t\t\t\"properties\": {\n\t\t\t\t\t\"success\": {\n\t\t\t\t\t\t\"type\": \"boolean\",\n\t\t\t\t\t\t\"example\": false\n\t\t\t\t\t},\n\t\t\t\t\t\"msg\": {\n\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\"example\": \"An error occurred\"\n\t\t\t\t\t},\n\t\t\t\t\t\"details\": {\n\t\t\t\t\t\t\"type\": \"object\",\n\t\t\t\t\t\t\"description\": \"Additional error details\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"RegisterRequest\": {\n\t\t\t\t\"type\": \"object\",\n\t\t\t\t\"required\": [\"firstName\", \"lastName\", \"email\", \"password\"],\n\t\t\t\t\"properties\": {\n\t\t\t\t\t\"firstName\": {\n\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\"minLength\": 1,\n\t\t\t\t\t\t\"maxLength\": 50,\n\t\t\t\t\t\t\"example\": \"John\"\n\t\t\t\t\t},\n\t\t\t\t\t\"lastName\": {\n\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\"minLength\": 1,\n\t\t\t\t\t\t\"maxLength\": 50,\n\t\t\t\t\t\t\"example\": \"Doe\"\n\t\t\t\t\t},\n\t\t\t\t\t\"email\": {\n\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\"format\": \"email\",\n\t\t\t\t\t\t\"example\": \"john@example.com\"\n\t\t\t\t\t},\n\t\t\t\t\t\"password\": {\n\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\"minLength\": 8,\n\t\t\t\t\t\t\"format\": \"password\",\n\t\t\t\t\t\t\"example\": \"SecurePass123!\"\n\t\t\t\t\t},\n\t\t\t\t\t\"profileImage\": {\n\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\"format\": \"binary\",\n\t\t\t\t\t\t\"description\": \"Optional profile image file\"\n\t\t\t\t\t},\n\t\t\t\t\t\"role\": {\n\t\t\t\t\t\t\"type\": \"array\",\n\t\t\t\t\t\t\"items\": {\n\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\"enum\": [\"user\", \"admin\", \"superadmin\", \"Demo\"]\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"default\": [\"user\"]\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"LoginRequest\": {\n\t\t\t\t\"type\": \"object\",\n\t\t\t\t\"required\": [\"email\", \"password\"],\n\t\t\t\t\"properties\": {\n\t\t\t\t\t\"email\": {\n\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\"format\": \"email\",\n\t\t\t\t\t\t\"example\": \"john@example.com\"\n\t\t\t\t\t},\n\t\t\t\t\t\"password\": {\n\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\"format\": \"password\",\n\t\t\t\t\t\t\"example\": \"SecurePass123!\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"AuthResponse\": {\n\t\t\t\t\"allOf\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"$ref\": \"#/components/schemas/SuccessResponse\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"type\": \"object\",\n\t\t\t\t\t\t\"properties\": {\n\t\t\t\t\t\t\t\"data\": {\n\t\t\t\t\t\t\t\t\"type\": \"object\",\n\t\t\t\t\t\t\t\t\"properties\": {\n\t\t\t\t\t\t\t\t\t\"token\": {\n\t\t\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\t\t\"description\": \"JWT access token\"\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\"user\": {\n\t\t\t\t\t\t\t\t\t\t\"$ref\": \"#/components/schemas/User\"\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t},\n\t\t\t\"UserUpdateRequest\": {\n\t\t\t\t\"type\": \"object\",\n\t\t\t\t\"properties\": {\n\t\t\t\t\t\"firstName\": {\n\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\"minLength\": 1,\n\t\t\t\t\t\t\"maxLength\": 50\n\t\t\t\t\t},\n\t\t\t\t\t\"lastName\": {\n\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\"minLength\": 1,\n\t\t\t\t\t\t\"maxLength\": 50\n\t\t\t\t\t},\n\t\t\t\t\t\"password\": {\n\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\"format\": \"password\",\n\t\t\t\t\t\t\"description\": \"Current password for verification\"\n\t\t\t\t\t},\n\t\t\t\t\t\"newPassword\": {\n\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\"minLength\": 8,\n\t\t\t\t\t\t\"format\": \"password\",\n\t\t\t\t\t\t\"description\": \"New password (if changing)\"\n\t\t\t\t\t},\n\t\t\t\t\t\"profileImage\": {\n\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\"format\": \"binary\",\n\t\t\t\t\t\t\"description\": \"New profile image file\"\n\t\t\t\t\t},\n\t\t\t\t\t\"deleteProfileImage\": {\n\t\t\t\t\t\t\"type\": \"boolean\",\n\t\t\t\t\t\t\"description\": \"Flag to delete current profile image\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"User\": {\n\t\t\t\t\"type\": \"object\",\n\t\t\t\t\"properties\": {\n\t\t\t\t\t\"_id\": {\n\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\"example\": \"64f123a456b789012c345def\"\n\t\t\t\t\t},\n\t\t\t\t\t\"firstName\": {\n\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\"example\": \"John\"\n\t\t\t\t\t},\n\t\t\t\t\t\"lastName\": {\n\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\"example\": \"Doe\"\n\t\t\t\t\t},\n\t\t\t\t\t\"email\": {\n\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\"format\": \"email\",\n\t\t\t\t\t\t\"example\": \"john@example.com\"\n\t\t\t\t\t},\n\t\t\t\t\t\"role\": {\n\t\t\t\t\t\t\"type\": \"array\",\n\t\t\t\t\t\t\"items\": {\n\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\"enum\": [\"user\", \"admin\", \"superadmin\", \"Demo\"]\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"profileImage\": {\n\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\"description\": \"URL or path to profile image\"\n\t\t\t\t\t},\n\t\t\t\t\t\"isActive\": {\n\t\t\t\t\t\t\"type\": \"boolean\"\n\t\t\t\t\t},\n\t\t\t\t\t\"teamId\": {\n\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t},\n\t\t\t\t\t\"createdAt\": {\n\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\"format\": \"date-time\"\n\t\t\t\t\t},\n\t\t\t\t\t\"updatedAt\": {\n\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\"format\": \"date-time\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"CreateMonitorRequest\": {\n\t\t\t\t\"type\": \"object\",\n\t\t\t\t\"required\": [\"name\", \"type\", \"url\"],\n\t\t\t\t\"properties\": {\n\t\t\t\t\t\"name\": {\n\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\"example\": \"My Website Monitor\"\n\t\t\t\t\t},\n\t\t\t\t\t\"description\": {\n\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\"example\": \"Monitors the main website homepage\"\n\t\t\t\t\t},\n\t\t\t\t\t\"type\": {\n\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\"enum\": [\"http\", \"ping\", \"pagespeed\", \"hardware\", \"docker\", \"port\", \"game\", \"grpc\", \"websocket\"],\n\t\t\t\t\t\t\"example\": \"http\"\n\t\t\t\t\t},\n\t\t\t\t\t\"url\": {\n\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\"format\": \"uri\",\n\t\t\t\t\t\t\"example\": \"https://example.com\"\n\t\t\t\t\t},\n\t\t\t\t\t\"interval\": {\n\t\t\t\t\t\t\"type\": \"integer\",\n\t\t\t\t\t\t\"example\": 300,\n\t\t\t\t\t\t\"description\": \"Check interval in seconds\"\n\t\t\t\t\t},\n\t\t\t\t\t\"statusWindowSize\": {\n\t\t\t\t\t\t\"type\": \"integer\",\n\t\t\t\t\t\t\"minimum\": 1,\n\t\t\t\t\t\t\"maximum\": 20,\n\t\t\t\t\t\t\"default\": 5\n\t\t\t\t\t},\n\t\t\t\t\t\"statusWindowThreshold\": {\n\t\t\t\t\t\t\"type\": \"integer\",\n\t\t\t\t\t\t\"minimum\": 1,\n\t\t\t\t\t\t\"maximum\": 100,\n\t\t\t\t\t\t\"default\": 60\n\t\t\t\t\t},\n\t\t\t\t\t\"isActive\": {\n\t\t\t\t\t\t\"type\": \"boolean\"\n\t\t\t\t\t},\n\t\t\t\t\t\"ignoreTlsErrors\": {\n\t\t\t\t\t\t\"type\": \"boolean\",\n\t\t\t\t\t\t\"default\": false\n\t\t\t\t\t},\n\t\t\t\t\t\"useAdvancedMatching\": {\n\t\t\t\t\t\t\"type\": \"boolean\",\n\t\t\t\t\t\t\"default\": false\n\t\t\t\t\t},\n\t\t\t\t\t\"port\": {\n\t\t\t\t\t\t\"type\": \"integer\"\n\t\t\t\t\t},\n\t\t\t\t\t\"notifications\": {\n\t\t\t\t\t\t\"type\": \"array\",\n\t\t\t\t\t\t\"items\": {\n\t\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"description\": \"Array of notification IDs to associate with this monitor\"\n\t\t\t\t\t},\n\t\t\t\t\t\"secret\": {\n\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t},\n\t\t\t\t\t\"jsonPath\": {\n\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t},\n\t\t\t\t\t\"expectedValue\": {\n\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t},\n\t\t\t\t\t\"matchMethod\": {\n\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\"enum\": [\"equal\", \"include\", \"regex\", \"\"]\n\t\t\t\t\t},\n\t\t\t\t\t\"cpuAlertThreshold\": {\n\t\t\t\t\t\t\"type\": \"number\"\n\t\t\t\t\t},\n\t\t\t\t\t\"memoryAlertThreshold\": {\n\t\t\t\t\t\t\"type\": \"number\"\n\t\t\t\t\t},\n\t\t\t\t\t\"diskAlertThreshold\": {\n\t\t\t\t\t\t\"type\": \"number\"\n\t\t\t\t\t},\n\t\t\t\t\t\"tempAlertThreshold\": {\n\t\t\t\t\t\t\"type\": \"number\"\n\t\t\t\t\t},\n\t\t\t\t\t\"gameId\": {\n\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t},\n\t\t\t\t\t\"grpcServiceName\": {\n\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\"default\": \"\"\n\t\t\t\t\t},\n\t\t\t\t\t\"selectedDisks\": {\n\t\t\t\t\t\t\"type\": \"array\",\n\t\t\t\t\t\t\"items\": {\n\t\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"group\": {\n\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\"nullable\": true,\n\t\t\t\t\t\t\"maxLength\": 50\n\t\t\t\t\t},\n\t\t\t\t\t\"geoCheckEnabled\": {\n\t\t\t\t\t\t\"type\": \"boolean\"\n\t\t\t\t\t},\n\t\t\t\t\t\"geoCheckLocations\": {\n\t\t\t\t\t\t\"type\": \"array\",\n\t\t\t\t\t\t\"items\": {\n\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\"enum\": [\"northAmerica\", \"southAmerica\", \"europe\", \"asia\", \"africa\", \"oceania\"]\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"geoCheckInterval\": {\n\t\t\t\t\t\t\"type\": \"integer\",\n\t\t\t\t\t\t\"minimum\": 300000\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"UpdateMonitorRequest\": {\n\t\t\t\t\"type\": \"object\",\n\t\t\t\t\"properties\": {\n\t\t\t\t\t\"name\": {\n\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t},\n\t\t\t\t\t\"type\": {\n\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\"enum\": [\"http\", \"ping\", \"pagespeed\", \"hardware\", \"docker\", \"port\", \"game\", \"grpc\", \"websocket\", \"unknown\"]\n\t\t\t\t\t},\n\t\t\t\t\t\"url\": {\n\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t},\n\t\t\t\t\t\"statusWindowSize\": {\n\t\t\t\t\t\t\"type\": \"integer\",\n\t\t\t\t\t\t\"minimum\": 1,\n\t\t\t\t\t\t\"maximum\": 20,\n\t\t\t\t\t\t\"default\": 5\n\t\t\t\t\t},\n\t\t\t\t\t\"statusWindowThreshold\": {\n\t\t\t\t\t\t\"type\": \"integer\",\n\t\t\t\t\t\t\"minimum\": 1,\n\t\t\t\t\t\t\"maximum\": 100,\n\t\t\t\t\t\t\"default\": 60\n\t\t\t\t\t},\n\t\t\t\t\t\"description\": {\n\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t},\n\t\t\t\t\t\"interval\": {\n\t\t\t\t\t\t\"type\": \"integer\"\n\t\t\t\t\t},\n\t\t\t\t\t\"notifications\": {\n\t\t\t\t\t\t\"type\": \"array\",\n\t\t\t\t\t\t\"items\": {\n\t\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"secret\": {\n\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t},\n\t\t\t\t\t\"ignoreTlsErrors\": {\n\t\t\t\t\t\t\"type\": \"boolean\"\n\t\t\t\t\t},\n\t\t\t\t\t\"useAdvancedMatching\": {\n\t\t\t\t\t\t\"type\": \"boolean\"\n\t\t\t\t\t},\n\t\t\t\t\t\"jsonPath\": {\n\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t},\n\t\t\t\t\t\"expectedValue\": {\n\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t},\n\t\t\t\t\t\"matchMethod\": {\n\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\"enum\": [\"equal\", \"include\", \"regex\", \"\"]\n\t\t\t\t\t},\n\t\t\t\t\t\"port\": {\n\t\t\t\t\t\t\"type\": \"integer\",\n\t\t\t\t\t\t\"minimum\": 1,\n\t\t\t\t\t\t\"maximum\": 65535\n\t\t\t\t\t},\n\t\t\t\t\t\"cpuAlertThreshold\": {\n\t\t\t\t\t\t\"type\": \"number\"\n\t\t\t\t\t},\n\t\t\t\t\t\"memoryAlertThreshold\": {\n\t\t\t\t\t\t\"type\": \"number\"\n\t\t\t\t\t},\n\t\t\t\t\t\"diskAlertThreshold\": {\n\t\t\t\t\t\t\"type\": \"number\"\n\t\t\t\t\t},\n\t\t\t\t\t\"tempAlertThreshold\": {\n\t\t\t\t\t\t\"type\": \"number\"\n\t\t\t\t\t},\n\t\t\t\t\t\"gameId\": {\n\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t},\n\t\t\t\t\t\"grpcServiceName\": {\n\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t},\n\t\t\t\t\t\"selectedDisks\": {\n\t\t\t\t\t\t\"type\": \"array\",\n\t\t\t\t\t\t\"items\": {\n\t\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"group\": {\n\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\"nullable\": true,\n\t\t\t\t\t\t\"maxLength\": 50\n\t\t\t\t\t},\n\t\t\t\t\t\"geoCheckEnabled\": {\n\t\t\t\t\t\t\"type\": \"boolean\"\n\t\t\t\t\t},\n\t\t\t\t\t\"geoCheckLocations\": {\n\t\t\t\t\t\t\"type\": \"array\",\n\t\t\t\t\t\t\"items\": {\n\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\"enum\": [\"northAmerica\", \"southAmerica\", \"europe\", \"asia\", \"africa\", \"oceania\"]\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"geoCheckInterval\": {\n\t\t\t\t\t\t\"type\": \"integer\",\n\t\t\t\t\t\t\"minimum\": 300000\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"Monitor\": {\n\t\t\t\t\"type\": \"object\",\n\t\t\t\t\"properties\": {\n\t\t\t\t\t\"_id\": {\n\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\"example\": \"64f123a456b789012c345def\"\n\t\t\t\t\t},\n\t\t\t\t\t\"userId\": {\n\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t},\n\t\t\t\t\t\"teamId\": {\n\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t},\n\t\t\t\t\t\"name\": {\n\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\"example\": \"My Website Monitor\"\n\t\t\t\t\t},\n\t\t\t\t\t\"description\": {\n\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\"example\": \"Monitors the main website homepage\"\n\t\t\t\t\t},\n\t\t\t\t\t\"type\": {\n\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\"enum\": [\"http\", \"ping\", \"pagespeed\", \"hardware\", \"docker\", \"port\"]\n\t\t\t\t\t},\n\t\t\t\t\t\"url\": {\n\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\"format\": \"uri\",\n\t\t\t\t\t\t\"example\": \"https://example.com\"\n\t\t\t\t\t},\n\t\t\t\t\t\"interval\": {\n\t\t\t\t\t\t\"type\": \"integer\",\n\t\t\t\t\t\t\"example\": 300\n\t\t\t\t\t},\n\t\t\t\t\t\"isActive\": {\n\t\t\t\t\t\t\"type\": \"boolean\",\n\t\t\t\t\t\t\"example\": true\n\t\t\t\t\t},\n\t\t\t\t\t\"status\": {\n\t\t\t\t\t\t\"type\": \"boolean\",\n\t\t\t\t\t\t\"description\": \"Current monitor status (up/down)\"\n\t\t\t\t\t},\n\t\t\t\t\t\"lastChecked\": {\n\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\"format\": \"date-time\",\n\t\t\t\t\t\t\"description\": \"Timestamp of last check\"\n\t\t\t\t\t},\n\t\t\t\t\t\"notifications\": {\n\t\t\t\t\t\t\"type\": \"array\",\n\t\t\t\t\t\t\"items\": {\n\t\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"httpOptions\": {\n\t\t\t\t\t\t\"type\": \"object\",\n\t\t\t\t\t\t\"properties\": {\n\t\t\t\t\t\t\t\"method\": {\n\t\t\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"headers\": {\n\t\t\t\t\t\t\t\t\"type\": \"object\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"body\": {\n\t\t\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"timeout\": {\n\t\t\t\t\t\t\t\t\"type\": \"integer\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"assertions\": {\n\t\t\t\t\t\t\"type\": \"array\",\n\t\t\t\t\t\t\"items\": {\n\t\t\t\t\t\t\t\"type\": \"object\"\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"createdAt\": {\n\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\"format\": \"date-time\"\n\t\t\t\t\t},\n\t\t\t\t\t\"updatedAt\": {\n\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\"format\": \"date-time\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"CreateNotificationRequest\": {\n\t\t\t\t\"type\": \"object\",\n\t\t\t\t\"required\": [\"type\", \"name\"],\n\t\t\t\t\"properties\": {\n\t\t\t\t\t\"type\": {\n\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\"enum\": [\"email\", \"webhook\", \"slack\", \"discord\", \"telegram\", \"zapier\"],\n\t\t\t\t\t\t\"example\": \"email\"\n\t\t\t\t\t},\n\t\t\t\t\t\"name\": {\n\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\"minLength\": 1,\n\t\t\t\t\t\t\"maxLength\": 100,\n\t\t\t\t\t\t\"example\": \"Admin Email Notifications\"\n\t\t\t\t\t},\n\t\t\t\t\t\"config\": {\n\t\t\t\t\t\t\"type\": \"object\",\n\t\t\t\t\t\t\"description\": \"Configuration specific to notification type\",\n\t\t\t\t\t\t\"oneOf\": [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\"title\": \"Email Configuration\",\n\t\t\t\t\t\t\t\t\"properties\": {\n\t\t\t\t\t\t\t\t\t\"to\": {\n\t\t\t\t\t\t\t\t\t\t\"type\": \"array\",\n\t\t\t\t\t\t\t\t\t\t\"items\": {\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\t\t\t\"format\": \"email\"\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\"title\": \"Webhook Configuration\",\n\t\t\t\t\t\t\t\t\"properties\": {\n\t\t\t\t\t\t\t\t\t\"url\": {\n\t\t\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\t\t\"format\": \"uri\"\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\"headers\": {\n\t\t\t\t\t\t\t\t\t\t\"type\": \"object\",\n\t\t\t\t\t\t\t\t\t\t\"additionalProperties\": {\n\t\t\t\t\t\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\"title\": \"Slack Configuration\",\n\t\t\t\t\t\t\t\t\"properties\": {\n\t\t\t\t\t\t\t\t\t\"webhookUrl\": {\n\t\t\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\t\t\"format\": \"uri\"\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\"channel\": {\n\t\t\t\t\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\"title\": \"Discord Configuration\",\n\t\t\t\t\t\t\t\t\"properties\": {\n\t\t\t\t\t\t\t\t\t\"webhookUrl\": {\n\t\t\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\t\t\"format\": \"uri\"\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\t\"isActive\": {\n\t\t\t\t\t\t\"type\": \"boolean\",\n\t\t\t\t\t\t\"default\": true\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"Notification\": {\n\t\t\t\t\"type\": \"object\",\n\t\t\t\t\"properties\": {\n\t\t\t\t\t\"_id\": {\n\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t},\n\t\t\t\t\t\"userId\": {\n\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t},\n\t\t\t\t\t\"teamId\": {\n\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t},\n\t\t\t\t\t\"type\": {\n\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\"enum\": [\"email\", \"webhook\", \"slack\", \"discord\", \"telegram\", \"zapier\"]\n\t\t\t\t\t},\n\t\t\t\t\t\"name\": {\n\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t},\n\t\t\t\t\t\"config\": {\n\t\t\t\t\t\t\"type\": \"object\",\n\t\t\t\t\t\t\"description\": \"Type-specific configuration\"\n\t\t\t\t\t},\n\t\t\t\t\t\"isActive\": {\n\t\t\t\t\t\t\"type\": \"boolean\"\n\t\t\t\t\t},\n\t\t\t\t\t\"createdAt\": {\n\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\"format\": \"date-time\"\n\t\t\t\t\t},\n\t\t\t\t\t\"updatedAt\": {\n\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\"format\": \"date-time\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"AppSettings\": {\n\t\t\t\t\"type\": \"object\",\n\t\t\t\t\"properties\": {\n\t\t\t\t\t\"appName\": {\n\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\"example\": \"Checkmate\"\n\t\t\t\t\t},\n\t\t\t\t\t\"appUrl\": {\n\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\"format\": \"uri\",\n\t\t\t\t\t\t\"example\": \"https://checkmate.example.com\"\n\t\t\t\t\t},\n\t\t\t\t\t\"logLevel\": {\n\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\"enum\": [\"error\", \"warn\", \"info\", \"debug\"],\n\t\t\t\t\t\t\"default\": \"info\"\n\t\t\t\t\t},\n\t\t\t\t\t\"emailConfig\": {\n\t\t\t\t\t\t\"type\": \"object\",\n\t\t\t\t\t\t\"properties\": {\n\t\t\t\t\t\t\t\"host\": {\n\t\t\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"port\": {\n\t\t\t\t\t\t\t\t\"type\": \"integer\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"secure\": {\n\t\t\t\t\t\t\t\t\"type\": \"boolean\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"user\": {\n\t\t\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"pass\": {\n\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\"format\": \"password\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"from\": {\n\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\"format\": \"email\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"webhookRetries\": {\n\t\t\t\t\t\t\"type\": \"integer\",\n\t\t\t\t\t\t\"minimum\": 0,\n\t\t\t\t\t\t\"maximum\": 10,\n\t\t\t\t\t\t\"default\": 3\n\t\t\t\t\t},\n\t\t\t\t\t\"checksRetention\": {\n\t\t\t\t\t\t\"type\": \"integer\",\n\t\t\t\t\t\t\"minimum\": 1,\n\t\t\t\t\t\t\"maximum\": 365,\n\t\t\t\t\t\t\"default\": 90,\n\t\t\t\t\t\t\"description\": \"Days to retain check results\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"SystemDiagnostics\": {\n\t\t\t\t\"type\": \"object\",\n\t\t\t\t\"properties\": {\n\t\t\t\t\t\"uptime\": {\n\t\t\t\t\t\t\"type\": \"number\",\n\t\t\t\t\t\t\"description\": \"System uptime in seconds\"\n\t\t\t\t\t},\n\t\t\t\t\t\"memory\": {\n\t\t\t\t\t\t\"type\": \"object\",\n\t\t\t\t\t\t\"properties\": {\n\t\t\t\t\t\t\t\"total\": {\n\t\t\t\t\t\t\t\t\"type\": \"number\",\n\t\t\t\t\t\t\t\t\"description\": \"Total memory in bytes\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"used\": {\n\t\t\t\t\t\t\t\t\"type\": \"number\",\n\t\t\t\t\t\t\t\t\"description\": \"Used memory in bytes\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"free\": {\n\t\t\t\t\t\t\t\t\"type\": \"number\",\n\t\t\t\t\t\t\t\t\"description\": \"Free memory in bytes\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"cpu\": {\n\t\t\t\t\t\t\"type\": \"object\",\n\t\t\t\t\t\t\"properties\": {\n\t\t\t\t\t\t\t\"usage\": {\n\t\t\t\t\t\t\t\t\"type\": \"number\",\n\t\t\t\t\t\t\t\t\"description\": \"CPU usage percentage\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"cores\": {\n\t\t\t\t\t\t\t\t\"type\": \"integer\",\n\t\t\t\t\t\t\t\t\"description\": \"Number of CPU cores\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"database\": {\n\t\t\t\t\t\t\"type\": \"object\",\n\t\t\t\t\t\t\"properties\": {\n\t\t\t\t\t\t\t\"status\": {\n\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\"enum\": [\"connected\", \"disconnected\", \"error\"]\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"responseTime\": {\n\t\t\t\t\t\t\t\t\"type\": \"number\",\n\t\t\t\t\t\t\t\t\"description\": \"Database response time in milliseconds\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"queue\": {\n\t\t\t\t\t\t\"type\": \"object\",\n\t\t\t\t\t\t\"properties\": {\n\t\t\t\t\t\t\t\"active\": {\n\t\t\t\t\t\t\t\t\"type\": \"integer\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"waiting\": {\n\t\t\t\t\t\t\t\t\"type\": \"integer\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"completed\": {\n\t\t\t\t\t\t\t\t\"type\": \"integer\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"failed\": {\n\t\t\t\t\t\t\t\t\"type\": \"integer\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"Incident\": {\n\t\t\t\t\"type\": \"object\",\n\t\t\t\t\"properties\": {\n\t\t\t\t\t\"_id\": {\n\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\"description\": \"Unique incident identifier\"\n\t\t\t\t\t},\n\t\t\t\t\t\"monitorId\": {\n\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\"description\": \"ID of the associated monitor\"\n\t\t\t\t\t},\n\t\t\t\t\t\"teamId\": {\n\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\"description\": \"ID of the team\"\n\t\t\t\t\t},\n\t\t\t\t\t\"startTime\": {\n\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\"format\": \"date-time\",\n\t\t\t\t\t\t\"description\": \"When the incident started\"\n\t\t\t\t\t},\n\t\t\t\t\t\"endTime\": {\n\t\t\t\t\t\t\"type\": [\"string\", \"null\"],\n\t\t\t\t\t\t\"format\": \"date-time\",\n\t\t\t\t\t\t\"description\": \"When the incident was resolved (null if ongoing)\"\n\t\t\t\t\t},\n\t\t\t\t\t\"status\": {\n\t\t\t\t\t\t\"type\": \"boolean\",\n\t\t\t\t\t\t\"description\": \"Incident status (true = ongoing, false = resolved)\"\n\t\t\t\t\t},\n\t\t\t\t\t\"message\": {\n\t\t\t\t\t\t\"type\": [\"string\", \"null\"],\n\t\t\t\t\t\t\"description\": \"Error message or description\"\n\t\t\t\t\t},\n\t\t\t\t\t\"statusCode\": {\n\t\t\t\t\t\t\"type\": [\"integer\", \"null\"],\n\t\t\t\t\t\t\"description\": \"HTTP status code if applicable\"\n\t\t\t\t\t},\n\t\t\t\t\t\"resolutionType\": {\n\t\t\t\t\t\t\"type\": [\"string\", \"null\"],\n\t\t\t\t\t\t\"enum\": [\"automatic\", \"manual\", null],\n\t\t\t\t\t\t\"description\": \"How the incident was resolved\"\n\t\t\t\t\t},\n\t\t\t\t\t\"resolvedBy\": {\n\t\t\t\t\t\t\"type\": [\"string\", \"null\"],\n\t\t\t\t\t\t\"description\": \"User ID who resolved the incident (for manual resolution)\"\n\t\t\t\t\t},\n\t\t\t\t\t\"comment\": {\n\t\t\t\t\t\t\"type\": [\"string\", \"null\"],\n\t\t\t\t\t\t\"description\": \"Resolution comment\"\n\t\t\t\t\t},\n\t\t\t\t\t\"checks\": {\n\t\t\t\t\t\t\"type\": \"array\",\n\t\t\t\t\t\t\"items\": {\n\t\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"description\": \"Array of check IDs associated with this incident\"\n\t\t\t\t\t},\n\t\t\t\t\t\"createdAt\": {\n\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\"format\": \"date-time\"\n\t\t\t\t\t},\n\t\t\t\t\t\"updatedAt\": {\n\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\"format\": \"date-time\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"IncidentSummary\": {\n\t\t\t\t\"type\": \"object\",\n\t\t\t\t\"properties\": {\n\t\t\t\t\t\"totalIncidents\": {\n\t\t\t\t\t\t\"type\": \"integer\",\n\t\t\t\t\t\t\"description\": \"Total number of incidents\"\n\t\t\t\t\t},\n\t\t\t\t\t\"activeIncidents\": {\n\t\t\t\t\t\t\"type\": \"integer\",\n\t\t\t\t\t\t\"description\": \"Number of ongoing incidents\"\n\t\t\t\t\t},\n\t\t\t\t\t\"resolvedIncidents\": {\n\t\t\t\t\t\t\"type\": \"integer\",\n\t\t\t\t\t\t\"description\": \"Number of resolved incidents\"\n\t\t\t\t\t},\n\t\t\t\t\t\"averageResolutionTime\": {\n\t\t\t\t\t\t\"type\": \"number\",\n\t\t\t\t\t\t\"description\": \"Average time to resolve incidents in milliseconds\"\n\t\t\t\t\t},\n\t\t\t\t\t\"incidentsByMonitor\": {\n\t\t\t\t\t\t\"type\": \"array\",\n\t\t\t\t\t\t\"items\": {\n\t\t\t\t\t\t\t\"type\": \"object\",\n\t\t\t\t\t\t\t\"properties\": {\n\t\t\t\t\t\t\t\t\"monitorId\": {\n\t\t\t\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\"monitorName\": {\n\t\t\t\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\"count\": {\n\t\t\t\t\t\t\t\t\t\"type\": \"integer\"\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"QueueJob\": {\n\t\t\t\t\"type\": \"object\",\n\t\t\t\t\"properties\": {\n\t\t\t\t\t\"id\": {\n\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\"description\": \"Job ID\"\n\t\t\t\t\t},\n\t\t\t\t\t\"name\": {\n\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\"description\": \"Job name\"\n\t\t\t\t\t},\n\t\t\t\t\t\"data\": {\n\t\t\t\t\t\t\"type\": \"object\",\n\t\t\t\t\t\t\"description\": \"Job payload data\"\n\t\t\t\t\t},\n\t\t\t\t\t\"status\": {\n\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\"enum\": [\"waiting\", \"active\", \"completed\", \"failed\", \"delayed\"],\n\t\t\t\t\t\t\"description\": \"Current job status\"\n\t\t\t\t\t},\n\t\t\t\t\t\"progress\": {\n\t\t\t\t\t\t\"type\": \"number\",\n\t\t\t\t\t\t\"description\": \"Job progress percentage\"\n\t\t\t\t\t},\n\t\t\t\t\t\"attemptsMade\": {\n\t\t\t\t\t\t\"type\": \"integer\",\n\t\t\t\t\t\t\"description\": \"Number of attempts made\"\n\t\t\t\t\t},\n\t\t\t\t\t\"timestamp\": {\n\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\"format\": \"date-time\",\n\t\t\t\t\t\t\"description\": \"When the job was created\"\n\t\t\t\t\t},\n\t\t\t\t\t\"processedOn\": {\n\t\t\t\t\t\t\"type\": [\"string\", \"null\"],\n\t\t\t\t\t\t\"format\": \"date-time\",\n\t\t\t\t\t\t\"description\": \"When the job started processing\"\n\t\t\t\t\t},\n\t\t\t\t\t\"finishedOn\": {\n\t\t\t\t\t\t\"type\": [\"string\", \"null\"],\n\t\t\t\t\t\t\"format\": \"date-time\",\n\t\t\t\t\t\t\"description\": \"When the job finished\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"QueueMetrics\": {\n\t\t\t\t\"type\": \"object\",\n\t\t\t\t\"properties\": {\n\t\t\t\t\t\"waiting\": {\n\t\t\t\t\t\t\"type\": \"integer\",\n\t\t\t\t\t\t\"description\": \"Number of jobs waiting\"\n\t\t\t\t\t},\n\t\t\t\t\t\"active\": {\n\t\t\t\t\t\t\"type\": \"integer\",\n\t\t\t\t\t\t\"description\": \"Number of jobs currently processing\"\n\t\t\t\t\t},\n\t\t\t\t\t\"completed\": {\n\t\t\t\t\t\t\"type\": \"integer\",\n\t\t\t\t\t\t\"description\": \"Number of completed jobs\"\n\t\t\t\t\t},\n\t\t\t\t\t\"failed\": {\n\t\t\t\t\t\t\"type\": \"integer\",\n\t\t\t\t\t\t\"description\": \"Number of failed jobs\"\n\t\t\t\t\t},\n\t\t\t\t\t\"delayed\": {\n\t\t\t\t\t\t\"type\": \"integer\",\n\t\t\t\t\t\t\"description\": \"Number of delayed jobs\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"Check\": {\n\t\t\t\t\"type\": \"object\",\n\t\t\t\t\"description\": \"A monitoring check result\",\n\t\t\t\t\"properties\": {\n\t\t\t\t\t\"_id\": {\n\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\"description\": \"Check ID\"\n\t\t\t\t\t},\n\t\t\t\t\t\"metadata\": {\n\t\t\t\t\t\t\"type\": \"object\",\n\t\t\t\t\t\t\"properties\": {\n\t\t\t\t\t\t\t\"monitorId\": {\n\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\"description\": \"Associated monitor ID\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"teamId\": {\n\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\"description\": \"Associated team ID\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"type\": {\n\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\"enum\": [\"http\", \"ping\", \"pagespeed\", \"hardware\", \"docker\", \"port\"],\n\t\t\t\t\t\t\t\t\"description\": \"Monitor type\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"required\": [\"monitorId\", \"teamId\", \"type\"]\n\t\t\t\t\t},\n\t\t\t\t\t\"status\": {\n\t\t\t\t\t\t\"type\": \"boolean\",\n\t\t\t\t\t\t\"description\": \"Check status (true = up, false = down)\"\n\t\t\t\t\t},\n\t\t\t\t\t\"responseTime\": {\n\t\t\t\t\t\t\"type\": \"number\",\n\t\t\t\t\t\t\"description\": \"Response time in milliseconds\"\n\t\t\t\t\t},\n\t\t\t\t\t\"statusCode\": {\n\t\t\t\t\t\t\"type\": \"integer\",\n\t\t\t\t\t\t\"description\": \"HTTP status code (for HTTP monitors)\"\n\t\t\t\t\t},\n\t\t\t\t\t\"message\": {\n\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\"description\": \"Status message or error description\"\n\t\t\t\t\t},\n\t\t\t\t\t\"timings\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/schemas/CheckTimings\"\n\t\t\t\t\t},\n\t\t\t\t\t\"cpu\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/schemas/CheckCpuInfo\"\n\t\t\t\t\t},\n\t\t\t\t\t\"memory\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/schemas/CheckMemoryInfo\"\n\t\t\t\t\t},\n\t\t\t\t\t\"disk\": {\n\t\t\t\t\t\t\"type\": \"array\",\n\t\t\t\t\t\t\"items\": {\n\t\t\t\t\t\t\t\"$ref\": \"#/components/schemas/CheckDiskInfo\"\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"host\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/schemas/CheckHostInfo\"\n\t\t\t\t\t},\n\t\t\t\t\t\"errors\": {\n\t\t\t\t\t\t\"type\": \"array\",\n\t\t\t\t\t\t\"items\": {\n\t\t\t\t\t\t\t\"$ref\": \"#/components/schemas/CheckErrorInfo\"\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"capture\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/schemas/CheckCaptureInfo\"\n\t\t\t\t\t},\n\t\t\t\t\t\"net\": {\n\t\t\t\t\t\t\"type\": \"array\",\n\t\t\t\t\t\t\"items\": {\n\t\t\t\t\t\t\t\"$ref\": \"#/components/schemas/CheckNetworkInfo\"\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"accessibility\": {\n\t\t\t\t\t\t\"type\": \"number\",\n\t\t\t\t\t\t\"description\": \"PageSpeed accessibility score (0-100)\"\n\t\t\t\t\t},\n\t\t\t\t\t\"bestPractices\": {\n\t\t\t\t\t\t\"type\": \"number\",\n\t\t\t\t\t\t\"description\": \"PageSpeed best practices score (0-100)\"\n\t\t\t\t\t},\n\t\t\t\t\t\"seo\": {\n\t\t\t\t\t\t\"type\": \"number\",\n\t\t\t\t\t\t\"description\": \"PageSpeed SEO score (0-100)\"\n\t\t\t\t\t},\n\t\t\t\t\t\"performance\": {\n\t\t\t\t\t\t\"type\": \"number\",\n\t\t\t\t\t\t\"description\": \"PageSpeed performance score (0-100)\"\n\t\t\t\t\t},\n\t\t\t\t\t\"audits\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/schemas/CheckAudits\"\n\t\t\t\t\t},\n\t\t\t\t\t\"ack\": {\n\t\t\t\t\t\t\"type\": \"boolean\",\n\t\t\t\t\t\t\"description\": \"Whether the check has been acknowledged\"\n\t\t\t\t\t},\n\t\t\t\t\t\"ackAt\": {\n\t\t\t\t\t\t\"type\": [\"string\", \"null\"],\n\t\t\t\t\t\t\"format\": \"date-time\",\n\t\t\t\t\t\t\"description\": \"When the check was acknowledged\"\n\t\t\t\t\t},\n\t\t\t\t\t\"expiry\": {\n\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\"format\": \"date-time\",\n\t\t\t\t\t\t\"description\": \"When the check expires\"\n\t\t\t\t\t},\n\t\t\t\t\t\"createdAt\": {\n\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\"format\": \"date-time\"\n\t\t\t\t\t},\n\t\t\t\t\t\"updatedAt\": {\n\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\"format\": \"date-time\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"CheckTimings\": {\n\t\t\t\t\"type\": \"object\",\n\t\t\t\t\"description\": \"Detailed timing information for HTTP checks\",\n\t\t\t\t\"properties\": {\n\t\t\t\t\t\"start\": {\n\t\t\t\t\t\t\"type\": \"number\"\n\t\t\t\t\t},\n\t\t\t\t\t\"socket\": {\n\t\t\t\t\t\t\"type\": \"number\"\n\t\t\t\t\t},\n\t\t\t\t\t\"lookup\": {\n\t\t\t\t\t\t\"type\": \"number\"\n\t\t\t\t\t},\n\t\t\t\t\t\"connect\": {\n\t\t\t\t\t\t\"type\": \"number\"\n\t\t\t\t\t},\n\t\t\t\t\t\"secureConnect\": {\n\t\t\t\t\t\t\"type\": \"number\"\n\t\t\t\t\t},\n\t\t\t\t\t\"upload\": {\n\t\t\t\t\t\t\"type\": \"number\"\n\t\t\t\t\t},\n\t\t\t\t\t\"response\": {\n\t\t\t\t\t\t\"type\": \"number\"\n\t\t\t\t\t},\n\t\t\t\t\t\"end\": {\n\t\t\t\t\t\t\"type\": \"number\"\n\t\t\t\t\t},\n\t\t\t\t\t\"phases\": {\n\t\t\t\t\t\t\"type\": \"object\",\n\t\t\t\t\t\t\"properties\": {\n\t\t\t\t\t\t\t\"wait\": {\n\t\t\t\t\t\t\t\t\"type\": \"number\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"dns\": {\n\t\t\t\t\t\t\t\t\"type\": \"number\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"tcp\": {\n\t\t\t\t\t\t\t\t\"type\": \"number\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"tls\": {\n\t\t\t\t\t\t\t\t\"type\": \"number\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"request\": {\n\t\t\t\t\t\t\t\t\"type\": \"number\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"firstByte\": {\n\t\t\t\t\t\t\t\t\"type\": \"number\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"download\": {\n\t\t\t\t\t\t\t\t\"type\": \"number\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"total\": {\n\t\t\t\t\t\t\t\t\"type\": \"number\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"CheckCpuInfo\": {\n\t\t\t\t\"type\": \"object\",\n\t\t\t\t\"description\": \"CPU information for infrastructure checks\",\n\t\t\t\t\"properties\": {\n\t\t\t\t\t\"physical_core\": {\n\t\t\t\t\t\t\"type\": \"integer\"\n\t\t\t\t\t},\n\t\t\t\t\t\"logical_core\": {\n\t\t\t\t\t\t\"type\": \"integer\"\n\t\t\t\t\t},\n\t\t\t\t\t\"frequency\": {\n\t\t\t\t\t\t\"type\": \"number\"\n\t\t\t\t\t},\n\t\t\t\t\t\"temperature\": {\n\t\t\t\t\t\t\"type\": \"array\",\n\t\t\t\t\t\t\"items\": {\n\t\t\t\t\t\t\t\"type\": \"number\"\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"free_percent\": {\n\t\t\t\t\t\t\"type\": \"number\"\n\t\t\t\t\t},\n\t\t\t\t\t\"usage_percent\": {\n\t\t\t\t\t\t\"type\": \"number\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"CheckMemoryInfo\": {\n\t\t\t\t\"type\": \"object\",\n\t\t\t\t\"description\": \"Memory information for infrastructure checks\",\n\t\t\t\t\"properties\": {\n\t\t\t\t\t\"total_bytes\": {\n\t\t\t\t\t\t\"type\": \"number\"\n\t\t\t\t\t},\n\t\t\t\t\t\"available_bytes\": {\n\t\t\t\t\t\t\"type\": \"number\"\n\t\t\t\t\t},\n\t\t\t\t\t\"used_bytes\": {\n\t\t\t\t\t\t\"type\": \"number\"\n\t\t\t\t\t},\n\t\t\t\t\t\"usage_percent\": {\n\t\t\t\t\t\t\"type\": \"number\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"CheckDiskInfo\": {\n\t\t\t\t\"type\": \"object\",\n\t\t\t\t\"description\": \"Disk information for infrastructure checks\",\n\t\t\t\t\"properties\": {\n\t\t\t\t\t\"device\": {\n\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t},\n\t\t\t\t\t\"mountpoint\": {\n\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t},\n\t\t\t\t\t\"read_speed_bytes\": {\n\t\t\t\t\t\t\"type\": \"number\"\n\t\t\t\t\t},\n\t\t\t\t\t\"write_speed_bytes\": {\n\t\t\t\t\t\t\"type\": \"number\"\n\t\t\t\t\t},\n\t\t\t\t\t\"total_bytes\": {\n\t\t\t\t\t\t\"type\": \"number\"\n\t\t\t\t\t},\n\t\t\t\t\t\"free_bytes\": {\n\t\t\t\t\t\t\"type\": \"number\"\n\t\t\t\t\t},\n\t\t\t\t\t\"usage_percent\": {\n\t\t\t\t\t\t\"type\": \"number\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"CheckHostInfo\": {\n\t\t\t\t\"type\": \"object\",\n\t\t\t\t\"description\": \"Host information for infrastructure checks\",\n\t\t\t\t\"properties\": {\n\t\t\t\t\t\"os\": {\n\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t},\n\t\t\t\t\t\"platform\": {\n\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t},\n\t\t\t\t\t\"kernel_version\": {\n\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"CheckErrorInfo\": {\n\t\t\t\t\"type\": \"object\",\n\t\t\t\t\"description\": \"Error information from checks\",\n\t\t\t\t\"properties\": {\n\t\t\t\t\t\"metric\": {\n\t\t\t\t\t\t\"type\": \"array\",\n\t\t\t\t\t\t\"items\": {\n\t\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"err\": {\n\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"CheckCaptureInfo\": {\n\t\t\t\t\"type\": \"object\",\n\t\t\t\t\"description\": \"Capture agent information\",\n\t\t\t\t\"properties\": {\n\t\t\t\t\t\"version\": {\n\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t},\n\t\t\t\t\t\"mode\": {\n\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"CheckNetworkInfo\": {\n\t\t\t\t\"type\": \"object\",\n\t\t\t\t\"description\": \"Network interface information\",\n\t\t\t\t\"properties\": {\n\t\t\t\t\t\"name\": {\n\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t},\n\t\t\t\t\t\"bytes_sent\": {\n\t\t\t\t\t\t\"type\": \"number\"\n\t\t\t\t\t},\n\t\t\t\t\t\"bytes_recv\": {\n\t\t\t\t\t\t\"type\": \"number\"\n\t\t\t\t\t},\n\t\t\t\t\t\"packets_sent\": {\n\t\t\t\t\t\t\"type\": \"number\"\n\t\t\t\t\t},\n\t\t\t\t\t\"packets_recv\": {\n\t\t\t\t\t\t\"type\": \"number\"\n\t\t\t\t\t},\n\t\t\t\t\t\"err_in\": {\n\t\t\t\t\t\t\"type\": \"number\"\n\t\t\t\t\t},\n\t\t\t\t\t\"err_out\": {\n\t\t\t\t\t\t\"type\": \"number\"\n\t\t\t\t\t},\n\t\t\t\t\t\"drop_in\": {\n\t\t\t\t\t\t\"type\": \"number\"\n\t\t\t\t\t},\n\t\t\t\t\t\"drop_out\": {\n\t\t\t\t\t\t\"type\": \"number\"\n\t\t\t\t\t},\n\t\t\t\t\t\"fifo_in\": {\n\t\t\t\t\t\t\"type\": \"number\"\n\t\t\t\t\t},\n\t\t\t\t\t\"fifo_out\": {\n\t\t\t\t\t\t\"type\": \"number\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"CheckAudits\": {\n\t\t\t\t\"type\": \"object\",\n\t\t\t\t\"description\": \"PageSpeed audit results\",\n\t\t\t\t\"properties\": {\n\t\t\t\t\t\"cls\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/schemas/LighthouseAudit\"\n\t\t\t\t\t},\n\t\t\t\t\t\"si\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/schemas/LighthouseAudit\"\n\t\t\t\t\t},\n\t\t\t\t\t\"fcp\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/schemas/LighthouseAudit\"\n\t\t\t\t\t},\n\t\t\t\t\t\"lcp\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/schemas/LighthouseAudit\"\n\t\t\t\t\t},\n\t\t\t\t\t\"tbt\": {\n\t\t\t\t\t\t\"$ref\": \"#/components/schemas/LighthouseAudit\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t\"LighthouseAudit\": {\n\t\t\t\t\"type\": \"object\",\n\t\t\t\t\"description\": \"Individual Lighthouse audit result\",\n\t\t\t\t\"properties\": {\n\t\t\t\t\t\"id\": {\n\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t},\n\t\t\t\t\t\"title\": {\n\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t},\n\t\t\t\t\t\"score\": {\n\t\t\t\t\t\t\"type\": \"number\"\n\t\t\t\t\t},\n\t\t\t\t\t\"displayValue\": {\n\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t},\n\t\t\t\t\t\"numericValue\": {\n\t\t\t\t\t\t\"type\": \"number\"\n\t\t\t\t\t},\n\t\t\t\t\t\"numericUnit\": {\n\t\t\t\t\t\t\"type\": \"string\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "server/package.json",
    "content": "{\n\t\"name\": \"server\",\n\t\"version\": \"1.0.0\",\n\t\"description\": \"\",\n\t\"main\": \"index.js\",\n\t\"type\": \"module\",\n\t\"scripts\": {\n\t\t\"test\": \"NODE_OPTIONS=--experimental-vm-modules c8 jest --runInBand\",\n\t\t\"dev\": \"nodemon --exec tsx src/index.js\",\n\t\t\"start\": \"node --watch ./dist/index.js\",\n\t\t\"build\": \"tsc && tsc-alias && cp -r src/templates dist/templates\",\n\t\t\"lint\": \"eslint .\",\n\t\t\"lint-fix\": \"eslint --fix .\",\n\t\t\"format\": \"prettier --write .\",\n\t\t\"format-check\": \"prettier --check .\"\n\t},\n\t\"lint-staged\": {\n\t\t\"**/*\": \"prettier --write\"\n\t},\n\t\"keywords\": [],\n\t\"author\": \"\",\n\t\"license\": \"ISC\",\n\t\"engines\": {\n\t\t\"node\": \">=20\"\n\t},\n\t\"dependencies\": {\n\t\t\"@grpc/grpc-js\": \"^1.14.3\",\n\t\t\"@grpc/proto-loader\": \"^0.8.0\",\n\t\t\"@pulsecron/pulse\": \"1.6.8\",\n\t\t\"axios\": \"^1.7.2\",\n\t\t\"bcryptjs\": \"3.0.2\",\n\t\t\"bullmq\": \"5.41.2\",\n\t\t\"cacheable-lookup\": \"7.0.0\",\n\t\t\"compression\": \"1.8.1\",\n\t\t\"cookie-parser\": \"^1.4.7\",\n\t\t\"cors\": \"^2.8.5\",\n\t\t\"dockerode\": \"4.0.6\",\n\t\t\"dotenv\": \"^16.4.5\",\n\t\t\"express\": \"^4.19.2\",\n\t\t\"express-rate-limit\": \"8.0.1\",\n\t\t\"gamedig\": \"5.2.0\",\n\t\t\"got\": \"14.4.7\",\n\t\t\"handlebars\": \"^4.7.8\",\n\t\t\"helmet\": \"^8.0.0\",\n\t\t\"ioredis\": \"^5.4.2\",\n\t\t\"isomorphic-dompurify\": \"^2.26.0\",\n\t\t\"jmespath\": \"^0.16.0\",\n\t\t\"jsdom\": \"^26.1.0\",\n\t\t\"jsonwebtoken\": \"9.0.2\",\n\t\t\"mailersend\": \"^2.2.0\",\n\t\t\"mjml\": \"^5.0.0-alpha.4\",\n\t\t\"mongoose\": \"^8.3.3\",\n\t\t\"multer\": \"^1.4.5-lts.1\",\n\t\t\"nodemailer\": \"8.0.1\",\n\t\t\"ping\": \"0.4.4\",\n\t\t\"sharp\": \"0.33.5\",\n\t\t\"ssl-checker\": \"2.0.10\",\n\t\t\"super-simple-scheduler\": \"1.4.5\",\n\t\t\"swagger-ui-express\": \"5.0.1\",\n\t\t\"winston\": \"^3.13.0\",\n\t\t\"ws\": \"^8.19.0\",\n\t\t\"zod\": \"^4.3.6\"\n\t},\n\t\"devDependencies\": {\n\t\t\"@eslint/js\": \"^9.17.0\",\n\t\t\"@types/compression\": \"1.8.1\",\n\t\t\"@types/cookie-parser\": \"1.4.10\",\n\t\t\"@types/cors\": \"2.8.19\",\n\t\t\"@types/dockerode\": \"^4.0.0\",\n\t\t\"@types/express\": \"5.0.3\",\n\t\t\"@types/gamedig\": \"^5.0.3\",\n\t\t\"@types/jest\": \"^30.0.0\",\n\t\t\"@types/jmespath\": \"^0.15.2\",\n\t\t\"@types/jsdom\": \"^27.0.0\",\n\t\t\"@types/jsonwebtoken\": \"9.0.10\",\n\t\t\"@types/mjml\": \"^4.7.4\",\n\t\t\"@types/multer\": \"^2.0.0\",\n\t\t\"@types/nodemailer\": \"7.0.1\",\n\t\t\"@types/papaparse\": \"^5.5.2\",\n\t\t\"@types/ping\": \"0.4.4\",\n\t\t\"@types/swagger-ui-express\": \"4.1.8\",\n\t\t\"@types/ws\": \"^8.18.1\",\n\t\t\"@typescript-eslint/eslint-plugin\": \"^8.56.1\",\n\t\t\"@typescript-eslint/parser\": \"^8.56.1\",\n\t\t\"c8\": \"10.1.3\",\n\t\t\"eslint\": \"^9.17.0\",\n\t\t\"eslint-plugin-mocha\": \"^10.5.0\",\n\t\t\"esm\": \"3.2.25\",\n\t\t\"globals\": \"^15.14.0\",\n\t\t\"jest\": \"^30.2.0\",\n\t\t\"lint-staged\": \"^16.2.7\",\n\t\t\"nodemon\": \"^3.1.11\",\n\t\t\"prettier\": \"^3.3.3\",\n\t\t\"ts-jest\": \"^29.4.6\",\n\t\t\"ts-node\": \"^10.9.2\",\n\t\t\"tsc-alias\": \"1.8.16\",\n\t\t\"tsx\": \"4.20.5\",\n\t\t\"typescript\": \"5.9.2\",\n\t\t\"typescript-eslint\": \"^8.56.1\"\n\t}\n}\n"
  },
  {
    "path": "server/scripts/generate-checks.js",
    "content": "import mongoose from \"mongoose\";\nimport { MonitorModel } from \"../dist/db/models/Monitor.js\";\nimport { CheckModel } from \"../dist/db/models/Check.js\";\n\nconst DEFAULT_MONITOR_ID = \"000000000000000000000001\";\nconst DEFAULT_MONITOR_TYPE = \"http\";\nconst DEFAULT_TOTAL = 1_000_000;\nconst DEFAULT_BATCH_SIZE = 5_000;\n\nconst parseObjectId = (value, fallback) => {\n\ttry {\n\t\treturn new mongoose.Types.ObjectId(value || fallback);\n\t} catch {\n\t\tconsole.warn(`Invalid ObjectId '${value}', falling back to '${fallback}'.`);\n\t\treturn new mongoose.Types.ObjectId(fallback);\n\t}\n};\n\nasync function ensureMonitor({ monitorId, teamId, userId, type }) {\n\tconst existing = await MonitorModel.findById(monitorId);\n\tif (existing) {\n\t\treturn existing;\n\t}\n\n\tconsole.log(`Monitor ${monitorId.toString()} not found, creating it.`);\n\tconst monitor = new MonitorModel({\n\t\t_id: monitorId,\n\t\tuserId,\n\t\tteamId,\n\t\tname: `Seed Monitor ${monitorId.toString()}`,\n\t\tdescription: \"Synthetic monitor for performance testing\",\n\t\tstatusWindow: [],\n\t\tstatusWindowSize: 5,\n\t\tstatusWindowThreshold: 60,\n\t\ttype,\n\t\tignoreTlsErrors: false,\n\t\turl: \"https://example.com\",\n\t\tisActive: true,\n\t\tinterval: 60000,\n\t\talertThreshold: 5,\n\t\tcpuAlertThreshold: 5,\n\t\tmemoryAlertThreshold: 5,\n\t\tdiskAlertThreshold: 5,\n\t\ttempAlertThreshold: 5,\n\t\tselectedDisks: [],\n\t});\n\n\tawait monitor.save();\n\treturn monitor;\n}\n\nasync function run() {\n\tconst mongoUri = process.env.MONGO_URI ?? \"mongodb://localhost:27017/uptime_db\";\n\tconst monitorId = parseObjectId(process.env.MONITOR_ID ?? DEFAULT_MONITOR_ID, DEFAULT_MONITOR_ID);\n\tconst teamId = parseObjectId(\"6971546de1b2bc3de6498e6e\");\n\tconst userId = parseObjectId(\"6971546de1b2bc3de6498e70\");\n\tconst monitorType = process.env.MONITOR_TYPE ?? DEFAULT_MONITOR_TYPE;\n\tconst total = Number(process.env.CHECK_TOTAL ?? DEFAULT_TOTAL);\n\tconst batchSize = Number(process.env.CHECK_BATCH_SIZE ?? DEFAULT_BATCH_SIZE);\n\n\tconsole.log(`Connecting to MongoDB at ${mongoUri}`);\n\tawait mongoose.connect(mongoUri);\n\n\tawait ensureMonitor({ monitorId, teamId, userId, type: monitorType });\n\n\tconsole.log(`Seeding ${total} checks for monitor ${monitorId.toString()} (team ${teamId.toString()}) in batches of ${batchSize}.`);\n\n\tconst docs = [];\n\tconst startTime = Date.now();\n\n\tfor (let i = 0; i < total; i += 1) {\n\t\tconst baseTime = Date.now() - (total - i) * 1000;\n\t\tconst createdAt = new Date(baseTime);\n\t\tdocs.push({\n\t\t\tmetadata: {\n\t\t\t\tmonitorId,\n\t\t\t\tteamId,\n\t\t\t\ttype: monitorType,\n\t\t\t},\n\t\t\tstatus: i % 50 !== 0,\n\t\t\tstatusCode: i % 50 !== 0 ? 200 : 500,\n\t\t\tresponseTime: Math.floor(Math.random() * 1000),\n\t\t\tmessage: i % 50 !== 0 ? \"OK\" : \"Error\",\n\t\t\texpiry: createdAt,\n\t\t\tcreatedAt,\n\t\t\tupdatedAt: createdAt,\n\t\t\ttimings: {\n\t\t\t\tstart: baseTime,\n\t\t\t\tsocket: baseTime,\n\t\t\t\tlookup: baseTime,\n\t\t\t\tconnect: baseTime,\n\t\t\t\tsecureConnect: baseTime,\n\t\t\t\tupload: baseTime,\n\t\t\t\tresponse: baseTime + 40,\n\t\t\t\tend: baseTime + 45,\n\t\t\t\tphases: {\n\t\t\t\t\twait: 0,\n\t\t\t\t\tdns: 1,\n\t\t\t\t\ttcp: 2,\n\t\t\t\t\ttls: 4,\n\t\t\t\t\trequest: 0,\n\t\t\t\t\tfirstByte: 30,\n\t\t\t\t\tdownload: 5,\n\t\t\t\t\ttotal: 45,\n\t\t\t\t},\n\t\t\t},\n\t\t\tcpu: {\n\t\t\t\tphysical_core: 8,\n\t\t\t\tlogical_core: 16,\n\t\t\t\tfrequency: 3600,\n\t\t\t\ttemperature: [50 + Math.random() * 10],\n\t\t\t\tfree_percent: 40,\n\t\t\t\tusage_percent: Math.random() * 100,\n\t\t\t},\n\t\t\tmemory: {\n\t\t\t\ttotal_bytes: 32 * 1024 ** 3,\n\t\t\t\tavailable_bytes: 16 * 1024 ** 3,\n\t\t\t\tused_bytes: 16 * 1024 ** 3,\n\t\t\t\tusage_percent: Math.random() * 100,\n\t\t\t},\n\t\t\tdisk: [\n\t\t\t\t{\n\t\t\t\t\tdevice: \"/dev/sda1\",\n\t\t\t\t\tmountpoint: \"/\",\n\t\t\t\t\tread_speed_bytes: Math.random() * 10_000_000,\n\t\t\t\t\twrite_speed_bytes: Math.random() * 10_000_000,\n\t\t\t\t\ttotal_bytes: 512 * 1024 ** 3,\n\t\t\t\t\tfree_bytes: 128 * 1024 ** 3,\n\t\t\t\t\tusage_percent: Math.random() * 100,\n\t\t\t\t},\n\t\t\t],\n\t\t\thost: {\n\t\t\t\tos: \"linux\",\n\t\t\t\tplatform: \"ubuntu\",\n\t\t\t\tkernel_version: \"5.15.0\",\n\t\t\t},\n\t\t\tnet: [\n\t\t\t\t{\n\t\t\t\t\tname: \"eth0\",\n\t\t\t\t\tbytes_sent: Math.random() * 10_000_000,\n\t\t\t\t\tbytes_recv: Math.random() * 10_000_000,\n\t\t\t\t\tpackets_sent: Math.random() * 1_000_000,\n\t\t\t\t\tpackets_recv: Math.random() * 1_000_000,\n\t\t\t\t\terr_in: 0,\n\t\t\t\t\terr_out: 0,\n\t\t\t\t\tdrop_in: 0,\n\t\t\t\t\tdrop_out: 0,\n\t\t\t\t\tfifo_in: 0,\n\t\t\t\t\tfifo_out: 0,\n\t\t\t\t},\n\t\t\t],\n\t\t\terrors: i % 50 === 0 ? [{ metric: [\"uptime\"], err: \"500\" }] : [],\n\t\t});\n\n\t\tif (docs.length === batchSize) {\n\t\t\tawait CheckModel.insertMany(docs, { ordered: false });\n\t\t\tconsole.log(`Inserted ${i + 1} / ${total}`);\n\t\t\tdocs.length = 0;\n\t\t}\n\t}\n\n\tif (docs.length > 0) {\n\t\tawait CheckModel.insertMany(docs, { ordered: false });\n\t}\n\n\tawait mongoose.disconnect();\n\tconst duration = ((Date.now() - startTime) / 1000).toFixed(2);\n\tconsole.log(`Finished inserting ${total} checks in ${duration}s`);\n}\n\nrun().catch((error) => {\n\tconsole.error(\"Failed to seed checks\", error);\n\tprocess.exit(1);\n});\n"
  },
  {
    "path": "server/src/app.ts",
    "content": "import express from \"express\";\nimport path from \"path\";\nimport cors from \"cors\";\nimport helmet from \"helmet\";\nimport compression from \"compression\";\nimport cookieParser from \"cookie-parser\";\nimport swaggerUi, { type JsonObject } from \"swagger-ui-express\";\nimport { handleErrors } from \"@/middleware/handleErrors.js\";\nimport { generalApiLimiter } from \"@/middleware/rateLimiter.js\";\nimport { sanitizeBody, sanitizeQuery } from \"@/middleware/sanitization.js\";\nimport { setupRoutes } from \"@/config/routes.js\";\nimport { InitializedServices } from \"@/config/services.js\";\nimport { InitializedControllers } from \"@/config/controllers.js\";\nimport { EnvConfig } from \"@/service/system/settingsService.js\";\n\nexport const createApp = ({\n\tservices,\n\tcontrollers,\n\tenvSettings,\n\tfrontendPath,\n\topenApiSpec,\n}: {\n\tservices: InitializedServices;\n\tcontrollers: InitializedControllers;\n\tenvSettings: EnvConfig;\n\tfrontendPath: string;\n\topenApiSpec: JsonObject;\n}) => {\n\tconst allowedOrigin = envSettings.clientHost;\n\tconst app = express();\n\n\tapp.use(generalApiLimiter);\n\n\tapp.use(\n\t\tcors({\n\t\t\torigin: allowedOrigin,\n\t\t\tmethods: \"GET,HEAD,PUT,PATCH,POST,DELETE,OPTIONS\",\n\t\t\tallowedHeaders: [\"Content-Type\", \"Authorization\", \"Accept-Language\"],\n\t\t\tcredentials: true,\n\t\t})\n\t);\n\n\tapp.use(express.static(frontendPath));\n\n\tapp.use(express.json());\n\tapp.use(cookieParser());\n\n\tapp.use(sanitizeBody());\n\tapp.use(sanitizeQuery());\n\n\tapp.use(\n\t\thelmet({\n\t\t\thsts: false,\n\t\t\tcontentSecurityPolicy: {\n\t\t\t\tuseDefaults: true,\n\t\t\t\tdirectives: {\n\t\t\t\t\tupgradeInsecureRequests: null,\n\t\t\t\t\t\"script-src\": [\"'self'\", \"'unsafe-inline'\", \"'unsafe-eval'\"],\n\t\t\t\t\t\"object-src\": [\"'none'\"],\n\t\t\t\t\t\"base-uri\": [\"'self'\"],\n\t\t\t\t},\n\t\t\t},\n\t\t})\n\t);\n\tapp.use(\n\t\tcompression({\n\t\t\tlevel: 6,\n\t\t\tthreshold: 1024,\n\t\t\tfilter: (req, res) => {\n\t\t\t\tif (req.headers[\"x-no-compression\"]) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\treturn compression.filter(req, res);\n\t\t\t},\n\t\t})\n\t);\n\t// Swagger UI — dynamically set server URL from request\n\tapp.use(\"/api-docs\", swaggerUi.serve, (req: express.Request, res: express.Response, next: express.NextFunction) => {\n\t\tconst protocol = req.protocol;\n\t\tconst host = req.get(\"host\");\n\t\tconst dynamicSpec = {\n\t\t\t...openApiSpec,\n\t\t\tservers: [\n\t\t\t\t{\n\t\t\t\t\turl: `${protocol}://${host}/api/v1`,\n\t\t\t\t\tdescription: \"Current Server\",\n\t\t\t\t},\n\t\t\t\t...openApiSpec.servers,\n\t\t\t],\n\t\t};\n\t\tswaggerUi.setup(dynamicSpec)(req, res, next);\n\t});\n\n\tapp.use(\"/api/v1/health\", (req, res) => {\n\t\tres.json({\n\t\t\tstatus: \"OK\",\n\t\t});\n\t});\n\n\t// Main app routes\n\tsetupRoutes(app, controllers, services);\n\n\t// FE routes\n\tapp.get(\"*\", (req, res) => {\n\t\tres.sendFile(path.join(frontendPath, \"index.html\"));\n\t});\n\tapp.use(handleErrors);\n\treturn app;\n};\n"
  },
  {
    "path": "server/src/config/controllers.ts",
    "content": "import MonitorController from \"../controllers/monitorController.js\";\nimport AuthController from \"../controllers/authController.js\";\nimport SettingsController from \"../controllers/settingsController.js\";\nimport CheckController from \"../controllers/checkController.js\";\nimport GeoCheckController from \"../controllers/geoCheckController.js\";\nimport InviteController from \"../controllers/inviteController.js\";\nimport MaintenanceWindowController from \"../controllers/maintenanceWindowController.js\";\nimport QueueController from \"../controllers/queueController.js\";\nimport LogController from \"../controllers/logController.js\";\nimport StatusPageController from \"../controllers/statusPageController.js\";\nimport NotificationController from \"../controllers/notificationController.js\";\nimport DiagnosticController from \"../controllers/diagnosticController.js\";\nimport IncidentController from \"../controllers/incidentController.js\";\nimport type { InitializedServices } from \"@/config/services.js\";\n\nexport interface InitializedControllers {\n\tauthController: AuthController;\n\tmonitorController: MonitorController;\n\tsettingsController: SettingsController;\n\tcheckController: CheckController;\n\tgeoCheckController: GeoCheckController;\n\tinviteController: InviteController;\n\tmaintenanceWindowController: MaintenanceWindowController;\n\tqueueController: QueueController;\n\tlogController: LogController;\n\tstatusPageController: StatusPageController;\n\tnotificationController: NotificationController;\n\tdiagnosticController: DiagnosticController;\n\tincidentController: IncidentController;\n}\nexport const initializeControllers = (services: InitializedServices): InitializedControllers => {\n\treturn {\n\t\tauthController: new AuthController(services.userService),\n\t\tmonitorController: new MonitorController(services.monitorService),\n\t\tsettingsController: new SettingsController(services.settingsService, services.emailService),\n\t\tcheckController: new CheckController(services.checkService),\n\t\tgeoCheckController: new GeoCheckController(services.geoChecksService),\n\t\tinviteController: new InviteController(services.inviteService),\n\t\tmaintenanceWindowController: new MaintenanceWindowController(services.maintenanceWindowService),\n\t\tqueueController: new QueueController(services.jobQueue),\n\t\tlogController: new LogController(services.logger),\n\t\tstatusPageController: new StatusPageController(services.statusPageService, services.monitorsRepository, services.settingsService),\n\t\tnotificationController: new NotificationController(services.notificationsService, services.monitorsRepository),\n\t\tdiagnosticController: new DiagnosticController(services.diagnosticService),\n\t\tincidentController: new IncidentController(services.incidentService),\n\t};\n};\n"
  },
  {
    "path": "server/src/config/routes.ts",
    "content": "import type { Application } from \"express\";\nimport { createVerifyJWT } from \"../middleware/verifyJWT.js\";\nimport { createVerifyStatusPageAccess } from \"../middleware/verifyStatusPageAccess.js\";\nimport { authApiLimiter } from \"../middleware/rateLimiter.js\";\nimport type { InitializedControllers } from \"./controllers.js\";\nimport type { InitializedServices } from \"./services.js\";\n\nimport AuthRoutes from \"../routes/authRoute.js\";\nimport InviteRoutes from \"../routes/inviteRoute.js\";\nimport MonitorRoutes from \"../routes/monitorRoute.js\";\nimport CheckRoutes from \"../routes/checkRoute.js\";\nimport GeoCheckRoutes from \"../routes/geoCheckRoutes.js\";\nimport SettingsRoutes from \"../routes/settingsRoute.js\";\nimport MaintenanceWindowRoutes from \"../routes/maintenanceWindowRoute.js\";\nimport StatusPageRoutes from \"../routes/statusPageRoute.js\";\nimport QueueRoutes from \"../routes/queueRoute.js\";\nimport LogRoutes from \"../routes/logRoutes.js\";\nimport DiagnosticRoutes from \"../routes/diagnosticRoute.js\";\nimport NotificationRoutes from \"../routes/notificationRoute.js\";\n\nimport IncidentRoutes from \"../routes/incidentRoute.js\";\n\nexport const setupRoutes = (app: Application, controllers: InitializedControllers, services: InitializedServices) => {\n\tconst verifyJWT = createVerifyJWT(services.settingsService);\n\tconst authRoutes = new AuthRoutes(controllers.authController, verifyJWT);\n\tconst monitorRoutes = new MonitorRoutes(controllers.monitorController);\n\tconst settingsRoutes = new SettingsRoutes(controllers.settingsController);\n\tconst checkRoutes = new CheckRoutes(controllers.checkController);\n\tconst geoCheckRoutes = new GeoCheckRoutes(controllers.geoCheckController);\n\tconst inviteRoutes = new InviteRoutes(controllers.inviteController, verifyJWT);\n\tconst maintenanceWindowRoutes = new MaintenanceWindowRoutes(controllers.maintenanceWindowController);\n\tconst queueRoutes = new QueueRoutes(controllers.queueController);\n\tconst logRoutes = new LogRoutes(controllers.logController);\n\tconst verifyStatusPageAccess = createVerifyStatusPageAccess(services.statusPagesRepository, verifyJWT);\n\tconst statusPageRoutes = new StatusPageRoutes(controllers.statusPageController, verifyJWT, verifyStatusPageAccess);\n\tconst notificationRoutes = new NotificationRoutes(controllers.notificationController);\n\tconst diagnosticRoutes = new DiagnosticRoutes(controllers.diagnosticController, verifyJWT);\n\tconst incidentRoutes = new IncidentRoutes(controllers.incidentController);\n\n\tapp.use(\"/api/v1/auth\", authApiLimiter, authRoutes.getRouter());\n\tapp.use(\"/api/v1/monitors\", verifyJWT, monitorRoutes.getRouter());\n\tapp.use(\"/api/v1/settings\", verifyJWT, settingsRoutes.getRouter());\n\tapp.use(\"/api/v1/checks\", verifyJWT, checkRoutes.getRouter());\n\tapp.use(\"/api/v1/geo-checks\", verifyJWT, geoCheckRoutes.getRouter());\n\tapp.use(\"/api/v1/invite\", inviteRoutes.getRouter());\n\tapp.use(\"/api/v1/maintenance-window\", verifyJWT, maintenanceWindowRoutes.getRouter());\n\tapp.use(\"/api/v1/queue\", verifyJWT, queueRoutes.getRouter());\n\tapp.use(\"/api/v1/logs\", verifyJWT, logRoutes.getRouter());\n\tapp.use(\"/api/v1/status-page\", statusPageRoutes.getRouter());\n\tapp.use(\"/api/v1/notifications\", verifyJWT, notificationRoutes.getRouter());\n\tapp.use(\"/api/v1/diagnostic\", verifyJWT, diagnosticRoutes.getRouter());\n\tapp.use(\"/api/v1/incidents\", verifyJWT, incidentRoutes.getRouter());\n};\n"
  },
  {
    "path": "server/src/config/services.ts",
    "content": "import MongoDB from \"../db/MongoDB.js\";\nimport { IDb } from \"@/db/IDb.js\";\nimport {\n\t// Service classes\n\tNetworkService,\n\tEmailService,\n\tBufferService,\n\tGlobalPingService,\n\tSuperSimpleQueue,\n\tSuperSimpleQueueHelper,\n\tNotificationsService,\n\tStatusService,\n\tNotificationMessageBuilder,\n\tMonitorService,\n\tStatusPageService,\n\tUserService,\n\tCheckService,\n\tGeoChecksService,\n\tDiagnosticService,\n\tInviteService,\n\tMaintenanceWindowService,\n\tIncidentService,\n\t// Notification providers\n\tWebhookProvider,\n\tSlackProvider,\n\tEmailProvider,\n\tDiscordProvider,\n\tPagerDutyProvider,\n\tMatrixProvider,\n\tTeamsProvider,\n\t// Interfaces\n\tINetworkService,\n\tIEmailService,\n\tIBufferService,\n\tISuperSimpleQueue,\n\tINotificationsService,\n\tIStatusService,\n\tIMonitorService,\n\tIUserService,\n\tICheckService,\n\tIGeoChecksService,\n\tIDiagnosticService,\n\tIInviteService,\n\tIMaintenanceWindowService,\n\tIStatusPageService,\n\tIIncidentService,\n\tINotificationMessageBuilder,\n\tISettingsService,\n\tEnvConfig,\n} from \"@/service/index.js\";\n\n// Network providers\nimport { PingProvider } from \"@/service/infrastructure/network/PingProvider.js\";\nimport { HttpProvider } from \"@/service/infrastructure/network/HttpProvider.js\";\nimport { AdvancedMatcher } from \"@/service/infrastructure/network/AdvancedMatcher.js\";\nimport { PageSpeedProvider } from \"@/service/infrastructure/network/PageSpeedProvider.js\";\nimport { HardwareProvider } from \"@/service/infrastructure/network/HardwareProvider.js\";\nimport { DockerProvider } from \"@/service/infrastructure/network/DockerProvider.js\";\nimport { PortProvider } from \"@/service/infrastructure/network/PortProvider.js\";\nimport { GameProvider } from \"@/service/infrastructure/network/GameProvider.js\";\nimport { GrpcProvider } from \"@/service/infrastructure/network/GrpcProvider.js\";\nimport { WebSocketProvider } from \"@/service/infrastructure/network/WebSocketProvider.js\";\n\n// Third-party\nimport axios from \"axios\";\nimport got from \"got\";\nimport ping from \"ping\";\nimport Docker from \"dockerode\";\nimport net from \"net\";\nimport fs from \"fs\";\nimport path from \"path\";\nimport nodemailer from \"nodemailer\";\nimport pkg from \"handlebars\";\nconst { compile } = pkg;\nimport mjml2html from \"mjml\";\nimport jwt from \"jsonwebtoken\";\nimport crypto from \"crypto\";\nimport { games, GameDig } from \"gamedig\";\nimport jmespath from \"jmespath\";\nimport * as grpc from \"@grpc/grpc-js\";\nimport * as protoLoader from \"@grpc/proto-loader\";\nimport WebSocket from \"ws\";\n\n// Repositories\nimport {\n\tMongoMonitorsRepository,\n\tMongoChecksRepository,\n\tMongoGeoChecksRepository,\n\tMongoMonitorStatsRepository,\n\tMongoStatusPagesRepository,\n\tMongoUsersRepository,\n\tMongoInvitesRepository,\n\tMongoRecoveryTokensRepository,\n\tMongoNotificationsRepository,\n\tMongoIncidentRepository,\n\tMongoTeamsRepository,\n\tMongoMaintenanceWindowsRepository,\n\tIMonitorsRepository,\n\tIChecksRepository,\n\tIGeoChecksRepository,\n\tIMonitorStatsRepository,\n\tIStatusPagesRepository,\n\tIUsersRepository,\n\tIInvitesRepository,\n\tIRecoveryTokensRepository,\n\tISettingsRepository,\n\tINotificationsRepository,\n\tIIncidentsRepository,\n\tITeamsRepository,\n\tIMaintenanceWindowsRepository,\n} from \"@/repositories/index.js\";\nimport { ILogger } from \"@/utils/logger.js\";\n\nexport type InitializedServices = {\n\tsettingsService: ISettingsService;\n\tdb: IDb;\n\tnetworkService: INetworkService;\n\temailService: IEmailService;\n\tbufferService: IBufferService;\n\tstatusService: IStatusService;\n\tjobQueue: ISuperSimpleQueue;\n\tuserService: IUserService;\n\tcheckService: ICheckService;\n\tgeoChecksService: IGeoChecksService;\n\tdiagnosticService: IDiagnosticService;\n\tinviteService: IInviteService;\n\tmaintenanceWindowService: IMaintenanceWindowService;\n\tmonitorService: IMonitorService;\n\tincidentService: IIncidentService;\n\tlogger: ILogger;\n\tnotificationsService: INotificationsService;\n\tstatusPageService: IStatusPageService;\n\tnotificationMessageBuilder: INotificationMessageBuilder;\n\n\t// Repositories\n\tmonitorsRepository: IMonitorsRepository;\n\tchecksRepository: IChecksRepository;\n\tgeoChecksRepository: IGeoChecksRepository;\n\tmonitorStatsRepository: IMonitorStatsRepository;\n\tstatusPagesRepository: IStatusPagesRepository;\n\tusersRepository: IUsersRepository;\n\tinvitesRepository: IInvitesRepository;\n\trecoveryTokensRepository: IRecoveryTokensRepository;\n\tsettingsRepository: ISettingsRepository;\n\tnotificationsRepository: INotificationsRepository;\n\tincidentsRepository: IIncidentsRepository;\n\tteamsRepository: ITeamsRepository;\n\tmaintenanceWindowsRepository: IMaintenanceWindowsRepository;\n};\n\nexport const initializeServices = async ({\n\tlogger,\n\tenvSettings,\n\tsettingsService,\n\tsettingsRepository,\n}: {\n\tlogger: ILogger;\n\tenvSettings: EnvConfig;\n\tsettingsService: ISettingsService;\n\tsettingsRepository: ISettingsRepository;\n}): Promise<InitializedServices> => {\n\t// Create DB\n\n\tconst db = new MongoDB(logger, envSettings);\n\n\tawait db.connect();\n\n\t// Repositories\n\tconst monitorsRepository = new MongoMonitorsRepository();\n\tconst checksRepository = new MongoChecksRepository(logger);\n\tconst geoChecksRepository = new MongoGeoChecksRepository(logger);\n\tconst monitorStatsRepository = new MongoMonitorStatsRepository();\n\tconst statusPagesRepository = new MongoStatusPagesRepository();\n\tconst usersRepository = new MongoUsersRepository();\n\tconst invitesRepository = new MongoInvitesRepository();\n\tconst recoveryTokensRepository = new MongoRecoveryTokensRepository();\n\tconst notificationsRepository = new MongoNotificationsRepository();\n\tconst incidentsRepository = new MongoIncidentRepository();\n\tconst teamsRepository = new MongoTeamsRepository();\n\tconst maintenanceWindowsRepository = new MongoMaintenanceWindowsRepository();\n\n\t// Network providers\n\tconst pingProvider = new PingProvider(ping);\n\tconst httpProvider = new HttpProvider(got, new AdvancedMatcher(jmespath));\n\tconst pageSpeedProvider = new PageSpeedProvider(httpProvider, settingsService, logger);\n\tconst hardwareProvider = new HardwareProvider(httpProvider);\n\tconst dockerProvider = new DockerProvider(logger, Docker);\n\tconst portProvider = new PortProvider(net);\n\tconst gameProvider = new GameProvider(logger, GameDig);\n\tconst grpcProvider = new GrpcProvider(grpc, protoLoader);\n\tconst webSocketProvider = new WebSocketProvider(WebSocket);\n\n\tconst networkService = new NetworkService(axios, logger, [\n\t\tpingProvider,\n\t\thttpProvider,\n\t\tpageSpeedProvider,\n\t\thardwareProvider,\n\t\tdockerProvider,\n\t\tportProvider,\n\t\tgameProvider,\n\t\tgrpcProvider,\n\t\twebSocketProvider,\n\t]);\n\tconst emailService = new EmailService(settingsService, fs, path, compile, mjml2html, nodemailer, logger);\n\n\tconst notificationMessageBuilder = new NotificationMessageBuilder();\n\n\tconst incidentService = new IncidentService(logger, incidentsRepository, monitorsRepository, usersRepository, notificationMessageBuilder);\n\n\tconst checkService = new CheckService(monitorsRepository, logger, checksRepository);\n\n\tconst globalPingService = new GlobalPingService(logger);\n\n\tconst geoChecksService = new GeoChecksService({\n\t\tlogger,\n\t\tgeoChecksRepository,\n\t\tglobalPingService,\n\t\tmonitorsRepository,\n\t});\n\n\tconst bufferService = new BufferService(logger, checkService, geoChecksService, settingsService);\n\n\tconst statusService = new StatusService(logger, bufferService, monitorsRepository, monitorStatsRepository, checksRepository);\n\n\t// Notification providers\n\tconst webhookProvider = new WebhookProvider(logger);\n\tconst slackProvider = new SlackProvider(logger);\n\tconst emailProvider = new EmailProvider(emailService, logger);\n\tconst discordProvider = new DiscordProvider(logger);\n\tconst pagerDutyProvider = new PagerDutyProvider(logger);\n\tconst matrixProvider = new MatrixProvider(logger);\n\tconst teamsProvider = new TeamsProvider(logger);\n\n\tconst notificationsService = new NotificationsService(\n\t\tnotificationsRepository,\n\t\tmonitorsRepository,\n\t\twebhookProvider,\n\t\temailProvider,\n\t\tslackProvider,\n\t\tdiscordProvider,\n\t\tpagerDutyProvider,\n\t\tmatrixProvider,\n\t\tteamsProvider,\n\t\tsettingsService,\n\t\tlogger,\n\t\tnotificationMessageBuilder\n\t);\n\n\tconst superSimpleQueueHelper = new SuperSimpleQueueHelper(\n\t\tlogger,\n\t\tnetworkService,\n\t\tstatusService,\n\t\tnotificationsService,\n\t\tcheckService,\n\t\tsettingsService,\n\t\tbufferService,\n\t\tincidentService,\n\t\tmaintenanceWindowsRepository,\n\t\tmonitorsRepository,\n\t\tteamsRepository,\n\t\tmonitorStatsRepository,\n\t\tchecksRepository,\n\t\tincidentsRepository,\n\t\tgeoChecksService,\n\t\tgeoChecksRepository\n\t);\n\n\tconst superSimpleQueue = await SuperSimpleQueue.create(logger, superSimpleQueueHelper, monitorsRepository);\n\n\t// Business services\n\tconst userService = new UserService({\n\t\tcrypto,\n\t\temailService,\n\t\tsettingsService,\n\t\tlogger,\n\t\tjwt,\n\t\tjobQueue: superSimpleQueue,\n\t\tmonitorsRepository,\n\t\tusersRepository,\n\t\tinvitesRepository,\n\t\trecoveryTokensRepository,\n\t\tsettingsRepository,\n\t\tteamsRepository,\n\t});\n\n\tconst diagnosticService = new DiagnosticService();\n\tconst inviteService = new InviteService({\n\t\tinvitesRepository,\n\t\tsettingsService,\n\t\temailService,\n\t});\n\tconst maintenanceWindowService = new MaintenanceWindowService({\n\t\tmonitorsRepository,\n\t\tmaintenanceWindowsRepository,\n\t});\n\tconst monitorService = new MonitorService({\n\t\tjobQueue: superSimpleQueue,\n\t\temailService,\n\t\tlogger,\n\t\tgames,\n\t\tmonitorsRepository,\n\t\tchecksRepository,\n\t\tgeoChecksRepository,\n\t\tmonitorStatsRepository,\n\t\tstatusPagesRepository,\n\t\tincidentsRepository,\n\t});\n\n\tconst statusPageService = new StatusPageService(statusPagesRepository);\n\n\tconst services = {\n\t\tsettingsService,\n\t\tdb,\n\t\tnetworkService,\n\t\temailService,\n\t\tbufferService,\n\t\tstatusService,\n\t\tjobQueue: superSimpleQueue,\n\t\tuserService,\n\t\tcheckService,\n\t\tgeoChecksService,\n\t\tdiagnosticService,\n\t\tinviteService,\n\t\tmaintenanceWindowService,\n\t\tmonitorService,\n\t\tincidentService,\n\t\tlogger,\n\t\tnotificationsService,\n\t\tstatusPageService,\n\t\tnotificationMessageBuilder,\n\n\t\t// Repositories\n\t\tmonitorsRepository,\n\t\tchecksRepository,\n\t\tgeoChecksRepository,\n\t\tmonitorStatsRepository,\n\t\tstatusPagesRepository,\n\t\tusersRepository,\n\t\tinvitesRepository,\n\t\trecoveryTokensRepository,\n\t\tsettingsRepository,\n\t\tnotificationsRepository,\n\t\tincidentsRepository,\n\t\tteamsRepository,\n\t\tmaintenanceWindowsRepository,\n\t};\n\n\treturn services;\n};\n"
  },
  {
    "path": "server/src/controllers/authController.ts",
    "content": "import { Request, Response, NextFunction } from \"express\";\nimport { AppError } from \"@/utils/AppError.js\";\nimport { requireTeamId, requireUserEmail, requireUserId, requireUserRoles } from \"@/controllers/controllerUtils.js\";\n\nimport {\n\tregistrationBodyValidation,\n\tloginValidation,\n\trecoveryValidation,\n\trecoveryTokenBodyValidation,\n\tnewPasswordValidation,\n} from \"@/validation/authValidation.js\";\n\nimport {\n\teditUserBodyValidation,\n\tcreateUserBodyValidation,\n\tgetUserByIdParamValidation,\n\teditUserByIdParamValidation,\n\teditUserByIdBodyValidation,\n\teditSuperadminUserByIdBodyValidation,\n\teditUserPasswordByIdBodyValidation,\n} from \"@/validation/userValidation.js\";\nimport { IUserService } from \"@/service/index.js\";\n\nconst SERVICE_NAME = \"authController\";\n\nexport interface IAuthController {\n\tregisterUser(req: Request, res: Response, next: NextFunction): Promise<Response | void>;\n\tcreateUser(req: Request, res: Response, next: NextFunction): Promise<Response | void>;\n\tloginUser(req: Request, res: Response, next: NextFunction): Promise<Response | void>;\n\teditUser(req: Request, res: Response, next: NextFunction): Promise<Response | void>;\n\tcheckSuperadminExists(req: Request, res: Response, next: NextFunction): Promise<Response | void>;\n\trequestRecovery(req: Request, res: Response, next: NextFunction): Promise<Response | void>;\n\tvalidateRecovery(req: Request, res: Response, next: NextFunction): Promise<Response | void>;\n\tresetPassword(req: Request, res: Response, next: NextFunction): Promise<Response | void>;\n\tdeleteUser(req: Request, res: Response, next: NextFunction): Promise<Response | void>;\n\tdeleteUserById(req: Request, res: Response, next: NextFunction): Promise<Response | void>;\n\tgetAllUsers(req: Request, res: Response, next: NextFunction): Promise<Response | void>;\n\tgetUserById(req: Request, res: Response, next: NextFunction): Promise<Response | void>;\n\teditUserById(req: Request, res: Response, next: NextFunction): Promise<Response | void>;\n\teditUserPasswordById(req: Request, res: Response, next: NextFunction): Promise<Response | void>;\n}\n\nclass AuthController implements IAuthController {\n\tstatic SERVICE_NAME = SERVICE_NAME;\n\n\tprivate userService: IUserService;\n\n\tconstructor(userService: IUserService) {\n\t\tthis.userService = userService;\n\t}\n\n\tget serviceName() {\n\t\treturn AuthController.SERVICE_NAME;\n\t}\n\n\tregisterUser = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tconst newUser = req.body.user;\n\t\t\tconst newUserToken = req.body.token;\n\t\t\tif (newUser?.email) {\n\t\t\t\tconst newUserEmail = requireUserEmail(newUser.email);\n\t\t\t\tnewUser.email = newUserEmail.toLowerCase();\n\t\t\t}\n\t\t\tconst validatedBody = registrationBodyValidation.parse(newUser);\n\n\t\t\tconst { user, token } = await this.userService.registerUser(validatedBody, newUserToken, req?.file ?? null);\n\t\t\tres.status(200).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: \"User registered successfully\",\n\t\t\t\tdata: { user, token },\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n\n\tcreateUser = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tconst userData = req.body;\n\t\t\tif (userData?.email) {\n\t\t\t\tuserData.email = userData.email.toLowerCase();\n\t\t\t}\n\t\t\tconst validatedBody = createUserBodyValidation.parse(userData);\n\n\t\t\tconst teamId = requireTeamId(req.user?.teamId);\n\t\t\tconst actorRoles = requireUserRoles(req.user?.role);\n\t\t\tconst newUser = await this.userService.createUser(validatedBody, teamId, actorRoles, req?.file ?? null);\n\t\t\tres.status(201).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: \"User created successfully\",\n\t\t\t\tdata: newUser,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n\n\tloginUser = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tif (req.body?.email) {\n\t\t\t\treq.body.email = req.body.email?.toLowerCase();\n\t\t\t}\n\t\t\tloginValidation.parse(req.body);\n\t\t\tconst { user, token } = await this.userService.loginUser(req.body.email, req.body.password);\n\n\t\t\treturn res.status(200).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: \"User logged in successfully\",\n\t\t\t\tdata: {\n\t\t\t\t\tuser,\n\t\t\t\t\ttoken,\n\t\t\t\t},\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n\n\teditUser = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tconst validatedBody = editUserBodyValidation.parse(req.body);\n\t\t\tconst userId = requireUserId(req.user?.id);\n\t\t\tconst userEmail = requireUserEmail(req.user?.email);\n\t\t\tconst updatedUser = await this.userService.editUser(validatedBody, req?.file ?? null, userId, userEmail);\n\n\t\t\tres.status(200).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: \"User updated successfully\",\n\t\t\t\tdata: updatedUser,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n\n\tcheckSuperadminExists = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tconst superAdminExists = await this.userService.checkSuperadminExists();\n\t\t\treturn res.status(200).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: \"Superadmin existence checked successfully\",\n\t\t\t\tdata: superAdminExists,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n\n\trequestRecovery = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\trecoveryValidation.parse(req.body);\n\t\t\tconst email = req?.body?.email;\n\t\t\tconst msgId = await this.userService.requestRecovery(email);\n\t\t\treturn res.status(200).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: \"Password recovery email sent successfully\",\n\t\t\t\tdata: msgId,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n\n\tvalidateRecovery = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\trecoveryTokenBodyValidation.parse(req.body);\n\t\t\tawait this.userService.validateRecovery(req.body.recoveryToken);\n\t\t\treturn res.status(200).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: \"Recovery token is valid\",\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n\n\tresetPassword = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tnewPasswordValidation.parse(req.body);\n\t\t\tconst { user, token } = await this.userService.resetPassword(req.body.password, req.body.recoveryToken);\n\t\t\treturn res.status(200).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: \"Password has been reset successfully\",\n\t\t\t\tdata: { user, token },\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n\n\tdeleteUser = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tconst userId = requireUserId(req.user?.id);\n\t\t\tconst teamId = requireTeamId(req.user?.teamId);\n\t\t\tconst roles = requireUserRoles(req.user?.role);\n\n\t\t\tawait this.userService.deleteUser({\n\t\t\t\tuserId,\n\t\t\t\tteamId,\n\t\t\t\troles,\n\t\t\t});\n\t\t\treturn res.status(200).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: \"User deleted successfully\",\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n\n\tdeleteUserById = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tconst validatedParams = getUserByIdParamValidation.parse(req.params);\n\t\t\tconst targetUserId = validatedParams.userId;\n\t\t\tconst actorId = requireUserId(req.user?.id);\n\t\t\tconst actorTeamId = requireTeamId(req.user?.teamId);\n\t\t\tconst actorRoles = requireUserRoles(req.user?.role);\n\t\t\tawait this.userService.deleteUserById({ actorId, actorTeamId, actorRoles, targetUserId });\n\t\t\treturn res.status(200).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: \"User removed successfully\",\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n\n\tgetAllUsers = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tconst allUsers = await this.userService.getAllUsers();\n\t\t\treturn res.status(200).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: \"Users retrieved successfully\",\n\t\t\t\tdata: allUsers,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n\n\tgetUserById = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tconst validatedParams = getUserByIdParamValidation.parse(req.params);\n\t\t\tconst actorRoles = requireUserRoles(req.user?.role);\n\t\t\tconst user = await this.userService.getUserById(actorRoles, validatedParams.userId);\n\n\t\t\treturn res.status(200).json({ success: true, msg: \"ok\", data: user });\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n\n\teditUserById = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tconst actorRoles = requireUserRoles(req.user?.role);\n\t\t\tconst actorId = requireUserId(req.user?.id);\n\n\t\t\tif (!actorRoles.includes(\"superadmin\")) {\n\t\t\t\tthrow new AppError({ message: \"Unauthorized\", status: 403 });\n\t\t\t}\n\n\t\t\tconst validatedParams = editUserByIdParamValidation.parse(req.params);\n\t\t\t// If this is superadmin self edit, allow \"superadmin\" role\n\t\t\tconst validatedBody =\n\t\t\t\tvalidatedParams.userId === actorId ? editSuperadminUserByIdBodyValidation.parse(req.body) : editUserByIdBodyValidation.parse(req.body);\n\n\t\t\tawait this.userService.editUserById(validatedParams.userId, validatedBody);\n\t\t\treturn res.status(200).json({ success: true, msg: \"ok\" });\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n\n\teditUserPasswordById = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tconst actorRoles = requireUserRoles(req.user?.role);\n\t\t\tif (!actorRoles.includes(\"superadmin\")) {\n\t\t\t\tthrow new AppError({ message: \"Unauthorized\", status: 403 });\n\t\t\t}\n\n\t\t\tconst validatedParams = editUserByIdParamValidation.parse(req.params);\n\t\t\tconst validatedBody = editUserPasswordByIdBodyValidation.parse(req.body);\n\t\t\tawait this.userService.setPasswordByUserId(validatedParams.userId, validatedBody.password);\n\t\t\treturn res.status(200).json({ success: true, msg: \"Password reset successfully\" });\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n}\n\nexport default AuthController;\n"
  },
  {
    "path": "server/src/controllers/checkController.ts",
    "content": "import { Request, Response, NextFunction } from \"express\";\n\nimport {\n\tgetChecksParamValidation,\n\tgetChecksQueryValidation,\n\tgetTeamChecksQueryValidation,\n\tgetChecksSummaryByTeamIdQueryValidation,\n\tdeleteChecksParamValidation,\n} from \"@/validation/checkValidation.js\";\nimport { ICheckService } from \"@/service/index.js\";\nimport { requireTeamId } from \"@/controllers/controllerUtils.js\";\n\nconst SERVICE_NAME = \"checkController\";\n\nexport interface ICheckController {\n\tserviceName: string;\n\tgetChecksByMonitor: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;\n\tgetChecksByTeam: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;\n\tgetChecksSummaryByTeamId: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;\n\tdeleteChecks: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;\n\tdeleteChecksByTeamId: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;\n}\n\nclass CheckController implements ICheckController {\n\tstatic SERVICE_NAME = SERVICE_NAME;\n\n\tprivate checkService: ICheckService;\n\tconstructor(checkService: ICheckService) {\n\t\tthis.checkService = checkService;\n\t}\n\n\tget serviceName() {\n\t\treturn CheckController.SERVICE_NAME;\n\t}\n\n\tgetChecksByMonitor = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tconst validatedParams = getChecksParamValidation.parse(req.params);\n\t\t\tconst validatedQuery = getChecksQueryValidation.parse(req.query);\n\n\t\t\tconst teamId = requireTeamId(req.user?.teamId);\n\n\t\t\tconst result = await this.checkService.getChecksByMonitor({\n\t\t\t\tmonitorId: validatedParams.monitorId,\n\t\t\t\tteamId,\n\t\t\t\tsortOrder: validatedQuery.sortOrder,\n\t\t\t\tdateRange: validatedQuery.dateRange,\n\t\t\t\tfilter: validatedQuery.filter,\n\t\t\t\tpage: validatedQuery.page,\n\t\t\t\trowsPerPage: validatedQuery.rowsPerPage,\n\t\t\t\tstatus: validatedQuery.status,\n\t\t\t});\n\n\t\t\treturn res.status(200).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: \"Checks retrieved successfully\",\n\t\t\t\tdata: result,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n\n\tgetChecksByTeam = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tconst validatedQuery = getTeamChecksQueryValidation.parse(req.query);\n\t\t\tconst teamId = requireTeamId(req.user?.teamId);\n\n\t\t\tconst checkData = await this.checkService.getChecksByTeam({\n\t\t\t\tteamId,\n\t\t\t\tsortOrder: validatedQuery.sortOrder,\n\t\t\t\tdateRange: validatedQuery.dateRange,\n\t\t\t\tpage: validatedQuery.page,\n\t\t\t\trowsPerPage: validatedQuery.rowsPerPage,\n\t\t\t\tfilter: validatedQuery.filter,\n\t\t\t});\n\t\t\treturn res.status(200).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: \"Team checks retrieved successfully\",\n\t\t\t\tdata: checkData,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n\n\tgetChecksSummaryByTeamId = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tconst validatedQuery = getChecksSummaryByTeamIdQueryValidation.parse(req.query);\n\t\t\tconst teamId = requireTeamId(req.user?.teamId);\n\t\t\tconst dateRange = validatedQuery.dateRange ?? \"hour\";\n\n\t\t\tconst summary = await this.checkService.getChecksSummaryByTeamId({ teamId, dateRange });\n\t\t\treturn res.status(200).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: \"Checks summary retrieved successfully\",\n\t\t\t\tdata: summary,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n\n\tdeleteChecks = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tconst validatedParams = deleteChecksParamValidation.parse(req.params);\n\t\t\tconst teamId = requireTeamId(req.user?.teamId);\n\n\t\t\tconst deletedCount = await this.checkService.deleteChecks({\n\t\t\t\tmonitorId: validatedParams.monitorId,\n\t\t\t\tteamId,\n\t\t\t});\n\n\t\t\treturn res.status(200).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: \"Checks deleted successfully\",\n\t\t\t\tdata: { deletedCount },\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n\n\tdeleteChecksByTeamId = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tconst teamId = requireTeamId(req.user?.teamId);\n\n\t\t\tconst deletedCount = await this.checkService.deleteChecksByTeamId({ teamId });\n\n\t\t\treturn res.status(200).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: \"Checks deleted successfully\",\n\t\t\t\tdata: { deletedCount },\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n}\n\nexport default CheckController;\n"
  },
  {
    "path": "server/src/controllers/controllerUtils.ts",
    "content": "import { AppError } from \"@/utils/AppError.js\";\nimport { Monitor, type MonitorType, MonitorTypes, UserRole } from \"@/types/index.js\";\nimport sslChecker, { SSLDetails } from \"ssl-checker\";\ntype SSLCheckerType = typeof sslChecker;\n\nexport const fetchMonitorCertificate = async (checker: SSLCheckerType, monitor: Monitor): Promise<SSLDetails> => {\n\tconst monitorUrl = new URL(monitor.url);\n\tconst hostname = monitorUrl.hostname;\n\tconst cert = await checker(hostname);\n\tif (cert?.validTo === null || cert?.validTo === undefined) {\n\t\tthrow new Error(\"Certificate not found\");\n\t}\n\treturn cert;\n};\nexport const requireString = (value: unknown, fieldName: string): string => {\n\tif (typeof value === \"string\" && value.trim().length > 0) {\n\t\treturn value;\n\t}\n\tthrow new AppError({ message: `${fieldName} is required`, status: 400 });\n};\n\nexport const optionalString = (value: unknown, fieldName: string): string | undefined => {\n\tif (value === undefined) {\n\t\treturn undefined;\n\t}\n\tif (typeof value === \"string\") {\n\t\treturn value;\n\t}\n\tthrow new AppError({ message: `${fieldName} must be a string`, status: 400 });\n};\n\nexport const optionalNumber = (value: unknown, fieldName: string): number | undefined => {\n\tif (value === undefined) {\n\t\treturn undefined;\n\t}\n\tif (typeof value === \"number\" && Number.isFinite(value)) {\n\t\treturn value;\n\t}\n\tif (typeof value === \"string\" && value.trim() !== \"\") {\n\t\tconst parsed = Number(value);\n\t\tif (!Number.isNaN(parsed)) {\n\t\t\treturn parsed;\n\t\t}\n\t}\n\tthrow new AppError({ message: `${fieldName} must be a number`, status: 400 });\n};\n\nexport const optionalBoolean = (value: unknown, fieldName: string): boolean | undefined => {\n\tif (value === undefined) {\n\t\treturn undefined;\n\t}\n\tif (typeof value === \"boolean\") {\n\t\treturn value;\n\t}\n\tif (typeof value === \"string\") {\n\t\tif (value === \"true\") {\n\t\t\treturn true;\n\t\t}\n\t\tif (value === \"false\") {\n\t\t\treturn false;\n\t\t}\n\t}\n\tthrow new AppError({ message: `${fieldName} must be a boolean`, status: 400 });\n};\n\nexport const parseMonitorTypeFilter = (value: unknown): MonitorType | MonitorType[] | undefined => {\n\tconst parseSingle = (input: unknown): MonitorType => {\n\t\tif (typeof input !== \"string\") {\n\t\t\tthrow new AppError({ message: \"Monitor type must be a string\", status: 400 });\n\t\t}\n\t\tif (!MonitorTypes.includes(input as MonitorType)) {\n\t\t\tthrow new AppError({ message: `Invalid monitor type: ${input}`, status: 400 });\n\t\t}\n\t\treturn input as MonitorType;\n\t};\n\n\tif (value === undefined) {\n\t\treturn undefined;\n\t}\n\tif (Array.isArray(value)) {\n\t\treturn value.map((entry) => parseSingle(entry));\n\t}\n\treturn parseSingle(value);\n};\n\nexport const parseSortOrder = (value: unknown): \"asc\" | \"desc\" | undefined => {\n\tif (value === undefined) {\n\t\treturn undefined;\n\t}\n\tif (value === \"asc\" || value === \"desc\") {\n\t\treturn value;\n\t}\n\tthrow new AppError({ message: \"order must be either 'asc' or 'desc'\", status: 400 });\n};\n\nexport const requireTeamId = (teamId?: string): string => {\n\tif (!teamId) {\n\t\tthrow new AppError({ message: \"Team ID is required\", status: 400 });\n\t}\n\treturn teamId;\n};\n\nexport const requireUserId = (userId?: string): string => {\n\tif (!userId) {\n\t\tthrow new AppError({ message: \"User ID is required\", status: 400 });\n\t}\n\treturn userId;\n};\nexport const requireUserEmail = (userEmail?: string): string => {\n\tif (!userEmail) {\n\t\tthrow new AppError({ message: \"User email is required\", status: 400 });\n\t}\n\treturn userEmail;\n};\n\nexport const requireFirstName = (firstName?: string): string => {\n\tif (!firstName) {\n\t\tthrow new AppError({ message: \"First name is required\", status: 400 });\n\t}\n\treturn firstName;\n};\n\nexport const requireUserRoles = (userRoles?: UserRole[]): UserRole[] => {\n\tif (!userRoles || userRoles.length === 0) {\n\t\tthrow new AppError({ message: \"User roles are required\", status: 400 });\n\t}\n\treturn userRoles;\n};\n"
  },
  {
    "path": "server/src/controllers/diagnosticController.ts",
    "content": "import { IDiagnosticService } from \"@/service/index.js\";\nimport { Request, Response, NextFunction } from \"express\";\n\nconst SERVICE_NAME = \"diagnosticController\";\n\nexport interface IDiagnosticController {\n\tgetSystemStats: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;\n}\n\nclass DiagnosticController implements IDiagnosticController {\n\tstatic SERVICE_NAME = SERVICE_NAME;\n\n\tprivate diagnosticService: IDiagnosticService;\n\n\tconstructor(diagnosticService: IDiagnosticService) {\n\t\tthis.diagnosticService = diagnosticService;\n\t}\n\n\tget serviceName() {\n\t\treturn DiagnosticController.SERVICE_NAME;\n\t}\n\n\tgetSystemStats = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tconst diagnostics = await this.diagnosticService.getSystemStats();\n\t\t\treturn res.status(200).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: \"OK\",\n\t\t\t\tdata: diagnostics,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n}\n\nexport default DiagnosticController;\n"
  },
  {
    "path": "server/src/controllers/geoCheckController.ts",
    "content": "import { Request, Response, NextFunction } from \"express\";\nimport { getChecksParamValidation, getChecksQueryValidation } from \"@/validation/checkValidation.js\";\nimport type { IGeoChecksService } from \"@/service/business/geoChecksService.js\";\nimport { requireTeamId } from \"./controllerUtils.js\";\nimport { AppError } from \"@/utils/AppError.js\";\n\nconst SERVICE_NAME = \"geoCheckController\";\n\nexport interface IGeoCheckController {\n\tgetGeoChecksByMonitor: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;\n}\nclass GeoCheckController implements IGeoCheckController {\n\tstatic SERVICE_NAME = SERVICE_NAME;\n\n\tprivate geoChecksService: IGeoChecksService;\n\tconstructor(geoChecksService: IGeoChecksService) {\n\t\tthis.geoChecksService = geoChecksService;\n\t}\n\n\tget serviceName() {\n\t\treturn GeoCheckController.SERVICE_NAME;\n\t}\n\n\tgetGeoChecksByMonitor = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tconst validatedParams = getChecksParamValidation.parse(req.params);\n\t\t\tconst validatedQuery = getChecksQueryValidation.parse(req.query);\n\n\t\t\tif (!validatedQuery.continent || validatedQuery.continent.length === 0) {\n\t\t\t\tthrow new AppError({\n\t\t\t\t\tmessage: \"At least one continent must be specified\",\n\t\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\t\tmethod: \"getGeoChecksByMonitor\",\n\t\t\t\t\tdetails: { monitorId: validatedParams.monitorId },\n\t\t\t\t\tstatus: 400,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst teamId = requireTeamId(req.user?.teamId);\n\n\t\t\tconst result = await this.geoChecksService.getGeoChecksByMonitor({\n\t\t\t\tmonitorId: validatedParams.monitorId,\n\t\t\t\tteamId: teamId,\n\t\t\t\tsortOrder: validatedQuery.sortOrder,\n\t\t\t\tdateRange: validatedQuery.dateRange,\n\t\t\t\tpage: validatedQuery.page,\n\t\t\t\trowsPerPage: validatedQuery.rowsPerPage,\n\t\t\t\tcontinent: validatedQuery.continent,\n\t\t\t});\n\n\t\t\treturn res.status(200).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: \"Geo checks retrieved successfully\",\n\t\t\t\tdata: result,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n}\n\nexport default GeoCheckController;\n"
  },
  {
    "path": "server/src/controllers/incidentController.ts",
    "content": "import { AppError } from \"@/utils/AppError.js\";\nimport { Request, Response, NextFunction } from \"express\";\nimport { requireTeamId, requireUserId, requireUserEmail } from \"./controllerUtils.js\";\nimport { IIncidentService } from \"@/service/index.js\";\nimport { getIncidentsByTeamQueryValidation, getIncidentSummaryQueryValidation } from \"@/validation/incidentValidation.js\";\n\nconst SERVICE_NAME = \"IncidentController\";\n\nexport interface IIncidentController {\n\tgetIncidentsByTeam: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;\n\tgetIncidentSummary: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;\n\tgetIncidentById: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;\n\tresolveIncidentManually: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;\n}\nclass IncidentController implements IIncidentController {\n\tprivate incidentService: IIncidentService;\n\tconstructor(incidentService: IIncidentService) {\n\t\tthis.incidentService = incidentService;\n\t}\n\n\tgetIncidentsByTeam = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tconst validatedQuery = getIncidentsByTeamQueryValidation.parse(req.query);\n\n\t\t\tconst teamId = requireTeamId(req.user?.teamId);\n\t\t\tconst result = await this.incidentService.getIncidentsByTeam(\n\t\t\t\tteamId,\n\t\t\t\tvalidatedQuery.sortOrder,\n\t\t\t\tvalidatedQuery.dateRange,\n\t\t\t\tvalidatedQuery.page,\n\t\t\t\tvalidatedQuery.rowsPerPage,\n\t\t\t\tvalidatedQuery.status,\n\t\t\t\tvalidatedQuery.monitorId,\n\t\t\t\tvalidatedQuery.resolutionType\n\t\t\t);\n\n\t\t\treturn res.status(200).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: \"Incidents retrieved successfully\",\n\t\t\t\tdata: result,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n\n\tgetIncidentSummary = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tconst teamId = requireTeamId(req.user?.teamId);\n\t\t\tconst validatedQuery = getIncidentSummaryQueryValidation.parse(req.query);\n\n\t\t\tconst summary = await this.incidentService.getIncidentSummary(teamId, validatedQuery.limit);\n\t\t\treturn res.status(200).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: \"Incident summary retrieved successfully\",\n\t\t\t\tdata: summary,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n\n\tgetIncidentById = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tconst teamId = requireTeamId(req.user?.teamId);\n\t\t\tconst incidentId = req.params.incidentId as string;\n\t\t\tif (!incidentId) {\n\t\t\t\tthrow new AppError({ message: \"Incident ID is required\", service: SERVICE_NAME, status: 400 });\n\t\t\t}\n\n\t\t\tconst incident = await this.incidentService.getIncidentById(incidentId, teamId);\n\n\t\t\treturn res.status(200).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: \"Incident retrieved successfully\",\n\t\t\t\tdata: incident,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n\n\tresolveIncidentManually = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tconst teamId = requireTeamId(req.user?.teamId);\n\t\t\tconst userId = requireUserId(req.user?.id);\n\t\t\tconst userEmail = requireUserEmail(req.user?.email);\n\t\t\tconst incidentId = req.params?.incidentId;\n\t\t\tif (!incidentId) {\n\t\t\t\tthrow new AppError({ message: \"Incident ID is required\", service: SERVICE_NAME, status: 400 });\n\t\t\t}\n\n\t\t\tconst resolvedIncident = await this.incidentService.resolveIncident(incidentId, userId, teamId, req?.body?.comment, userEmail);\n\n\t\t\treturn res.status(200).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: \"Incident resolved successfully\",\n\t\t\t\tdata: resolvedIncident,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n}\n\nexport default IncidentController;\n"
  },
  {
    "path": "server/src/controllers/inviteController.ts",
    "content": "import { Request, Response, NextFunction } from \"express\";\nimport { inviteBodyValidation, inviteVerificationBodyValidation } from \"@/validation/authValidation.js\";\nimport { requireFirstName, requireTeamId, requireUserRoles } from \"@/controllers/controllerUtils.js\";\nimport { IInviteService } from \"@/service/index.js\";\nconst SERVICE_NAME = \"inviteController\";\n\nexport interface IInviteController {\n\tgetInviteToken: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;\n\tsendInviteEmail: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;\n\tverifyInviteToken: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;\n}\n\nclass InviteController implements IInviteController {\n\tstatic SERVICE_NAME = SERVICE_NAME;\n\tprivate inviteService: IInviteService;\n\tconstructor(inviteService: IInviteService) {\n\t\tthis.inviteService = inviteService;\n\t}\n\n\tget serviceName() {\n\t\treturn InviteController.SERVICE_NAME;\n\t}\n\n\tgetInviteToken = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tconst teamId = requireTeamId(req.user?.teamId);\n\t\t\tconst userRoles = requireUserRoles(req.user?.role);\n\t\t\tconst invite = req.body;\n\t\t\tinvite.teamId = teamId;\n\t\t\tinviteBodyValidation.parse(invite);\n\t\t\tconst inviteToken = await this.inviteService.getInviteToken({ invite, teamId, userRoles });\n\t\t\treturn res.status(200).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: \"Invite token generated successfully\",\n\t\t\t\tdata: inviteToken,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n\n\tsendInviteEmail = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tconst teamId = requireTeamId(req.user?.teamId);\n\t\t\tconst userRoles = requireUserRoles(req.user?.role);\n\t\t\tconst firstName = requireFirstName(req.user?.firstName);\n\n\t\t\tconst inviteRequest = req.body;\n\t\t\tinviteRequest.teamId = teamId;\n\t\t\tinviteBodyValidation.parse(inviteRequest);\n\n\t\t\tconst inviteToken = await this.inviteService.sendInviteEmail({\n\t\t\t\tinvite: inviteRequest,\n\t\t\t\tfirstName,\n\t\t\t\tuserRoles,\n\t\t\t});\n\t\t\treturn res.status(200).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: \"Invite issued successfully\",\n\t\t\t\tdata: inviteToken,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n\n\tverifyInviteToken = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tinviteVerificationBodyValidation.parse(req.body);\n\t\t\tconst invite = await this.inviteService.verifyInviteToken({ inviteToken: req?.body?.token });\n\t\t\treturn res.status(200).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: \"Invite verified successfully\",\n\t\t\t\tdata: invite,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n}\n\nexport default InviteController;\n"
  },
  {
    "path": "server/src/controllers/logController.ts",
    "content": "import { ILogger } from \"@/utils/logger.js\";\nimport { Request, Response, NextFunction } from \"express\";\n\nconst SERVICE_NAME = \"LogController\";\n\nexport interface ILogController {\n\tgetLogs: (req: Request, res: Response, next: NextFunction) => Promise<void>;\n}\n\nclass LogController {\n\tstatic SERVICE_NAME = SERVICE_NAME;\n\tprivate logger: ILogger;\n\tconstructor(logger: ILogger) {\n\t\tthis.logger = logger;\n\t}\n\tget serviceName() {\n\t\treturn LogController.SERVICE_NAME;\n\t}\n\n\tgetLogs = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tconst logs = this.logger.getLogs();\n\t\t\tres.status(200).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: \"Logs fetched successfully\",\n\t\t\t\tdata: logs,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n}\nexport default LogController;\n"
  },
  {
    "path": "server/src/controllers/maintenanceWindowController.ts",
    "content": "import { Request, Response, NextFunction } from \"express\";\nimport {\n\tcreateMaintenanceWindowBodyValidation,\n\teditMaintenanceWindowByIdParamValidation,\n\teditMaintenanceByIdWindowBodyValidation,\n\tgetMaintenanceWindowByIdParamValidation,\n\tgetMaintenanceWindowsByMonitorIdParamValidation,\n\tgetMaintenanceWindowsByTeamIdQueryValidation,\n\tdeleteMaintenanceWindowByIdParamValidation,\n} from \"@/validation/maintenanceWindowValidation.js\";\nimport { requireTeamId } from \"@/controllers/controllerUtils.js\";\nimport { IMaintenanceWindowService } from \"@/service/index.js\";\n\nexport interface IMaintenanceWindowController {\n\tcreateMaintenanceWindows: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;\n\tgetMaintenanceWindowById: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;\n\tgetMaintenanceWindowsByTeamId: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;\n\tgetMaintenanceWindowsByMonitorId: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;\n\tdeleteMaintenanceWindow: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;\n\teditMaintenanceWindow: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;\n}\nclass MaintenanceWindowController implements IMaintenanceWindowController {\n\tprivate maintenanceWindowService: IMaintenanceWindowService;\n\tconstructor(maintenanceWindowService: IMaintenanceWindowService) {\n\t\tthis.maintenanceWindowService = maintenanceWindowService;\n\t}\n\n\tcreateMaintenanceWindows = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tconst validatedBody = createMaintenanceWindowBodyValidation.parse(req.body);\n\t\t\tconst teamId = requireTeamId(req?.user?.teamId);\n\n\t\t\tconst monitorIDs = validatedBody.monitors;\n\t\t\tconst name = validatedBody.name;\n\t\t\tconst active = validatedBody.active ?? true;\n\t\t\tconst duration = validatedBody.duration;\n\t\t\tconst durationUnit = validatedBody.durationUnit;\n\t\t\tconst repeat = validatedBody.repeat;\n\t\t\tconst start = validatedBody.start;\n\t\t\tconst end = validatedBody.end;\n\n\t\t\tawait this.maintenanceWindowService.createMaintenanceWindow({ teamId, monitorIDs, name, active, duration, durationUnit, repeat, start, end });\n\n\t\t\treturn res.status(200).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: \"Maintenance window created successfully\",\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n\tgetMaintenanceWindowById = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tconst validatedParams = getMaintenanceWindowByIdParamValidation.parse(req.params);\n\n\t\t\tconst teamId = requireTeamId(req.user?.teamId);\n\n\t\t\tconst maintenanceWindow = await this.maintenanceWindowService.getMaintenanceWindowById({ id: validatedParams.id, teamId });\n\n\t\t\treturn res.status(200).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: \"Maintenance window fetched successfully\",\n\t\t\t\tdata: maintenanceWindow,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n\n\tgetMaintenanceWindowsByTeamId = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tconst validatedQuery = getMaintenanceWindowsByTeamIdQueryValidation.parse(req.query);\n\n\t\t\tconst teamId = requireTeamId(req?.user?.teamId);\n\n\t\t\tconst maintenanceWindows = await this.maintenanceWindowService.getMaintenanceWindowsByTeamId({\n\t\t\t\tteamId,\n\t\t\t\tactive: validatedQuery.active,\n\t\t\t\tpage: validatedQuery.page,\n\t\t\t\trowsPerPage: validatedQuery.rowsPerPage,\n\t\t\t\tfield: validatedQuery.field,\n\t\t\t\torder: validatedQuery.order,\n\t\t\t});\n\n\t\t\treturn res.status(200).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: \"Maintenance windows fetched successfully\",\n\t\t\t\tdata: maintenanceWindows,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n\n\tgetMaintenanceWindowsByMonitorId = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tconst validatedParams = getMaintenanceWindowsByMonitorIdParamValidation.parse(req.params);\n\n\t\t\tconst teamId = requireTeamId(req?.user?.teamId);\n\n\t\t\tconst maintenanceWindows = await this.maintenanceWindowService.getMaintenanceWindowsByMonitorId({\n\t\t\t\tmonitorId: validatedParams.monitorId,\n\t\t\t\tteamId,\n\t\t\t});\n\n\t\t\treturn res.status(200).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: \"Maintenance windows fetched successfully\",\n\t\t\t\tdata: maintenanceWindows,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n\tdeleteMaintenanceWindow = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tconst validatedParams = deleteMaintenanceWindowByIdParamValidation.parse(req.params);\n\n\t\t\tconst teamId = requireTeamId(req?.user?.teamId);\n\n\t\t\tawait this.maintenanceWindowService.deleteMaintenanceWindow({ id: validatedParams.id, teamId });\n\n\t\t\treturn res.status(200).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: \"Maintenance window deleted successfully\",\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n\n\teditMaintenanceWindow = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tconst validatedParams = editMaintenanceWindowByIdParamValidation.parse(req.params);\n\t\t\tconst validatedBody = editMaintenanceByIdWindowBodyValidation.parse(req.body);\n\n\t\t\tconst teamId = requireTeamId(req.user?.teamId);\n\n\t\t\tconst editedMaintenanceWindow = await this.maintenanceWindowService.editMaintenanceWindow({\n\t\t\t\tid: validatedParams.id,\n\t\t\t\tbody: validatedBody,\n\t\t\t\tteamId,\n\t\t\t});\n\t\t\treturn res.status(200).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: \"Maintenance window edited successfully\",\n\t\t\t\tdata: editedMaintenanceWindow,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n}\n\nexport default MaintenanceWindowController;\n"
  },
  {
    "path": "server/src/controllers/monitorController.ts",
    "content": "import { Request, Response, NextFunction } from \"express\";\n\nimport {\n\tgetMonitorByIdParamValidation,\n\tgetMonitorByIdQueryValidation,\n\tgetMonitorsByTeamIdQueryValidation,\n\tgetMonitorsWithChecksQueryValidation,\n\tcreateMonitorBodyValidation,\n\teditMonitorBodyValidation,\n\tpauseMonitorParamValidation,\n\tgetCertificateParamValidation,\n\tgetHardwareDetailsByIdParamValidation,\n\tgetHardwareDetailsByIdQueryValidation,\n\tgetUptimeDetailsByIdParamValidation,\n\tgetUptimeDetailsByIdQueryValidation,\n\timportMonitorsBodyValidation,\n} from \"@/validation/monitorValidation.js\";\nimport sslChecker from \"ssl-checker\";\nimport { fetchMonitorCertificate, requireTeamId, requireUserId } from \"@/controllers/controllerUtils.js\";\nimport { IMonitorService } from \"@/service/index.js\";\n\nconst SERVICE_NAME = \"monitorController\";\n\nexport interface IMonitorController {\n\tgetMonitorCertificate: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;\n\tgetUptimeDetailsById: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;\n\tgetHardwareDetailsById: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;\n\tgetPageSpeedDetailsById: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;\n\tgetGeoChecksByMonitorId: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;\n\tgetMonitorById: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;\n\tcreateMonitor: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;\n\timportMonitorsFromJSON: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;\n\tdeleteMonitor: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;\n\tdeleteAllMonitors: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;\n\teditMonitor: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;\n\tpauseMonitor: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;\n\taddDemoMonitors: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;\n\tgetMonitorsByTeamId: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;\n\tgetMonitorsWithChecksByTeamId: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;\n\texportMonitorsToJSON: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;\n\tgetAllGames: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;\n\tgetGroupsByTeamId: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;\n}\nclass MonitorController implements IMonitorController {\n\tstatic SERVICE_NAME = SERVICE_NAME;\n\n\tprivate monitorService: IMonitorService;\n\n\tconstructor(monitorService: IMonitorService) {\n\t\tthis.monitorService = monitorService;\n\t}\n\n\tget serviceName() {\n\t\treturn MonitorController.SERVICE_NAME;\n\t}\n\n\tgetMonitorCertificate = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tconst validatedParams = getCertificateParamValidation.parse(req.params);\n\t\t\tconst teamId = requireTeamId(req.user?.teamId);\n\t\t\tconst monitor = await this.monitorService.getMonitorById({ teamId, monitorId: validatedParams.monitorId });\n\t\t\tconst certificate = await fetchMonitorCertificate(sslChecker, monitor);\n\n\t\t\treturn res.status(200).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: \"SSL certificate retrieved successfully\",\n\t\t\t\tdata: {\n\t\t\t\t\tcertificateDate: new Date(certificate.validTo),\n\t\t\t\t},\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n\n\tgetUptimeDetailsById = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tconst validatedParams = getUptimeDetailsByIdParamValidation.parse(req.params);\n\t\t\tconst validatedQuery = getUptimeDetailsByIdQueryValidation.parse(req.query);\n\n\t\t\tconst monitorId = validatedParams.monitorId;\n\t\t\tconst dateRange = validatedQuery.dateRange;\n\n\t\t\tconst teamId = requireTeamId(req.user?.teamId);\n\n\t\t\tconst data = await this.monitorService.getUptimeDetailsById({\n\t\t\t\tteamId,\n\t\t\t\tmonitorId,\n\t\t\t\tdateRange,\n\t\t\t});\n\t\t\treturn res.status(200).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: \"Uptime details retrieved successfully\",\n\t\t\t\tdata: data,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n\n\tgetHardwareDetailsById = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tconst validatedParams = getHardwareDetailsByIdParamValidation.parse(req.params);\n\t\t\tconst validatedQuery = getHardwareDetailsByIdQueryValidation.parse(req.query);\n\n\t\t\tconst monitorId = validatedParams.monitorId;\n\t\t\tconst dateRange = validatedQuery.dateRange || \"recent\";\n\t\t\tconst teamId = requireTeamId(req.user?.teamId);\n\n\t\t\tconst data = await this.monitorService.getHardwareDetailsById({\n\t\t\t\tteamId,\n\t\t\t\tmonitorId,\n\t\t\t\tdateRange,\n\t\t\t});\n\n\t\t\treturn res.status(200).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: \"Hardware details retrieved successfully\",\n\t\t\t\tdata: data,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n\tgetPageSpeedDetailsById = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tconst validatedParams = getHardwareDetailsByIdParamValidation.parse(req.params);\n\t\t\tconst validatedQuery = getHardwareDetailsByIdQueryValidation.parse(req.query);\n\n\t\t\tconst monitorId = validatedParams.monitorId;\n\t\t\tconst dateRange = validatedQuery.dateRange || \"recent\";\n\t\t\tconst teamId = requireTeamId(req.user?.teamId);\n\n\t\t\tconst data = await this.monitorService.getPageSpeedDetailsById({\n\t\t\t\tteamId,\n\t\t\t\tmonitorId,\n\t\t\t\tdateRange,\n\t\t\t});\n\n\t\t\treturn res.status(200).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: \"Page speed details retrieved successfully\",\n\t\t\t\tdata,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n\n\tgetGeoChecksByMonitorId = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tconst validatedParams = getMonitorByIdParamValidation.parse(req.params);\n\t\t\tconst validatedQuery = getMonitorByIdQueryValidation.parse(req.query);\n\n\t\t\tconst monitorId = validatedParams.monitorId;\n\t\t\tconst dateRange = validatedQuery.dateRange || \"recent\";\n\t\t\tconst continentParam = validatedQuery.continent;\n\t\t\tconst continents = continentParam ? (Array.isArray(continentParam) ? continentParam : [continentParam]) : undefined;\n\t\t\tconst teamId = requireTeamId(req.user?.teamId);\n\n\t\t\tconst data = await this.monitorService.getGeoChecksByMonitorId({\n\t\t\t\tteamId,\n\t\t\t\tmonitorId,\n\t\t\t\tdateRange,\n\t\t\t\tcontinents,\n\t\t\t});\n\n\t\t\treturn res.status(200).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: \"Geo checks retrieved successfully\",\n\t\t\t\tdata,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n\n\tgetMonitorById = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tconst validatedParams = getMonitorByIdParamValidation.parse(req.params);\n\n\t\t\tconst teamId = requireTeamId(req.user?.teamId);\n\t\t\tconst monitorId = validatedParams.monitorId;\n\n\t\t\tconst monitor = await this.monitorService.getMonitorById({ teamId, monitorId });\n\n\t\t\treturn res.status(200).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: \"Monitor retrieved successfully\",\n\t\t\t\tdata: monitor,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n\n\tcreateMonitor = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tconst validatedBody = createMonitorBodyValidation.parse(req.body);\n\n\t\t\tconst userId = requireUserId(req.user?.id);\n\t\t\tconst teamId = requireTeamId(req.user?.teamId);\n\n\t\t\tconst monitor = await this.monitorService.createMonitor(teamId, userId, validatedBody);\n\n\t\t\treturn res.status(200).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: \"Monitor created successfully\",\n\t\t\t\tdata: monitor,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n\n\timportMonitorsFromJSON = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tconst teamId = requireTeamId(req.user?.teamId);\n\t\t\tconst userId = requireUserId(req.user?.id);\n\t\t\tconst validatedBody = importMonitorsBodyValidation.parse(req.body);\n\t\t\tconst monitors = validatedBody.monitors;\n\n\t\t\tconst result = await this.monitorService.importMonitorsFromJSON({ teamId, userId, monitors });\n\n\t\t\treturn res.status(200).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: `Successfully imported ${result.imported} monitor(s)`,\n\t\t\t\tdata: result,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n\n\tdeleteMonitor = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tconst validatedParams = getMonitorByIdParamValidation.parse(req.params);\n\t\t\tconst teamId = requireTeamId(req.user?.teamId);\n\t\t\tconst monitorId = validatedParams.monitorId;\n\n\t\t\tconst deletedMonitor = await this.monitorService.deleteMonitor({ teamId, monitorId });\n\n\t\t\treturn res.status(200).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: \"Monitor deleted successfully\",\n\t\t\t\tdata: deletedMonitor,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n\n\tdeleteAllMonitors = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tconst teamId = requireTeamId(req.user?.teamId);\n\t\t\tconst deletedCount = await this.monitorService.deleteAllMonitors({ teamId });\n\n\t\t\treturn res.status(200).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: `Deleted ${deletedCount} monitors`,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n\n\teditMonitor = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tconst validatedParams = getMonitorByIdParamValidation.parse(req.params);\n\t\t\tconst validatedBody = editMonitorBodyValidation.parse(req.body);\n\t\t\tconst monitorId = validatedParams.monitorId;\n\t\t\tconst teamId = requireTeamId(req.user?.teamId);\n\n\t\t\tconst editedMonitor = await this.monitorService.editMonitor({ teamId, monitorId, body: validatedBody });\n\n\t\t\treturn res.status(200).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: \"Monitor edited successfully\",\n\t\t\t\tdata: editedMonitor,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n\n\tpauseMonitor = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tconst validatedParams = pauseMonitorParamValidation.parse(req.params);\n\n\t\t\tconst monitorId = validatedParams.monitorId;\n\t\t\tconst teamId = requireTeamId(req.user?.teamId);\n\n\t\t\tconst monitor = await this.monitorService.pauseMonitor({ teamId, monitorId });\n\n\t\t\treturn res.status(200).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: monitor.isActive ? \"Monitor resumed successfully\" : \"Monitor paused successfully\",\n\t\t\t\tdata: monitor,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n\n\taddDemoMonitors = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tconst id = requireUserId(req.user?.id);\n\t\t\tconst teamId = requireTeamId(req.user?.teamId);\n\t\t\tconst demoMonitors = await this.monitorService.addDemoMonitors({ userId: id, teamId });\n\n\t\t\treturn res.status(200).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: \"Demo monitors added successfully\",\n\t\t\t\tdata: demoMonitors?.length ?? 0,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n\n\tgetMonitorsByTeamId = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tconst validatedQuery = getMonitorsByTeamIdQueryValidation.parse(req.query);\n\n\t\t\tconst teamId = requireTeamId(req.user?.teamId);\n\t\t\tconst type = validatedQuery.type;\n\t\t\tconst filter = validatedQuery.filter;\n\n\t\t\tconst monitors = await this.monitorService.getMonitorsByTeamId({ teamId, type, filter });\n\n\t\t\treturn res.status(200).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: \"Monitors retrieved successfully\",\n\t\t\t\tdata: monitors,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n\n\tgetMonitorsWithChecksByTeamId = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tconst validatedQuery = getMonitorsWithChecksQueryValidation.parse(req.query);\n\n\t\t\tconst limit = validatedQuery.limit;\n\t\t\tconst page = validatedQuery.page;\n\t\t\tconst rowsPerPage = validatedQuery.rowsPerPage;\n\t\t\tconst filter = validatedQuery.filter;\n\t\t\tconst field = validatedQuery.field;\n\t\t\tconst order = validatedQuery.order;\n\t\t\tconst type = validatedQuery.type;\n\t\t\tconst teamId = requireTeamId(req.user?.teamId);\n\n\t\t\tconst monitors = await this.monitorService.getMonitorsWithChecksByTeamId({\n\t\t\t\tteamId,\n\t\t\t\tlimit,\n\t\t\t\ttype,\n\t\t\t\tpage,\n\t\t\t\trowsPerPage,\n\t\t\t\tfilter,\n\t\t\t\tfield,\n\t\t\t\torder,\n\t\t\t});\n\n\t\t\treturn res.status(200).json({\n\t\t\t\tmsg: \"Monitors retrieved successfully\",\n\t\t\t\tdata: monitors,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n\n\texportMonitorsToJSON = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tconst teamId = requireTeamId(req.user?.teamId);\n\t\t\tconst json = await this.monitorService.exportMonitorsToJSON({ teamId });\n\n\t\t\treturn res.status(200).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: \"Monitors exported successfully\",\n\t\t\t\tdata: json,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n\n\tgetAllGames = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tconst games = this.monitorService.getAllGames();\n\t\t\treturn res.status(200).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: \"Supported games retrieved successfully\",\n\t\t\t\tdata: games,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n\n\tgetGroupsByTeamId = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tconst teamId = requireTeamId(req.user?.teamId);\n\t\t\tconst groups = await this.monitorService.getGroupsByTeamId({ teamId });\n\n\t\t\treturn res.status(200).json({\n\t\t\t\tmsg: \"Groups retrieved successfully\",\n\t\t\t\tdata: groups,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n}\n\nexport default MonitorController;\n"
  },
  {
    "path": "server/src/controllers/notificationController.ts",
    "content": "import { Request, Response, NextFunction } from \"express\";\n\nimport {\n\tcreateNotificationBodyValidation,\n\tdeleteNotificationParamValidation,\n\tgetNotificationByIdParamValidation,\n\ttestNotificationBodyValidation,\n\teditNotificationParamValidation,\n\ttestAllNotificationsBodyValidation,\n} from \"@/validation/notificationValidation.js\";\nimport { AppError } from \"@/utils/AppError.js\";\nimport { IMonitorsRepository } from \"@/repositories/index.js\";\nimport { INotificationsService } from \"@/service/index.js\";\nimport { requireTeamId, requireUserId } from \"./controllerUtils.js\";\n\nconst SERVICE_NAME = \"NotificationController\";\n\nexport interface INotificationController {\n\ttestNotification: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;\n\tcreateNotification: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;\n\tgetNotificationsByTeamId: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;\n\tdeleteNotification: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;\n\tgetNotificationById: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;\n\teditNotification: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;\n\ttestAllNotifications: (req: Request, res: Response, next: NextFunction) => Promise<Response | void>;\n}\nclass NotificationController implements INotificationController {\n\tprivate notificationsService: INotificationsService;\n\tprivate monitorsRepository: IMonitorsRepository;\n\tconstructor(notificationsService: INotificationsService, monitorsRepository: IMonitorsRepository) {\n\t\tthis.notificationsService = notificationsService;\n\t\tthis.monitorsRepository = monitorsRepository;\n\t}\n\n\ttestNotification = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tconst notification = testNotificationBodyValidation.parse(req.body);\n\t\t\tconst success = await this.notificationsService.sendTestNotification(notification);\n\n\t\t\tif (!success) {\n\t\t\t\tthrow new AppError({ message: \"Sending notification failed\", status: 500 });\n\t\t\t}\n\n\t\t\treturn res.status(200).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: \"Notification sent successfully\",\n\t\t\t\tdetails: { service: SERVICE_NAME },\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n\n\tcreateNotification = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tconst validatedBody = createNotificationBodyValidation.parse(req.body);\n\n\t\t\tconst teamId = requireTeamId(req.user?.teamId);\n\t\t\tconst userId = requireUserId(req.user?.id);\n\n\t\t\tconst notification = await this.notificationsService.createNotification(validatedBody, userId, teamId);\n\t\t\treturn res.status(200).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: \"Notification created successfully\",\n\t\t\t\tdata: notification,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n\n\tgetNotificationsByTeamId = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tconst teamId = requireTeamId(req.user?.teamId);\n\t\t\tconst notifications = await this.notificationsService.findNotificationsByTeamId(teamId);\n\n\t\t\treturn res.status(200).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: \"Notifications fetched successfully\",\n\t\t\t\tdata: notifications,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n\n\tdeleteNotification = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tconst teamId = requireTeamId(req.user?.teamId);\n\t\t\tconst validatedParams = deleteNotificationParamValidation.parse(req.params);\n\n\t\t\tawait this.notificationsService.deleteById(validatedParams.id, teamId);\n\t\t\treturn res.status(200).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: \"Notification deleted successfully\",\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n\n\tgetNotificationById = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tconst teamId = requireTeamId(req.user?.teamId);\n\t\t\tconst validatedParams = getNotificationByIdParamValidation.parse(req.params);\n\n\t\t\tconst notification = await this.notificationsService.findById(validatedParams.id, teamId);\n\n\t\t\treturn res.status(200).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: \"Notification fetched successfully\",\n\t\t\t\tdata: notification,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n\n\teditNotification = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tconst validatedBody = createNotificationBodyValidation.parse(req.body);\n\t\t\tconst validatedParams = editNotificationParamValidation.parse(req.params);\n\n\t\t\tconst teamId = requireTeamId(req.user?.teamId);\n\t\t\tconst notificationId = validatedParams.id;\n\n\t\t\tconst editedNotification = await this.notificationsService.updateById(notificationId, teamId, validatedBody);\n\t\t\treturn res.status(200).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: \"Notification updated successfully\",\n\t\t\t\tdata: editedNotification,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n\n\ttestAllNotifications = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tconst validatedBody = testAllNotificationsBodyValidation.parse(req.body);\n\n\t\t\tconst teamId = requireTeamId(req.user?.teamId);\n\n\t\t\tconst monitor = await this.monitorsRepository.findById(validatedBody.monitorId, teamId);\n\n\t\t\tconst notifications = monitor.notifications;\n\t\t\tif (notifications.length === 0) {\n\t\t\t\tthrow new AppError({ message: \"No notifications\", status: 400 });\n\t\t\t}\n\n\t\t\tconst result = await this.notificationsService.testAllNotifications(notifications);\n\n\t\t\tif (!result) {\n\t\t\t\tthrow new AppError({ message: \"Failed to send all notifications\", status: 500 });\n\t\t\t}\n\n\t\t\treturn res.status(200).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: \"All notifications sent successfully\",\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n}\n\nexport default NotificationController;\n"
  },
  {
    "path": "server/src/controllers/queueController.ts",
    "content": "import { ISuperSimpleQueue } from \"@/service/index.js\";\nimport { Request, Response, NextFunction } from \"express\";\n\nconst SERVICE_NAME = \"JobQueueController\";\n\nexport interface IJobQueueController {\n\tgetMetrics(req: Request, res: Response, next: NextFunction): Promise<void>;\n\tgetJobs(req: Request, res: Response, next: NextFunction): Promise<Response | void>;\n\tgetAllMetrics(req: Request, res: Response, next: NextFunction): Promise<Response | void>;\n\tflushQueue(req: Request, res: Response, next: NextFunction): Promise<Response | void>;\n}\n\nclass JobQueueController implements IJobQueueController {\n\tstatic SERVICE_NAME = SERVICE_NAME;\n\tprivate jobQueue: ISuperSimpleQueue;\n\tconstructor(jobQueue: ISuperSimpleQueue) {\n\t\tthis.jobQueue = jobQueue;\n\t}\n\n\tget serviceName() {\n\t\treturn JobQueueController.SERVICE_NAME;\n\t}\n\n\tgetMetrics = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tconst metrics = await this.jobQueue.getMetrics();\n\t\t\tres.status(200).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: \"Queue metrics fetched successfully\",\n\t\t\t\tdata: metrics,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n\n\tgetJobs = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tconst jobs = await this.jobQueue.getJobs();\n\t\t\treturn res.status(200).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: \"Queue jobs fetched successfully\",\n\t\t\t\tdata: jobs,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n\n\tgetAllMetrics = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tconst jobs = await this.jobQueue.getJobs();\n\t\t\tconst metrics = await this.jobQueue.getMetrics();\n\t\t\treturn res.status(200).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: \"Queue metrics fetched successfully\",\n\t\t\t\tdata: { jobs, metrics },\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n\n\tflushQueue = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tconst result = await this.jobQueue.flushQueues();\n\t\t\treturn res.status(200).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: \"Queue flushed successfully\",\n\t\t\t\tdata: result,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n}\nexport default JobQueueController;\n"
  },
  {
    "path": "server/src/controllers/settingsController.ts",
    "content": "import { Request, Response, NextFunction } from \"express\";\nimport { updateAppSettingsBodyValidation } from \"@/validation/settingsValidation.js\";\nimport { sendTestEmailBodyValidation } from \"@/validation/notificationValidation.js\";\nimport { AppError } from \"@/utils/AppError.js\";\nimport { IEmailService, ISettingsService } from \"@/service/index.js\";\nimport { Settings } from \"@/types/settings.js\";\n\nconst SERVICE_NAME = \"SettingsController\";\n\nexport interface ISettingsController {\n\tserviceName: string;\n\tgetAppSettings(req: Request, res: Response, next: NextFunction): Promise<Response | void>;\n\tupdateAppSettings(req: Request, res: Response, next: NextFunction): Promise<Response | void>;\n\tsendTestEmail(req: Request, res: Response, next: NextFunction): Promise<Response | void>;\n}\n\nclass SettingsController implements ISettingsController {\n\tstatic SERVICE_NAME = SERVICE_NAME;\n\tprivate settingsService: ISettingsService;\n\tprivate emailService: IEmailService;\n\tconstructor(settingsService: ISettingsService, emailService: IEmailService) {\n\t\tthis.settingsService = settingsService;\n\t\tthis.emailService = emailService;\n\t}\n\n\tget serviceName() {\n\t\treturn SettingsController.SERVICE_NAME;\n\t}\n\n\tbuildAppSettings = (dbSettings: Settings) => {\n\t\tconst sanitizedSettings: Record<string, unknown> = { ...dbSettings };\n\t\tdelete sanitizedSettings.version;\n\t\tdelete sanitizedSettings.jwtSecret;\n\t\tconst returnSettings: Record<string, unknown | null> = {\n\t\t\tpagespeedKeySet: false,\n\t\t\temailPasswordSet: false,\n\t\t\tsettings: null,\n\t\t};\n\n\t\tif (typeof sanitizedSettings.pagespeedApiKey !== \"undefined\") {\n\t\t\treturnSettings.pagespeedKeySet = true;\n\t\t\tdelete sanitizedSettings.pagespeedApiKey;\n\t\t}\n\t\tif (typeof sanitizedSettings.systemEmailPassword !== \"undefined\") {\n\t\t\treturnSettings.emailPasswordSet = true;\n\t\t\tdelete sanitizedSettings.systemEmailPassword;\n\t\t}\n\t\treturnSettings.settings = sanitizedSettings;\n\t\treturn returnSettings;\n\t};\n\n\tgetAppSettings = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tconst dbSettings = await this.settingsService.getDBSettings();\n\n\t\t\tconst returnSettings = this.buildAppSettings(dbSettings);\n\t\t\treturn res.status(200).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: \"App settings fetched successfully\",\n\t\t\t\tdata: returnSettings,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n\n\tupdateAppSettings = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tconst validatedBody = updateAppSettingsBodyValidation.parse(req.body);\n\n\t\t\tconst updatedSettings = await this.settingsService.updateDbSettings(validatedBody);\n\t\t\tconst returnSettings = this.buildAppSettings(updatedSettings);\n\t\t\treturn res.status(200).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: \"App settings updated successfully\",\n\t\t\t\tdata: returnSettings,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n\n\tsendTestEmail = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tsendTestEmailBodyValidation.parse(req.body);\n\n\t\t\tconst {\n\t\t\t\tto,\n\t\t\t\tsystemEmailHost,\n\t\t\t\tsystemEmailPort,\n\t\t\t\tsystemEmailAddress,\n\t\t\t\tsystemEmailPassword,\n\t\t\t\tsystemEmailUser,\n\t\t\t\tsystemEmailConnectionHost,\n\t\t\t\tsystemEmailSecure,\n\t\t\t\tsystemEmailPool,\n\t\t\t\tsystemEmailIgnoreTLS,\n\t\t\t\tsystemEmailRequireTLS,\n\t\t\t\tsystemEmailRejectUnauthorized,\n\t\t\t\tsystemEmailTLSServername,\n\t\t\t} = req.body;\n\n\t\t\tconst subject = \"This is a test email from Checkmate\";\n\t\t\tconst context = { testName: \"Monitoring System\" };\n\n\t\t\tconst html = await this.emailService.buildEmail(\"testEmailTemplate\", context);\n\t\t\tif (!html) {\n\t\t\t\tthrow new AppError({ message: \"Failed to build email template.\", status: 500 });\n\t\t\t}\n\t\t\tconst messageId = await this.emailService.sendEmail(to, subject, html, {\n\t\t\t\tsystemEmailHost,\n\t\t\t\tsystemEmailPort,\n\t\t\t\tsystemEmailUser,\n\t\t\t\tsystemEmailAddress,\n\t\t\t\tsystemEmailPassword,\n\t\t\t\tsystemEmailConnectionHost,\n\t\t\t\tsystemEmailSecure,\n\t\t\t\tsystemEmailPool,\n\t\t\t\tsystemEmailIgnoreTLS,\n\t\t\t\tsystemEmailRequireTLS,\n\t\t\t\tsystemEmailRejectUnauthorized,\n\t\t\t\tsystemEmailTLSServername,\n\t\t\t});\n\n\t\t\tif (!messageId) {\n\t\t\t\tthrow new AppError({ message: \"Failed to send test email.\", status: 500 });\n\t\t\t}\n\n\t\t\treturn res.status(200).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: \"Test email sent successfully\",\n\t\t\t\tdata: { messageId },\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n}\n\nexport default SettingsController;\n"
  },
  {
    "path": "server/src/controllers/statusPageController.ts",
    "content": "import { Request, Response, NextFunction } from \"express\";\n\nimport {\n\tcreateStatusPageBodyValidation,\n\tgetStatusPageParamValidation,\n\tgetStatusPageQueryValidation,\n\timageValidation,\n} from \"@/validation/statusPageValidation.js\";\nimport { AppError } from \"@/utils/AppError.js\";\nimport { requireTeamId, requireUserId } from \"@/controllers/controllerUtils.js\";\nimport { IStatusPageService } from \"@/service/business/statusPageService.js\";\nimport { IMonitorsRepository } from \"@/repositories/index.js\";\nimport { ISettingsService } from \"@/service/system/settingsService.js\";\nimport { NormalizeData } from \"@/utils/dataUtils.js\";\n\nconst SERVICE_NAME = \"statusPageController\";\n\nexport interface IStatusPageController {\n\treadonly serviceName: string;\n\tcreateStatusPage(req: Request, res: Response, next: NextFunction): Promise<Response | void>;\n\tupdateStatusPage(req: Request, res: Response, next: NextFunction): Promise<Response | void>;\n\tgetStatusPageByUrl(req: Request, res: Response, next: NextFunction): Promise<Response | void>;\n\tgetStatusPagesByTeamId(req: Request, res: Response, next: NextFunction): Promise<Response | void>;\n\tdeleteStatusPage(req: Request, res: Response, next: NextFunction): Promise<Response | void>;\n}\n\nclass StatusPageController implements IStatusPageController {\n\tstatic SERVICE_NAME = SERVICE_NAME;\n\tprivate statusPageService: IStatusPageService;\n\tprivate monitorsRepository: IMonitorsRepository;\n\tprivate settingsService: ISettingsService;\n\tconstructor(statusPageService: IStatusPageService, monitorsRepository: IMonitorsRepository, settingsService: ISettingsService) {\n\t\tthis.statusPageService = statusPageService;\n\t\tthis.monitorsRepository = monitorsRepository;\n\t\tthis.settingsService = settingsService;\n\t}\n\n\tget serviceName() {\n\t\treturn StatusPageController.SERVICE_NAME;\n\t}\n\n\tcreateStatusPage = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tcreateStatusPageBodyValidation.parse(req.body);\n\t\t\tif (req.file) {\n\t\t\t\timageValidation.parse(req.file);\n\t\t\t}\n\n\t\t\tconst teamId = requireTeamId(req?.user?.teamId);\n\t\t\tconst userId = requireUserId(req?.user?.id);\n\t\t\tconst statusPage = await this.statusPageService.createStatusPage(userId, teamId, req.file, req.body);\n\n\t\t\treturn res.status(200).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: \"Status page created successfully\",\n\t\t\t\tdata: statusPage,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n\n\tupdateStatusPage = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tcreateStatusPageBodyValidation.parse(req.body);\n\t\t\tif (req.file) {\n\t\t\t\timageValidation.parse(req.file);\n\t\t\t}\n\t\t\tconst teamId = requireTeamId(req?.user?.teamId);\n\t\t\tconst statusPageId = req.params.id as string;\n\t\t\tif (!statusPageId) {\n\t\t\t\tthrow new AppError({ message: \"Status page ID is required\", status: 400 });\n\t\t\t}\n\t\t\tconst statusPage = await this.statusPageService.updateStatusPage(statusPageId, teamId, req.file, req.body);\n\t\t\tif (statusPage === null) {\n\t\t\t\tthrow new AppError({ message: \"Status page not found\", status: 404 });\n\t\t\t}\n\t\t\tres.status(200).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: \"Status page updated successfully\",\n\t\t\t\tdata: statusPage,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n\n\tgetStatusPageByUrl = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tgetStatusPageParamValidation.parse(req.params);\n\t\t\tgetStatusPageQueryValidation.parse(req.query);\n\n\t\t\tif (!req.params.url) {\n\t\t\t\tthrow new AppError({ message: \"Status page URL is required\", status: 400 });\n\t\t\t}\n\n\t\t\tconst statusPage = await this.statusPageService.getStatusPageByUrl(req.params.url as string);\n\n\t\t\tif (!statusPage.isPublished) {\n\t\t\t\tconst teamId = requireTeamId(req?.user?.teamId);\n\t\t\t\tif (statusPage.teamId !== teamId) {\n\t\t\t\t\tthrow new AppError({ message: \"Forbidden\", status: 403 });\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst settings = await this.settingsService.getDBSettings();\n\t\t\tconst showURL = settings.showURL;\n\n\t\t\tconst monitors = await this.monitorsRepository.findByIds(statusPage.monitors);\n\t\t\t// Sort monitors according to the order in statusPage.monitors\n\t\t\tconst monitorOrder = new Map(statusPage.monitors.map((id, index) => [id, index]));\n\t\t\tconst sortedMonitors = [...monitors].sort((a, b) => {\n\t\t\t\tconst orderA = monitorOrder.get(a.id) ?? Number.MAX_SAFE_INTEGER;\n\t\t\t\tconst orderB = monitorOrder.get(b.id) ?? Number.MAX_SAFE_INTEGER;\n\t\t\t\treturn orderA - orderB;\n\t\t\t});\n\n\t\t\tconst normalizedMonitors = sortedMonitors.map((monitor) => {\n\t\t\t\tconst normalizedChecks = NormalizeData(monitor.recentChecks, 10, 100);\n\t\t\t\tif (!showURL) {\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-unused-vars\n\t\t\t\t\tconst { url, port, secret, notifications, ...rest } = monitor;\n\t\t\t\t\treturn { ...rest, checks: normalizedChecks };\n\t\t\t\t}\n\t\t\t\treturn { ...monitor, checks: normalizedChecks };\n\t\t\t});\n\t\t\treturn res.status(200).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: \"Status page retrieved successfully\",\n\t\t\t\tdata: { statusPage, monitors: normalizedMonitors },\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n\tgetStatusPagesByTeamId = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tconst teamId = requireTeamId(req.user?.teamId);\n\t\t\tconst statusPages = await this.statusPageService.getStatusPagesByTeamId(teamId);\n\n\t\t\treturn res.status(200).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: \"Status pages retrieved successfully\",\n\t\t\t\tdata: statusPages,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n\n\tdeleteStatusPage = async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tconst statusPageId = req.params.id as string;\n\t\t\tif (!statusPageId) {\n\t\t\t\tthrow new AppError({ message: \"Status page ID is required\", status: 400 });\n\t\t\t}\n\t\t\tconst teamId = requireTeamId(req.user?.teamId);\n\t\t\tawait this.statusPageService.deleteStatusPage(statusPageId, teamId);\n\t\t\treturn res.status(200).json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmsg: \"Status page deleted successfully\",\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n}\n\nexport default StatusPageController;\n"
  },
  {
    "path": "server/src/db/IDb.ts",
    "content": "export interface IDb {\n\tconnect(): Promise<void>;\n\tdisconnect(): Promise<void>;\n}\n"
  },
  {
    "path": "server/src/db/MongoDB.ts",
    "content": "import mongoose from \"mongoose\";\nimport AppSettings from \"@/db/models/AppSettings.js\";\nimport { runMigrations } from \"@/db/migration/index.js\";\nimport { ILogger } from \"@/utils/logger.js\";\nimport { EnvConfig } from \"@/service/system/settingsService.js\";\nconst SERVICE_NAME = \"MongoDB\";\nimport { IDb } from \"@/db/IDb.js\";\n\nclass MongoDB implements IDb {\n\tstatic SERVICE_NAME = SERVICE_NAME;\n\n\tprivate logger: ILogger;\n\tprivate envSettings: EnvConfig;\n\n\tconstructor(logger: ILogger, envSettings: EnvConfig) {\n\t\tthis.logger = logger;\n\t\tthis.envSettings = envSettings;\n\t}\n\n\tget serviceName() {\n\t\treturn MongoDB.SERVICE_NAME;\n\t}\n\n\tconnect = async () => {\n\t\ttry {\n\t\t\tconst connectionString = this.envSettings.dbConnectionString || \"mongodb://localhost:27017/uptime_db\";\n\t\t\tawait mongoose.connect(connectionString);\n\t\t\t// If there are no AppSettings, create one // TODO why is this here?\n\t\t\tawait AppSettings.findOneAndUpdate(\n\t\t\t\t{}, // empty filter to match any document\n\t\t\t\t{}, // empty update\n\t\t\t\t{\n\t\t\t\t\tnew: true,\n\t\t\t\t\tsetDefaultsOnInsert: true,\n\t\t\t\t}\n\t\t\t);\n\t\t\t// Sync indexes\n\t\t\tconst models = mongoose.modelNames();\n\t\t\tfor (const modelName of models) {\n\t\t\t\tconst model = mongoose.model(modelName);\n\t\t\t\tawait model.syncIndexes();\n\t\t\t}\n\n\t\t\tthis.logger.info({\n\t\t\t\tmessage: \"Connected to MongoDB\",\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"connect\",\n\t\t\t});\n\n\t\t\tawait runMigrations();\n\t\t} catch (error: unknown) {\n\t\t\tthis.logger.error({\n\t\t\t\tmessage: error instanceof Error ? error.message : \"Unknown error\",\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"connect\",\n\t\t\t\tstack: error instanceof Error ? error.stack : undefined,\n\t\t\t});\n\t\t\tthrow error;\n\t\t}\n\t};\n\n\tdisconnect = async () => {\n\t\ttry {\n\t\t\tthis.logger.info({ message: \"Disconnecting from MongoDB\", service: SERVICE_NAME, method: \"disconnect\" });\n\t\t\tawait mongoose.disconnect();\n\t\t\tthis.logger.info({ message: \"Disconnected from MongoDB\", service: SERVICE_NAME, method: \"disconnect\" });\n\t\t\treturn;\n\t\t} catch (error: unknown) {\n\t\t\tthis.logger.error({\n\t\t\t\tmessage: error instanceof Error ? error.message : \"Unknown error\",\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"disconnect\",\n\t\t\t\tstack: error instanceof Error ? error.stack : undefined,\n\t\t\t});\n\t\t}\n\t};\n}\n\nexport default MongoDB;\n"
  },
  {
    "path": "server/src/db/migration/0001_migrateStatusWindowThreshold.ts",
    "content": "import Monitor from \"@/db/models/Monitor.js\";\nasync function migrateStatusWindowThreshold() {\n\tconst monitors = await Monitor.find({ statusWindowThreshold: { $lt: 1 } });\n\tfor (const monitor of monitors) {\n\t\tmonitor.statusWindowThreshold = monitor.statusWindowThreshold * 100;\n\t\tawait monitor.save();\n\t}\n}\n\nexport { migrateStatusWindowThreshold };\n"
  },
  {
    "path": "server/src/db/migration/0002_convertChecksToTimeSeries.ts",
    "content": "import mongoose from \"mongoose\";\nimport type { Document, AnyBulkWriteOperation } from \"mongodb\";\n\nconst CHECKS_COLLECTION = \"checks\";\nconst BACKUP_COLLECTION = \"checks_backup\";\nconst FAILED_DOCS_COLLECTION = \"checks_migration_failed\";\nconst BATCH_SIZE = 1000;\n\ninterface MigrationStats {\n\ttotalSource: number;\n\ttotalMigrated: number;\n\ttotalFailed: number;\n}\n\nconst getDb = () => {\n\tconst db = mongoose.connection.db;\n\tif (!db) {\n\t\tthrow new Error(\"Database connection is not initialized\");\n\t}\n\treturn db;\n};\n\nconst restoreFromBackup = async () => {\n\tconst db = getDb();\n\tconst backupExists = await db.listCollections({ name: BACKUP_COLLECTION }).toArray();\n\tif (backupExists.length === 0) {\n\t\tthrow new Error(\"Cannot restore: backup collection does not exist\");\n\t}\n\n\tconst checksExists = await db.listCollections({ name: CHECKS_COLLECTION }).toArray();\n\tif (checksExists.length > 0) {\n\t\tawait db.collection(CHECKS_COLLECTION).drop();\n\t}\n\n\tawait db.collection(BACKUP_COLLECTION).rename(CHECKS_COLLECTION);\n};\n\nconst backupAndDropExistingCollection = async () => {\n\tconst db = getDb();\n\tconst collections = await db.listCollections({ name: CHECKS_COLLECTION }).toArray();\n\tif (collections.length === 0) {\n\t\treturn false;\n\t}\n\tconst backupExists = await db.listCollections({ name: BACKUP_COLLECTION }).toArray();\n\tif (backupExists.length > 0) {\n\t\tthrow new Error(`Backup collection \"${BACKUP_COLLECTION}\" already exists. ` + `Please remove it manually before running migration.`);\n\t}\n\n\tawait db\n\t\t.collection(CHECKS_COLLECTION)\n\t\t.aggregate([{ $match: {} }, { $out: BACKUP_COLLECTION }])\n\t\t.toArray();\n\tawait db.collection(CHECKS_COLLECTION).drop();\n\treturn true;\n};\n\nconst createTimeSeriesCollection = async (backedUp: boolean) => {\n\tconst db = getDb();\n\ttry {\n\t\tconst existing = await db.listCollections({ name: CHECKS_COLLECTION }).toArray();\n\t\tif (existing.length === 0) {\n\t\t\tawait db.createCollection(CHECKS_COLLECTION, {\n\t\t\t\ttimeseries: {\n\t\t\t\t\ttimeField: \"createdAt\",\n\t\t\t\t\tmetaField: \"metadata\",\n\t\t\t\t\tgranularity: \"seconds\",\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\n\t\tawait db\n\t\t\t.collection(CHECKS_COLLECTION)\n\t\t\t.createIndexes([\n\t\t\t\t{ key: { createdAt: 1 } },\n\t\t\t\t{ key: { \"metadata.monitorId\": 1, createdAt: 1 } },\n\t\t\t\t{ key: { \"metadata.monitorId\": 1, createdAt: -1 } },\n\t\t\t\t{ key: { \"metadata.teamId\": 1, createdAt: -1 } },\n\t\t\t\t{ key: { \"metadata.monitorId\": 1, \"metadata.type\": 1, createdAt: -1 } },\n\t\t\t\t{ key: { \"metadata.teamId\": 1, status: 1, createdAt: -1 } },\n\t\t\t]);\n\t} catch (error) {\n\t\tif (backedUp) {\n\t\t\tawait restoreFromBackup();\n\t\t}\n\t\tthrow error;\n\t}\n};\n\nconst validateDocument = (doc: Document): boolean => {\n\tif (!doc.createdAt) {\n\t\treturn false;\n\t}\n\tif (!doc.monitorId || !doc.teamId || !doc.type) {\n\t\treturn false;\n\t}\n\treturn true;\n};\n\nconst storeFailedDocument = async (doc: Document, reason: string) => {\n\tconst db = getDb();\n\tawait db.collection(FAILED_DOCS_COLLECTION).insertOne({\n\t\toriginalDoc: doc,\n\t\treason,\n\t\tfailedAt: new Date(),\n\t});\n};\n\nconst migrateBackupData = async (backedUp: boolean): Promise<MigrationStats> => {\n\tconst db = getDb();\n\tconst backupExists = await db.listCollections({ name: BACKUP_COLLECTION }).toArray();\n\tif (backupExists.length === 0) {\n\t\treturn { totalSource: 0, totalMigrated: 0, totalFailed: 0 };\n\t}\n\n\tconst stats: MigrationStats = {\n\t\ttotalSource: 0,\n\t\ttotalMigrated: 0,\n\t\ttotalFailed: 0,\n\t};\n\n\ttry {\n\t\tconst source = db.collection(BACKUP_COLLECTION);\n\t\tconst target = db.collection(CHECKS_COLLECTION);\n\n\t\tstats.totalSource = await source.countDocuments();\n\n\t\tconst cursor = source.find().addCursorFlag(\"noCursorTimeout\", true);\n\t\tconst operations: AnyBulkWriteOperation<Document>[] = [];\n\t\tconst invalidDocs: Document[] = [];\n\n\t\twhile (await cursor.hasNext()) {\n\t\t\tconst doc = await cursor.next();\n\t\t\tif (!doc) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (!validateDocument(doc)) {\n\t\t\t\tinvalidDocs.push(doc);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst { _id, monitorId, teamId, type, ...rest } = doc;\n\t\t\tvoid _id;\n\t\t\tconst metadata = { monitorId, teamId, type };\n\t\t\toperations.push({ insertOne: { document: { ...rest, metadata } } });\n\n\t\t\tif (operations.length >= BATCH_SIZE) {\n\t\t\t\tconst result = await target.bulkWrite(operations, { ordered: false });\n\t\t\t\tstats.totalMigrated += result.insertedCount;\n\t\t\t\toperations.length = 0;\n\t\t\t}\n\t\t}\n\n\t\tif (operations.length) {\n\t\t\tconst result = await target.bulkWrite(operations, { ordered: false });\n\t\t\tstats.totalMigrated += result.insertedCount;\n\t\t}\n\n\t\tfor (const doc of invalidDocs) {\n\t\t\tawait storeFailedDocument(doc, \"Missing required fields (createdAt, monitorId, teamId, or type)\");\n\t\t\tstats.totalFailed++;\n\t\t}\n\n\t\tawait cursor.close();\n\n\t\treturn stats;\n\t} catch (error) {\n\t\tif (backedUp) {\n\t\t\tawait restoreFromBackup();\n\t\t}\n\t\tthrow error;\n\t}\n};\n\nexport const convertChecksToTimeSeries = async () => {\n\tconst backedUp = await backupAndDropExistingCollection();\n\tawait createTimeSeriesCollection(backedUp);\n\tif (backedUp) {\n\t\tconst stats = await migrateBackupData(backedUp);\n\t\tconsole.log(\n\t\t\t`Migration completed: ${stats.totalMigrated} documents migrated, ` +\n\t\t\t\t`${stats.totalFailed} documents failed (stored in ${FAILED_DOCS_COLLECTION})`\n\t\t);\n\t}\n};\n"
  },
  {
    "path": "server/src/db/migration/0003_cleanupDuplicateMonitorStats.ts",
    "content": "import { MonitorStatsModel } from \"../models/MonitorStats.js\";\nimport { logger } from \"@/utils/logger.js\";\n\n/**\n * Cleanup duplicate MonitorStats documents\n * Keeps the most recent document (by updatedAt) for each monitorId\n * and deletes all older duplicates\n */\nexport async function cleanupDuplicateMonitorStats(): Promise<void> {\n\tconst SERVICE_NAME = \"Migration:CleanupDuplicateMonitorStats\";\n\n\ttry {\n\t\tlogger.info({ service: SERVICE_NAME, message: \"Starting cleanup of duplicate MonitorStats\" });\n\n\t\t// Find all duplicate monitorIds\n\t\tconst duplicates = await MonitorStatsModel.aggregate([\n\t\t\t{\n\t\t\t\t$group: {\n\t\t\t\t\t_id: \"$monitorId\",\n\t\t\t\t\tids: { $push: \"$_id\" },\n\t\t\t\t\tupdatedAts: { $push: \"$updatedAt\" },\n\t\t\t\t\tcount: { $sum: 1 },\n\t\t\t\t},\n\t\t\t},\n\t\t\t{ $match: { count: { $gt: 1 } } },\n\t\t]);\n\n\t\tif (duplicates.length === 0) {\n\t\t\tlogger.info({ service: SERVICE_NAME, message: \"No duplicate MonitorStats found\" });\n\t\t\treturn;\n\t\t}\n\n\t\tlogger.info({\n\t\t\tservice: SERVICE_NAME,\n\t\t\tmessage: `Found ${duplicates.length} monitors with duplicate stats`,\n\t\t});\n\n\t\tlet totalDeleted = 0;\n\n\t\t// For each set of duplicates, keep the newest and delete the rest\n\t\tfor (const duplicate of duplicates) {\n\t\t\tconst monitorId = duplicate._id;\n\t\t\tconst { ids, updatedAts } = duplicate;\n\n\t\t\ttype DocPair = { id: string; updatedAt: Date };\n\n\t\t\t// Create array of {id, updatedAt} pairs and sort by updatedAt descending\n\t\t\tconst docs: DocPair[] = ids.map((id: string, index: number) => ({\n\t\t\t\tid,\n\t\t\t\tupdatedAt: updatedAts[index],\n\t\t\t}));\n\n\t\t\tdocs.sort((a: DocPair, b: DocPair) => b.updatedAt.getTime() - a.updatedAt.getTime());\n\n\t\t\t// Keep the first (newest), delete the rest\n\t\t\tconst toDelete = docs.slice(1).map((doc: DocPair) => doc.id);\n\n\t\t\tif (toDelete.length > 0) {\n\t\t\t\tconst result = await MonitorStatsModel.deleteMany({\n\t\t\t\t\t_id: { $in: toDelete },\n\t\t\t\t});\n\n\t\t\t\ttotalDeleted += result.deletedCount ?? 0;\n\n\t\t\t\tlogger.debug({\n\t\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\t\tmessage: `Deleted ${result.deletedCount} duplicate stats for monitor ${monitorId}`,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tlogger.info({\n\t\t\tservice: SERVICE_NAME,\n\t\t\tmessage: `Cleanup complete. Deleted ${totalDeleted} duplicate MonitorStats documents`,\n\t\t});\n\t} catch (error) {\n\t\tconst errorMessage = error instanceof Error ? error.message : String(error);\n\t\tlogger.error({ service: SERVICE_NAME, message: `Error during MonitorStats cleanup: ${errorMessage}` });\n\t\tthrow error;\n\t}\n}\n"
  },
  {
    "path": "server/src/db/migration/0004_fixInfrastructureThresholds.ts",
    "content": "import { MonitorModel } from \"../models/Monitor.js\";\nimport { logger } from \"@/utils/logger.js\";\n\n/**\n * Fix infrastructure monitors that had thresholds incorrectly set to 0 or 5\n * due to the old default value. Updates them to 100 (disabled).\n */\nexport async function fixInfrastructureThresholds(): Promise<void> {\n\tconst SERVICE_NAME = \"Migration:FixInfrastructureThresholds\";\n\n\ttry {\n\t\tlogger.info({ service: SERVICE_NAME, message: \"Starting infrastructure threshold fix\" });\n\n\t\tconst thresholdFields = [\"cpuAlertThreshold\", \"memoryAlertThreshold\", \"diskAlertThreshold\", \"tempAlertThreshold\"];\n\n\t\t// Find hardware monitors with any threshold set to 0 or 5\n\t\tconst filter = {\n\t\t\ttype: \"hardware\",\n\t\t\t$or: thresholdFields.flatMap((field) => [{ [field]: 0 }, { [field]: 5 }]),\n\t\t};\n\n\t\tconst monitors = await MonitorModel.find(filter);\n\n\t\tif (monitors.length === 0) {\n\t\t\tlogger.info({ service: SERVICE_NAME, message: \"No monitors with threshold value of 0 or 5 found\" });\n\t\t\treturn;\n\t\t}\n\n\t\tlogger.info({\n\t\t\tservice: SERVICE_NAME,\n\t\t\tmessage: `Found ${monitors.length} monitors with threshold value of 0 or 5`,\n\t\t});\n\n\t\tlet updatedCount = 0;\n\n\t\tfor (const monitor of monitors) {\n\t\t\tconst update: Record<string, number> = {};\n\n\t\t\tfor (const field of thresholdFields) {\n\t\t\t\tconst value = monitor.get(field);\n\t\t\t\tif (value === 0 || value === 5) {\n\t\t\t\t\tupdate[field] = 100;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (Object.keys(update).length > 0) {\n\t\t\t\tawait MonitorModel.updateOne({ _id: monitor._id }, { $set: update });\n\t\t\t\tupdatedCount++;\n\t\t\t}\n\t\t}\n\n\t\tlogger.info({\n\t\t\tservice: SERVICE_NAME,\n\t\t\tmessage: `Fixed ${updatedCount} monitors — thresholds updated from 0/5 to 100`,\n\t\t});\n\t} catch (error) {\n\t\tconst errorMessage = error instanceof Error ? error.message : String(error);\n\t\tlogger.error({ service: SERVICE_NAME, message: `Error fixing thresholds: ${errorMessage}` });\n\t\tthrow error;\n\t}\n}\n"
  },
  {
    "path": "server/src/db/migration/0005_migrateStatusPageTypeToArray.ts",
    "content": "import mongoose from \"mongoose\";\nimport { logger } from \"@/utils/logger.js\";\nimport StatusPageModel from \"../models/StatusPage.js\";\n\nexport async function migrateStatusPageTypeToArray(): Promise<void> {\n\tconst SERVICE_NAME = \"Migration:MigrateStatusPageTypeToArray\";\n\n\ttry {\n\t\tlogger.info({ service: SERVICE_NAME, message: \"Starting migration of StatusPage type field from string to array\" });\n\n\t\tconst db = mongoose.connection.db;\n\t\tif (!db) {\n\t\t\tthrow new Error(\"Database connection is not initialized\");\n\t\t}\n\n\t\tconst result = await StatusPageModel.updateMany(\n\t\t\t{\n\t\t\t\t$expr: {\n\t\t\t\t\t$eq: [{ $type: \"$type\" }, \"string\"], // only scalar string, not existing array\n\t\t\t\t},\n\t\t\t},\n\t\t\t[\n\t\t\t\t{\n\t\t\t\t\t$set: {\n\t\t\t\t\t\ttype: [\"$type\"],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t]\n\t\t);\n\n\t\tif (result.modifiedCount === 0) {\n\t\t\tlogger.info({ service: SERVICE_NAME, message: \"No StatusPage documents needed migration\" });\n\t\t\treturn;\n\t\t}\n\n\t\tlogger.info({\n\t\t\tservice: SERVICE_NAME,\n\t\t\tmessage: `Migration complete. Converted ${result.modifiedCount} StatusPage document(s) from string type to array type`,\n\t\t});\n\t} catch (error) {\n\t\tconst errorMessage = error instanceof Error ? error.message : String(error);\n\t\tlogger.error({ service: SERVICE_NAME, message: `Error during StatusPage type migration: ${errorMessage}` });\n\t\tthrow error;\n\t}\n}\n"
  },
  {
    "path": "server/src/db/migration/index.ts",
    "content": "import { migrateStatusWindowThreshold } from \"./0001_migrateStatusWindowThreshold.js\";\nimport { convertChecksToTimeSeries } from \"./0002_convertChecksToTimeSeries.js\";\nimport { cleanupDuplicateMonitorStats } from \"./0003_cleanupDuplicateMonitorStats.js\";\nimport { fixInfrastructureThresholds } from \"./0004_fixInfrastructureThresholds.js\";\nimport MigrationModel from \"../models/Migration.js\";\nimport { migrateStatusPageTypeToArray } from \"./0005_migrateStatusPageTypeToArray.js\";\nimport type { ILogger } from \"@/utils/logger.js\";\n\ntype MigrationEntry = {\n\tname: string;\n\texecute: () => Promise<void>;\n};\n\nconst migrations: MigrationEntry[] = [\n\t{ name: \"0001_migrateStatusWindowThreshold\", execute: migrateStatusWindowThreshold },\n\t{ name: \"0002_convertChecksToTimeSeries\", execute: convertChecksToTimeSeries },\n\t{ name: \"0003_cleanupDuplicateMonitorStats\", execute: cleanupDuplicateMonitorStats },\n\t{ name: \"0004_fixInfrastructureThresholds\", execute: fixInfrastructureThresholds },\n\t{ name: \"0005_migrateStatusPageTypeToArray\", execute: migrateStatusPageTypeToArray },\n];\n\nconst runMigrations = async (logger?: ILogger) => {\n\ttry {\n\t\tlogger?.info({ message: \"Running migrations\", service: \"Migrations\" });\n\t\tfor (const migration of migrations) {\n\t\t\tconst exists = await MigrationModel.findOne({ name: migration.name, status: \"completed\" });\n\t\t\tif (exists) {\n\t\t\t\tlogger?.info({ message: `Skipping ${migration.name}`, service: \"Migrations\" });\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tawait migration.execute();\n\t\t\t\tawait MigrationModel.findOneAndUpdate(\n\t\t\t\t\t{ name: migration.name },\n\t\t\t\t\t{ status: \"completed\", completedAt: new Date(), error: undefined },\n\t\t\t\t\t{ upsert: true }\n\t\t\t\t);\n\t\t\t\tlogger?.info({ message: `Completed ${migration.name}`, service: \"Migrations\" });\n\t\t\t} catch (error) {\n\t\t\t\tconst err = error as Error;\n\t\t\t\tawait MigrationModel.findOneAndUpdate({ name: migration.name }, { status: \"failed\", error: err?.message }, { upsert: true });\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\t\tlogger?.info({ message: \"Migrations completed\", service: \"Migrations\" });\n\t} catch (error) {\n\t\tconst err = error as Error;\n\t\tlogger?.error({ message: \"Migration failed\", service: \"Migrations\", details: { error: err?.message }, stack: err?.stack });\n\t\tthrow error;\n\t}\n};\n\nexport { runMigrations };\n"
  },
  {
    "path": "server/src/db/models/AppSettings.ts",
    "content": "import { Schema, model, type Types } from \"mongoose\";\nimport type { Settings, SettingsThresholds } from \"@/types/settings.js\";\n\ninterface AppSettingsDocument extends Omit<Settings, \"id\" | \"createdAt\" | \"updatedAt\"> {\n\t_id: Types.ObjectId;\n\tcreatedAt: Date;\n\tupdatedAt: Date;\n}\n\nconst thresholdsSchema = new Schema<SettingsThresholds>(\n\t{\n\t\tcpu: { type: Number },\n\t\tmemory: { type: Number },\n\t\tdisk: { type: Number },\n\t\ttemperature: { type: Number },\n\t},\n\t{ _id: false }\n);\n\nconst AppSettingsSchema = new Schema<AppSettingsDocument>(\n\t{\n\t\tcheckTTL: { type: Number, default: 30 },\n\t\tlanguage: { type: String, default: \"gb\" },\n\t\tjwtSecret: { type: String },\n\t\tpagespeedApiKey: { type: String },\n\t\tsystemEmailHost: { type: String },\n\t\tsystemEmailPort: { type: Number },\n\t\tsystemEmailAddress: { type: String },\n\t\tsystemEmailPassword: { type: String },\n\t\tsystemEmailUser: { type: String },\n\t\tsystemEmailConnectionHost: { type: String, default: \"localhost\" },\n\t\tsystemEmailTLSServername: { type: String },\n\t\tsystemEmailSecure: { type: Boolean, default: false },\n\t\tsystemEmailPool: { type: Boolean, default: false },\n\t\tsystemEmailIgnoreTLS: { type: Boolean, default: false },\n\t\tsystemEmailRequireTLS: { type: Boolean, default: false },\n\t\tsystemEmailRejectUnauthorized: { type: Boolean, default: true },\n\t\tshowURL: { type: Boolean, default: false },\n\t\tsingleton: { type: Boolean, required: true, unique: true, default: true },\n\t\tversion: { type: Number, default: 1 },\n\t\tglobalThresholds: { type: thresholdsSchema },\n\t},\n\t{ timestamps: true }\n);\n\nconst AppSettingsModel = model<AppSettingsDocument>(\"AppSettings\", AppSettingsSchema);\n\nexport type { AppSettingsDocument };\nexport { AppSettingsModel };\nexport default AppSettingsModel;\n"
  },
  {
    "path": "server/src/db/models/Check.ts",
    "content": "import { Schema, model, Types } from \"mongoose\";\nimport { MonitorTypes, type MonitorType } from \"@/types/monitor.js\";\nimport type {\n\tCheck,\n\tCheckAudits,\n\tCheckCaptureInfo,\n\tCheckCpuInfo,\n\tCheckDiskInfo,\n\tCheckErrorInfo,\n\tCheckHostInfo,\n\tCheckMemoryInfo,\n\tCheckMetadata,\n\tCheckNetworkInterfaceInfo,\n\tGotTimings,\n\tILighthouseAudit,\n} from \"@/types/check.js\";\n\ntype CheckMetadataDocument = Omit<CheckMetadata, \"monitorId\" | \"teamId\"> & {\n\tmonitorId: Types.ObjectId;\n\tteamId: Types.ObjectId;\n\ttype: MonitorType;\n};\n\ntype CheckDocumentBase = Omit<Check, \"id\" | \"metadata\" | \"createdAt\" | \"updatedAt\"> & {\n\tmetadata: CheckMetadataDocument;\n\tcreatedAt: Date;\n\tupdatedAt: Date;\n};\n\ninterface CheckDocument extends CheckDocumentBase {\n\t_id: Types.ObjectId;\n}\n\nconst timingPhasesSchema = new Schema<GotTimings[\"phases\"]>(\n\t{\n\t\twait: { type: Number, default: 0 },\n\t\tdns: { type: Number, default: 0 },\n\t\ttcp: { type: Number, default: 0 },\n\t\ttls: { type: Number, default: 0 },\n\t\trequest: { type: Number, default: 0 },\n\t\tfirstByte: { type: Number, default: 0 },\n\t\tdownload: { type: Number, default: 0 },\n\t\ttotal: { type: Number, default: 0 },\n\t},\n\t{ _id: false }\n);\n\nconst timingsSchema = new Schema<GotTimings>(\n\t{\n\t\tstart: { type: Number, default: 0 },\n\t\tsocket: { type: Number, default: 0 },\n\t\tlookup: { type: Number, default: 0 },\n\t\tconnect: { type: Number, default: 0 },\n\t\tsecureConnect: { type: Number, default: 0 },\n\t\tupload: { type: Number, default: 0 },\n\t\tresponse: { type: Number, default: 0 },\n\t\tend: { type: Number, default: 0 },\n\t\tphases: {\n\t\t\ttype: timingPhasesSchema,\n\t\t\tdefault: () => ({}),\n\t\t},\n\t},\n\t{ _id: false }\n);\n\nconst cpuSchema = new Schema<CheckCpuInfo>(\n\t{\n\t\tphysical_core: { type: Number, default: 0 },\n\t\tlogical_core: { type: Number, default: 0 },\n\t\tfrequency: { type: Number, default: 0 },\n\t\tcurrent_frequency: { type: Number, default: 0 },\n\t\ttemperature: { type: [Number], default: [] },\n\t\tfree_percent: { type: Number, default: 0 },\n\t\tusage_percent: { type: Number, default: 0 },\n\t},\n\t{ _id: false }\n);\n\nconst memorySchema = new Schema<CheckMemoryInfo>(\n\t{\n\t\ttotal_bytes: { type: Number, default: 0 },\n\t\tavailable_bytes: { type: Number, default: 0 },\n\t\tused_bytes: { type: Number, default: 0 },\n\t\tusage_percent: { type: Number, default: 0 },\n\t},\n\t{ _id: false }\n);\n\nconst diskSchema = new Schema<CheckDiskInfo>(\n\t{\n\t\tdevice: { type: String, default: \"\" },\n\t\tmountpoint: { type: String, default: \"\" },\n\t\ttotal_bytes: { type: Number, default: 0 },\n\t\tfree_bytes: { type: Number, default: 0 },\n\t\tused_bytes: { type: Number, default: 0 },\n\t\tusage_percent: { type: Number, default: 0 },\n\t\ttotal_inodes: { type: Number, default: 0 },\n\t\tfree_inodes: { type: Number, default: 0 },\n\t\tused_inodes: { type: Number, default: 0 },\n\t\tinodes_usage_percent: { type: Number, default: 0 },\n\t\tread_bytes: { type: Number, default: 0 },\n\t\twrite_bytes: { type: Number, default: 0 },\n\t\tread_time: { type: Number, default: 0 },\n\t\twrite_time: { type: Number, default: 0 },\n\t},\n\t{ _id: false }\n);\n\nconst hostSchema = new Schema<CheckHostInfo>(\n\t{\n\t\tos: { type: String, default: \"\" },\n\t\tplatform: { type: String, default: \"\" },\n\t\tkernel_version: { type: String, default: \"\" },\n\t\tpretty_name: { type: String, default: \"\" },\n\t},\n\t{ _id: false }\n);\n\nconst errorSchema = new Schema<CheckErrorInfo>(\n\t{\n\t\tmetric: { type: [String], default: [] },\n\t\terr: { type: String, default: \"\" },\n\t},\n\t{ _id: false }\n);\n\nconst captureSchema = new Schema<CheckCaptureInfo>(\n\t{\n\t\tversion: { type: String, default: \"\" },\n\t\tmode: { type: String, default: \"\" },\n\t},\n\t{ _id: false }\n);\n\nconst networkInterfaceSchema = new Schema<CheckNetworkInterfaceInfo>(\n\t{\n\t\tname: { type: String, default: \"\" },\n\t\tbytes_sent: { type: Number, default: 0 },\n\t\tbytes_recv: { type: Number, default: 0 },\n\t\tpackets_sent: { type: Number, default: 0 },\n\t\tpackets_recv: { type: Number, default: 0 },\n\t\terr_in: { type: Number, default: 0 },\n\t\terr_out: { type: Number, default: 0 },\n\t\tdrop_in: { type: Number, default: 0 },\n\t\tdrop_out: { type: Number, default: 0 },\n\t\tfifo_in: { type: Number, default: 0 },\n\t\tfifo_out: { type: Number, default: 0 },\n\t},\n\t{ _id: false }\n);\n\nconst lighthouseAuditSchema = new Schema<ILighthouseAudit>(\n\t{\n\t\tid: { type: String },\n\t\ttitle: { type: String },\n\t\tscore: { type: Number },\n\t\tdisplayValue: { type: String },\n\t\tnumericValue: { type: Number },\n\t\tnumericUnit: { type: String },\n\t},\n\t{ _id: false }\n);\n\nconst auditsSchema = new Schema<CheckAudits>(\n\t{\n\t\tcls: { type: lighthouseAuditSchema, default: undefined },\n\t\tsi: { type: lighthouseAuditSchema, default: undefined },\n\t\tfcp: { type: lighthouseAuditSchema, default: undefined },\n\t\tlcp: { type: lighthouseAuditSchema, default: undefined },\n\t\ttbt: { type: lighthouseAuditSchema, default: undefined },\n\t},\n\t{ _id: false }\n);\n\nconst metadataSchema = new Schema<CheckMetadataDocument>(\n\t{\n\t\tmonitorId: {\n\t\t\ttype: Schema.Types.ObjectId,\n\t\t\tref: \"Monitor\",\n\t\t\trequired: true,\n\t\t\timmutable: true,\n\t\t\tindex: true,\n\t\t},\n\t\tteamId: {\n\t\t\ttype: Schema.Types.ObjectId,\n\t\t\tref: \"Team\",\n\t\t\trequired: true,\n\t\t\timmutable: true,\n\t\t\tindex: true,\n\t\t},\n\t\ttype: {\n\t\t\ttype: String,\n\t\t\tenum: MonitorTypes,\n\t\t\trequired: true,\n\t\t\tindex: true,\n\t\t},\n\t},\n\t{ _id: false }\n);\n\nconst CheckSchema = new Schema<CheckDocument>(\n\t{\n\t\tmetadata: {\n\t\t\ttype: metadataSchema,\n\t\t\trequired: true,\n\t\t},\n\t\tstatus: {\n\t\t\ttype: Boolean,\n\t\t\tindex: true,\n\t\t},\n\t\tresponseTime: {\n\t\t\ttype: Number,\n\t\t},\n\t\ttimings: {\n\t\t\ttype: timingsSchema,\n\t\t\tdefault: undefined,\n\t\t},\n\t\tstatusCode: {\n\t\t\ttype: Number,\n\t\t\tindex: true,\n\t\t},\n\t\tmessage: {\n\t\t\ttype: String,\n\t\t},\n\n\t\tcpu: {\n\t\t\ttype: cpuSchema,\n\t\t\tdefault: () => ({}),\n\t\t},\n\t\tmemory: {\n\t\t\ttype: memorySchema,\n\t\t\tdefault: () => ({}),\n\t\t},\n\t\tdisk: {\n\t\t\ttype: [diskSchema],\n\t\t\tdefault: () => [],\n\t\t},\n\t\thost: {\n\t\t\ttype: hostSchema,\n\t\t\tdefault: () => ({}),\n\t\t},\n\t\terrors: {\n\t\t\ttype: [errorSchema],\n\t\t\tdefault: () => [],\n\t\t},\n\t\tcapture: {\n\t\t\ttype: captureSchema,\n\t\t\tdefault: () => ({}),\n\t\t},\n\t\tnet: {\n\t\t\ttype: [networkInterfaceSchema],\n\t\t\tdefault: () => [],\n\t\t},\n\t\taccessibility: {\n\t\t\ttype: Number,\n\t\t},\n\t\tbestPractices: {\n\t\t\ttype: Number,\n\t\t},\n\t\tseo: {\n\t\t\ttype: Number,\n\t\t},\n\t\tperformance: {\n\t\t\ttype: Number,\n\t\t},\n\t\taudits: {\n\t\t\ttype: auditsSchema,\n\t\t\tdefault: undefined,\n\t\t},\n\t},\n\t{\n\t\ttimestamps: true,\n\t\tstrict: false,\n\t\ttimeseries: {\n\t\t\ttimeField: \"createdAt\",\n\t\t\tmetaField: \"metadata\",\n\t\t\tgranularity: \"seconds\",\n\t\t},\n\t}\n);\n\nCheckSchema.index({ \"metadata.monitorId\": 1, createdAt: -1 });\nCheckSchema.index({ \"metadata.monitorId\": 1, createdAt: 1 });\nCheckSchema.index({ createdAt: 1 });\nCheckSchema.index({ \"metadata.teamId\": 1, createdAt: -1 });\nCheckSchema.index({ \"metadata.monitorId\": 1, \"metadata.type\": 1, createdAt: -1 });\nCheckSchema.index({ \"metadata.teamId\": 1, status: 1, createdAt: -1 });\n\nconst CheckModel = model<CheckDocument>(\"Check\", CheckSchema);\n\nexport type { CheckDocument, CheckMetadataDocument };\nexport { CheckModel };\nexport default CheckModel;\n"
  },
  {
    "path": "server/src/db/models/GeoCheck.ts",
    "content": "import { Schema, model, Types } from \"mongoose\";\nimport { MonitorTypes, type MonitorType } from \"@/types/monitor.js\";\nimport type { GeoCheck, GeoCheckLocation, GeoCheckMetadata, GeoCheckResult, GeoCheckTimings } from \"@/types/geoCheck.js\";\n\ntype GeoCheckMetadataDocument = Omit<GeoCheckMetadata, \"monitorId\" | \"teamId\"> & {\n\tmonitorId: Types.ObjectId;\n\tteamId: Types.ObjectId;\n\ttype: MonitorType;\n};\n\ntype GeoCheckDocumentBase = Omit<GeoCheck, \"id\" | \"metadata\" | \"expiry\" | \"createdAt\" | \"updatedAt\" | \"results\"> & {\n\tmetadata: GeoCheckMetadataDocument;\n\tresults: GeoCheckResult[];\n\texpiry: Date;\n\tcreatedAt: Date;\n\tupdatedAt: Date;\n\t__v: number;\n};\n\nexport interface GeoCheckDocument extends GeoCheckDocumentBase {\n\t_id: Types.ObjectId;\n}\n\nconst geoCheckMetadataSchema = new Schema<GeoCheckMetadataDocument>(\n\t{\n\t\tmonitorId: { type: Schema.Types.ObjectId, required: true, index: true },\n\t\tteamId: { type: Schema.Types.ObjectId, required: true, index: true },\n\t\ttype: { type: String, required: true, enum: MonitorTypes },\n\t},\n\t{ _id: false }\n);\n\nconst geoCheckTimingsSchema = new Schema<GeoCheckTimings>(\n\t{\n\t\ttotal: { type: Number, default: 0 },\n\t\tdns: { type: Number, default: 0 },\n\t\ttcp: { type: Number, default: 0 },\n\t\ttls: { type: Number, default: 0 },\n\t\tfirstByte: { type: Number, default: 0 },\n\t\tdownload: { type: Number, default: 0 },\n\t},\n\t{ _id: false }\n);\n\nconst geoCheckLocationSchema = new Schema<GeoCheckLocation>(\n\t{\n\t\tcontinent: { type: String, required: true },\n\t\tregion: { type: String, default: \"\" },\n\t\tcountry: { type: String, default: \"\" },\n\t\tstate: { type: String, default: \"\" },\n\t\tcity: { type: String, default: \"\" },\n\t\tlongitude: { type: Number, default: 0 },\n\t\tlatitude: { type: Number, default: 0 },\n\t},\n\t{ _id: false }\n);\n\nconst geoCheckResultSchema = new Schema<GeoCheckResult>(\n\t{\n\t\tlocation: {\n\t\t\ttype: geoCheckLocationSchema,\n\t\t\trequired: true,\n\t\t},\n\t\tstatus: {\n\t\t\ttype: Boolean,\n\t\t\trequired: true,\n\t\t},\n\t\tstatusCode: {\n\t\t\ttype: Number,\n\t\t\trequired: true,\n\t\t},\n\t\ttimings: {\n\t\t\ttype: geoCheckTimingsSchema,\n\t\t\trequired: true,\n\t\t},\n\t},\n\t{ _id: false }\n);\n\nconst GeoCheckSchema = new Schema<GeoCheckDocument>(\n\t{\n\t\tmetadata: {\n\t\t\ttype: geoCheckMetadataSchema,\n\t\t\trequired: true,\n\t\t},\n\t\tresults: {\n\t\t\ttype: [geoCheckResultSchema],\n\t\t\trequired: true,\n\t\t\tdefault: [],\n\t\t},\n\t\texpiry: {\n\t\t\ttype: Date,\n\t\t\tdefault: Date.now,\n\t\t},\n\t},\n\t{\n\t\ttimestamps: true,\n\t\tstrict: false,\n\t\ttimeseries: {\n\t\t\ttimeField: \"createdAt\",\n\t\t\tmetaField: \"metadata\",\n\t\t\tgranularity: \"seconds\",\n\t\t},\n\t}\n);\n\nGeoCheckSchema.index({ \"metadata.monitorId\": 1, createdAt: -1 });\nGeoCheckSchema.index({ \"metadata.monitorId\": 1, createdAt: 1 });\nGeoCheckSchema.index({ \"metadata.teamId\": 1, createdAt: -1 });\nGeoCheckSchema.index({ createdAt: 1 });\n\nconst GeoCheckModel = model<GeoCheckDocument>(\"GeoCheck\", GeoCheckSchema);\n\nexport type { GeoCheckMetadataDocument };\nexport { GeoCheckModel };\nexport default GeoCheckModel;\n"
  },
  {
    "path": "server/src/db/models/Incident.ts",
    "content": "import { Schema, model, type Types } from \"mongoose\";\nimport { IncidentResolutionTypes, type Incident } from \"@/types/incident.js\";\n\ntype IncidentDocumentBase = Omit<Incident, \"id\" | \"monitorId\" | \"teamId\" | \"resolvedBy\" | \"startTime\" | \"endTime\" | \"createdAt\" | \"updatedAt\"> & {\n\tmonitorId: Types.ObjectId;\n\tteamId: Types.ObjectId;\n\tresolvedBy?: Types.ObjectId | null;\n\tstartTime: Date;\n\tendTime: Date | null;\n\tcreatedAt: Date;\n\tupdatedAt: Date;\n};\n\nexport interface IncidentDocument extends IncidentDocumentBase {\n\t_id: Types.ObjectId;\n}\n\nconst IncidentSchema = new Schema<IncidentDocument>(\n\t{\n\t\tmonitorId: {\n\t\t\ttype: Schema.Types.ObjectId,\n\t\t\tref: \"Monitor\",\n\t\t\trequired: true,\n\t\t\timmutable: true,\n\t\t\tindex: true,\n\t\t},\n\t\tteamId: {\n\t\t\ttype: Schema.Types.ObjectId,\n\t\t\tref: \"Team\",\n\t\t\trequired: true,\n\t\t\timmutable: true,\n\t\t\tindex: true,\n\t\t},\n\t\tstartTime: {\n\t\t\ttype: Date,\n\t\t\timmutable: true,\n\t\t\trequired: true,\n\t\t},\n\t\tendTime: {\n\t\t\ttype: Date,\n\t\t\tdefault: null,\n\t\t},\n\t\tstatus: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t\tindex: true,\n\t\t},\n\t\tmessage: {\n\t\t\ttype: String,\n\t\t\tdefault: null,\n\t\t},\n\t\tstatusCode: {\n\t\t\ttype: Number,\n\t\t\tdefault: null,\n\t\t\tindex: true,\n\t\t},\n\t\tresolutionType: {\n\t\t\ttype: String,\n\t\t\tenum: IncidentResolutionTypes,\n\t\t\tdefault: null,\n\t\t},\n\t\tresolvedBy: {\n\t\t\ttype: Schema.Types.ObjectId,\n\t\t\tref: \"User\",\n\t\t\tdefault: null,\n\t\t},\n\t\tresolvedByEmail: {\n\t\t\ttype: String,\n\t\t\tdefault: null,\n\t\t},\n\t\tcomment: {\n\t\t\ttype: String,\n\t\t\tdefault: null,\n\t\t},\n\t},\n\t{ timestamps: true }\n);\n\nIncidentSchema.index({ monitorId: 1, status: 1 });\nIncidentSchema.index({ teamId: 1, status: 1 });\nIncidentSchema.index({ teamId: 1, startTime: -1 });\nIncidentSchema.index({ status: 1, startTime: -1 });\nIncidentSchema.index({ resolutionType: 1, status: 1 });\nIncidentSchema.index({ resolvedBy: 1, status: 1 });\nIncidentSchema.index({ createdAt: -1 });\n\nconst IncidentModel = model<IncidentDocument>(\"Incident\", IncidentSchema);\n\nexport { IncidentModel };\nexport default IncidentModel;\n"
  },
  {
    "path": "server/src/db/models/Invite.ts",
    "content": "import { Schema, model, type Types } from \"mongoose\";\nimport type { Invite } from \"@/types/invite.js\";\n\ntype InviteDocumentBase = Omit<Invite, \"id\" | \"teamId\" | \"createdAt\" | \"updatedAt\" | \"expiry\"> & {\n\tteamId: Types.ObjectId;\n\texpiry: Date;\n};\n\ninterface InviteDocument extends InviteDocumentBase {\n\t_id: Types.ObjectId;\n\tcreatedAt: Date;\n\tupdatedAt: Date;\n}\n\nconst InviteSchema = new Schema<InviteDocument>(\n\t{\n\t\temail: { type: String, required: true, unique: true },\n\t\tteamId: { type: Schema.Types.ObjectId, ref: \"Team\", immutable: true, required: true },\n\t\trole: { type: [String], required: true, default: [\"user\"] },\n\t\ttoken: { type: String, required: true },\n\t\texpiry: { type: Date, default: Date.now, expires: 3600 },\n\t},\n\t{ timestamps: true }\n);\n\nconst InviteModel = model<InviteDocument>(\"Invite\", InviteSchema);\n\nexport type { InviteDocument };\nexport { InviteModel };\nexport default InviteModel;\n"
  },
  {
    "path": "server/src/db/models/MaintenanceWindow.ts",
    "content": "import { Schema, model, type Types } from \"mongoose\";\nimport type { MaintenanceWindow } from \"@/types/maintenanceWindow.js\";\n\ntype MaintenanceWindowDocumentBase = Omit<MaintenanceWindow, \"id\" | \"monitorId\" | \"teamId\" | \"start\" | \"end\" | \"createdAt\" | \"updatedAt\"> & {\n\tmonitorId: Types.ObjectId;\n\tteamId: Types.ObjectId;\n\tstart: Date;\n\tend: Date;\n\texpiry?: Date;\n\tcreatedAt: Date;\n\tupdatedAt: Date;\n};\n\ninterface MaintenanceWindowDocument extends MaintenanceWindowDocumentBase {\n\t_id: Types.ObjectId;\n}\n\nconst MaintenanceWindowSchema = new Schema<MaintenanceWindowDocument>(\n\t{\n\t\tmonitorId: {\n\t\t\ttype: Schema.Types.ObjectId,\n\t\t\tref: \"Monitor\",\n\t\t\timmutable: true,\n\t\t},\n\t\tteamId: {\n\t\t\ttype: Schema.Types.ObjectId,\n\t\t\tref: \"Team\",\n\t\t\timmutable: true,\n\t\t},\n\t\tactive: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\t\tname: {\n\t\t\ttype: String,\n\t\t},\n\t\tduration: {\n\t\t\ttype: Number,\n\t\t},\n\t\tdurationUnit: {\n\t\t\ttype: String,\n\t\t\tenum: [\"seconds\", \"minutes\", \"hours\", \"days\"],\n\t\t},\n\t\trepeat: {\n\t\t\ttype: Number,\n\t\t},\n\t\tstart: {\n\t\t\ttype: Date,\n\t\t},\n\t\tend: {\n\t\t\ttype: Date,\n\t\t},\n\t\texpiry: {\n\t\t\ttype: Date,\n\t\t\tindex: { expires: \"0s\" },\n\t\t},\n\t},\n\t{\n\t\ttimestamps: true,\n\t}\n);\n\nconst MaintenanceWindowModel = model<MaintenanceWindowDocument>(\"MaintenanceWindow\", MaintenanceWindowSchema);\n\nexport type { MaintenanceWindowDocument };\nexport { MaintenanceWindowModel };\nexport default MaintenanceWindowModel;\n"
  },
  {
    "path": "server/src/db/models/Migration.ts",
    "content": "import mongoose from \"mongoose\";\n\nconst MigrationSchema = new mongoose.Schema(\n\t{\n\t\tname: { type: String, required: true, unique: true },\n\t\tstatus: { type: String, enum: [\"completed\", \"failed\"], default: \"completed\" },\n\t\tcompletedAt: { type: Date },\n\t\terror: { type: String },\n\t},\n\t{ timestamps: true }\n);\n\nexport default mongoose.model(\"Migration\", MigrationSchema);\n"
  },
  {
    "path": "server/src/db/models/Monitor.ts",
    "content": "import { Schema, model, Types } from \"mongoose\";\nimport type { Monitor, MonitorMatchMethod, CheckSnapshot } from \"@/types/monitor.js\";\nimport { MonitorTypes, MonitorStatuses } from \"@/types/monitor.js\";\nimport type {\n\tCheckAudits,\n\tCheckCaptureInfo,\n\tCheckCpuInfo,\n\tCheckDiskInfo,\n\tCheckErrorInfo,\n\tCheckHostInfo,\n\tCheckMemoryInfo,\n\tCheckNetworkInterfaceInfo,\n\tGotTimings,\n\tILighthouseAudit,\n} from \"@/types/check.js\";\n\ntype CheckSnapshotDocument = Omit<CheckSnapshot, \"createdAt\"> & { createdAt: Date };\n\ntype MonitorDocumentBase = Omit<\n\tMonitor,\n\t\"id\" | \"userId\" | \"teamId\" | \"notifications\" | \"selectedDisks\" | \"statusWindow\" | \"recentChecks\" | \"createdAt\" | \"updatedAt\"\n> & {\n\tstatusWindow: boolean[];\n\trecentChecks: CheckSnapshotDocument[];\n\tnotifications: Types.ObjectId[];\n\tselectedDisks: string[];\n\tmatchMethod?: MonitorMatchMethod;\n};\n\ninterface MonitorDocument extends MonitorDocumentBase {\n\t_id: Types.ObjectId;\n\tuserId: Types.ObjectId;\n\tteamId: Types.ObjectId;\n\tcreatedAt: Date;\n\tupdatedAt: Date;\n}\n\nconst snapshotTimingPhasesSchema = new Schema<GotTimings[\"phases\"]>(\n\t{\n\t\twait: { type: Number },\n\t\tdns: { type: Number },\n\t\ttcp: { type: Number },\n\t\ttls: { type: Number },\n\t\trequest: { type: Number },\n\t\tfirstByte: { type: Number },\n\t\tdownload: { type: Number },\n\t\ttotal: { type: Number },\n\t},\n\t{ _id: false }\n);\n\nconst snapshotTimingsSchema = new Schema<GotTimings>(\n\t{\n\t\tstart: { type: Number },\n\t\tsocket: { type: Number },\n\t\tlookup: { type: Number },\n\t\tconnect: { type: Number },\n\t\tsecureConnect: { type: Number },\n\t\tupload: { type: Number },\n\t\tresponse: { type: Number },\n\t\tend: { type: Number },\n\t\tphases: { type: snapshotTimingPhasesSchema },\n\t},\n\t{ _id: false }\n);\n\nconst snapshotCpuSchema = new Schema<CheckCpuInfo>(\n\t{\n\t\tphysical_core: { type: Number },\n\t\tlogical_core: { type: Number },\n\t\tfrequency: { type: Number },\n\t\tcurrent_frequency: { type: Number },\n\t\ttemperature: { type: [Number] },\n\t\tfree_percent: { type: Number },\n\t\tusage_percent: { type: Number },\n\t},\n\t{ _id: false }\n);\n\nconst snapshotMemorySchema = new Schema<CheckMemoryInfo>(\n\t{\n\t\ttotal_bytes: { type: Number },\n\t\tavailable_bytes: { type: Number },\n\t\tused_bytes: { type: Number },\n\t\tusage_percent: { type: Number },\n\t},\n\t{ _id: false }\n);\n\nconst snapshotDiskSchema = new Schema<CheckDiskInfo>(\n\t{\n\t\tdevice: { type: String },\n\t\tmountpoint: { type: String },\n\t\ttotal_bytes: { type: Number },\n\t\tfree_bytes: { type: Number },\n\t\tused_bytes: { type: Number },\n\t\tusage_percent: { type: Number },\n\t\ttotal_inodes: { type: Number },\n\t\tfree_inodes: { type: Number },\n\t\tused_inodes: { type: Number },\n\t\tinodes_usage_percent: { type: Number },\n\t\tread_bytes: { type: Number },\n\t\twrite_bytes: { type: Number },\n\t\tread_time: { type: Number },\n\t\twrite_time: { type: Number },\n\t},\n\t{ _id: false }\n);\n\nconst snapshotHostSchema = new Schema<CheckHostInfo>(\n\t{\n\t\tos: { type: String },\n\t\tplatform: { type: String },\n\t\tkernel_version: { type: String },\n\t\tpretty_name: { type: String },\n\t},\n\t{ _id: false }\n);\n\nconst snapshotErrorSchema = new Schema<CheckErrorInfo>(\n\t{\n\t\tmetric: { type: [String] },\n\t\terr: { type: String },\n\t},\n\t{ _id: false }\n);\n\nconst snapshotCaptureSchema = new Schema<CheckCaptureInfo>(\n\t{\n\t\tversion: { type: String },\n\t\tmode: { type: String },\n\t},\n\t{ _id: false }\n);\n\nconst snapshotNetworkInterfaceSchema = new Schema<CheckNetworkInterfaceInfo>(\n\t{\n\t\tname: { type: String },\n\t\tbytes_sent: { type: Number },\n\t\tbytes_recv: { type: Number },\n\t\tpackets_sent: { type: Number },\n\t\tpackets_recv: { type: Number },\n\t\terr_in: { type: Number },\n\t\terr_out: { type: Number },\n\t\tdrop_in: { type: Number },\n\t\tdrop_out: { type: Number },\n\t\tfifo_in: { type: Number },\n\t\tfifo_out: { type: Number },\n\t},\n\t{ _id: false }\n);\n\nconst snapshotLighthouseAuditSchema = new Schema<ILighthouseAudit>(\n\t{\n\t\tid: { type: String },\n\t\ttitle: { type: String },\n\t\tscore: { type: Number },\n\t\tdisplayValue: { type: String },\n\t\tnumericValue: { type: Number },\n\t\tnumericUnit: { type: String },\n\t},\n\t{ _id: false }\n);\n\nconst snapshotAuditsSchema = new Schema<CheckAudits>(\n\t{\n\t\tcls: { type: snapshotLighthouseAuditSchema },\n\t\tsi: { type: snapshotLighthouseAuditSchema },\n\t\tfcp: { type: snapshotLighthouseAuditSchema },\n\t\tlcp: { type: snapshotLighthouseAuditSchema },\n\t\ttbt: { type: snapshotLighthouseAuditSchema },\n\t},\n\t{ _id: false }\n);\n\nconst checkSnapshotSchema = new Schema<CheckSnapshotDocument>(\n\t{\n\t\tid: { type: String, required: true },\n\t\tstatus: { type: Boolean, required: true },\n\t\tresponseTime: { type: Number },\n\t\ttimings: { type: snapshotTimingsSchema },\n\t\tstatusCode: { type: Number },\n\t\tmessage: { type: String },\n\t\tcpu: { type: snapshotCpuSchema },\n\t\tmemory: { type: snapshotMemorySchema },\n\t\tdisk: { type: [snapshotDiskSchema] },\n\t\thost: { type: snapshotHostSchema },\n\t\terrors: { type: [snapshotErrorSchema] },\n\t\tcapture: { type: snapshotCaptureSchema },\n\t\tnet: { type: [snapshotNetworkInterfaceSchema] },\n\t\taccessibility: { type: Number },\n\t\tbestPractices: { type: Number },\n\t\tseo: { type: Number },\n\t\tperformance: { type: Number },\n\t\taudits: { type: snapshotAuditsSchema },\n\t\tcreatedAt: { type: Date, required: true },\n\t},\n\t{ _id: false }\n);\n\nconst MonitorSchema = new Schema<MonitorDocument>(\n\t{\n\t\tuserId: {\n\t\t\ttype: Schema.Types.ObjectId,\n\t\t\tref: \"User\",\n\t\t\timmutable: true,\n\t\t\trequired: true,\n\t\t},\n\t\tteamId: {\n\t\t\ttype: Schema.Types.ObjectId,\n\t\t\tref: \"Team\",\n\t\t\timmutable: true,\n\t\t\trequired: true,\n\t\t},\n\t\tname: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t},\n\t\tdescription: {\n\t\t\ttype: String,\n\t\t},\n\t\tstatus: {\n\t\t\ttype: String,\n\t\t\tenum: MonitorStatuses,\n\t\t\tdefault: \"initializing\",\n\t\t},\n\t\tstatusWindow: {\n\t\t\ttype: [Boolean],\n\t\t\tdefault: [],\n\t\t},\n\t\tstatusWindowSize: {\n\t\t\ttype: Number,\n\t\t\tdefault: 5,\n\t\t},\n\t\tstatusWindowThreshold: {\n\t\t\ttype: Number,\n\t\t\tdefault: 60,\n\t\t},\n\t\ttype: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t\tenum: MonitorTypes,\n\t\t},\n\t\tignoreTlsErrors: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\t\tuseAdvancedMatching: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\t\tjsonPath: {\n\t\t\ttype: String,\n\t\t},\n\t\texpectedValue: {\n\t\t\ttype: String,\n\t\t},\n\t\tmatchMethod: {\n\t\t\ttype: String,\n\t\t\tenum: [\"equal\", \"include\", \"regex\", \"\"],\n\t\t},\n\t\turl: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t},\n\t\tport: {\n\t\t\ttype: Number,\n\t\t},\n\t\tisActive: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\t\tinterval: {\n\t\t\ttype: Number,\n\t\t\tdefault: 60000,\n\t\t},\n\t\tuptimePercentage: {\n\t\t\ttype: Number,\n\t\t\tdefault: undefined,\n\t\t},\n\t\tnotifications: [\n\t\t\t{\n\t\t\t\ttype: Schema.Types.ObjectId,\n\t\t\t\tref: \"Notification\",\n\t\t\t},\n\t\t],\n\t\tsecret: {\n\t\t\ttype: String,\n\t\t},\n\t\tcpuAlertThreshold: {\n\t\t\ttype: Number,\n\t\t\tdefault: 100,\n\t\t},\n\t\tcpuAlertCounter: {\n\t\t\ttype: Number,\n\t\t\tdefault: 5,\n\t\t},\n\t\tmemoryAlertThreshold: {\n\t\t\ttype: Number,\n\t\t\tdefault: 100,\n\t\t},\n\t\tmemoryAlertCounter: {\n\t\t\ttype: Number,\n\t\t\tdefault: 5,\n\t\t},\n\t\tdiskAlertThreshold: {\n\t\t\ttype: Number,\n\t\t\tdefault: 100,\n\t\t},\n\t\tdiskAlertCounter: {\n\t\t\ttype: Number,\n\t\t\tdefault: 5,\n\t\t},\n\t\ttempAlertThreshold: {\n\t\t\ttype: Number,\n\t\t\tdefault: 100,\n\t\t},\n\t\ttempAlertCounter: {\n\t\t\ttype: Number,\n\t\t\tdefault: 5,\n\t\t},\n\t\tselectedDisks: {\n\t\t\ttype: [String],\n\t\t\tdefault: [],\n\t\t},\n\t\tgameId: {\n\t\t\ttype: String,\n\t\t},\n\t\tgrpcServiceName: {\n\t\t\ttype: String,\n\t\t\tdefault: \"\",\n\t\t},\n\t\tgroup: {\n\t\t\ttype: String,\n\t\t\ttrim: true,\n\t\t\tmaxLength: 50,\n\t\t\tdefault: null,\n\t\t\tset(value: string | null) {\n\t\t\t\treturn value && value.trim() ? value.trim() : null;\n\t\t\t},\n\t\t},\n\t\tgeoCheckEnabled: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\t\tgeoCheckLocations: {\n\t\t\ttype: [String],\n\t\t\tdefault: [],\n\t\t},\n\t\tgeoCheckInterval: {\n\t\t\ttype: Number,\n\t\t\tdefault: 300000,\n\t\t},\n\t\trecentChecks: {\n\t\t\ttype: [checkSnapshotSchema],\n\t\t\tdefault: [],\n\t\t},\n\t},\n\t{\n\t\ttimestamps: true,\n\t}\n);\n\nMonitorSchema.index({ teamId: 1, type: 1 });\n\nconst MonitorModel = model<MonitorDocument>(\"Monitor\", MonitorSchema);\n\nexport type { MonitorDocument, CheckSnapshotDocument };\nexport { MonitorModel };\nexport default MonitorModel;\n"
  },
  {
    "path": "server/src/db/models/MonitorStats.ts",
    "content": "import { Schema, model, type Types } from \"mongoose\";\nimport type { MonitorStats as MonitorStatsEntity } from \"@/types/monitorStats.js\";\n\ntype MonitorStatsDocumentBase = Omit<MonitorStatsEntity, \"id\" | \"monitorId\" | \"createdAt\" | \"updatedAt\"> & {\n\tmonitorId: Types.ObjectId;\n};\n\ninterface MonitorStatsDocument extends MonitorStatsDocumentBase {\n\t_id: Types.ObjectId;\n\tcreatedAt: Date;\n\tupdatedAt: Date;\n}\n\nconst MonitorStatsSchema = new Schema<MonitorStatsDocument>(\n\t{\n\t\tmonitorId: {\n\t\t\ttype: Schema.Types.ObjectId,\n\t\t\tref: \"Monitor\",\n\t\t\tindex: true,\n\t\t\trequired: true,\n\t\t},\n\t\tavgResponseTime: {\n\t\t\ttype: Number,\n\t\t\tdefault: 0,\n\t\t},\n\t\tmaxResponseTime: {\n\t\t\ttype: Number,\n\t\t\tdefault: 0,\n\t\t},\n\t\ttotalChecks: {\n\t\t\ttype: Number,\n\t\t\tdefault: 0,\n\t\t},\n\t\ttotalUpChecks: {\n\t\t\ttype: Number,\n\t\t\tdefault: 0,\n\t\t},\n\t\ttotalDownChecks: {\n\t\t\ttype: Number,\n\t\t\tdefault: 0,\n\t\t},\n\t\tuptimePercentage: {\n\t\t\ttype: Number,\n\t\t\tdefault: 0,\n\t\t},\n\t\tlastCheckTimestamp: {\n\t\t\ttype: Number,\n\t\t\tdefault: 0,\n\t\t},\n\t\tlastResponseTime: {\n\t\t\ttype: Number,\n\t\t\tdefault: 0,\n\t\t},\n\t\ttimeOfLastFailure: {\n\t\t\ttype: Number,\n\t\t\tdefault: undefined,\n\t\t},\n\t},\n\t{ timestamps: true }\n);\n\nconst MonitorStatsModel = model<MonitorStatsDocument>(\"MonitorStats\", MonitorStatsSchema);\n\nexport type { MonitorStatsDocument };\nexport { MonitorStatsModel };\nexport default MonitorStatsModel;\n"
  },
  {
    "path": "server/src/db/models/Notification.ts",
    "content": "import { Schema, model, type Types } from \"mongoose\";\nimport type { Notification, NotificationChannel } from \"@/types/notification.js\";\n\ninterface NotificationDocument extends Omit<Notification, \"id\" | \"userId\" | \"teamId\" | \"createdAt\" | \"updatedAt\"> {\n\t_id: Types.ObjectId;\n\tuserId: Types.ObjectId;\n\tteamId: Types.ObjectId;\n\tcreatedAt: Date;\n\tupdatedAt: Date;\n}\n\nconst NotificationSchema = new Schema<NotificationDocument>(\n\t{\n\t\tuserId: {\n\t\t\ttype: Schema.Types.ObjectId,\n\t\t\tref: \"User\",\n\t\t\timmutable: true,\n\t\t\trequired: true,\n\t\t},\n\t\tteamId: {\n\t\t\ttype: Schema.Types.ObjectId,\n\t\t\tref: \"Team\",\n\t\t\timmutable: true,\n\t\t\trequired: true,\n\t\t},\n\t\ttype: {\n\t\t\ttype: String,\n\t\t\tenum: [\"email\", \"slack\", \"discord\", \"webhook\", \"pager_duty\", \"matrix\", \"teams\"] as NotificationChannel[],\n\t\t\trequired: true,\n\t\t},\n\t\tnotificationName: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t},\n\t\taddress: { type: String },\n\t\tphone: { type: String },\n\t\thomeserverUrl: { type: String },\n\t\troomId: { type: String },\n\t\taccessToken: { type: String },\n\t},\n\t{\n\t\ttimestamps: true,\n\t}\n);\n\nconst NotificationModel = model<NotificationDocument>(\"Notification\", NotificationSchema);\n\nexport type { NotificationDocument };\nexport { NotificationModel };\nexport default NotificationModel;\n"
  },
  {
    "path": "server/src/db/models/RecoveryToken.ts",
    "content": "import { Schema, model, type Types } from \"mongoose\";\nimport type { RecoveryToken as RecoveryTokenEntity } from \"@/types/recoveryToken.js\";\n\ntype RecoveryTokenDocumentBase = Omit<RecoveryTokenEntity, \"id\" | \"createdAt\" | \"updatedAt\" | \"expiry\"> & {\n\texpiry: Date;\n};\n\ninterface RecoveryTokenDocument extends RecoveryTokenDocumentBase {\n\t_id: Types.ObjectId;\n\tcreatedAt: Date;\n\tupdatedAt: Date;\n}\n\nconst RecoveryTokenSchema = new Schema<RecoveryTokenDocument>(\n\t{\n\t\temail: { type: String, required: true, unique: true },\n\t\ttoken: { type: String, required: true },\n\t\texpiry: { type: Date, default: Date.now, expires: 600 },\n\t},\n\t{ timestamps: true }\n);\n\nconst RecoveryTokenModel = model<RecoveryTokenDocument>(\"RecoveryToken\", RecoveryTokenSchema);\n\nexport type { RecoveryTokenDocument };\nexport { RecoveryTokenModel };\nexport default RecoveryTokenModel;\n"
  },
  {
    "path": "server/src/db/models/StatusPage.ts",
    "content": "import { Schema, model, type Types } from \"mongoose\";\nimport type { StatusPage, StatusPageLogoDocument } from \"@/types/statusPage.js\";\nimport { StatusPageTypes } from \"@/types/statusPage.js\";\n\ntype StatusPageDocumentBase = Omit<\n\tStatusPage,\n\t\"id\" | \"userId\" | \"teamId\" | \"monitors\" | \"subMonitors\" | \"originalMonitors\" | \"logo\" | \"createdAt\" | \"updatedAt\"\n> & {\n\tmonitors: Types.ObjectId[];\n\tsubMonitors: Types.ObjectId[];\n\toriginalMonitors?: Types.ObjectId[];\n\tlogo?: StatusPageLogoDocument | null;\n};\n\ninterface StatusPageDocument extends StatusPageDocumentBase {\n\t_id: Types.ObjectId;\n\tuserId: Types.ObjectId;\n\tteamId: Types.ObjectId;\n\tcreatedAt: Date;\n\tupdatedAt: Date;\n}\n\nconst logoSchema = new Schema<StatusPageLogoDocument>(\n\t{\n\t\tdata: { type: Buffer },\n\t\tcontentType: { type: String },\n\t},\n\t{ _id: false }\n);\n\nconst StatusPageSchema = new Schema<StatusPageDocument>(\n\t{\n\t\tuserId: {\n\t\t\ttype: Schema.Types.ObjectId,\n\t\t\tref: \"User\",\n\t\t\timmutable: true,\n\t\t\trequired: true,\n\t\t},\n\t\tteamId: {\n\t\t\ttype: Schema.Types.ObjectId,\n\t\t\tref: \"Team\",\n\t\t\timmutable: true,\n\t\t\trequired: true,\n\t\t},\n\t\ttype: {\n\t\t\ttype: [String],\n\t\t\trequired: true,\n\t\t\tdefault: [\"uptime\"],\n\t\t\tenum: StatusPageTypes,\n\t\t},\n\t\tcompanyName: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t\tdefault: \"\",\n\t\t},\n\t\turl: {\n\t\t\ttype: String,\n\t\t\tunique: true,\n\t\t\trequired: true,\n\t\t\tdefault: \"\",\n\t\t},\n\t\ttimezone: {\n\t\t\ttype: String,\n\t\t},\n\t\tcolor: {\n\t\t\ttype: String,\n\t\t\tdefault: \"#4169E1\",\n\t\t},\n\t\tmonitors: [\n\t\t\t{\n\t\t\t\ttype: Schema.Types.ObjectId,\n\t\t\t\tref: \"Monitor\",\n\t\t\t\trequired: true,\n\t\t\t},\n\t\t],\n\t\tsubMonitors: [\n\t\t\t{\n\t\t\t\ttype: Schema.Types.ObjectId,\n\t\t\t\tref: \"Monitor\",\n\t\t\t\trequired: true,\n\t\t\t},\n\t\t],\n\t\tlogo: {\n\t\t\ttype: logoSchema,\n\t\t\tdefault: null,\n\t\t},\n\t\tisPublished: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\t\tshowCharts: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\t\tshowUptimePercentage: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\t\tshowAdminLoginLink: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\t\tshowInfrastructure: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\t\tcustomCSS: {\n\t\t\ttype: String,\n\t\t\tdefault: \"\",\n\t\t},\n\t},\n\t{ timestamps: true }\n);\n\nconst StatusPageModel = model<StatusPageDocument>(\"StatusPage\", StatusPageSchema);\n\nexport type { StatusPageDocument };\nexport { StatusPageModel };\nexport default StatusPageModel;\n"
  },
  {
    "path": "server/src/db/models/Team.ts",
    "content": "import { Schema, model, type Types } from \"mongoose\";\n\nimport type { Team } from \"@/types/index.js\";\n\ntype TeamDocumentBase = Omit<Team, \"id\" | \"createdAt\" | \"updatedAt\"> & {};\ninterface TeamDocument extends TeamDocumentBase {\n\t_id: Types.ObjectId;\n\tcreatedAt: Date;\n\tupdatedAt: Date;\n}\n\nconst TeamSchema = new Schema<TeamDocument>(\n\t{\n\t\temail: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t\tunique: true,\n\t\t},\n\t},\n\t{\n\t\ttimestamps: true,\n\t}\n);\nconst TeamModel = model<TeamDocument>(\"Team\", TeamSchema);\n\nexport type { TeamDocument };\nexport { TeamModel };\nexport default TeamModel;\n"
  },
  {
    "path": "server/src/db/models/User.ts",
    "content": "import { Schema, model, type Types } from \"mongoose\";\nimport bcrypt from \"bcryptjs\";\nimport type { User, UserProfileImage, UserRole } from \"@/types/index.js\";\nimport { MonitorModel } from \"@/db/models/index.js\";\nimport Team from \"./Team.js\";\nimport NotificationModel from \"./Notification.js\";\n\ntype UserDocumentBase = Omit<User, \"id\" | \"teamId\" | \"createdAt\" | \"updatedAt\"> & {\n\tteamId?: Types.ObjectId;\n\tprofileImage?: Required<UserProfileImage>;\n};\n\ninterface UserDocument extends UserDocumentBase {\n\t_id: Types.ObjectId;\n\tteamId?: Types.ObjectId;\n\tcreatedAt: Date;\n\tupdatedAt: Date;\n}\n\nconst profileImageSchema = new Schema<Required<UserProfileImage>>(\n\t{\n\t\tdata: { type: Buffer },\n\t\tcontentType: { type: String },\n\t},\n\t{ _id: false }\n);\n\nconst UserSchema = new Schema<UserDocument>(\n\t{\n\t\tfirstName: { type: String, required: true },\n\t\tlastName: { type: String, required: true },\n\t\temail: { type: String, required: true, unique: true },\n\t\tpassword: { type: String, required: true },\n\t\tavatarImage: { type: String },\n\t\tprofileImage: { type: profileImageSchema },\n\t\tisActive: { type: Boolean, default: true },\n\t\tisVerified: { type: Boolean, default: false },\n\t\trole: {\n\t\t\ttype: [String],\n\t\t\tenum: [\"user\", \"admin\", \"superadmin\", \"demo\" satisfies UserRole],\n\t\t\tdefault: [\"user\"],\n\t\t},\n\t\tteamId: {\n\t\t\ttype: Schema.Types.ObjectId,\n\t\t\tref: \"Team\",\n\t\t\timmutable: true,\n\t\t},\n\t\tcheckTTL: { type: Number },\n\t},\n\t{ timestamps: true }\n);\n\nUserSchema.pre(\"findOneAndDelete\", async function (next) {\n\ttry {\n\t\tconst userToDelete = await this.model.findOne(this.getFilter());\n\t\tif (!userToDelete) return next();\n\t\tif (userToDelete.role.includes(\"superadmin\")) {\n\t\t\tawait Team.deleteOne({ _id: userToDelete.teamId });\n\t\t\tawait MonitorModel.deleteMany({ userId: userToDelete._id });\n\t\t\tawait this.model.deleteMany({ teamId: userToDelete.teamId, _id: { $ne: userToDelete._id } });\n\t\t\tawait NotificationModel.deleteMany({ teamId: userToDelete.teamId });\n\t\t}\n\t\tnext();\n\t} catch (error) {\n\t\tnext(error as Error);\n\t}\n});\n\nUserSchema.methods.comparePassword = async function (submittedPassword: string) {\n\treturn bcrypt.compare(submittedPassword, this.password);\n};\n\nconst UserModel = model<UserDocument>(\"User\", UserSchema);\n\nexport type { UserDocument };\nexport { UserModel };\nexport default UserModel;\n"
  },
  {
    "path": "server/src/db/models/index.ts",
    "content": "export * from \"@/db/models/Monitor.js\";\nexport { default as MonitorModel } from \"@/db/models/Monitor.js\";\n\nexport * from \"@/db/models/Check.js\";\nexport { default as CheckModel } from \"@/db/models/Check.js\";\n\nexport * from \"@/db/models/MonitorStats.js\";\nexport { default as MonitorStatsModel } from \"@/db/models/MonitorStats.js\";\n\nexport * from \"@/db/models/StatusPage.js\";\nexport { default as StatusPageModel } from \"@/db/models/StatusPage.js\";\n\nexport * from \"@/db/models/User.js\";\nexport { default as UserModel } from \"@/db/models/User.js\";\n\nexport * from \"@/db/models/Invite.js\";\nexport { default as InviteModel } from \"@/db/models/Invite.js\";\n\nexport * from \"@/db/models/AppSettings.js\";\nexport { default as AppSettingsModel } from \"@/db/models/AppSettings.js\";\n\nexport * from \"@/db/models/RecoveryToken.js\";\nexport { default as RecoveryTokenModel } from \"@/db/models/RecoveryToken.js\";\n\nexport * from \"@/db/models/Notification.js\";\nexport { default as NotificationModel } from \"@/db/models/Notification.js\";\n\nexport * from \"@/db/models/Incident.js\";\nexport { default as IncidentModel } from \"@/db/models/Incident.js\";\n\nexport * from \"@/db/models/Team.js\";\nexport { default as TeamModel } from \"@/db/models/Team.js\";\n\nexport * from \"@/db/models/MaintenanceWindow.js\";\nexport { default as MaintenanceWindowModel } from \"@/db/models/MaintenanceWindow.js\";\n\nexport * from \"@/db/models/GeoCheck.js\";\nexport { default as GeoCheckModel } from \"@/db/models/GeoCheck.js\";\n"
  },
  {
    "path": "server/src/index.ts",
    "content": "import { initializeServices } from \"./config/services.js\";\nimport { initializeControllers } from \"./config/controllers.js\";\nimport { createApp } from \"./app.js\";\nimport { initShutdownListener } from \"./shutdown.js\";\nimport { validateEnv } from \"./validation/envValidation.js\";\nimport { fileURLToPath } from \"url\";\nimport path from \"path\";\nimport fs from \"fs\";\nimport { runMigrations } from \"./db/migration/index.js\";\n\nimport Logger, { ILogger } from \"@/utils/logger.js\";\nimport { SettingsService } from \"@/service/index.js\";\nimport { MongoSettingsRepository } from \"./repositories/index.js\";\n\nconst SERVICE_NAME = \"Server\";\nlet logger: ILogger;\n\nconst startApp = async () => {\n\t// Validate environment variables first\n\tconst env = validateEnv();\n\n\t// FE path\n\tconst __filename = fileURLToPath(import.meta.url);\n\tconst __dirname = path.dirname(__filename);\n\tconst openApiSpec = JSON.parse(fs.readFileSync(path.join(__dirname, \"../openapi.json\"), \"utf8\"));\n\tconst frontendPath = path.join(__dirname, \"..\", \"public\");\n\n\t// Create services\n\tconst settingsRepository = new MongoSettingsRepository();\n\tconst settingsService = new SettingsService(settingsRepository, env);\n\n\tconst envSettings = settingsService.loadSettings();\n\n\t// Create logger\n\tlogger = new Logger({ envSettings });\n\n\t// Initialize services\n\tconst services = await initializeServices({ logger, envSettings, settingsService, settingsRepository });\n\n\tawait runMigrations(logger);\n\n\t// Initialize controllers\n\tconst controllers = initializeControllers(services);\n\n\tconst app = createApp({\n\t\tservices,\n\t\tcontrollers,\n\t\tenvSettings,\n\t\tfrontendPath,\n\t\topenApiSpec,\n\t});\n\n\tconst server = app.listen(env.PORT, () => {\n\t\tlogger.info({ message: `Server started on port:${env.PORT}` });\n\t});\n\n\tinitShutdownListener(server, services);\n};\n\nstartApp().catch((error) => {\n\tlogger.error({\n\t\tmessage: error.message,\n\t\tservice: SERVICE_NAME,\n\t\tmethod: \"startApp\",\n\t\tstack: error.stack,\n\t});\n\tprocess.exit(1);\n});\n"
  },
  {
    "path": "server/src/middleware/handleErrors.ts",
    "content": "import type { NextFunction, Request, Response } from \"express\";\nimport { logger } from \"@/utils/logger.js\";\nimport { AppError } from \"@/utils/AppError.js\";\n\nconst handleErrors = (error: unknown, req: Request, res: Response, _next: NextFunction) => {\n\tconst status = error instanceof AppError ? error.status || 500 : 500;\n\tconst message = error instanceof AppError ? error.message : \"Server error\";\n\tconst service = error instanceof AppError ? error.service : \"unknownService\";\n\tconst method = error instanceof AppError ? error.method : \"unknownMethod\";\n\tlogger.error({\n\t\tmessage: message,\n\t\tservice: service,\n\t\tmethod: method,\n\t\tstack: error instanceof AppError ? error.stack : undefined,\n\t\tdetails: error instanceof AppError ? error.details : undefined,\n\t});\n\tres.status(status).json({\n\t\tstatus,\n\t\tmsg: message,\n\t});\n};\n\nexport { handleErrors };\n"
  },
  {
    "path": "server/src/middleware/isAllowed.ts",
    "content": "import type { Request, Response, NextFunction } from \"express\";\nconst SERVICE_NAME = \"allowedRoles\";\nimport { AppError } from \"@/utils/AppError.js\";\nimport type { UserRole } from \"@/types/index.js\";\n\nconst isAllowed = (allowedRoles: UserRole[]) => {\n\treturn (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tconst user = req.user;\n\t\t\tif (!user) {\n\t\t\t\tthrow new AppError({ message: \"Unauthorized\", status: 403, service: SERVICE_NAME });\n\t\t\t}\n\t\t\tconst userRoles = req.user?.role || [];\n\n\t\t\t// Check if the user has the required role\n\t\t\tif (userRoles.some((role) => allowedRoles.includes(role))) {\n\t\t\t\tnext();\n\t\t\t\treturn;\n\t\t\t} else {\n\t\t\t\tthrow new AppError({ message: \"Unauthorized\", status: 403, service: SERVICE_NAME });\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t\treturn;\n\t\t}\n\t};\n};\n\nexport { isAllowed };\n"
  },
  {
    "path": "server/src/middleware/rateLimiter.ts",
    "content": "import rateLimit from \"express-rate-limit\";\n\nexport const generalApiLimiter = rateLimit({\n\twindowMs: 60 * 1000,\n\tlimit: 600,\n\tstandardHeaders: true,\n\tlegacyHeaders: false,\n\tipv6Subnet: 64,\n});\n\nexport const authApiLimiter = rateLimit({\n\twindowMs: 60 * 1000,\n\tlimit: 15,\n\tstandardHeaders: true,\n\tlegacyHeaders: false,\n\tipv6Subnet: 64,\n});\n"
  },
  {
    "path": "server/src/middleware/sanitization.ts",
    "content": "import type { Request, Response, NextFunction } from \"express\";\nimport DOMPurify from \"isomorphic-dompurify\";\n\nexport function sanitizeInput(input: string, options?: object): string;\nexport function sanitizeInput(input: unknown, options?: object): unknown;\nexport function sanitizeInput(input: unknown, options = {}): unknown {\n\tif (typeof input !== \"string\") {\n\t\treturn input;\n\t}\n\n\t// Default configuration - remove all HTML tags and attributes\n\tconst defaultConfig = {\n\t\tALLOWED_TAGS: [] as string[],\n\t\tALLOWED_ATTR: [] as string[],\n\t\tKEEP_CONTENT: true,\n\t\t...options,\n\t};\n\n\treturn DOMPurify.sanitize(input, defaultConfig);\n}\n\nexport const sanitizeObject = (obj: unknown, options = {}): unknown => {\n\tif (typeof obj !== \"object\" || obj === null) {\n\t\treturn obj;\n\t}\n\n\tif (Array.isArray(obj)) {\n\t\treturn obj.map((item) => sanitizeObject(item, options));\n\t}\n\n\tconst sanitized: Record<string, unknown> = {};\n\tfor (const [key, value] of Object.entries(obj)) {\n\t\tif (typeof value === \"string\") {\n\t\t\tsanitized[key] = sanitizeInput(value, options);\n\t\t} else if (typeof value === \"object\" && value !== null) {\n\t\t\tsanitized[key] = sanitizeObject(value, options);\n\t\t} else {\n\t\t\tsanitized[key] = value;\n\t\t}\n\t}\n\n\treturn sanitized;\n};\n\nexport const sanitizeBody = (options = {}): ((req: Request, res: Response, next: NextFunction) => void) => {\n\treturn (req: Request, res: Response, next: NextFunction) => {\n\t\tif (req.body && typeof req.body === \"object\") {\n\t\t\treq.body = sanitizeObject(req.body, options);\n\t\t}\n\t\tnext();\n\t};\n};\n\nexport const sanitizeQuery = (options = {}): ((req: Request, res: Response, next: NextFunction) => void) => {\n\treturn (req: Request, res: Response, next: NextFunction) => {\n\t\tif (req.query && typeof req.query === \"object\") {\n\t\t\tfor (const key of Object.keys(req.query)) {\n\t\t\t\tconst value = req.query[key];\n\t\t\t\tif (typeof value === \"string\") {\n\t\t\t\t\treq.query[key] = sanitizeInput(value, options);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tnext();\n\t};\n};\n"
  },
  {
    "path": "server/src/middleware/verifyJWT.ts",
    "content": "import { NextFunction, Request, Response } from \"express\";\n\nimport jwt from \"jsonwebtoken\";\nimport { AppError } from \"@/utils/AppError.js\";\nimport type { ISettingsService } from \"@/service/system/settingsService.js\";\nimport type { User } from \"@/types/user.js\";\n\nconst SERVICE_NAME = \"verifyJWT\";\nconst TOKEN_PREFIX = \"Bearer \";\n\nconst isUser = (payload: unknown): payload is User => {\n\treturn typeof payload === \"object\" && payload !== null && \"id\" in payload && \"teamId\" in payload && \"role\" in payload;\n};\n\nexport const createVerifyJWT = (settingsService: ISettingsService) => {\n\treturn (req: Request, res: Response, next: NextFunction) => {\n\t\tconst token = req.headers[\"authorization\"];\n\t\t// Make sure a token is provided\n\t\tif (!token) {\n\t\t\tconst error = new AppError({ message: \"No token provided\", status: 401, service: SERVICE_NAME });\n\t\t\tnext(error);\n\t\t\treturn;\n\t\t}\n\t\t// Make sure it is properly formatted\n\t\tif (!token.startsWith(TOKEN_PREFIX)) {\n\t\t\tconst error = new AppError({ message: \"Invalid token format\", status: 401, service: SERVICE_NAME, method: \"verifyJWT\" });\n\t\t\tnext(error);\n\t\t\treturn;\n\t\t}\n\n\t\tconst parsedToken = token.slice(TOKEN_PREFIX.length, token.length);\n\t\t// Verify the token's authenticity\n\t\tconst { jwtSecret } = settingsService.getSettings();\n\t\tif (!jwtSecret) {\n\t\t\tconst error = new AppError({ message: \"JWT secret not configured\", status: 500, service: SERVICE_NAME });\n\t\t\tnext(error);\n\t\t\treturn;\n\t\t}\n\t\tjwt.verify(parsedToken, jwtSecret, (err: jwt.VerifyErrors | null, decoded: jwt.JwtPayload | string | undefined) => {\n\t\t\tif (err) {\n\t\t\t\tconst error = new AppError({\n\t\t\t\t\tmessage: err instanceof Error ? err.message : \"Failed to authenticate token\",\n\t\t\t\t\tstatus: 401,\n\t\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\t\tdetails: err instanceof Error ? { error: err } : undefined,\n\t\t\t\t\tmethod: \"verifyJWT\",\n\t\t\t\t});\n\t\t\t\tnext(error);\n\t\t\t\treturn;\n\t\t\t} else if (isUser(decoded)) {\n\t\t\t\treq.user = decoded;\n\t\t\t\tnext();\n\t\t\t} else {\n\t\t\t\tnext(new AppError({ message: \"Invalid token payload\", status: 401, service: SERVICE_NAME, method: \"verifyJWT\" }));\n\t\t\t}\n\t\t});\n\t};\n};\n"
  },
  {
    "path": "server/src/middleware/verifyStatusPageAccess.ts",
    "content": "import { NextFunction, Request, RequestHandler, Response } from \"express\";\nimport { IStatusPagesRepository } from \"@/repositories/index.js\";\nimport { AppError } from \"@/utils/AppError.js\";\n\nexport const createVerifyStatusPageAccess = (statusPagesRepository: IStatusPagesRepository, verifyJWT: RequestHandler) => {\n\treturn async (req: Request, res: Response, next: NextFunction) => {\n\t\ttry {\n\t\t\tconst url = Array.isArray(req.params.url) ? req.params.url[0] : req.params.url;\n\t\t\tif (!url) {\n\t\t\t\tthrow new AppError({ message: \"Status page URL is required\", status: 400 });\n\t\t\t}\n\t\t\tconst statusPage = await statusPagesRepository.findByUrl(url);\n\t\t\tif (statusPage.isPublished) {\n\t\t\t\tnext(); // Published — no auth needed\n\t\t\t} else {\n\t\t\t\tverifyJWT(req, res, next); // Unpublished — require JWT\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tnext(error);\n\t\t}\n\t};\n};\n"
  },
  {
    "path": "server/src/repositories/checks/IChecksRepository.ts",
    "content": "import type {\n\tCheck,\n\tChecksQueryResult,\n\tChecksSummary,\n\tMonitorType,\n\tPageSpeedChecksResult,\n\tHardwareChecksResult,\n\tUptimeChecksResult,\n} from \"@/types/index.js\";\nimport type { LatestChecksMap } from \"@/repositories/checks/MongoChecksRepistory.js\";\n\nexport interface IChecksRepository {\n\t// create\n\tcreate(check: Check): Promise<Check>;\n\tcreateChecks(checks: Check[]): Promise<Check[]>;\n\n\t// single fetch\n\t// collection fetch\n\tfindByMonitorId(\n\t\tmonitorId: string,\n\t\tsortOrder: string,\n\t\tdateRange: string,\n\t\tfilter: string | undefined,\n\t\tpage: number,\n\t\trowsPerPage: number,\n\t\tstatus: boolean | undefined\n\t): Promise<ChecksQueryResult>;\n\tfindByTeamId(\n\t\tsortOrder: string,\n\t\tdateRange: string,\n\t\tfilter: string | undefined,\n\t\tpage: number,\n\t\trowsPerPage: number,\n\t\tteamId: string\n\t): Promise<ChecksQueryResult>;\n\tfindLatestByMonitorIds(monitorIds: string[], options?: { limitPerMonitor?: number }): Promise<LatestChecksMap>;\n\tfindByDateRangeAndMonitorId(\n\t\tmonitorId: string,\n\t\tstartDate: Date,\n\t\tendDate: Date,\n\t\tdateString: string,\n\t\toptions?: { type?: MonitorType }\n\t): Promise<UptimeChecksResult | HardwareChecksResult | PageSpeedChecksResult>;\n\tfindSummaryByTeamId(teamId: string, dateRange: string): Promise<ChecksSummary>;\n\t// update\n\t//delete\n\tdeleteByMonitorId(monitorId: string): Promise<number>;\n\tdeleteByTeamId(teamId: string): Promise<number>;\n\tdeleteByMonitorIdsNotIn(monitorIds: string[]): Promise<number>;\n\tdeleteOlderThan(date: Date): Promise<number>;\n}\n"
  },
  {
    "path": "server/src/repositories/checks/MongoChecksRepistory.ts",
    "content": "import { IChecksRepository } from \"@/repositories/index.js\";\nimport type {\n\tCheck,\n\tCheckAudits,\n\tCheckCaptureInfo,\n\tCheckCpuInfo,\n\tCheckDiskInfo,\n\tCheckErrorInfo,\n\tCheckHostInfo,\n\tCheckMemoryInfo,\n\tCheckMetadata,\n\tCheckNetworkInterfaceInfo,\n\tGotTimings,\n\tMonitorType,\n} from \"@/types/index.js\";\nimport { CheckModel, type CheckDocument } from \"@/db/models/index.js\";\nimport mongoose from \"mongoose\";\nimport { getDateForRange } from \"@/utils/dataUtils.js\";\nimport { ILogger } from \"@/utils/logger.js\";\n\nconst SERVICE_NAME = \"StatusService\";\n\nexport type LatestChecksMap = Record<string, Check[]>;\ntype DateRange = { start: Date; end: Date };\ntype HardwareUpChecks = { totalChecks: number };\n\nclass MongoChecksRepository implements IChecksRepository {\n\tstatic SERVICE_NAME = SERVICE_NAME;\n\n\tprivate logger: ILogger;\n\tconstructor(logger: ILogger) {\n\t\tthis.logger = logger;\n\t}\n\n\tprivate toEntity = (doc: CheckDocument): Check => {\n\t\tconst toStringId = (value: mongoose.Types.ObjectId | string | undefined | null): string => {\n\t\t\tif (!value) {\n\t\t\t\treturn \"\";\n\t\t\t}\n\t\t\treturn value instanceof mongoose.Types.ObjectId ? value.toString() : String(value);\n\t\t};\n\n\t\tconst toDateString = (value?: Date | string | null): string => {\n\t\t\tif (!value) {\n\t\t\t\treturn new Date(0).toISOString();\n\t\t\t}\n\t\t\treturn value instanceof Date ? value.toISOString() : new Date(value).toISOString();\n\t\t};\n\n\t\tconst mapTimings = (timings?: GotTimings): GotTimings => {\n\t\t\tconst phases = timings?.phases ?? {\n\t\t\t\twait: 0,\n\t\t\t\tdns: 0,\n\t\t\t\ttcp: 0,\n\t\t\t\ttls: 0,\n\t\t\t\trequest: 0,\n\t\t\t\tfirstByte: 0,\n\t\t\t\tdownload: 0,\n\t\t\t\ttotal: 0,\n\t\t\t};\n\n\t\t\treturn {\n\t\t\t\tstart: timings?.start ?? 0,\n\t\t\t\tsocket: timings?.socket ?? 0,\n\t\t\t\tlookup: timings?.lookup ?? 0,\n\t\t\t\tconnect: timings?.connect ?? 0,\n\t\t\t\tsecureConnect: timings?.secureConnect ?? 0,\n\t\t\t\tupload: timings?.upload ?? 0,\n\t\t\t\tresponse: timings?.response ?? 0,\n\t\t\t\tend: timings?.end ?? 0,\n\t\t\t\tphases,\n\t\t\t};\n\t\t};\n\n\t\tconst mapCpu = (cpu?: CheckCpuInfo): CheckCpuInfo => ({\n\t\t\tphysical_core: cpu?.physical_core ?? 0,\n\t\t\tlogical_core: cpu?.logical_core ?? 0,\n\t\t\tfrequency: cpu?.frequency ?? 0,\n\t\t\ttemperature: cpu?.temperature ?? [],\n\t\t\tfree_percent: cpu?.free_percent ?? 0,\n\t\t\tusage_percent: cpu?.usage_percent ?? 0,\n\t\t});\n\n\t\tconst mapMemory = (memory?: CheckMemoryInfo): CheckMemoryInfo => ({\n\t\t\ttotal_bytes: memory?.total_bytes ?? 0,\n\t\t\tavailable_bytes: memory?.available_bytes ?? 0,\n\t\t\tused_bytes: memory?.used_bytes ?? 0,\n\t\t\tusage_percent: memory?.usage_percent ?? 0,\n\t\t});\n\n\t\tconst mapHost = (host?: CheckHostInfo): CheckHostInfo => ({\n\t\t\tos: host?.os ?? \"\",\n\t\t\tplatform: host?.platform ?? \"\",\n\t\t\tkernel_version: host?.kernel_version ?? \"\",\n\t\t});\n\n\t\tconst mapCapture = (capture?: CheckCaptureInfo): CheckCaptureInfo => ({\n\t\t\tversion: capture?.version ?? \"\",\n\t\t\tmode: capture?.mode ?? \"\",\n\t\t});\n\n\t\tconst mapDisks = (disks?: CheckDiskInfo[]): CheckDiskInfo[] =>\n\t\t\t(disks ?? []).map((disk) => ({\n\t\t\t\tdevice: disk?.device ?? \"\",\n\t\t\t\tmountpoint: disk?.mountpoint ?? \"\",\n\t\t\t\ttotal_bytes: disk?.total_bytes ?? 0,\n\t\t\t\tfree_bytes: disk?.free_bytes ?? 0,\n\t\t\t\tused_bytes: disk?.used_bytes ?? 0,\n\t\t\t\tusage_percent: disk?.usage_percent ?? 0,\n\t\t\t\ttotal_inodes: disk?.total_inodes ?? 0,\n\t\t\t\tfree_inodes: disk?.free_inodes ?? 0,\n\t\t\t\tused_inodes: disk?.used_inodes ?? 0,\n\t\t\t\tinodes_usage_percent: disk?.inodes_usage_percent ?? 0,\n\t\t\t\tread_bytes: disk?.read_bytes ?? 0,\n\t\t\t\twrite_bytes: disk?.write_bytes ?? 0,\n\t\t\t\tread_time: disk?.read_time ?? 0,\n\t\t\t\twrite_time: disk?.write_time ?? 0,\n\t\t\t}));\n\n\t\tconst mapErrors = (errors?: CheckErrorInfo[]): CheckErrorInfo[] =>\n\t\t\t(errors ?? []).map((error) => ({\n\t\t\t\tmetric: error?.metric ?? [],\n\t\t\t\terr: error?.err ?? \"\",\n\t\t\t}));\n\n\t\tconst mapNet = (net?: CheckNetworkInterfaceInfo[]): CheckNetworkInterfaceInfo[] =>\n\t\t\t(net ?? []).map((iface) => ({\n\t\t\t\tname: iface?.name ?? \"\",\n\t\t\t\tbytes_sent: iface?.bytes_sent ?? 0,\n\t\t\t\tbytes_recv: iface?.bytes_recv ?? 0,\n\t\t\t\tpackets_sent: iface?.packets_sent ?? 0,\n\t\t\t\tpackets_recv: iface?.packets_recv ?? 0,\n\t\t\t\terr_in: iface?.err_in ?? 0,\n\t\t\t\terr_out: iface?.err_out ?? 0,\n\t\t\t\tdrop_in: iface?.drop_in ?? 0,\n\t\t\t\tdrop_out: iface?.drop_out ?? 0,\n\t\t\t\tfifo_in: iface?.fifo_in ?? 0,\n\t\t\t\tfifo_out: iface?.fifo_out ?? 0,\n\t\t\t}));\n\n\t\tconst mapAudits = (audits?: CheckAudits): CheckAudits | undefined => {\n\t\t\tif (!audits) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tcls: audits.cls,\n\t\t\t\tsi: audits.si,\n\t\t\t\tfcp: audits.fcp,\n\t\t\t\tlcp: audits.lcp,\n\t\t\t\ttbt: audits.tbt,\n\t\t\t};\n\t\t};\n\n\t\tconst mapMetadata = (metadata: CheckDocument[\"metadata\"]): CheckMetadata => ({\n\t\t\tmonitorId: toStringId(metadata.monitorId),\n\t\t\tteamId: toStringId(metadata.teamId),\n\t\t\ttype: metadata.type,\n\t\t});\n\n\t\treturn {\n\t\t\tid: toStringId(doc._id),\n\t\t\tmetadata: mapMetadata(doc.metadata),\n\t\t\tstatus: doc.status ?? false,\n\t\t\tresponseTime: doc.responseTime ?? 0,\n\t\t\ttimings: mapTimings(doc.timings),\n\t\t\tstatusCode: doc.statusCode ?? 0,\n\t\t\tmessage: doc.message ?? \"\",\n\t\t\tcpu: mapCpu(doc.cpu),\n\t\t\tmemory: mapMemory(doc.memory),\n\t\t\tdisk: mapDisks(doc.disk),\n\t\t\thost: mapHost(doc.host),\n\t\t\terrors: mapErrors(doc.errors),\n\t\t\tcapture: mapCapture(doc.capture),\n\t\t\tnet: mapNet(doc.net),\n\t\t\taccessibility: doc.accessibility,\n\t\t\tbestPractices: doc.bestPractices,\n\t\t\tseo: doc.seo,\n\t\t\tperformance: doc.performance,\n\t\t\taudits: mapAudits(doc.audits),\n\t\t\tcreatedAt: toDateString(doc.createdAt),\n\t\t\tupdatedAt: toDateString(doc.updatedAt),\n\t\t};\n\t};\n\n\tprivate mapDocuments = (documents: CheckDocument[]): Check[] => {\n\t\tif (!documents?.length) {\n\t\t\treturn [];\n\t\t}\n\t\treturn documents.map((doc) => this.toEntity(doc));\n\t};\n\n\tprivate toDocument = (check: Partial<Check>): CheckDocument => {\n\t\t// Map id to _id for MongoDB storage\n\t\tconst { id, metadata, ...rest } = check;\n\t\tif (!metadata || !metadata.monitorId || !metadata.teamId) {\n\t\t\tthrow new Error(`Check must have valid metadata with monitorId and teamId. Got: ${JSON.stringify({ id, metadata })}`);\n\t\t}\n\t\treturn {\n\t\t\t_id: id ? new mongoose.Types.ObjectId(id) : new mongoose.Types.ObjectId(),\n\t\t\tmetadata: {\n\t\t\t\tmonitorId: new mongoose.Types.ObjectId(metadata.monitorId),\n\t\t\t\tteamId: new mongoose.Types.ObjectId(metadata.teamId),\n\t\t\t\ttype: metadata.type,\n\t\t\t},\n\t\t\t...rest,\n\t\t} as unknown as CheckDocument;\n\t};\n\n\tcreate = async (check: Check) => {\n\t\tconst savedCheck = await CheckModel.create(check);\n\t\treturn this.toEntity(savedCheck);\n\t};\n\n\tcreateChecks = async (checks: Check[]) => {\n\t\tconst docs = checks.map((check) => this.toDocument(check));\n\t\tconst inserted = await CheckModel.insertMany(docs);\n\t\treturn this.mapDocuments(inserted as unknown as CheckDocument[]);\n\t};\n\n\tfindByMonitorId = async (\n\t\tmonitorId: string,\n\t\tsortOrder: string,\n\t\tdateRange: string,\n\t\tfilter: string | undefined,\n\t\tpage: number,\n\t\trowsPerPage: number,\n\t\tstatus: boolean | undefined\n\t) => {\n\t\t// Match\n\t\tconst matchStage: Record<string, unknown> = {\n\t\t\t\"metadata.monitorId\": new mongoose.Types.ObjectId(monitorId),\n\t\t\t...(typeof status !== \"undefined\" && { status }),\n\t\t\t...(getDateForRange(dateRange) && {\n\t\t\t\tcreatedAt: {\n\t\t\t\t\t$gte: getDateForRange(dateRange),\n\t\t\t\t},\n\t\t\t}),\n\t\t};\n\n\t\tif (filter !== undefined) {\n\t\t\tswitch (filter) {\n\t\t\t\tcase \"all\":\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"up\":\n\t\t\t\t\tmatchStage.status = true;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"down\":\n\t\t\t\t\tmatchStage.status = false;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"resolve\":\n\t\t\t\t\tmatchStage.status = false;\n\t\t\t\t\tmatchStage.statusCode = 5000;\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tthis.logger.warn({\n\t\t\t\t\t\tmessage: \"invalid filter\",\n\t\t\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\t\t\tmethod: \"getChecks\",\n\t\t\t\t\t});\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t//Sort\n\t\tconst convertedSortOrder = sortOrder === \"asc\" ? 1 : -1;\n\n\t\t// Pagination\n\t\tlet skip = 0;\n\t\tif (page && rowsPerPage) {\n\t\t\tskip = page * rowsPerPage;\n\t\t}\n\n\t\tconst [checksCount, checks] = await Promise.all([\n\t\t\tCheckModel.countDocuments(matchStage),\n\t\t\tCheckModel.find(matchStage).sort({ createdAt: convertedSortOrder }).skip(skip).limit(rowsPerPage).lean() as Promise<CheckDocument[]>,\n\t\t]);\n\n\t\treturn { checksCount, checks: this.mapDocuments(checks) };\n\t};\n\n\tfindByTeamId = async (sortOrder: string, dateRange: string, filter: string, page: number, rowsPerPage: number, teamId: string) => {\n\t\tconst matchStage: Record<string, unknown> = {\n\t\t\t\"metadata.teamId\": new mongoose.Types.ObjectId(teamId),\n\t\t\t...(getDateForRange(dateRange) && {\n\t\t\t\tcreatedAt: {\n\t\t\t\t\t$gte: getDateForRange(dateRange),\n\t\t\t\t},\n\t\t\t}),\n\t\t};\n\t\t// Add filter to match stage\n\t\tif (filter !== undefined) {\n\t\t\tswitch (filter) {\n\t\t\t\tcase \"all\":\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"up\":\n\t\t\t\t\tmatchStage.status = true;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"down\":\n\t\t\t\t\tmatchStage.status = false;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"resolve\":\n\t\t\t\t\tmatchStage.status = false;\n\t\t\t\t\tmatchStage.statusCode = 5000;\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tthis.logger.warn({\n\t\t\t\t\t\tmessage: \"invalid filter\",\n\t\t\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\t\t\tmethod: \"getChecksByTeam\",\n\t\t\t\t\t});\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tconst parsedSortOrder = sortOrder === \"asc\" ? 1 : -1;\n\n\t\t// pagination\n\t\tlet skip = 0;\n\t\tif (page && rowsPerPage) {\n\t\t\tskip = page * rowsPerPage;\n\t\t}\n\n\t\tconst [checksCount, checks] = await Promise.all([\n\t\t\tCheckModel.countDocuments(matchStage),\n\t\t\tCheckModel.find(matchStage).sort({ createdAt: parsedSortOrder }).skip(skip).limit(rowsPerPage).lean() as Promise<CheckDocument[]>,\n\t\t]);\n\n\t\treturn { checksCount, checks: this.mapDocuments(checks) };\n\t};\n\n\tfindLatestByMonitorIds = async (monitorIds: string[], options?: { limitPerMonitor?: number }): Promise<LatestChecksMap> => {\n\t\tif (monitorIds.length === 0) {\n\t\t\treturn {};\n\t\t}\n\t\tconst limitPerMonitor = options?.limitPerMonitor ?? 25;\n\t\tconst dateFilter = new Date(Date.now() - 24 * 60 * 60 * 1000);\n\t\tconst results = await Promise.all(\n\t\t\tmonitorIds.map(async (monitorId) => {\n\t\t\t\tconst docs = await CheckModel.find({\n\t\t\t\t\t\"metadata.monitorId\": new mongoose.Types.ObjectId(monitorId),\n\t\t\t\t\tcreatedAt: { $gte: dateFilter },\n\t\t\t\t})\n\t\t\t\t\t.sort({ createdAt: -1 })\n\t\t\t\t\t.limit(limitPerMonitor)\n\t\t\t\t\t.lean();\n\t\t\t\treturn { monitorId, docs };\n\t\t\t})\n\t\t);\n\n\t\tconst mapped = results.reduce<LatestChecksMap>((acc, { monitorId, docs }) => {\n\t\t\tacc[monitorId] = docs.map((doc: CheckDocument) => this.toEntity(doc));\n\t\t\treturn acc;\n\t\t}, {});\n\t\treturn mapped;\n\t};\n\n\tfindByDateRangeAndMonitorId = async (monitorId: string, startDate: Date, endDate: Date, dateString: string, options?: { type?: MonitorType }) => {\n\t\tconst monitorObjectId = new mongoose.Types.ObjectId(monitorId);\n\t\tif (options?.type === \"hardware\") {\n\t\t\treturn this.findHardwareDateRangeChecks(monitorObjectId, startDate, endDate, dateString);\n\t\t}\n\t\tif (options?.type === \"pagespeed\") {\n\t\t\treturn this.findPageSpeedDateRangeChecks(monitorObjectId, startDate, endDate, dateString);\n\t\t}\n\t\treturn this.findUptimeDateRangeChecks(options?.type ?? \"http\", monitorObjectId, startDate, endDate, dateString);\n\t};\n\n\tfindSummaryByTeamId = async (teamId: string, dateRange: string) => {\n\t\tconst baseMatch = {\n\t\t\t\"metadata.teamId\": new mongoose.Types.ObjectId(teamId),\n\t\t\t...(getDateForRange(dateRange) && {\n\t\t\t\tcreatedAt: {\n\t\t\t\t\t$gte: getDateForRange(dateRange),\n\t\t\t\t},\n\t\t\t}),\n\t\t};\n\n\t\tconst [totalResult, downResult] = await Promise.all([\n\t\t\tCheckModel.countDocuments(baseMatch),\n\t\t\tCheckModel.countDocuments({ ...baseMatch, status: false }),\n\t\t]);\n\n\t\treturn {\n\t\t\ttotalChecks: totalResult,\n\t\t\tdownChecks: downResult,\n\t\t};\n\t};\n\n\tdeleteByMonitorId = async (monitorId: string): Promise<number> => {\n\t\tconst result = await CheckModel.deleteMany({ \"metadata.monitorId\": new mongoose.Types.ObjectId(monitorId) });\n\t\treturn result.deletedCount;\n\t};\n\n\tdeleteByTeamId = async (teamId: string) => {\n\t\tconst deleteResult = await CheckModel.deleteMany({ \"metadata.teamId\": teamId });\n\t\treturn deleteResult.deletedCount;\n\t};\n\n\tdeleteByMonitorIdsNotIn = async (monitorIds: string[]): Promise<number> => {\n\t\tconst objectIds = monitorIds.map((id) => new mongoose.Types.ObjectId(id));\n\t\tconst result = await CheckModel.deleteMany({ \"metadata.monitorId\": { $nin: objectIds } });\n\t\treturn result.deletedCount ?? 0;\n\t};\n\n\tdeleteOlderThan = async (cutoffDate: Date, batchDays: number = 30): Promise<number> => {\n\t\t// Find the oldest check that is older than the cutoff\n\t\tconst oldest = await CheckModel.findOne({ createdAt: { $lt: cutoffDate } })\n\t\t\t.sort({ createdAt: 1 })\n\t\t\t.select({ createdAt: 1 });\n\t\tif (!oldest?.createdAt) return 0;\n\n\t\tlet totalDeleted = 0;\n\t\tlet batchStart = new Date(oldest.createdAt);\n\t\tconst batchMs = batchDays * 24 * 60 * 60 * 1000;\n\n\t\t// Delete in 30 day chunks until we reach the cutoff\n\t\twhile (batchStart < cutoffDate) {\n\t\t\t// Advance startTime by batchMs to get to the end of last batch\n\t\t\tconst nextStart = batchStart.getTime() + batchMs;\n\t\t\tconst batchEnd = new Date(Math.min(nextStart, cutoffDate.getTime()));\n\t\t\tconst result = await CheckModel.deleteMany({\n\t\t\t\tcreatedAt: { $gte: batchStart, $lt: batchEnd },\n\t\t\t});\n\t\t\ttotalDeleted += result.deletedCount ?? 0;\n\t\t\tbatchStart = batchEnd;\n\t\t}\n\n\t\treturn totalDeleted;\n\t};\n\tprivate findUptimeDateRangeChecks = async (\n\t\tmonitorType: Exclude<MonitorType, \"hardware\" | \"pagespeed\">,\n\t\tmonitorObjectId: mongoose.Types.ObjectId,\n\t\tstartDate: Date,\n\t\tendDate: Date,\n\t\tdateString: string\n\t) => {\n\t\tconst matchStage = {\n\t\t\t\"metadata.monitorId\": monitorObjectId,\n\t\t\tcreatedAt: { $gte: startDate, $lte: endDate },\n\t\t};\n\t\tconst [result] = await CheckModel.aggregate([\n\t\t\t{ $match: matchStage },\n\t\t\t{ $sort: { createdAt: 1 } },\n\t\t\t{\n\t\t\t\t$facet: {\n\t\t\t\t\tuptimePercentage: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$group: {\n\t\t\t\t\t\t\t\t_id: null,\n\t\t\t\t\t\t\t\tupChecks: { $sum: { $cond: [{ $eq: [\"$status\", true] }, 1, 0] } },\n\t\t\t\t\t\t\t\ttotalChecks: { $sum: 1 },\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$project: {\n\t\t\t\t\t\t\t\t_id: 0,\n\t\t\t\t\t\t\t\tpercentage: {\n\t\t\t\t\t\t\t\t\t$cond: [{ $eq: [\"$totalChecks\", 0] }, 0, { $divide: [\"$upChecks\", \"$totalChecks\"] }],\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tgroupedAvgResponseTime: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$group: {\n\t\t\t\t\t\t\t\t_id: null,\n\t\t\t\t\t\t\t\tavgResponseTime: { $avg: \"$responseTime\" },\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tgroupedChecks: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$group: {\n\t\t\t\t\t\t\t\t_id: {\n\t\t\t\t\t\t\t\t\t$dateToString: { format: dateString, date: \"$createdAt\" },\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tavgResponseTime: { $avg: \"$responseTime\" },\n\t\t\t\t\t\t\t\ttotalChecks: { $sum: 1 },\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{ $sort: { _id: 1 } },\n\t\t\t\t\t\t{ $project: { bucketDate: \"$_id\", avgResponseTime: 1, totalChecks: 1, _id: 0 } },\n\t\t\t\t\t],\n\t\t\t\t\tgroupedUpChecks: [\n\t\t\t\t\t\t{ $match: { status: true } },\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$group: {\n\t\t\t\t\t\t\t\t_id: {\n\t\t\t\t\t\t\t\t\t$dateToString: { format: dateString, date: \"$createdAt\" },\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\ttotalChecks: { $sum: 1 },\n\t\t\t\t\t\t\t\tavgResponseTime: { $avg: \"$responseTime\" },\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{ $sort: { _id: 1 } },\n\t\t\t\t\t\t{ $project: { bucketDate: \"$_id\", avgResponseTime: 1, totalChecks: 1, _id: 0 } },\n\t\t\t\t\t],\n\t\t\t\t\tgroupedDownChecks: [\n\t\t\t\t\t\t{ $match: { status: false } },\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$group: {\n\t\t\t\t\t\t\t\t_id: {\n\t\t\t\t\t\t\t\t\t$dateToString: { format: dateString, date: \"$createdAt\" },\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\ttotalChecks: { $sum: 1 },\n\t\t\t\t\t\t\t\tavgResponseTime: { $avg: \"$responseTime\" },\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{ $sort: { _id: 1 } },\n\t\t\t\t\t\t{ $project: { bucketDate: \"$_id\", avgResponseTime: 1, totalChecks: 1, _id: 0 } },\n\t\t\t\t\t],\n\t\t\t\t},\n\t\t\t},\n\t\t]);\n\n\t\tconst uptimePercentage = result?.uptimePercentage?.[0]?.percentage ?? 0;\n\t\tconst avgResponseTime = result?.groupedAvgResponseTime?.[0]?.avgResponseTime ?? 0;\n\n\t\treturn {\n\t\t\tmonitorType,\n\t\t\tgroupedChecks: result?.groupedChecks ?? [],\n\t\t\tgroupedUpChecks: result?.groupedUpChecks ?? [],\n\t\t\tgroupedDownChecks: result?.groupedDownChecks ?? [],\n\t\t\tuptimePercentage,\n\t\t\tavgResponseTime,\n\t\t};\n\t};\n\n\tprivate findHardwareDateRangeChecks = async (monitorObjectId: mongoose.Types.ObjectId, startDate: Date, endDate: Date, dateString: string) => {\n\t\tconst monitorId = monitorObjectId.toHexString();\n\t\tconst dates = { start: startDate, end: endDate };\n\t\tconst [aggregateDataDoc, upChecksDoc, hardwareMetrics] = await Promise.all([\n\t\t\tthis.getHardwareTotalChecks(monitorId, dates),\n\t\t\tthis.getHardwareUpChecks(monitorId, dates),\n\t\t\tthis.getHardwareStats(monitorId, dates, dateString),\n\t\t]);\n\n\t\tconst aggregateData = {\n\t\t\ttotalChecks: aggregateDataDoc ?? 0,\n\t\t};\n\n\t\tconst upChecks = {\n\t\t\ttotalChecks: upChecksDoc?.totalChecks ?? 0,\n\t\t};\n\n\t\tconst checks = (hardwareMetrics ?? []).map((metric) => ({\n\t\t\tbucketDate: metric._id,\n\t\t\tavgCpuUsage: metric.avgCpuUsage ?? 0,\n\t\t\tavgMemoryUsage: metric.avgMemoryUsage ?? 0,\n\t\t\tavgTemperature: metric.avgTemperature ?? [],\n\t\t\tdisks: (metric.disks ?? []).map((disk: { [key: string]: number | string | undefined }) => ({\n\t\t\t\tname: disk?.name ?? \"\",\n\t\t\t\treadSpeed: disk?.readSpeed ?? 0,\n\t\t\t\twriteSpeed: disk?.writeSpeed ?? 0,\n\t\t\t\ttotalBytes: disk?.totalBytes ?? 0,\n\t\t\t\tfreeBytes: disk?.freeBytes ?? 0,\n\t\t\t\tusagePercent: disk?.usagePercent ?? 0,\n\t\t\t})),\n\t\t\tnet: (metric.net ?? []).map((iface: { [key: string]: number | string | undefined }) => ({\n\t\t\t\tname: iface?.name ?? \"\",\n\t\t\t\tbytesSentPerSecond: iface?.bytesSentPerSecond ?? 0,\n\t\t\t\tdeltaBytesRecv: iface?.deltaBytesRecv ?? 0,\n\t\t\t\tdeltaPacketsSent: iface?.deltaPacketsSent ?? 0,\n\t\t\t\tdeltaPacketsRecv: iface?.deltaPacketsRecv ?? 0,\n\t\t\t\tdeltaErrIn: iface?.deltaErrIn ?? 0,\n\t\t\t\tdeltaErrOut: iface?.deltaErrOut ?? 0,\n\t\t\t\tdeltaDropIn: iface?.deltaDropIn ?? 0,\n\t\t\t\tdeltaDropOut: iface?.deltaDropOut ?? 0,\n\t\t\t\tdeltaFifoIn: iface?.deltaFifoIn ?? 0,\n\t\t\t\tdeltaFifoOut: iface?.deltaFifoOut ?? 0,\n\t\t\t})),\n\t\t}));\n\n\t\treturn {\n\t\t\tmonitorType: \"hardware\" as const,\n\t\t\taggregateData,\n\t\t\tupChecks,\n\t\t\tchecks,\n\t\t};\n\t};\n\n\tprivate findPageSpeedDateRangeChecks = async (monitorObjectId: mongoose.Types.ObjectId, startDate: Date, endDate: Date, dateString: string) => {\n\t\tconst matchStage = {\n\t\t\t\"metadata.monitorId\": monitorObjectId,\n\t\t\tcreatedAt: { $gte: startDate, $lte: endDate },\n\t\t};\n\n\t\tconst [result] = await CheckModel.aggregate([\n\t\t\t{ $match: matchStage },\n\t\t\t{ $sort: { createdAt: 1 } },\n\t\t\t{\n\t\t\t\t$facet: {\n\t\t\t\t\tgroupedChecks: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$group: {\n\t\t\t\t\t\t\t\t_id: {\n\t\t\t\t\t\t\t\t\t$dateToString: { format: dateString, date: \"$createdAt\" },\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tavgPerformance: { $avg: \"$performance\" },\n\t\t\t\t\t\t\t\tavgAccessibility: { $avg: \"$accessibility\" },\n\t\t\t\t\t\t\t\tavgBestPractices: { $avg: \"$bestPractices\" },\n\t\t\t\t\t\t\t\tavgSeo: { $avg: \"$seo\" },\n\t\t\t\t\t\t\t\ttotalChecks: { $sum: 1 },\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{ $sort: { _id: 1 } },\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$project: {\n\t\t\t\t\t\t\t\tbucketDate: \"$_id\",\n\t\t\t\t\t\t\t\tperformance: \"$avgPerformance\",\n\t\t\t\t\t\t\t\taccessibility: \"$avgAccessibility\",\n\t\t\t\t\t\t\t\tbestPractices: \"$avgBestPractices\",\n\t\t\t\t\t\t\t\tseo: \"$avgSeo\",\n\t\t\t\t\t\t\t\ttotalChecks: 1,\n\t\t\t\t\t\t\t\t_id: 0,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t},\n\t\t\t},\n\t\t]);\n\n\t\treturn {\n\t\t\tmonitorType: \"pagespeed\" as const,\n\t\t\tgroupedChecks: result?.groupedChecks ?? [],\n\t\t};\n\t};\n\n\tprivate getHardwareTotalChecks = async (monitorId: string, dates: DateRange): Promise<number> => {\n\t\treturn await CheckModel.countDocuments({\n\t\t\t\"metadata.monitorId\": new mongoose.Types.ObjectId(monitorId),\n\t\t\t\"metadata.type\": \"hardware\",\n\t\t\tcreatedAt: { $gte: dates.start, $lte: dates.end },\n\t\t});\n\t};\n\n\tprivate getHardwareUpChecks = async (monitorId: string, dates: DateRange): Promise<HardwareUpChecks> => {\n\t\tconst count = await CheckModel.countDocuments({\n\t\t\t\"metadata.monitorId\": new mongoose.Types.ObjectId(monitorId),\n\t\t\t\"metadata.type\": \"hardware\",\n\t\t\tcreatedAt: { $gte: dates.start, $lte: dates.end },\n\t\t\tstatus: true,\n\t\t});\n\t\treturn { totalChecks: count };\n\t};\n\n\tprivate getHardwareStats = async (monitorId: string, dates: DateRange, dateString: string) => {\n\t\treturn await CheckModel.aggregate([\n\t\t\t{\n\t\t\t\t$match: {\n\t\t\t\t\t\"metadata.monitorId\": new mongoose.Types.ObjectId(monitorId),\n\t\t\t\t\t\"metadata.type\": \"hardware\",\n\t\t\t\t\tcreatedAt: { $gte: dates.start, $lte: dates.end },\n\t\t\t\t},\n\t\t\t},\n\t\t\t{ $sort: { createdAt: 1 } },\n\t\t\t{\n\t\t\t\t$group: {\n\t\t\t\t\t_id: { $dateToString: { format: dateString, date: \"$createdAt\" } },\n\t\t\t\t\tavgCpuUsage: { $avg: \"$cpu.usage_percent\" },\n\t\t\t\t\tavgMemoryUsage: { $avg: \"$memory.usage_percent\" },\n\t\t\t\t\tavgTemperatures: { $push: { $ifNull: [\"$cpu.temperature\", [0]] } },\n\t\t\t\t\tdisks: { $push: \"$disk\" },\n\t\t\t\t\tnet: { $push: \"$net\" },\n\t\t\t\t\tcreatedAts: { $push: \"$createdAt\" },\n\t\t\t\t\tsampleDoc: { $first: \"$$ROOT\" },\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\t$project: {\n\t\t\t\t\t_id: 1,\n\t\t\t\t\tavgCpuUsage: 1,\n\t\t\t\t\tavgMemoryUsage: 1,\n\t\t\t\t\tavgTemperature: {\n\t\t\t\t\t\t$map: {\n\t\t\t\t\t\t\tinput: { $range: [0, { $size: { $ifNull: [{ $arrayElemAt: [\"$avgTemperatures\", 0] }, [0]] } }] },\n\t\t\t\t\t\t\tas: \"idx\",\n\t\t\t\t\t\t\tin: { $avg: { $map: { input: \"$avgTemperatures\", as: \"t\", in: { $arrayElemAt: [\"$$t\", \"$$idx\"] } } } },\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tdisks: {\n\t\t\t\t\t\t$map: {\n\t\t\t\t\t\t\tinput: { $range: [0, { $size: { $ifNull: [\"$sampleDoc.disk\", []] } }] },\n\t\t\t\t\t\t\tas: \"dIdx\",\n\t\t\t\t\t\t\tin: {\n\t\t\t\t\t\t\t\tname: { $concat: [\"disk\", { $toString: \"$$dIdx\" }] },\n\t\t\t\t\t\t\t\treadSpeed: { $avg: { $map: { input: \"$disks\", as: \"dA\", in: { $arrayElemAt: [\"$$dA.read_bytes\", \"$$dIdx\"] } } } },\n\t\t\t\t\t\t\t\twriteSpeed: { $avg: { $map: { input: \"$disks\", as: \"dA\", in: { $arrayElemAt: [\"$$dA.write_bytes\", \"$$dIdx\"] } } } },\n\t\t\t\t\t\t\t\ttotalBytes: { $avg: { $map: { input: \"$disks\", as: \"dA\", in: { $arrayElemAt: [\"$$dA.total_bytes\", \"$$dIdx\"] } } } },\n\t\t\t\t\t\t\t\tfreeBytes: { $avg: { $map: { input: \"$disks\", as: \"dA\", in: { $arrayElemAt: [\"$$dA.free_bytes\", \"$$dIdx\"] } } } },\n\t\t\t\t\t\t\t\tusagePercent: { $avg: { $map: { input: \"$disks\", as: \"dA\", in: { $arrayElemAt: [\"$$dA.usage_percent\", \"$$dIdx\"] } } } },\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tnet: {\n\t\t\t\t\t\t$map: {\n\t\t\t\t\t\t\tinput: { $range: [0, { $size: { $ifNull: [\"$sampleDoc.net\", []] } }] },\n\t\t\t\t\t\t\tas: \"nIdx\",\n\t\t\t\t\t\t\tin: {\n\t\t\t\t\t\t\t\tname: { $arrayElemAt: [\"$sampleDoc.net.name\", \"$$nIdx\"] },\n\t\t\t\t\t\t\t\tbytesSentPerSecond: {\n\t\t\t\t\t\t\t\t\t$let: {\n\t\t\t\t\t\t\t\t\t\tvars: {\n\t\t\t\t\t\t\t\t\t\t\ttDiff: { $divide: [{ $subtract: [{ $last: \"$createdAts\" }, { $first: \"$createdAts\" }] }, 1000] },\n\t\t\t\t\t\t\t\t\t\t\tf: { $arrayElemAt: [{ $map: { input: { $first: \"$net\" }, as: \"i\", in: \"$$i.bytes_sent\" } }, \"$$nIdx\"] },\n\t\t\t\t\t\t\t\t\t\t\tl: { $arrayElemAt: [{ $map: { input: { $last: \"$net\" }, as: \"i\", in: \"$$i.bytes_sent\" } }, \"$$nIdx\"] },\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\tin: { $cond: [{ $gt: [\"$$tDiff\", 0] }, { $divide: [{ $subtract: [\"$$l\", \"$$f\"] }, \"$$tDiff\"] }, 0] },\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tdeltaBytesRecv: {\n\t\t\t\t\t\t\t\t\t$let: {\n\t\t\t\t\t\t\t\t\t\tvars: {\n\t\t\t\t\t\t\t\t\t\t\ttDiff: { $divide: [{ $subtract: [{ $last: \"$createdAts\" }, { $first: \"$createdAts\" }] }, 1000] },\n\t\t\t\t\t\t\t\t\t\t\tf: { $arrayElemAt: [{ $map: { input: { $first: \"$net\" }, as: \"i\", in: \"$$i.bytes_recv\" } }, \"$$nIdx\"] },\n\t\t\t\t\t\t\t\t\t\t\tl: { $arrayElemAt: [{ $map: { input: { $last: \"$net\" }, as: \"i\", in: \"$$i.bytes_recv\" } }, \"$$nIdx\"] },\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\tin: { $cond: [{ $gt: [\"$$tDiff\", 0] }, { $divide: [{ $subtract: [\"$$l\", \"$$f\"] }, \"$$tDiff\"] }, 0] },\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tdeltaPacketsSent: {\n\t\t\t\t\t\t\t\t\t$let: {\n\t\t\t\t\t\t\t\t\t\tvars: {\n\t\t\t\t\t\t\t\t\t\t\ttDiff: { $divide: [{ $subtract: [{ $last: \"$createdAts\" }, { $first: \"$createdAts\" }] }, 1000] },\n\t\t\t\t\t\t\t\t\t\t\tf: { $arrayElemAt: [{ $map: { input: { $first: \"$net\" }, as: \"i\", in: \"$$i.packets_sent\" } }, \"$$nIdx\"] },\n\t\t\t\t\t\t\t\t\t\t\tl: { $arrayElemAt: [{ $map: { input: { $last: \"$net\" }, as: \"i\", in: \"$$i.packets_sent\" } }, \"$$nIdx\"] },\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\tin: { $cond: [{ $gt: [\"$$tDiff\", 0] }, { $divide: [{ $subtract: [\"$$l\", \"$$f\"] }, \"$$tDiff\"] }, 0] },\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tdeltaPacketsRecv: {\n\t\t\t\t\t\t\t\t\t$let: {\n\t\t\t\t\t\t\t\t\t\tvars: {\n\t\t\t\t\t\t\t\t\t\t\ttDiff: { $divide: [{ $subtract: [{ $last: \"$createdAts\" }, { $first: \"$createdAts\" }] }, 1000] },\n\t\t\t\t\t\t\t\t\t\t\tf: { $arrayElemAt: [{ $map: { input: { $first: \"$net\" }, as: \"i\", in: \"$$i.packets_recv\" } }, \"$$nIdx\"] },\n\t\t\t\t\t\t\t\t\t\t\tl: { $arrayElemAt: [{ $map: { input: { $last: \"$net\" }, as: \"i\", in: \"$$i.packets_recv\" } }, \"$$nIdx\"] },\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\tin: { $cond: [{ $gt: [\"$$tDiff\", 0] }, { $divide: [{ $subtract: [\"$$l\", \"$$f\"] }, \"$$tDiff\"] }, 0] },\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tdeltaErrIn: {\n\t\t\t\t\t\t\t\t\t$let: {\n\t\t\t\t\t\t\t\t\t\tvars: {\n\t\t\t\t\t\t\t\t\t\t\ttDiff: { $divide: [{ $subtract: [{ $last: \"$createdAts\" }, { $first: \"$createdAts\" }] }, 1000] },\n\t\t\t\t\t\t\t\t\t\t\tf: { $arrayElemAt: [{ $map: { input: { $first: \"$net\" }, as: \"i\", in: \"$$i.err_in\" } }, \"$$nIdx\"] },\n\t\t\t\t\t\t\t\t\t\t\tl: { $arrayElemAt: [{ $map: { input: { $last: \"$net\" }, as: \"i\", in: \"$$i.err_in\" } }, \"$$nIdx\"] },\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\tin: { $cond: [{ $gt: [\"$$tDiff\", 0] }, { $divide: [{ $subtract: [\"$$l\", \"$$f\"] }, \"$$tDiff\"] }, 0] },\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tdeltaErrOut: {\n\t\t\t\t\t\t\t\t\t$let: {\n\t\t\t\t\t\t\t\t\t\tvars: {\n\t\t\t\t\t\t\t\t\t\t\ttDiff: { $divide: [{ $subtract: [{ $last: \"$createdAts\" }, { $first: \"$createdAts\" }] }, 1000] },\n\t\t\t\t\t\t\t\t\t\t\tf: { $arrayElemAt: [{ $map: { input: { $first: \"$net\" }, as: \"i\", in: \"$$i.err_out\" } }, \"$$nIdx\"] },\n\t\t\t\t\t\t\t\t\t\t\tl: { $arrayElemAt: [{ $map: { input: { $last: \"$net\" }, as: \"i\", in: \"$$i.err_out\" } }, \"$$nIdx\"] },\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\tin: { $cond: [{ $gt: [\"$$tDiff\", 0] }, { $divide: [{ $subtract: [\"$$l\", \"$$f\"] }, \"$$tDiff\"] }, 0] },\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tdeltaDropIn: {\n\t\t\t\t\t\t\t\t\t$let: {\n\t\t\t\t\t\t\t\t\t\tvars: {\n\t\t\t\t\t\t\t\t\t\t\ttDiff: { $divide: [{ $subtract: [{ $last: \"$createdAts\" }, { $first: \"$createdAts\" }] }, 1000] },\n\t\t\t\t\t\t\t\t\t\t\tf: { $arrayElemAt: [{ $map: { input: { $first: \"$net\" }, as: \"i\", in: \"$$i.drop_in\" } }, \"$$nIdx\"] },\n\t\t\t\t\t\t\t\t\t\t\tl: { $arrayElemAt: [{ $map: { input: { $last: \"$net\" }, as: \"i\", in: \"$$i.drop_in\" } }, \"$$nIdx\"] },\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\tin: { $cond: [{ $gt: [\"$$tDiff\", 0] }, { $divide: [{ $subtract: [\"$$l\", \"$$f\"] }, \"$$tDiff\"] }, 0] },\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tdeltaDropOut: {\n\t\t\t\t\t\t\t\t\t$let: {\n\t\t\t\t\t\t\t\t\t\tvars: {\n\t\t\t\t\t\t\t\t\t\t\ttDiff: { $divide: [{ $subtract: [{ $last: \"$createdAts\" }, { $first: \"$createdAts\" }] }, 1000] },\n\t\t\t\t\t\t\t\t\t\t\tf: { $arrayElemAt: [{ $map: { input: { $first: \"$net\" }, as: \"i\", in: \"$$i.drop_out\" } }, \"$$nIdx\"] },\n\t\t\t\t\t\t\t\t\t\t\tl: { $arrayElemAt: [{ $map: { input: { $last: \"$net\" }, as: \"i\", in: \"$$i.drop_out\" } }, \"$$nIdx\"] },\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\tin: { $cond: [{ $gt: [\"$$tDiff\", 0] }, { $divide: [{ $subtract: [\"$$l\", \"$$f\"] }, \"$$tDiff\"] }, 0] },\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{ $sort: { _id: 1 } },\n\t\t]);\n\t};\n}\n\nexport default MongoChecksRepository;\n"
  },
  {
    "path": "server/src/repositories/geo-checks/IGeoChecksRepository.ts",
    "content": "import type { GeoCheck, GroupedGeoCheck } from \"@/types/geoCheck.js\";\nimport type { GeoContinent, FlatGeoCheck } from \"@/types/geoCheck.js\";\n\nexport interface GeoChecksQueryResult {\n\tgeoChecksCount: number;\n\tgeoChecks: GeoCheck[];\n}\n\nexport interface FlatGeoChecksQueryResult {\n\tgeoChecksCount: number;\n\tgeoChecks: FlatGeoCheck[];\n}\n\nexport interface IGeoChecksRepository {\n\tcreateGeoChecks(geoChecks: Omit<GeoCheck, \"id\" | \"__v\" | \"createdAt\" | \"updatedAt\">[]): Promise<GeoCheck[]>;\n\tfindByMonitorId(\n\t\tmonitorId: string,\n\t\tsortOrder: string,\n\t\tdateRange: string,\n\t\tpage: number,\n\t\trowsPerPage: number,\n\t\tcontinents?: GeoContinent[]\n\t): Promise<FlatGeoChecksQueryResult>;\n\tfindByMonitorIdAndDateRange(monitorId: string, startDate: Date, endDate: Date): Promise<GeoCheck[]>;\n\tfindGroupedByMonitorIdAndDateRange(\n\t\tmonitorId: string,\n\t\tstartDate: Date,\n\t\tendDate: Date,\n\t\tdateFormat: string,\n\t\tcontinents?: GeoContinent[]\n\t): Promise<GroupedGeoCheck[]>;\n\tdeleteByMonitorId(monitorId: string): Promise<number>;\n\tdeleteByTeamId(teamId: string): Promise<number>;\n\tdeleteByMonitorIdsNotIn(monitorIds: string[]): Promise<number>;\n}\n"
  },
  {
    "path": "server/src/repositories/geo-checks/MongoGeoChecksRepository.ts",
    "content": "import { IGeoChecksRepository } from \"./IGeoChecksRepository.js\";\nimport type { GeoCheck, GeoCheckMetadata, GeoCheckResult, GroupedGeoCheck, GeoContinent, FlatGeoCheck } from \"@/types/geoCheck.js\";\nimport type { FlatGeoChecksQueryResult } from \"./IGeoChecksRepository.js\";\nimport { GeoCheckMetadataDocument, GeoCheckModel, type GeoCheckDocument } from \"@/db/models/index.js\";\nimport mongoose, { PipelineStage } from \"mongoose\";\nimport { getDateForRange } from \"@/utils/dataUtils.js\";\nimport { ILogger } from \"@/utils/logger.js\";\n\nconst SERVICE_NAME = \"GeoChecksRepository\";\n\nclass MongoGeoChecksRepository implements IGeoChecksRepository {\n\tstatic SERVICE_NAME = SERVICE_NAME;\n\n\tprivate logger: ILogger;\n\tconstructor(logger: ILogger) {\n\t\tthis.logger = logger;\n\t}\n\n\tprivate toEntity = (doc: GeoCheckDocument): GeoCheck => {\n\t\tconst toStringId = (value: mongoose.Types.ObjectId | string | undefined | null): string => {\n\t\t\tif (!value) {\n\t\t\t\treturn \"\";\n\t\t\t}\n\t\t\treturn value instanceof mongoose.Types.ObjectId ? value.toString() : String(value);\n\t\t};\n\n\t\tconst toDateString = (value?: Date | string | null): string => {\n\t\t\tif (!value) {\n\t\t\t\treturn new Date(0).toISOString();\n\t\t\t}\n\t\t\treturn value instanceof Date ? value.toISOString() : new Date(value).toISOString();\n\t\t};\n\n\t\tconst mapMetadata = (metadata: GeoCheckMetadataDocument): GeoCheckMetadata => ({\n\t\t\tmonitorId: toStringId(metadata.monitorId),\n\t\t\tteamId: toStringId(metadata.teamId),\n\t\t\ttype: metadata.type,\n\t\t});\n\n\t\tconst mapResults = (results: GeoCheckResult[]): GeoCheckResult[] => {\n\t\t\tif (!results || !Array.isArray(results)) {\n\t\t\t\treturn [];\n\t\t\t}\n\t\t\treturn results.map((result) => ({\n\t\t\t\tlocation: {\n\t\t\t\t\tcontinent: result.location?.continent ?? \"\",\n\t\t\t\t\tregion: result.location?.region ?? \"\",\n\t\t\t\t\tcountry: result.location?.country ?? \"\",\n\t\t\t\t\tstate: result.location?.state ?? \"\",\n\t\t\t\t\tcity: result.location?.city ?? \"\",\n\t\t\t\t\tlongitude: result.location?.longitude ?? 0,\n\t\t\t\t\tlatitude: result.location?.latitude ?? 0,\n\t\t\t\t},\n\t\t\t\tstatus: result.status ?? false,\n\t\t\t\tstatusCode: result.statusCode ?? 0,\n\t\t\t\ttimings: {\n\t\t\t\t\ttotal: result.timings?.total ?? 0,\n\t\t\t\t\tdns: result.timings?.dns ?? 0,\n\t\t\t\t\ttcp: result.timings?.tcp ?? 0,\n\t\t\t\t\ttls: result.timings?.tls ?? 0,\n\t\t\t\t\tfirstByte: result.timings?.firstByte ?? 0,\n\t\t\t\t\tdownload: result.timings?.download ?? 0,\n\t\t\t\t},\n\t\t\t}));\n\t\t};\n\n\t\treturn {\n\t\t\tid: toStringId(doc._id),\n\t\t\tmetadata: mapMetadata(doc.metadata),\n\t\t\tresults: mapResults(doc.results),\n\t\t\texpiry: toDateString(doc.expiry),\n\t\t\t__v: doc.__v ?? 0,\n\t\t\tcreatedAt: toDateString(doc.createdAt),\n\t\t\tupdatedAt: toDateString(doc.updatedAt),\n\t\t};\n\t};\n\n\tcreateGeoChecks = async (geoChecks: Omit<GeoCheck, \"id\" | \"__v\" | \"createdAt\" | \"updatedAt\">[]): Promise<GeoCheck[]> => {\n\t\ttry {\n\t\t\tconst docs = await GeoCheckModel.insertMany(\n\t\t\t\tgeoChecks.map((geoCheck) => ({\n\t\t\t\t\tmetadata: {\n\t\t\t\t\t\tmonitorId: new mongoose.Types.ObjectId(geoCheck.metadata.monitorId),\n\t\t\t\t\t\tteamId: new mongoose.Types.ObjectId(geoCheck.metadata.teamId),\n\t\t\t\t\t\ttype: geoCheck.metadata.type,\n\t\t\t\t\t},\n\t\t\t\t\tresults: geoCheck.results,\n\t\t\t\t\texpiry: new Date(geoCheck.expiry),\n\t\t\t\t}))\n\t\t\t);\n\t\t\treturn docs.map((doc) => this.toEntity(doc));\n\t\t} catch (error: unknown) {\n\t\t\tthis.logger.error({\n\t\t\t\tmessage: error instanceof Error ? `Failed to createGeoChecks: ${error.message}` : \"Failed to createGeoChecks\",\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"createGeoChecks\",\n\t\t\t\tstack: error instanceof Error ? error.stack : undefined,\n\t\t\t});\n\t\t\tthrow error;\n\t\t}\n\t};\n\n\tfindByMonitorId = async (\n\t\tmonitorId: string,\n\t\tsortOrder: string,\n\t\tdateRange: string,\n\t\tpage: number,\n\t\trowsPerPage: number,\n\t\tcontinents?: GeoContinent[]\n\t): Promise<FlatGeoChecksQueryResult> => {\n\t\ttry {\n\t\t\tconst matchStage: Record<string, unknown> = {\n\t\t\t\t\"metadata.monitorId\": new mongoose.Types.ObjectId(monitorId),\n\t\t\t\t...(getDateForRange(dateRange) && {\n\t\t\t\t\tcreatedAt: {\n\t\t\t\t\t\t$gte: getDateForRange(dateRange),\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t};\n\n\t\t\tconst convertedSortOrder = sortOrder === \"asc\" ? 1 : -1;\n\n\t\t\tlet skip = 0;\n\t\t\tif (page && rowsPerPage) {\n\t\t\t\tskip = page * rowsPerPage;\n\t\t\t}\n\n\t\t\t// Common pipeline stages for both paths\n\t\t\tconst pipeline: PipelineStage[] = [\n\t\t\t\t{ $match: matchStage },\n\t\t\t\t{ $unwind: \"$results\" },\n\t\t\t\t// Filter by continent if specified\n\t\t\t\t...(continents && continents.length > 0\n\t\t\t\t\t? [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t$match: {\n\t\t\t\t\t\t\t\t\t\"results.location.continent\": { $in: continents },\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t]\n\t\t\t\t\t: []),\n\t\t\t\t// Project to flat structure\n\t\t\t\t{\n\t\t\t\t\t$project: {\n\t\t\t\t\t\t_id: 0,\n\t\t\t\t\t\tmonitorId: \"$metadata.monitorId\",\n\t\t\t\t\t\tteamId: \"$metadata.teamId\",\n\t\t\t\t\t\ttype: \"$metadata.type\",\n\t\t\t\t\t\tlocation: \"$results.location\",\n\t\t\t\t\t\tstatus: \"$results.status\",\n\t\t\t\t\t\tstatusCode: \"$results.statusCode\",\n\t\t\t\t\t\ttimings: \"$results.timings\",\n\t\t\t\t\t\tcreatedAt: 1,\n\t\t\t\t\t\tupdatedAt: 1,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{ $sort: { createdAt: convertedSortOrder } },\n\t\t\t\t{ $skip: skip },\n\t\t\t\t{ $limit: rowsPerPage },\n\t\t\t];\n\n\t\t\t// Count pipeline\n\t\t\tconst countPipeline: PipelineStage[] = [\n\t\t\t\t{ $match: matchStage },\n\t\t\t\t{ $unwind: \"$results\" },\n\t\t\t\t...(continents && continents.length > 0\n\t\t\t\t\t? [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t$match: {\n\t\t\t\t\t\t\t\t\t\"results.location.continent\": { $in: continents },\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t]\n\t\t\t\t\t: []),\n\t\t\t\t{ $count: \"count\" },\n\t\t\t];\n\n\t\t\tconst [countResult, dataResults] = await Promise.all([GeoCheckModel.aggregate(countPipeline), GeoCheckModel.aggregate(pipeline)]);\n\n\t\t\tconst geoChecksCount = countResult[0]?.count || 0;\n\t\t\tconst geoChecks: FlatGeoCheck[] = dataResults.map((doc) => ({\n\t\t\t\tid: `${doc.monitorId.toString()}-${new Date(doc.createdAt).getTime()}-${doc.location.continent}-${doc.location.city}-${Math.random().toString(36).substring(2, 15)}`,\n\t\t\t\tmonitorId: doc.monitorId.toString(),\n\t\t\t\tteamId: doc.teamId.toString(),\n\t\t\t\ttype: doc.type,\n\t\t\t\tlocation: doc.location,\n\t\t\t\tstatus: doc.status,\n\t\t\t\tstatusCode: doc.statusCode,\n\t\t\t\ttimings: doc.timings,\n\t\t\t\tcreatedAt: new Date(doc.createdAt).toISOString(),\n\t\t\t\tupdatedAt: new Date(doc.updatedAt).toISOString(),\n\t\t\t}));\n\n\t\t\treturn { geoChecksCount, geoChecks };\n\t\t} catch (error: unknown) {\n\t\t\tthis.logger.error({\n\t\t\t\tmessage: error instanceof Error ? `Error finding geo checks by monitor ID: ${error.message}` : \"Error finding geo checks by monitor ID\",\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"findByMonitorId\",\n\t\t\t\tstack: error instanceof Error ? error.stack : undefined,\n\t\t\t});\n\t\t\tthrow error;\n\t\t}\n\t};\n\n\tfindByMonitorIdAndDateRange = async (monitorId: string, startDate: Date, endDate: Date): Promise<GeoCheck[]> => {\n\t\ttry {\n\t\t\tconst docs = await GeoCheckModel.find({\n\t\t\t\t\"metadata.monitorId\": new mongoose.Types.ObjectId(monitorId),\n\t\t\t\tcreatedAt: {\n\t\t\t\t\t$gte: startDate,\n\t\t\t\t\t$lte: endDate,\n\t\t\t\t},\n\t\t\t}).sort({ createdAt: -1 });\n\t\t\treturn docs.map(this.toEntity);\n\t\t} catch (error: unknown) {\n\t\t\tthis.logger.error({\n\t\t\t\tmessage:\n\t\t\t\t\terror instanceof Error\n\t\t\t\t\t\t? `Error finding geo checks by monitor ID and date range: ${error.message}`\n\t\t\t\t\t\t: \"Error finding geo checks by monitor ID and date range\",\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"findByMonitorIdAndDateRange\",\n\t\t\t\tstack: error instanceof Error ? error.stack : undefined,\n\t\t\t});\n\t\t\tthrow error;\n\t\t}\n\t};\n\n\tfindGroupedByMonitorIdAndDateRange = async (\n\t\tmonitorId: string,\n\t\tstartDate: Date,\n\t\tendDate: Date,\n\t\tdateFormat: string,\n\t\tcontinents?: GeoContinent[]\n\t): Promise<GroupedGeoCheck[]> => {\n\t\ttry {\n\t\t\tconst pipeline: PipelineStage[] = [\n\t\t\t\t// Match geo checks for this monitor in date range\n\t\t\t\t{\n\t\t\t\t\t$match: {\n\t\t\t\t\t\t\"metadata.monitorId\": new mongoose.Types.ObjectId(monitorId),\n\t\t\t\t\t\tcreatedAt: {\n\t\t\t\t\t\t\t$gte: startDate,\n\t\t\t\t\t\t\t$lte: endDate,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t// Unwind the results array to process each location separately\n\t\t\t\t{\n\t\t\t\t\t$unwind: \"$results\",\n\t\t\t\t},\n\t\t\t\t// Filter by continent if specified\n\t\t\t\t...(continents && continents.length > 0\n\t\t\t\t\t? [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t$match: {\n\t\t\t\t\t\t\t\t\t\"results.location.continent\": { $in: continents },\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t]\n\t\t\t\t\t: []),\n\t\t\t\t// Group by date bucket and continent\n\t\t\t\t{\n\t\t\t\t\t$group: {\n\t\t\t\t\t\t_id: {\n\t\t\t\t\t\t\tbucketDate: {\n\t\t\t\t\t\t\t\t$dateToString: {\n\t\t\t\t\t\t\t\t\tformat: dateFormat,\n\t\t\t\t\t\t\t\t\tdate: \"$createdAt\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tcontinent: \"$results.location.continent\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tavgResponseTime: { $avg: \"$results.timings.total\" },\n\t\t\t\t\t\ttotalChecks: { $sum: 1 },\n\t\t\t\t\t\tupChecks: {\n\t\t\t\t\t\t\t$sum: {\n\t\t\t\t\t\t\t\t$cond: [\"$results.status\", 1, 0],\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t// Calculate uptime percentage\n\t\t\t\t{\n\t\t\t\t\t$project: {\n\t\t\t\t\t\t_id: 0,\n\t\t\t\t\t\tbucketDate: \"$_id.bucketDate\",\n\t\t\t\t\t\tcontinent: \"$_id.continent\",\n\t\t\t\t\t\tavgResponseTime: { $round: [\"$avgResponseTime\", 2] },\n\t\t\t\t\t\ttotalChecks: 1,\n\t\t\t\t\t\tuptimePercentage: {\n\t\t\t\t\t\t\t$round: [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t$multiply: [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t$divide: [\"$upChecks\", \"$totalChecks\"],\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t100,\n\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t2,\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t// Sort by date and continent\n\t\t\t\t{\n\t\t\t\t\t$sort: {\n\t\t\t\t\t\tbucketDate: 1,\n\t\t\t\t\t\tcontinent: 1,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t];\n\n\t\t\tconst results = await GeoCheckModel.aggregate(pipeline);\n\t\t\treturn results as GroupedGeoCheck[];\n\t\t} catch (error: unknown) {\n\t\t\tthis.logger.error({\n\t\t\t\tmessage: error instanceof Error ? `Error finding grouped geo checks: ${error.message}` : \"Error finding grouped geo checks\",\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"findGroupedByMonitorIdAndDateRange\",\n\t\t\t\tstack: error instanceof Error ? error.stack : undefined,\n\t\t\t});\n\t\t\tthrow error;\n\t\t}\n\t};\n\n\tdeleteByMonitorId = async (monitorId: string): Promise<number> => {\n\t\ttry {\n\t\t\tconst result = await GeoCheckModel.deleteMany({\n\t\t\t\t\"metadata.monitorId\": new mongoose.Types.ObjectId(monitorId),\n\t\t\t});\n\t\t\treturn result.deletedCount || 0;\n\t\t} catch (error: unknown) {\n\t\t\tthis.logger.error({\n\t\t\t\tmessage: error instanceof Error ? `Error deleting geo checks by monitor ID: ${error.message}` : \"Error deleting geo checks by monitor ID\",\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"deleteByMonitorId\",\n\t\t\t\tstack: error instanceof Error ? error.stack : undefined,\n\t\t\t});\n\t\t\tthrow error;\n\t\t}\n\t};\n\n\tdeleteByTeamId = async (teamId: string): Promise<number> => {\n\t\ttry {\n\t\t\tconst result = await GeoCheckModel.deleteMany({\n\t\t\t\t\"metadata.teamId\": new mongoose.Types.ObjectId(teamId),\n\t\t\t});\n\t\t\treturn result.deletedCount || 0;\n\t\t} catch (error: unknown) {\n\t\t\tthis.logger.error({\n\t\t\t\tmessage: error instanceof Error ? `Error deleting geo checks by team ID: ${error.message}` : \"Error deleting geo checks by team ID\",\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"deleteByTeamId\",\n\t\t\t\tstack: error instanceof Error ? error.stack : undefined,\n\t\t\t});\n\t\t\tthrow error;\n\t\t}\n\t};\n\n\tdeleteByMonitorIdsNotIn = async (monitorIds: string[]): Promise<number> => {\n\t\ttry {\n\t\t\tconst objectIds = monitorIds.map((id) => new mongoose.Types.ObjectId(id));\n\t\t\tconst result = await GeoCheckModel.deleteMany({ \"metadata.monitorId\": { $nin: objectIds } });\n\t\t\treturn result.deletedCount || 0;\n\t\t} catch (error: unknown) {\n\t\t\tthis.logger.error({\n\t\t\t\tmessage: error instanceof Error ? `Error deleting orphaned geo checks: ${error.message}` : \"Error deleting orphaned geo checks\",\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"deleteByMonitorIdsNotIn\",\n\t\t\t\tstack: error instanceof Error ? error.stack : undefined,\n\t\t\t});\n\t\t\tthrow error;\n\t\t}\n\t};\n}\n\nexport { MongoGeoChecksRepository };\nexport default MongoGeoChecksRepository;\n"
  },
  {
    "path": "server/src/repositories/incidents/IIncidentsRepository.ts",
    "content": "import type { Incident } from \"@/types/index.js\";\nimport type { IncidentSummary } from \"@/types/index.js\";\nexport interface IIncidentsRepository {\n\t// create\n\tcreate(incident: Partial<Incident>): Promise<Incident>;\n\t// fetch\n\tfindById(incidentId: string, teamId: string): Promise<Incident>;\n\tfindActiveByIncidentId(incidentId: string, teamId: string): Promise<Incident | null>;\n\tfindActiveByMonitorId(monitorId: string, teamId: string): Promise<Incident | null>;\n\tfindByTeamId(\n\t\tteamId: string,\n\t\tstartDate: Date | undefined,\n\t\tpage: number,\n\t\trowsPerPage: number,\n\t\tsortOrder?: string,\n\t\tstatus?: boolean,\n\t\tmonitorId?: string,\n\t\tresolutionType?: string\n\t): Promise<Incident[]>;\n\tfindSummaryByTeamId(teamId: string, limit?: number): Promise<IncidentSummary>;\n\tcountByTeamId(teamId: string, startDate: Date | undefined, status?: boolean, monitorId?: string, resolutionType?: string): Promise<number>;\n\n\t// update\n\tupdateById(incidentId: string, teamId: string, updateData: Partial<Incident>): Promise<Incident>;\n\t// delete\n\tdeleteByMonitorId(monitorId: string, teamId: string): Promise<number>;\n\tdeleteByMonitorIdsNotIn(monitorIds: string[]): Promise<number>;\n\t// other\n}\n"
  },
  {
    "path": "server/src/repositories/incidents/MongoIncidentRepository.ts",
    "content": "import { IncidentModel } from \"@/db/models/index.js\";\nimport type { IncidentDocument } from \"@/db/models/Incident.js\";\nimport type { Incident, IncidentSummary } from \"@/types/index.js\";\nimport type { IIncidentsRepository } from \"@/repositories/index.js\";\nimport mongoose from \"mongoose\";\nimport { AppError } from \"@/utils/AppError.js\";\n\nclass MongoIncidentRepository implements IIncidentsRepository {\n\tprivate toStringId = (value?: mongoose.Types.ObjectId | string | null): string => {\n\t\tif (!value) {\n\t\t\treturn \"\";\n\t\t}\n\t\treturn value instanceof mongoose.Types.ObjectId ? value.toString() : String(value);\n\t};\n\n\tprivate toDateString = (value?: Date | string | null): string => {\n\t\tif (!value) {\n\t\t\treturn new Date(0).toISOString();\n\t\t}\n\t\treturn value instanceof Date ? value.toISOString() : new Date(value).toISOString();\n\t};\n\n\tprivate buildMatchStage({\n\t\tteamId,\n\t\tstartDate,\n\t\tstatus,\n\t\tmonitorId,\n\t\tresolutionType,\n\t}: {\n\t\tteamId: string;\n\t\tstartDate: Date | undefined;\n\t\tstatus?: boolean;\n\t\tmonitorId?: string;\n\t\tresolutionType?: string;\n\t}): Record<string, unknown> {\n\t\tconst matchStage: Record<string, unknown> = {\n\t\t\tteamId: new mongoose.Types.ObjectId(teamId),\n\t\t\t...(status !== undefined && { status }),\n\t\t\t...(monitorId && { monitorId: new mongoose.Types.ObjectId(monitorId) }),\n\t\t\t...(resolutionType && { resolutionType }),\n\t\t};\n\n\t\tif (startDate) {\n\t\t\tmatchStage.createdAt = { $gte: startDate };\n\t\t}\n\t\treturn matchStage;\n\t}\n\n\tprotected toEntity = (doc: IncidentDocument): Incident => {\n\t\treturn {\n\t\t\tid: this.toStringId(doc._id),\n\t\t\tmonitorId: this.toStringId(doc.monitorId),\n\t\t\tteamId: this.toStringId(doc.teamId),\n\t\t\tstartTime: this.toDateString(doc.startTime),\n\t\t\tendTime: doc.endTime ? this.toDateString(doc.endTime) : null,\n\t\t\tstatus: doc.status,\n\t\t\tmessage: doc.message ?? null,\n\t\t\tstatusCode: doc.statusCode ?? null,\n\t\t\tresolutionType: doc.resolutionType ?? null,\n\t\t\tresolvedBy: doc.resolvedBy ? this.toStringId(doc.resolvedBy) : null,\n\t\t\tresolvedByEmail: doc.resolvedByEmail ?? null,\n\t\t\tcomment: doc.comment ?? null,\n\t\t\tcreatedAt: this.toDateString(doc.createdAt),\n\t\t\tupdatedAt: this.toDateString(doc.updatedAt),\n\t\t};\n\t};\n\n\tprotected mapDocuments = (documents: IncidentDocument[] | IncidentDocument | null): Incident[] => {\n\t\tif (!documents) {\n\t\t\treturn [];\n\t\t}\n\t\tif (Array.isArray(documents)) {\n\t\t\treturn documents.map((doc) => this.toEntity(doc));\n\t\t}\n\t\treturn [this.toEntity(documents)];\n\t};\n\n\tasync create(incident: Partial<Incident>): Promise<Incident> {\n\t\tconst newIncident = await IncidentModel.create(incident);\n\t\treturn this.toEntity(newIncident);\n\t}\n\n\tfindById = async (incidentId: string, teamId: string): Promise<Incident> => {\n\t\tconst incident = await IncidentModel.findOne({\n\t\t\t_id: new mongoose.Types.ObjectId(incidentId),\n\t\t\tteamId: new mongoose.Types.ObjectId(teamId),\n\t\t});\n\t\tif (!incident) {\n\t\t\tthrow new AppError({ message: `Incident with id ${incidentId} not found`, status: 404 });\n\t\t}\n\t\treturn this.toEntity(incident);\n\t};\n\n\tfindActiveByIncidentId = async (incidentId: string, teamId: string): Promise<Incident | null> => {\n\t\tconst incident = await IncidentModel.findOne({\n\t\t\t_id: new mongoose.Types.ObjectId(incidentId),\n\t\t\tteamId: new mongoose.Types.ObjectId(teamId),\n\t\t\tstatus: true,\n\t\t});\n\t\tif (!incident) {\n\t\t\treturn null;\n\t\t}\n\t\treturn this.toEntity(incident);\n\t};\n\n\tfindActiveByMonitorId = async (monitorId: string, teamId: string): Promise<Incident | null> => {\n\t\tconst incident = await IncidentModel.findOne({\n\t\t\tmonitorId: new mongoose.Types.ObjectId(monitorId),\n\t\t\tteamId: new mongoose.Types.ObjectId(teamId),\n\t\t\tstatus: true,\n\t\t});\n\t\tif (!incident) {\n\t\t\treturn null;\n\t\t}\n\t\treturn this.toEntity(incident);\n\t};\n\n\tfindByTeamId = async (\n\t\tteamId: string,\n\t\tstartDate: Date | undefined,\n\t\tpage: number,\n\t\trowsPerPage: number,\n\t\tsortOrder?: string,\n\t\tstatus?: boolean,\n\t\tmonitorId?: string,\n\t\tresolutionType?: string\n\t): Promise<Incident[]> => {\n\t\tconst matchStage = this.buildMatchStage({ teamId, startDate, status, monitorId, resolutionType });\n\t\tconst incidents = await IncidentModel.find(matchStage)\n\t\t\t.sort({ createdAt: sortOrder === \"asc\" ? 1 : -1 })\n\t\t\t.skip(page * rowsPerPage)\n\t\t\t.limit(rowsPerPage);\n\t\treturn this.mapDocuments(incidents);\n\t};\n\n\tupdateById = async (incidentId: string, teamId: string, patch: Partial<Incident>) => {\n\t\tconst updatedIncident = await IncidentModel.findOneAndUpdate(\n\t\t\t{ _id: new mongoose.Types.ObjectId(incidentId), teamId: new mongoose.Types.ObjectId(teamId) },\n\t\t\t{\n\t\t\t\t$set: {\n\t\t\t\t\t...patch,\n\t\t\t\t},\n\t\t\t},\n\t\t\t{ new: true, runValidators: true }\n\t\t);\n\t\tif (!updatedIncident) {\n\t\t\tthrow new AppError({ message: `Failed to update incident with id ${incidentId}`, status: 500 });\n\t\t}\n\t\treturn this.toEntity(updatedIncident);\n\t};\n\n\tcountByTeamId = async (\n\t\tteamId: string,\n\t\tstartDate: Date | undefined,\n\t\tstatus?: boolean,\n\t\tmonitorId?: string,\n\t\tresolutionType?: string\n\t): Promise<number> => {\n\t\tconst matchStage = this.buildMatchStage({ teamId, startDate, status, monitorId, resolutionType });\n\t\treturn IncidentModel.countDocuments(matchStage);\n\t};\n\n\tfindSummaryByTeamId = async (teamId: string, limit: number): Promise<IncidentSummary> => {\n\t\tconst matchStage = { teamId: new mongoose.Types.ObjectId(teamId) };\n\n\t\tconst counts = await IncidentModel.aggregate([\n\t\t\t{ $match: matchStage },\n\t\t\t{\n\t\t\t\t$group: {\n\t\t\t\t\t_id: \"$status\",\n\t\t\t\t\tcount: { $sum: 1 },\n\t\t\t\t\tmanualResolutions: {\n\t\t\t\t\t\t$sum: { $cond: [{ $eq: [\"$resolutionType\", \"manual\"] }, 1, 0] },\n\t\t\t\t\t},\n\t\t\t\t\tautomaticResolutions: {\n\t\t\t\t\t\t$sum: { $cond: [{ $eq: [\"$resolutionType\", \"automatic\"] }, 1, 0] },\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t]);\n\n\t\tlet total = 0;\n\t\tlet active = 0;\n\t\tlet manual = 0;\n\t\tlet automatic = 0;\n\n\t\tcounts.forEach((item) => {\n\t\t\ttotal += item.count;\n\t\t\tif (item._id === true) {\n\t\t\t\tactive = item.count;\n\t\t\t}\n\t\t\tmanual += item.manualResolutions;\n\t\t\tautomatic += item.automaticResolutions;\n\t\t});\n\n\t\tconst resolutionTimeResult = await IncidentModel.aggregate([\n\t\t\t{ $match: { ...matchStage, status: false, endTime: { $exists: true, $ne: null } } },\n\t\t\t{ $project: { resolutionTime: { $subtract: [\"$endTime\", \"$startTime\"] } } },\n\t\t\t{ $group: { _id: null, avgResolutionTime: { $avg: \"$resolutionTime\" } } },\n\t\t]);\n\t\tconst avgResolutionTimeMs = resolutionTimeResult[0]?.avgResolutionTime || 0;\n\t\tconst avgResolutionTimeHours = Math.round((avgResolutionTimeMs / (1000 * 60 * 60) || 0) * 100) / 100;\n\n\t\tconst monitorResult = await IncidentModel.aggregate([\n\t\t\t{ $match: matchStage },\n\t\t\t{ $group: { _id: \"$monitorId\", count: { $sum: 1 } } },\n\t\t\t{ $sort: { count: -1 } },\n\t\t\t{ $limit: 1 },\n\t\t\t{\n\t\t\t\t$lookup: {\n\t\t\t\t\tfrom: \"monitors\",\n\t\t\t\t\tlocalField: \"_id\",\n\t\t\t\t\tforeignField: \"_id\",\n\t\t\t\t\tas: \"monitor\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{ $project: { monitorId: \"$_id\", count: 1, monitorName: { $arrayElemAt: [\"$monitor.name\", 0] } } },\n\t\t]);\n\n\t\tconst latestLimit = Math.max(1, Number.isFinite(Number(limit)) ? Number(limit) : 10);\n\t\tconst latestIncidents = await IncidentModel.aggregate([\n\t\t\t{ $match: matchStage },\n\t\t\t{ $sort: { createdAt: -1 } },\n\t\t\t{ $limit: latestLimit },\n\t\t\t{\n\t\t\t\t$lookup: {\n\t\t\t\t\tfrom: \"monitors\",\n\t\t\t\t\tlocalField: \"monitorId\",\n\t\t\t\t\tforeignField: \"_id\",\n\t\t\t\t\tas: \"monitor\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\t$project: {\n\t\t\t\t\t_id: 1,\n\t\t\t\t\tmonitorId: 1,\n\t\t\t\t\tmonitorName: { $arrayElemAt: [\"$monitor.name\", 0] },\n\t\t\t\t\tstatus: 1,\n\t\t\t\t\tstartTime: 1,\n\t\t\t\t\tendTime: 1,\n\t\t\t\t\tresolutionType: 1,\n\t\t\t\t\tmessage: 1,\n\t\t\t\t\tstatusCode: 1,\n\t\t\t\t\tcreatedAt: 1,\n\t\t\t\t},\n\t\t\t},\n\t\t]);\n\n\t\treturn {\n\t\t\ttotal,\n\t\t\ttotalActive: active,\n\t\t\ttotalManualResolutions: manual,\n\t\t\ttotalAutomaticResolutions: automatic,\n\t\t\tavgResolutionTimeHours,\n\t\t\ttopMonitor: monitorResult[0]\n\t\t\t\t? {\n\t\t\t\t\t\tmonitorId: this.toStringId(monitorResult[0].monitorId),\n\t\t\t\t\t\tmonitorName: monitorResult[0].monitorName ?? null,\n\t\t\t\t\t\tincidentCount: monitorResult[0].count,\n\t\t\t\t\t}\n\t\t\t\t: null,\n\t\t\tlatestIncidents: latestIncidents.map((incident) => ({\n\t\t\t\tid: this.toStringId(incident._id),\n\t\t\t\tmonitorId: this.toStringId(incident.monitorId),\n\t\t\t\tmonitorName: incident.monitorName ?? null,\n\t\t\t\tstatus: incident.status,\n\t\t\t\tstartTime: this.toDateString(incident.startTime),\n\t\t\t\tendTime: incident.endTime ? this.toDateString(incident.endTime) : null,\n\t\t\t\tresolutionType: incident.resolutionType ?? null,\n\t\t\t\tmessage: incident.message ?? null,\n\t\t\t\tstatusCode: incident.statusCode ?? null,\n\t\t\t\tcreatedAt: this.toDateString(incident.createdAt),\n\t\t\t})),\n\t\t};\n\t};\n\n\tdeleteByMonitorId = async (monitorId: string, teamId: string) => {\n\t\tconst result = await IncidentModel.deleteMany({\n\t\t\tmonitorId: new mongoose.Types.ObjectId(monitorId),\n\t\t\tteamId: new mongoose.Types.ObjectId(teamId),\n\t\t});\n\t\treturn result.deletedCount || 0;\n\t};\n\n\tdeleteByMonitorIdsNotIn = async (monitorIds: string[]): Promise<number> => {\n\t\tconst objectIds = monitorIds.map((id) => new mongoose.Types.ObjectId(id));\n\t\tconst result = await IncidentModel.deleteMany({ monitorId: { $nin: objectIds } });\n\t\treturn result.deletedCount ?? 0;\n\t};\n}\nexport default MongoIncidentRepository;\n"
  },
  {
    "path": "server/src/repositories/index.ts",
    "content": "export * from \"@/repositories/monitors/IMonitorsRepository.js\";\nexport { default as MongoMonitorsRepository } from \"@/repositories/monitors/MongoMonitorsRepository.js\";\n\nexport * from \"@/repositories/checks/IChecksRepository.js\";\nexport { default as MongoChecksRepository } from \"@/repositories/checks/MongoChecksRepistory.js\";\n\nexport * from \"@/repositories/monitor-stats/IMonitorStatsRepository.js\";\nexport { default as MongoMonitorStatsRepository } from \"@/repositories/monitor-stats/MongoMonitorStatsRepository.js\";\n\nexport * from \"@/repositories/status-pages/IStatusPagesRepository.js\";\nexport { default as MongoStatusPagesRepository } from \"@/repositories/status-pages/MongoStatusPagesRepository.js\";\n\nexport * from \"@/repositories/users/IUsersRepository.js\";\nexport { default as MongoUsersRepository } from \"@/repositories/users/MongoUsersRepository.js\";\n\nexport * from \"@/repositories/invites/IInvitesRepository.js\";\nexport { default as MongoInvitesRepository } from \"@/repositories/invites/MongoInviteRepository.js\";\n\nexport * from \"@/repositories/recovery-tokens/IRecoveryTokensRepository.js\";\nexport { default as MongoRecoveryTokensRepository } from \"@/repositories/recovery-tokens/MongoRecoveryTokensRepository.js\";\n\nexport * from \"@/repositories/settings/ISettingsRepository.js\";\nexport { default as MongoSettingsRepository } from \"@/repositories/settings/MongoSettingsRepository.js\";\n\nexport * from \"@/repositories/notifications/INotificationsRepository.js\";\nexport { default as MongoNotificationsRepository } from \"@/repositories/notifications/MongoNotificationsRepository.js\";\n\nexport * from \"@/repositories/incidents/IIncidentsRepository.js\";\nexport { default as MongoIncidentRepository } from \"@/repositories/incidents/MongoIncidentRepository.js\";\n\nexport * from \"@/repositories/teams/ITeamsRepository.js\";\nexport { default as MongoTeamsRepository } from \"@/repositories/teams/MongoTeamsRepository.js\";\n\nexport * from \"@/repositories/maintenance-windows/IMaintenanceWindowsRepository.js\";\nexport { default as MongoMaintenanceWindowsRepository } from \"@/repositories/maintenance-windows/MongoMaintenanceWindowsRepository.js\";\n\nexport * from \"@/repositories/geo-checks/IGeoChecksRepository.js\";\nexport { default as MongoGeoChecksRepository } from \"@/repositories/geo-checks/MongoGeoChecksRepository.js\";\n"
  },
  {
    "path": "server/src/repositories/invites/IInvitesRepository.ts",
    "content": "import type { Invite } from \"@/types/index.js\";\n\nexport interface IInvitesRepository {\n\t// create\n\tcreate(invite: Partial<Invite>): Promise<Invite>;\n\t// fetch\n\tfindByToken(token: string): Promise<Invite>;\n\tfindByTokenAndDelete(token: string): Promise<Invite>;\n\t// update\n\n\t// delete\n\t// other\n}\n"
  },
  {
    "path": "server/src/repositories/invites/MongoInviteRepository.ts",
    "content": "import { IInvitesRepository } from \"@/repositories/index.js\";\nimport type { Invite } from \"@/types/index.js\";\nimport { type InviteDocument, InviteModel } from \"@/db/models/index.js\";\nimport { AppError } from \"@/utils/AppError.js\";\nimport mongoose from \"mongoose\";\nimport crypto from \"crypto\";\n\nclass MongoInvitesRepository implements IInvitesRepository {\n\tprivate toStringId = (value?: mongoose.Types.ObjectId | string | null): string => {\n\t\tif (!value) {\n\t\t\treturn \"\";\n\t\t}\n\t\treturn value instanceof mongoose.Types.ObjectId ? value.toString() : String(value);\n\t};\n\n\tprivate toDateString = (value?: Date | string | null): string => {\n\t\tif (!value) {\n\t\t\treturn new Date(0).toISOString();\n\t\t}\n\t\treturn value instanceof Date ? value.toISOString() : new Date(value).toISOString();\n\t};\n\n\tprotected toEntity = (doc: InviteDocument): Invite => {\n\t\treturn {\n\t\t\tid: this.toStringId(doc._id),\n\t\t\temail: doc.email,\n\t\t\tteamId: this.toStringId(doc.teamId),\n\t\t\trole: doc.role ?? [],\n\t\t\ttoken: doc.token,\n\t\t\texpiry: this.toDateString(doc.expiry),\n\t\t\tcreatedAt: this.toDateString(doc.createdAt),\n\t\t\tupdatedAt: this.toDateString(doc.updatedAt),\n\t\t};\n\t};\n\n\tcreate = async (invite: Partial<Invite>) => {\n\t\tawait InviteModel.deleteMany({ email: invite.email });\n\t\tinvite.token = crypto.randomBytes(32).toString(\"hex\");\n\t\tconst inviteToken = await InviteModel.create(invite);\n\t\treturn this.toEntity(inviteToken);\n\t};\n\n\tfindByToken = async (token: string) => {\n\t\tconst invite = await InviteModel.findOne({\n\t\t\ttoken,\n\t\t});\n\t\tif (invite === null) {\n\t\t\tthrow new AppError({ message: \"Invite not found\", status: 404 });\n\t\t}\n\t\treturn this.toEntity(invite);\n\t};\n\n\tfindByTokenAndDelete = async (token: string) => {\n\t\tconst invite = await InviteModel.findOneAndDelete({\n\t\t\ttoken,\n\t\t});\n\t\tif (invite === null) {\n\t\t\tthrow new AppError({ message: \"Invite not found\", status: 404 });\n\t\t}\n\t\treturn this.toEntity(invite);\n\t};\n}\nexport default MongoInvitesRepository;\n"
  },
  {
    "path": "server/src/repositories/maintenance-windows/IMaintenanceWindowsRepository.ts",
    "content": "import type { MaintenanceWindow } from \"@/types/index.js\";\nexport interface IMaintenanceWindowsRepository {\n\t// create\n\tcreate(data: Partial<MaintenanceWindow>): Promise<MaintenanceWindow>;\n\t// fetch\n\tfindById(id: string, teamId: string): Promise<MaintenanceWindow>;\n\tfindByMonitorId(monitorId: string, teamId: string): Promise<MaintenanceWindow[]>;\n\tfindByTeamId(teamId: string, page: number, rowsPerPage: number, field?: string, order?: string, active?: boolean): Promise<MaintenanceWindow[]>;\n\n\t// update\n\tupdateById(id: string, teamId: string, data: Partial<MaintenanceWindow>): Promise<MaintenanceWindow>;\n\t// delete\n\tdeleteById(id: string, teamId: string): Promise<MaintenanceWindow>;\n\t// other\n\tcountByTeamId(teamId: string, active?: boolean): Promise<number>;\n}\n"
  },
  {
    "path": "server/src/repositories/maintenance-windows/MongoMaintenanceWindowsRepository.ts",
    "content": "import type { MaintenanceWindow } from \"@/types/index.js\";\nimport { type MaintenanceWindowDocument, MaintenanceWindowModel } from \"@/db/models/index.js\";\nimport { IMaintenanceWindowsRepository } from \"./IMaintenanceWindowsRepository.js\";\nimport mongoose, { SortOrder } from \"mongoose\";\nimport { AppError } from \"@/utils/AppError.js\";\n\nclass MongoMaintenanceWindowsRepository implements IMaintenanceWindowsRepository {\n\tprivate toStringId = (value?: mongoose.Types.ObjectId | string | null): string => {\n\t\tif (!value) {\n\t\t\treturn \"\";\n\t\t}\n\t\treturn value instanceof mongoose.Types.ObjectId ? value.toString() : String(value);\n\t};\n\n\tprivate toDateString = (value?: Date | string | null): string => {\n\t\tif (!value) {\n\t\t\treturn new Date(0).toISOString();\n\t\t}\n\t\treturn value instanceof Date ? value.toISOString() : new Date(value).toISOString();\n\t};\n\n\tprivate mapDocuments = (documents: MaintenanceWindowDocument[]): MaintenanceWindow[] => {\n\t\tif (!documents?.length) {\n\t\t\treturn [];\n\t\t}\n\t\treturn documents.map((doc) => this.toEntity(doc));\n\t};\n\n\tprivate toEntity = (doc: MaintenanceWindowDocument): MaintenanceWindow => {\n\t\treturn {\n\t\t\tid: this.toStringId(doc._id),\n\t\t\tmonitorId: this.toStringId(doc.monitorId),\n\t\t\tteamId: this.toStringId(doc.teamId),\n\t\t\tactive: doc.active,\n\t\t\tname: doc.name,\n\t\t\tduration: doc.duration,\n\t\t\tdurationUnit: doc.durationUnit,\n\t\t\trepeat: doc.repeat,\n\t\t\tstart: this.toDateString(doc.start),\n\t\t\tend: this.toDateString(doc.end),\n\t\t\tcreatedAt: this.toDateString(doc.createdAt),\n\t\t\tupdatedAt: this.toDateString(doc.updatedAt),\n\t\t};\n\t};\n\n\tcreate = async (data: Partial<MaintenanceWindow>): Promise<MaintenanceWindow> => {\n\t\tconst maintenanceWindow = new MaintenanceWindowModel(data);\n\n\t\t// If the maintenance window is a one time window, set the expiry to the end date\n\t\tif (maintenanceWindow.repeat === 0) {\n\t\t\tmaintenanceWindow.expiry = maintenanceWindow.end;\n\t\t}\n\t\tconst result = await maintenanceWindow.save();\n\t\treturn this.toEntity(result);\n\t};\n\n\tfindById = async (id: string, teamId: string): Promise<MaintenanceWindow> => {\n\t\tconst maintenanceWindow = await MaintenanceWindowModel.findOne({\n\t\t\t_id: id,\n\t\t\tteamId: teamId,\n\t\t});\n\t\tif (!maintenanceWindow) {\n\t\t\tthrow new AppError({ message: \"Maintenance Window not found\", status: 404 });\n\t\t}\n\t\treturn this.toEntity(maintenanceWindow);\n\t};\n\n\tfindByMonitorId = async (monitorId: string, teamId: string): Promise<MaintenanceWindow[]> => {\n\t\tconst maintenanceWindows = await MaintenanceWindowModel.find({\n\t\t\tmonitorId: monitorId,\n\t\t\tteamId: teamId,\n\t\t});\n\t\treturn this.mapDocuments(maintenanceWindows);\n\t};\n\n\tfindByTeamId = async (\n\t\tteamId: string,\n\t\tpage: number,\n\t\trowsPerPage: number,\n\t\tfield?: string,\n\t\torder?: string,\n\t\tactive?: boolean\n\t): Promise<MaintenanceWindow[]> => {\n\t\tconst maintenanceQuery: Record<string, unknown> = { teamId };\n\n\t\tif (active !== undefined) maintenanceQuery.active = active;\n\n\t\t// Pagination\n\t\tlet skip = 0;\n\t\tif (page && rowsPerPage) {\n\t\t\tskip = page * rowsPerPage;\n\t\t}\n\n\t\t// Sorting\n\t\tconst sort: Record<string, SortOrder> = {};\n\t\tif (field !== undefined && order !== undefined) {\n\t\t\tsort[field] = order === \"asc\" ? 1 : -1;\n\t\t}\n\n\t\tconst maintenanceWindows = await MaintenanceWindowModel.find(maintenanceQuery).skip(skip).limit(rowsPerPage).sort(sort);\n\t\treturn this.mapDocuments(maintenanceWindows);\n\t};\n\n\tupdateById = async (id: string, teamId: string, data: Partial<MaintenanceWindow>): Promise<MaintenanceWindow> => {\n\t\tconst updated = await MaintenanceWindowModel.findOneAndUpdate(\n\t\t\t{\n\t\t\t\t_id: new mongoose.Types.ObjectId(id),\n\t\t\t\tteamId: new mongoose.Types.ObjectId(teamId),\n\t\t\t},\n\t\t\t{ $set: data },\n\t\t\t{ new: true, runValidators: true }\n\t\t);\n\t\tif (!updated) {\n\t\t\tthrow new AppError({ message: \"Maintenance window not found or could not be updated\", status: 404 });\n\t\t}\n\t\treturn this.toEntity(updated);\n\t};\n\n\tdeleteById = async (id: string, teamId: string): Promise<MaintenanceWindow> => {\n\t\tconst deleted = await MaintenanceWindowModel.findOneAndDelete({\n\t\t\t_id: new mongoose.Types.ObjectId(id),\n\t\t\tteamId: new mongoose.Types.ObjectId(teamId),\n\t\t});\n\t\tif (!deleted) {\n\t\t\tthrow new AppError({ message: \"Maintenance window not found or could not be deleted\", status: 404 });\n\t\t}\n\t\treturn this.toEntity(deleted);\n\t};\n\tcountByTeamId = async (teamId: string, active?: boolean) => {\n\t\tconst maintenanceQuery: Record<string, unknown> = { teamId };\n\n\t\tif (active !== undefined) maintenanceQuery.active = active;\n\n\t\treturn await MaintenanceWindowModel.countDocuments(maintenanceQuery);\n\t};\n}\n\nexport default MongoMaintenanceWindowsRepository;\n"
  },
  {
    "path": "server/src/repositories/monitor-stats/IMonitorStatsRepository.ts",
    "content": "import type { MonitorStats } from \"@/types/index.js\";\nexport interface IMonitorStatsRepository {\n\t// create\n\tcreate(data: Omit<MonitorStats, \"id\" | \"createdAt\" | \"updatedAt\">): Promise<MonitorStats>;\n\t// single fetch\n\tfindByMonitorId(monitorId: string): Promise<MonitorStats>;\n\t// update\n\tupdateByMonitorId(monitorId: string, data: Omit<MonitorStats, \"id\" | \"monitorId\" | \"createdAt\" | \"updatedAt\">): Promise<MonitorStats>;\n\t// delete\n\tdeleteByMonitorId(monitorId: string): Promise<MonitorStats>;\n\tdeleteByMonitorIds(monitorIds: string[]): Promise<number>;\n\tdeleteByMonitorIdsNotIn(monitorIds: string[]): Promise<number>;\n\t// other\n}\n"
  },
  {
    "path": "server/src/repositories/monitor-stats/MongoMonitorStatsRepository.ts",
    "content": "import { type MonitorStatsDocument, MonitorStatsModel } from \"@/db/models/index.js\";\nimport type { MonitorStats } from \"@/types/index.js\";\nimport { IMonitorStatsRepository } from \"@/repositories/index.js\";\nimport mongoose from \"mongoose\";\nimport { AppError } from \"@/utils/AppError.js\";\nclass MongoMonitorStatsRepository implements IMonitorStatsRepository {\n\tprivate toEntity = (doc: MonitorStatsDocument): MonitorStats => {\n\t\tconst toStringId = (value: unknown): string => {\n\t\t\tif (value instanceof mongoose.Types.ObjectId) {\n\t\t\t\treturn value.toString();\n\t\t\t}\n\t\t\treturn value?.toString() ?? \"\";\n\t\t};\n\n\t\tconst toDateString = (value: Date | string): string => {\n\t\t\treturn value instanceof Date ? value.toISOString() : value;\n\t\t};\n\n\t\treturn {\n\t\t\tid: toStringId(doc._id),\n\t\t\tmonitorId: toStringId(doc.monitorId),\n\t\t\tavgResponseTime: doc.avgResponseTime,\n\t\t\tmaxResponseTime: doc.maxResponseTime,\n\t\t\ttotalChecks: doc.totalChecks,\n\t\t\ttotalUpChecks: doc.totalUpChecks,\n\t\t\ttotalDownChecks: doc.totalDownChecks,\n\t\t\tuptimePercentage: doc.uptimePercentage,\n\t\t\tlastCheckTimestamp: doc.lastCheckTimestamp,\n\t\t\tlastResponseTime: doc.lastResponseTime,\n\t\t\ttimeOfLastFailure: doc.timeOfLastFailure,\n\t\t\tcreatedAt: toDateString(doc.createdAt),\n\t\t\tupdatedAt: toDateString(doc.updatedAt),\n\t\t};\n\t};\n\n\tcreate = async (data: Omit<MonitorStats, \"id\" | \"createdAt\" | \"updatedAt\">): Promise<MonitorStats> => {\n\t\tconst created = await MonitorStatsModel.create(data);\n\t\treturn this.toEntity(created);\n\t};\n\n\tfindByMonitorId = async (monitorId: string): Promise<MonitorStats> => {\n\t\tconst monitorStats = await MonitorStatsModel.findOne({ monitorId: new mongoose.Types.ObjectId(monitorId) });\n\t\tif (!monitorStats) {\n\t\t\tthrow new AppError({ message: \"Monitor stats not found\", status: 404 });\n\t\t}\n\t\treturn this.toEntity(monitorStats);\n\t};\n\n\tupdateByMonitorId = async (monitorId: string, data: Omit<MonitorStats, \"id\" | \"monitorId\" | \"createdAt\" | \"updatedAt\">): Promise<MonitorStats> => {\n\t\tconst updated = await MonitorStatsModel.findOneAndUpdate({ monitorId: new mongoose.Types.ObjectId(monitorId) }, { $set: data }, { new: true });\n\t\tif (!updated) {\n\t\t\tthrow new AppError({ message: \"Monitor stats not found\", status: 404 });\n\t\t}\n\t\treturn this.toEntity(updated);\n\t};\n\n\tdeleteByMonitorId = async (monitorId: string) => {\n\t\tconst deleted = await MonitorStatsModel.findOneAndDelete({ monitorId: new mongoose.Types.ObjectId(monitorId) });\n\t\tif (!deleted) {\n\t\t\tthrow new AppError({ message: \"Monitor stats not found\", status: 404 });\n\t\t}\n\t\treturn this.toEntity(deleted);\n\t};\n\n\tdeleteByMonitorIds = async (monitorIds: string[]): Promise<number> => {\n\t\tconst objectIds = monitorIds.map((id) => new mongoose.Types.ObjectId(id));\n\t\tconst result = await MonitorStatsModel.deleteMany({ monitorId: { $in: objectIds } });\n\t\treturn result.deletedCount ?? 0;\n\t};\n\n\tdeleteByMonitorIdsNotIn = async (monitorIds: string[]): Promise<number> => {\n\t\tconst objectIds = monitorIds.map((id) => new mongoose.Types.ObjectId(id));\n\t\tconst result = await MonitorStatsModel.deleteMany({ monitorId: { $nin: objectIds } });\n\t\treturn result.deletedCount ?? 0;\n\t};\n}\n\nexport default MongoMonitorStatsRepository;\n"
  },
  {
    "path": "server/src/repositories/monitors/IMonitorsRepository.ts",
    "content": "import { type MonitorType, type Monitor, type MonitorsSummary } from \"@/types/index.js\";\n\nexport interface TeamQueryConfig {\n\tlimit?: number;\n\ttype?: MonitorType | MonitorType[];\n\tpage?: number;\n\trowsPerPage?: number;\n\tfilter?: string;\n\tfield?: string;\n\torder?: \"asc\" | \"desc\";\n}\n\nexport interface SummaryConfig {\n\ttype?: MonitorType | MonitorType[];\n}\n\nexport interface IMonitorsRepository {\n\t// create\n\tcreate(monitor: Monitor, teamId: string, userId: string): Promise<Monitor | null>;\n\tcreateMonitors(monitors: Monitor[]): Promise<Monitor[]>;\n\t// single fetch\n\tfindById(monitorId: string, teamId: string): Promise<Monitor>;\n\n\t// collection fetch\n\tfindAll(): Promise<Monitor[] | null>;\n\tfindByTeamId(teamId: string, config: TeamQueryConfig): Promise<Monitor[] | null>;\n\tfindByIds(monitorIds: string[]): Promise<Monitor[]>;\n\tfindByIdsWithChecks(monitorIds: string[], checksCount?: number): Promise<Monitor[]>;\n\n\t// update\n\tupdateById(monitorId: string, teamId: string, updates: Partial<Monitor>): Promise<Monitor>;\n\ttogglePauseById(monitorId: string, teamId: string): Promise<Monitor>;\n\t// delete\n\tdeleteById(monitorId: string, teamId: string): Promise<Monitor>;\n\tdeleteByTeamId(teamId: string): Promise<{ monitors: Monitor[]; deletedCount: number }>;\n\n\t// counts\n\tfindMonitorCountByTeamIdAndType(teamId: string, config: TeamQueryConfig): Promise<number>;\n\n\t// other\n\tfindMonitorsSummaryByTeamId(teamId: string, config?: SummaryConfig): Promise<MonitorsSummary>;\n\tfindGroupsByTeamId(teamId: string): Promise<string[]>;\n\tremoveNotificationFromMonitors(notificationId: string): Promise<void>;\n\tdeleteByTeamIdsNotIn(teamIds: string[]): Promise<number>;\n\tfindAllMonitorIds(): Promise<string[]>;\n}\n"
  },
  {
    "path": "server/src/repositories/monitors/MongoMonitorsRepository.ts",
    "content": "import { MonitorModel } from \"@/db/models/index.js\";\nimport type { MonitorDocument, CheckSnapshotDocument } from \"@/db/models/index.js\";\nimport type { Monitor, MonitorsSummary, CheckSnapshot } from \"@/types/index.js\";\nimport mongoose, { type FilterQuery, type PipelineStage } from \"mongoose\";\nimport type { IMonitorsRepository, TeamQueryConfig, SummaryConfig } from \"./IMonitorsRepository.js\";\nimport { MongoBulkWriteError } from \"mongodb\";\nimport { AppError } from \"@/utils/AppError.js\";\n\nclass MongoMonitorsRepository implements IMonitorsRepository {\n\tcreate = async (monitor: Monitor, teamId: string, userId: string) => {\n\t\tconst monitorModel = new MonitorModel({ ...monitor, teamId, userId });\n\t\tconst saved = await monitorModel.save();\n\t\treturn this.toEntity(saved);\n\t};\n\n\tcreateMonitors = async (monitors: Monitor[]): Promise<Monitor[]> => {\n\t\tif (!monitors.length) {\n\t\t\treturn [];\n\t\t}\n\t\tconst payload = monitors.map((monitor) => ({ ...monitor, notifications: undefined }));\n\t\ttry {\n\t\t\tconst inserted = await MonitorModel.insertMany(payload, { ordered: false });\n\t\t\treturn this.mapDocuments(inserted);\n\t\t} catch (error: unknown) {\n\t\t\tif (error instanceof MongoBulkWriteError && \"insertedDocs\" in error && Array.isArray(error.insertedDocs) && error.insertedDocs.length > 0) {\n\t\t\t\treturn this.mapDocuments(error.insertedDocs);\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t};\n\n\tfindById = async (monitorId: string, teamId: string): Promise<Monitor> => {\n\t\tconst match: { _id: string; teamId: string } = { _id: monitorId, teamId };\n\t\tconst monitor = await MonitorModel.findOne(match);\n\t\tif (!monitor) {\n\t\t\tthrow new AppError({ message: `Monitor with ID ${monitorId} not found`, status: 404 });\n\t\t}\n\t\treturn this.toEntity(monitor);\n\t};\n\n\tfindAll = async (): Promise<Monitor[]> => {\n\t\tconst monitors = await MonitorModel.find();\n\t\treturn this.mapDocuments(monitors);\n\t};\n\n\tfindByTeamId = async (teamId: string, config: TeamQueryConfig): Promise<Monitor[] | null> => {\n\t\tconst { page = 0, rowsPerPage = 0, filter, field = \"createdAt\", order = \"desc\", type } = config ?? {};\n\n\t\tconst query: Record<string, unknown> = {\n\t\t\tteamId: new mongoose.Types.ObjectId(teamId),\n\t\t};\n\n\t\tif (type !== undefined) {\n\t\t\tquery.type = Array.isArray(type) ? { $in: type } : type;\n\t\t}\n\n\t\tif (filter !== undefined) {\n\t\t\tswitch (field) {\n\t\t\t\tcase \"name\":\n\t\t\t\t\tquery.$or = [{ name: { $regex: filter, $options: \"i\" } }, { url: { $regex: filter, $options: \"i\" } }];\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"isActive\":\n\t\t\t\t\tquery.isActive = filter === \"true\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"status\":\n\t\t\t\t\tquery.status = filter;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"type\":\n\t\t\t\t\tquery.type = filter;\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tconst sort = { [field]: order === \"asc\" ? 1 : -1 } as const;\n\t\tconst skip = Math.max(page, 0) * rowsPerPage;\n\n\t\tconst documents = await MonitorModel.find(query).sort(sort).skip(skip).limit(rowsPerPage);\n\n\t\treturn this.mapDocuments(documents);\n\t};\n\n\tfindByIds = async (monitorIds: string[]): Promise<Monitor[]> => {\n\t\tconst objectIds = monitorIds.map((id) => new mongoose.Types.ObjectId(id));\n\t\tconst monitors = await MonitorModel.find({ _id: { $in: objectIds } });\n\t\treturn this.mapDocuments(monitors);\n\t};\n\n\tfindByIdsWithChecks = async (monitorIds: string[], checksCount: number = 25): Promise<Monitor[]> => {\n\t\tif (!monitorIds.length) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst objectIds = monitorIds.map((id) => new mongoose.Types.ObjectId(id));\n\n\t\tconst pipeline: PipelineStage[] = [\n\t\t\t{ $match: { _id: { $in: objectIds } } },\n\t\t\t{\n\t\t\t\t$lookup: {\n\t\t\t\t\tfrom: \"checks\",\n\t\t\t\t\tlet: { monitorId: \"$_id\" },\n\t\t\t\t\tpipeline: [{ $match: { $expr: { $eq: [\"$metadata.monitorId\", \"$$monitorId\"] } } }, { $sort: { createdAt: -1 } }, { $limit: checksCount }],\n\t\t\t\t\tas: \"checks\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\t$lookup: {\n\t\t\t\t\tfrom: \"maintenancewindows\",\n\t\t\t\t\tlet: { monitorId: \"$_id\" },\n\t\t\t\t\tpipeline: [{ $match: { $expr: { $eq: [\"$monitorId\", \"$$monitorId\"] } } }],\n\t\t\t\t\tas: \"maintenanceWindows\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\t$lookup: {\n\t\t\t\t\tfrom: \"monitorstats\",\n\t\t\t\t\tlocalField: \"_id\",\n\t\t\t\t\tforeignField: \"monitorId\",\n\t\t\t\t\tas: \"stats\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\t$addFields: {\n\t\t\t\t\tisMaintenance: {\n\t\t\t\t\t\t$reduce: {\n\t\t\t\t\t\t\tinput: \"$maintenanceWindows\",\n\t\t\t\t\t\t\tinitialValue: false,\n\t\t\t\t\t\t\tin: {\n\t\t\t\t\t\t\t\t$or: [\n\t\t\t\t\t\t\t\t\t\"$$value\",\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t$and: [{ $eq: [\"$$this.active\", true] }, { $lte: [\"$$this.start\", \"$$NOW\"] }, { $gte: [\"$$this.end\", \"$$NOW\"] }],\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tuptimePercentage: { $arrayElemAt: [\"$stats.uptimePercentage\", 0] },\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\t$project: {\n\t\t\t\t\tmaintenanceWindows: 0,\n\t\t\t\t\tstats: 0,\n\t\t\t\t},\n\t\t\t},\n\t\t];\n\n\t\tconst documents = await MonitorModel.aggregate(pipeline);\n\t\treturn documents.map((doc) => this.toEntityWithChecks(doc));\n\t};\n\n\tfindMonitorCountByTeamIdAndType = async (teamId: string, config?: TeamQueryConfig): Promise<number> => {\n\t\tconst { type } = config ?? {};\n\n\t\tconst query: FilterQuery<MonitorDocument> = {\n\t\t\tteamId: new mongoose.Types.ObjectId(teamId),\n\t\t};\n\n\t\tif (type !== undefined) {\n\t\t\tquery.type = Array.isArray(type) ? { $in: type } : type;\n\t\t}\n\n\t\tconst count = await MonitorModel.countDocuments(query);\n\t\treturn count;\n\t};\n\n\tupdateById = async (monitorId: string, teamId: string, patch: Partial<Monitor>) => {\n\t\tconst updatedMonitor = await MonitorModel.findOneAndUpdate(\n\t\t\t{ _id: monitorId, teamId },\n\t\t\t{\n\t\t\t\t$set: {\n\t\t\t\t\t...patch,\n\t\t\t\t},\n\t\t\t},\n\t\t\t{ new: true, runValidators: true }\n\t\t);\n\t\tif (!updatedMonitor) {\n\t\t\tthrow new AppError({ message: `Failed to update monitor with id ${monitorId}`, status: 500 });\n\t\t}\n\t\treturn this.toEntity(updatedMonitor);\n\t};\n\n\ttogglePauseById = async (monitorId: string, teamId: string) => {\n\t\tconst monitor = await MonitorModel.findOneAndUpdate(\n\t\t\t{ _id: monitorId, teamId },\n\t\t\t[\n\t\t\t\t{\n\t\t\t\t\t$set: {\n\t\t\t\t\t\tisActive: { $not: \"$isActive\" },\n\t\t\t\t\t\tstatus: {\n\t\t\t\t\t\t\t$cond: {\n\t\t\t\t\t\t\t\tif: { $eq: [\"$status\", \"paused\"] },\n\t\t\t\t\t\t\t\tthen: \"initializing\",\n\t\t\t\t\t\t\t\telse: \"paused\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t],\n\t\t\t{ new: true }\n\t\t);\n\t\tif (!monitor) {\n\t\t\tthrow new AppError({ message: `Monitor with ID ${monitorId} not found for the given team.`, status: 404 });\n\t\t}\n\t\treturn this.toEntity(monitor);\n\t};\n\n\tdeleteById = async (monitorId: string, teamId: string) => {\n\t\tconst deletedMonitor = await MonitorModel.findOneAndDelete({ _id: monitorId, teamId });\n\n\t\tif (!deletedMonitor) {\n\t\t\tthrow new AppError({ message: `Monitor with ID ${monitorId} not found for the given team.`, status: 404 });\n\t\t}\n\n\t\treturn this.toEntity(deletedMonitor);\n\t};\n\n\tdeleteByTeamId = async (teamId: string) => {\n\t\tconst monitors = await MonitorModel.find({ teamId });\n\t\tconst { deletedCount } = await MonitorModel.deleteMany({ teamId });\n\n\t\treturn { monitors: this.mapDocuments(monitors), deletedCount };\n\t};\n\n\tfindMonitorsSummaryByTeamId = async (teamId: string, config?: SummaryConfig): Promise<MonitorsSummary> => {\n\t\tconst match: FilterQuery<MonitorDocument> = { teamId: new mongoose.Types.ObjectId(teamId) };\n\t\tif (config?.type !== undefined) {\n\t\t\tmatch.type = Array.isArray(config.type) ? { $in: config.type } : config.type;\n\t\t}\n\t\tconst pipeline = [\n\t\t\t{ $match: match },\n\t\t\t{\n\t\t\t\t$group: {\n\t\t\t\t\t_id: null,\n\t\t\t\t\ttotalMonitors: { $sum: 1 },\n\t\t\t\t\tupMonitors: {\n\t\t\t\t\t\t$sum: {\n\t\t\t\t\t\t\t$cond: [{ $eq: [\"$status\", \"up\"] }, 1, 0],\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tdownMonitors: {\n\t\t\t\t\t\t$sum: {\n\t\t\t\t\t\t\t$cond: [{ $eq: [\"$status\", \"down\"] }, 1, 0],\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tpausedMonitors: {\n\t\t\t\t\t\t$sum: {\n\t\t\t\t\t\t\t$cond: [{ $eq: [\"$status\", \"paused\"] }, 1, 0],\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tinitializingMonitors: {\n\t\t\t\t\t\t$sum: {\n\t\t\t\t\t\t\t$cond: [{ $eq: [\"$status\", \"initializing\"] }, 1, 0],\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tmaintenanceMonitors: {\n\t\t\t\t\t\t$sum: {\n\t\t\t\t\t\t\t$cond: [{ $eq: [\"$status\", \"maintenance\"] }, 1, 0],\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tbreachedMonitors: {\n\t\t\t\t\t\t$sum: {\n\t\t\t\t\t\t\t$cond: [{ $eq: [\"$status\", \"breached\"] }, 1, 0],\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{ $project: { _id: 0 } },\n\t\t];\n\n\t\tconst [summary] = await MonitorModel.aggregate(pipeline);\n\t\treturn (\n\t\t\tsummary ?? {\n\t\t\t\ttotalMonitors: 0,\n\t\t\t\tupMonitors: 0,\n\t\t\t\tdownMonitors: 0,\n\t\t\t\tpausedMonitors: 0,\n\t\t\t\tinitializingMonitors: 0,\n\t\t\t\tmaintenanceMonitors: 0,\n\t\t\t\tbreachedMonitors: 0,\n\t\t\t}\n\t\t);\n\t};\n\n\tfindGroupsByTeamId = async (teamId: string): Promise<string[]> => {\n\t\tconst groups = await MonitorModel.distinct(\"group\", {\n\t\t\tteamId: new mongoose.Types.ObjectId(teamId),\n\t\t\tgroup: { $nin: [null, \"\"] },\n\t\t});\n\t\treturn groups.sort();\n\t};\n\n\tremoveNotificationFromMonitors = async (notificationId: string): Promise<void> => {\n\t\tawait MonitorModel.updateMany({ notifications: notificationId }, { $pull: { notifications: notificationId } });\n\t};\n\n\tprivate mapDocuments = (documents: MonitorDocument[]): Monitor[] => {\n\t\tif (!documents?.length) {\n\t\t\treturn [];\n\t\t}\n\t\treturn documents.map((doc) => this.toEntity(doc));\n\t};\n\n\tprivate toEntity = (doc: MonitorDocument): Monitor => {\n\t\tconst toStringId = (value: unknown): string => {\n\t\t\tif (value instanceof mongoose.Types.ObjectId) {\n\t\t\t\treturn value.toString();\n\t\t\t}\n\t\t\treturn value?.toString() ?? \"\";\n\t\t};\n\n\t\tconst toDateString = (value: Date | string): string => {\n\t\t\treturn value instanceof Date ? value.toISOString() : value;\n\t\t};\n\n\t\tconst notificationIds = (doc.notifications ?? []).map((notification) => toStringId(notification));\n\n\t\treturn {\n\t\t\tid: toStringId(doc._id),\n\t\t\tuserId: toStringId(doc.userId),\n\t\t\tteamId: toStringId(doc.teamId),\n\t\t\tname: doc.name,\n\t\t\tdescription: doc.description ?? undefined,\n\t\t\tstatus: doc.status ?? \"initializing\",\n\t\t\tstatusWindow: doc.statusWindow ?? [],\n\t\t\tstatusWindowSize: doc.statusWindowSize,\n\t\t\tstatusWindowThreshold: doc.statusWindowThreshold,\n\t\t\ttype: doc.type,\n\t\t\tignoreTlsErrors: doc.ignoreTlsErrors,\n\t\t\tuseAdvancedMatching: doc.useAdvancedMatching ?? false,\n\t\t\tjsonPath: doc.jsonPath ?? undefined,\n\t\t\texpectedValue: doc.expectedValue ?? undefined,\n\t\t\tmatchMethod: doc.matchMethod ?? undefined,\n\t\t\turl: doc.url,\n\t\t\tport: doc.port ?? undefined,\n\t\t\tisActive: doc.isActive,\n\t\t\tinterval: doc.interval,\n\t\t\tuptimePercentage: doc.uptimePercentage ?? undefined,\n\t\t\tnotifications: notificationIds,\n\t\t\tsecret: doc.secret ?? undefined,\n\t\t\tcpuAlertThreshold: doc.cpuAlertThreshold,\n\t\t\tcpuAlertCounter: doc.cpuAlertCounter,\n\t\t\tmemoryAlertThreshold: doc.memoryAlertThreshold,\n\t\t\tmemoryAlertCounter: doc.memoryAlertCounter,\n\t\t\tdiskAlertThreshold: doc.diskAlertThreshold,\n\t\t\tdiskAlertCounter: doc.diskAlertCounter,\n\t\t\ttempAlertThreshold: doc.tempAlertThreshold,\n\t\t\ttempAlertCounter: doc.tempAlertCounter,\n\t\t\tselectedDisks: doc.selectedDisks ?? [],\n\t\t\tgameId: doc.gameId ?? undefined,\n\t\t\tgrpcServiceName: doc.grpcServiceName ?? undefined,\n\t\t\tgroup: doc.group ?? null,\n\t\t\trecentChecks: (doc.recentChecks ?? []).map((check: CheckSnapshotDocument) => this.toCheckSnapshot(check)),\n\t\t\tgeoCheckEnabled: doc.geoCheckEnabled ?? false,\n\t\t\tgeoCheckLocations: doc.geoCheckLocations ?? [],\n\t\t\tgeoCheckInterval: doc.geoCheckInterval ?? 300000,\n\t\t\tcreatedAt: toDateString(doc.createdAt),\n\t\t\tupdatedAt: toDateString(doc.updatedAt),\n\t\t};\n\t};\n\n\tprivate toEntityWithChecks = (doc: MonitorDocument): Monitor => {\n\t\tconst toStringId = (value: unknown): string => {\n\t\t\tif (value instanceof mongoose.Types.ObjectId) {\n\t\t\t\treturn value.toString();\n\t\t\t}\n\t\t\treturn value?.toString() ?? \"\";\n\t\t};\n\n\t\tconst toDateString = (value: Date | string): string => {\n\t\t\tif (!value) return \"\";\n\t\t\treturn value instanceof Date ? value.toISOString() : value;\n\t\t};\n\n\t\tconst notificationIds = (doc.notifications ?? []).map((notification: unknown) => toStringId(notification));\n\n\t\treturn {\n\t\t\tid: toStringId(doc._id),\n\t\t\tuserId: toStringId(doc.userId),\n\t\t\tteamId: toStringId(doc.teamId),\n\t\t\tname: doc.name,\n\t\t\tdescription: doc.description ?? undefined,\n\t\t\tstatus: doc.status ?? \"initializing\",\n\t\t\tstatusWindow: doc.statusWindow ?? [],\n\t\t\tstatusWindowSize: doc.statusWindowSize,\n\t\t\tstatusWindowThreshold: doc.statusWindowThreshold,\n\t\t\ttype: doc.type,\n\t\t\tignoreTlsErrors: doc.ignoreTlsErrors,\n\t\t\tuseAdvancedMatching: doc.useAdvancedMatching ?? false,\n\t\t\tjsonPath: doc.jsonPath ?? undefined,\n\t\t\texpectedValue: doc.expectedValue ?? undefined,\n\t\t\tmatchMethod: doc.matchMethod ?? undefined,\n\t\t\turl: doc.url,\n\t\t\tport: doc.port ?? undefined,\n\t\t\tisActive: doc.isActive,\n\t\t\tinterval: doc.interval,\n\t\t\tuptimePercentage: doc.uptimePercentage ?? undefined,\n\t\t\tnotifications: notificationIds,\n\t\t\tsecret: doc.secret ?? undefined,\n\t\t\tcpuAlertThreshold: doc.cpuAlertThreshold,\n\t\t\tcpuAlertCounter: doc.cpuAlertCounter,\n\t\t\tmemoryAlertThreshold: doc.memoryAlertThreshold,\n\t\t\tmemoryAlertCounter: doc.memoryAlertCounter,\n\t\t\tdiskAlertThreshold: doc.diskAlertThreshold,\n\t\t\tdiskAlertCounter: doc.diskAlertCounter,\n\t\t\ttempAlertThreshold: doc.tempAlertThreshold,\n\t\t\ttempAlertCounter: doc.tempAlertCounter,\n\t\t\tselectedDisks: doc.selectedDisks ?? [],\n\t\t\tgameId: doc.gameId ?? undefined,\n\t\t\tgrpcServiceName: doc.grpcServiceName ?? undefined,\n\t\t\tgroup: doc.group ?? null,\n\t\t\trecentChecks: (doc.recentChecks ?? []).map((check: CheckSnapshotDocument) => this.toCheckSnapshot(check)),\n\t\t\tgeoCheckEnabled: doc.geoCheckEnabled ?? false,\n\t\t\tgeoCheckLocations: doc.geoCheckLocations ?? [],\n\t\t\tgeoCheckInterval: doc.geoCheckInterval ?? 300000,\n\t\t\tcreatedAt: toDateString(doc.createdAt),\n\t\t\tupdatedAt: toDateString(doc.updatedAt),\n\t\t};\n\t};\n\n\tprivate toCheckSnapshot = (doc: CheckSnapshotDocument): CheckSnapshot => {\n\t\tconst toDateString = (value: Date | string): string => {\n\t\t\treturn value instanceof Date ? value.toISOString() : value;\n\t\t};\n\n\t\treturn {\n\t\t\tid: doc.id,\n\t\t\tstatus: doc.status,\n\t\t\tresponseTime: doc.responseTime,\n\t\t\ttimings: doc.timings,\n\t\t\tstatusCode: doc.statusCode,\n\t\t\tmessage: doc.message,\n\t\t\tcpu: doc.cpu,\n\t\t\tmemory: doc.memory,\n\t\t\tdisk: doc.disk,\n\t\t\thost: doc.host,\n\t\t\terrors: doc.errors,\n\t\t\tcapture: doc.capture,\n\t\t\tnet: doc.net,\n\t\t\taccessibility: doc.accessibility,\n\t\t\tbestPractices: doc.bestPractices,\n\t\t\tseo: doc.seo,\n\t\t\tperformance: doc.performance,\n\t\t\taudits: doc.audits,\n\t\t\tcreatedAt: toDateString(doc.createdAt),\n\t\t};\n\t};\n\n\tdeleteByTeamIdsNotIn = async (teamIds: string[]): Promise<number> => {\n\t\tconst objectIds = teamIds.map((id) => new mongoose.Types.ObjectId(id));\n\t\tconst result = await MonitorModel.deleteMany({ teamId: { $nin: objectIds } });\n\t\treturn result.deletedCount ?? 0;\n\t};\n\n\tfindAllMonitorIds = async (): Promise<string[]> => {\n\t\tconst monitors = await MonitorModel.find({}, { _id: 1 }).lean();\n\t\treturn monitors.map((doc) => doc._id.toString());\n\t};\n}\n\nexport default MongoMonitorsRepository;\n"
  },
  {
    "path": "server/src/repositories/notifications/INotificationsRepository.ts",
    "content": "import type { Notification } from \"@/types/index.js\";\nexport interface INotificationsRepository {\n\t// create\n\tcreate(notificationData: Partial<Notification>): Promise<Notification>;\n\t// fetch\n\tfindById(id: string, teamId: string): Promise<Notification>;\n\tfindNotificationsByIds(ids: string[]): Promise<Notification[]>;\n\tfindByTeamId(teamId: string): Promise<Notification[]>;\n\t// update\n\tupdateById(id: string, teamId: string, updateData: Partial<Notification>): Promise<Notification>;\n\t// delete\n\tdeleteById(id: string, teamId: string): Promise<Notification>;\n}\n"
  },
  {
    "path": "server/src/repositories/notifications/MongoNotificationsRepository.ts",
    "content": "import mongoose from \"mongoose\";\nimport { NotificationModel, type NotificationDocument } from \"@/db/models/index.js\";\nimport { INotificationsRepository } from \"@/repositories/index.js\";\nimport type { Notification } from \"@/types/index.js\";\nimport { AppError } from \"@/utils/AppError.js\";\n\nclass MongoNotificationsRepository implements INotificationsRepository {\n\tprivate mapDocuments = (documents: NotificationDocument[]): Notification[] => {\n\t\tif (!documents?.length) {\n\t\t\treturn [];\n\t\t}\n\t\treturn documents.map((doc) => this.toEntity(doc));\n\t};\n\n\tprivate toEntity = (doc: NotificationDocument): Notification => {\n\t\tconst toStringId = (value: mongoose.Types.ObjectId | string): string => {\n\t\t\treturn value instanceof mongoose.Types.ObjectId ? value.toString() : value;\n\t\t};\n\n\t\tconst toDateString = (value: Date | string): string => {\n\t\t\treturn value instanceof Date ? value.toISOString() : value;\n\t\t};\n\n\t\treturn {\n\t\t\tid: toStringId(doc._id),\n\t\t\tuserId: toStringId(doc.userId),\n\t\t\tteamId: toStringId(doc.teamId),\n\t\t\ttype: doc.type,\n\t\t\tnotificationName: doc.notificationName,\n\t\t\taddress: doc.address ?? undefined,\n\t\t\tphone: doc.phone ?? undefined,\n\t\t\thomeserverUrl: doc.homeserverUrl ?? undefined,\n\t\t\troomId: doc.roomId ?? undefined,\n\t\t\taccessToken: doc.accessToken ?? undefined,\n\t\t\tcreatedAt: toDateString(doc.createdAt),\n\t\t\tupdatedAt: toDateString(doc.updatedAt),\n\t\t};\n\t};\n\n\tcreate = async (notificationData: Partial<Notification>) => {\n\t\tconst notification = await NotificationModel.create({ ...notificationData });\n\t\tif (!notification) {\n\t\t\tthrow new AppError({ message: \"Failed to create notification\", status: 500 });\n\t\t}\n\t\treturn this.toEntity(notification);\n\t};\n\n\tfindById = async (id: string, teamId: string): Promise<Notification> => {\n\t\tconst notification = await NotificationModel.findOne({\n\t\t\t_id: new mongoose.Types.ObjectId(id),\n\t\t\tteamId: new mongoose.Types.ObjectId(teamId),\n\t\t});\n\t\tif (!notification) {\n\t\t\tthrow new AppError({ message: \"Notification not found\", status: 404 });\n\t\t}\n\t\treturn this.toEntity(notification);\n\t};\n\n\tfindNotificationsByIds = async (ids: string[]) => {\n\t\tconst mongoIds = ids.map((id) => new mongoose.Types.ObjectId(id));\n\t\tconst documents = await NotificationModel.find({ _id: { $in: mongoIds } });\n\t\treturn this.mapDocuments(documents);\n\t};\n\n\tfindByTeamId = async (teamId: string): Promise<Notification[]> => {\n\t\tconst documents = await NotificationModel.find({ teamId });\n\t\treturn this.mapDocuments(documents);\n\t};\n\n\tupdateById = async (id: string, teamId: string, patch: Partial<Notification>): Promise<Notification> => {\n\t\tconst notification = await NotificationModel.findOneAndUpdate(\n\t\t\t{\n\t\t\t\t_id: new mongoose.Types.ObjectId(id),\n\t\t\t\tteamId: new mongoose.Types.ObjectId(teamId),\n\t\t\t},\n\t\t\t{ $set: patch },\n\t\t\t{ new: true, runValidators: true }\n\t\t);\n\t\tif (!notification) {\n\t\t\tthrow new AppError({ message: \"Notification not found or could not be updated\", status: 404 });\n\t\t}\n\t\treturn this.toEntity(notification);\n\t};\n\n\tdeleteById = async (id: string, teamId: string): Promise<Notification> => {\n\t\tconst deleted = await NotificationModel.findOneAndDelete({\n\t\t\t_id: new mongoose.Types.ObjectId(id),\n\t\t\tteamId: new mongoose.Types.ObjectId(teamId),\n\t\t});\n\t\tif (!deleted) {\n\t\t\tthrow new AppError({ message: \"Notification not found or could not be deleted\", status: 404 });\n\t\t}\n\t\treturn this.toEntity(deleted);\n\t};\n}\n\nexport default MongoNotificationsRepository;\n"
  },
  {
    "path": "server/src/repositories/recovery-tokens/IRecoveryTokensRepository.ts",
    "content": "import type { RecoveryToken } from \"@/types/recoveryToken.js\";\n\nexport interface IRecoveryTokensRepository {\n\t// create\n\tcreate(email: string): Promise<RecoveryToken>;\n\t// fetch\n\tfindByToken(token: string): Promise<RecoveryToken>;\n\t// update\n\t// delete\n\tdeleteManyByEmail(email: string): Promise<number>;\n\t// other\n}\n"
  },
  {
    "path": "server/src/repositories/recovery-tokens/MongoRecoveryTokensRepository.ts",
    "content": "import type { RecoveryToken } from \"@/types/index.js\";\nimport type { IRecoveryTokensRepository } from \"./IRecoveryTokensRepository.js\";\nimport type { RecoveryTokenDocument } from \"@/db/models/RecoveryToken.js\";\nimport { RecoveryTokenModel } from \"@/db/models/RecoveryToken.js\";\nimport mongoose from \"mongoose\";\nimport crypto from \"crypto\";\nimport { AppError } from \"@/utils/AppError.js\";\nconst SERVICE_NAME = \"MongoRecoveryTokensRepository\";\n\nclass MongoRecoveryTokensRepository implements IRecoveryTokensRepository {\n\tstatic SERVICE_NAME = SERVICE_NAME;\n\tprivate toStringId = (value?: mongoose.Types.ObjectId | string | null): string => {\n\t\tif (!value) {\n\t\t\treturn \"\";\n\t\t}\n\t\treturn value instanceof mongoose.Types.ObjectId ? value.toString() : String(value);\n\t};\n\n\tprivate toDateString = (value?: Date | string | null): string => {\n\t\tif (!value) {\n\t\t\treturn new Date(0).toISOString();\n\t\t}\n\t\treturn value instanceof Date ? value.toISOString() : new Date(value).toISOString();\n\t};\n\n\tprotected toEntity = (doc: RecoveryTokenDocument): RecoveryToken => {\n\t\treturn {\n\t\t\tid: this.toStringId(doc._id),\n\t\t\temail: doc.email,\n\t\t\ttoken: doc.token,\n\t\t\texpiry: this.toDateString(doc.expiry),\n\t\t\tcreatedAt: this.toDateString(doc.createdAt),\n\t\t\tupdatedAt: this.toDateString(doc.updatedAt),\n\t\t};\n\t};\n\n\tcreate = async (email: string): Promise<RecoveryToken> => {\n\t\tconst token = await RecoveryTokenModel.create({\n\t\t\temail,\n\t\t\ttoken: crypto.randomBytes(32).toString(\"hex\"),\n\t\t});\n\t\treturn this.toEntity(token);\n\t};\n\n\tfindByToken = async (token: string): Promise<RecoveryToken> => {\n\t\tconst recoveryToken = await RecoveryTokenModel.findOne({ token });\n\t\tif (!recoveryToken) {\n\t\t\tthrow new AppError({ message: \"Recovery token not found\", service: SERVICE_NAME, status: 404 });\n\t\t}\n\t\treturn this.toEntity(recoveryToken);\n\t};\n\n\tdeleteManyByEmail = async (email: string) => {\n\t\tconst result = await RecoveryTokenModel.deleteMany({\n\t\t\temail,\n\t\t});\n\t\treturn Promise.resolve(result.deletedCount || 0);\n\t};\n}\n\nexport default MongoRecoveryTokensRepository;\n"
  },
  {
    "path": "server/src/repositories/settings/ISettingsRepository.ts",
    "content": "import type { Settings, SettingsUpdate } from \"@/types/index.js\";\nexport interface ISettingsRepository {\n\t// create\n\tcreate(settings: Partial<Settings>): Promise<Settings>;\n\t// fetch\n\tfindSingleton(): Promise<Settings | null>;\n\t// update\n\tupdate(settings: SettingsUpdate): Promise<Settings>;\n\t// delete\n\tdeleteLegacy: () => Promise<boolean>;\n}\n"
  },
  {
    "path": "server/src/repositories/settings/MongoSettingsRepository.ts",
    "content": "import mongoose, { type UpdateQuery } from \"mongoose\";\nimport { ISettingsRepository } from \"@/repositories/settings/ISettingsRepository.js\";\nimport type { Settings, SettingsUpdate } from \"@/types/index.js\";\nimport { AppSettingsModel, type AppSettingsDocument } from \"@/db/models/index.js\";\n\nclass MongoSettingsRepository implements ISettingsRepository {\n\tprivate toStringId = (value?: mongoose.Types.ObjectId | string | null): string => {\n\t\tif (!value) {\n\t\t\treturn \"\";\n\t\t}\n\t\treturn value instanceof mongoose.Types.ObjectId ? value.toString() : String(value);\n\t};\n\n\tprivate toDateString = (value?: Date | string | null): string => {\n\t\tif (!value) {\n\t\t\treturn new Date(0).toISOString();\n\t\t}\n\t\treturn value instanceof Date ? value.toISOString() : new Date(value).toISOString();\n\t};\n\n\tprotected toEntity = (doc: AppSettingsDocument): Settings => {\n\t\treturn {\n\t\t\tid: this.toStringId(doc._id),\n\t\t\tcheckTTL: doc.checkTTL,\n\t\t\tlanguage: doc.language,\n\t\t\tjwtSecret: doc.jwtSecret ?? undefined,\n\t\t\tpagespeedApiKey: doc.pagespeedApiKey ?? undefined,\n\t\t\tsystemEmailHost: doc.systemEmailHost ?? undefined,\n\t\t\tsystemEmailPort: doc.systemEmailPort ?? undefined,\n\t\t\tsystemEmailAddress: doc.systemEmailAddress ?? undefined,\n\t\t\tsystemEmailPassword: doc.systemEmailPassword ?? undefined,\n\t\t\tsystemEmailUser: doc.systemEmailUser ?? undefined,\n\t\t\tsystemEmailConnectionHost: doc.systemEmailConnectionHost ?? undefined,\n\t\t\tsystemEmailTLSServername: doc.systemEmailTLSServername ?? undefined,\n\t\t\tsystemEmailSecure: doc.systemEmailSecure ?? false,\n\t\t\tsystemEmailPool: doc.systemEmailPool ?? false,\n\t\t\tsystemEmailIgnoreTLS: doc.systemEmailIgnoreTLS ?? false,\n\t\t\tsystemEmailRequireTLS: doc.systemEmailRequireTLS ?? false,\n\t\t\tsystemEmailRejectUnauthorized: doc.systemEmailRejectUnauthorized ?? true,\n\t\t\tshowURL: doc.showURL ?? false,\n\t\t\tsingleton: doc.singleton,\n\t\t\tversion: doc.version ?? 1,\n\t\t\tglobalThresholds: doc.globalThresholds ?? undefined,\n\t\t\tcreatedAt: this.toDateString(doc.createdAt),\n\t\t\tupdatedAt: this.toDateString(doc.updatedAt),\n\t\t};\n\t};\n\n\tcreate = async (settings: Partial<Settings>) => {\n\t\tconst newSettings = await AppSettingsModel.create(settings);\n\t\treturn this.toEntity(newSettings);\n\t};\n\n\tfindSingleton = async () => {\n\t\tconst settings = await AppSettingsModel.findOne({ singleton: true }).select(\"-__v -_id -createdAt -updatedAt -singleton\").lean();\n\t\tif (!settings) {\n\t\t\treturn null;\n\t\t}\n\t\treturn this.toEntity(settings);\n\t};\n\n\tupdate = async (settings: SettingsUpdate) => {\n\t\tconst $set: Record<string, unknown> = {};\n\t\tconst $unset: Record<string, string> = {};\n\n\t\t// Iterate through settings and separate into $set and $unset\n\t\tObject.entries(settings).forEach(([key, value]) => {\n\t\t\tif (value === undefined || value === null) {\n\t\t\t\t$unset[key] = \"\";\n\t\t\t} else {\n\t\t\t\t$set[key] = value;\n\t\t\t}\n\t\t});\n\n\t\tconst update: UpdateQuery<AppSettingsDocument> = {\n\t\t\t...(Object.keys($set).length > 0 && { $set }),\n\t\t\t...(Object.keys($unset).length > 0 && { $unset }),\n\t\t};\n\n\t\tawait AppSettingsModel.findOneAndUpdate({}, update, {\n\t\t\tupsert: true,\n\t\t});\n\n\t\tconst updatedSettings = await AppSettingsModel.findOneAndUpdate({}, update, {\n\t\t\tupsert: true,\n\t\t\tnew: true,\n\t\t\tprojection: \"-__v -_id -createdAt -updatedAt -singleton\",\n\t\t});\n\n\t\treturn this.toEntity(updatedSettings);\n\t};\n\n\tdeleteLegacy = async () => {\n\t\tconst res = await AppSettingsModel.deleteMany({ version: { $exists: false } });\n\t\treturn res.deletedCount > 0;\n\t};\n}\n\nexport default MongoSettingsRepository;\n"
  },
  {
    "path": "server/src/repositories/status-pages/IStatusPagesRepository.ts",
    "content": "import type { StatusPage } from \"@/types/statusPage.js\";\n\nexport interface IStatusPagesRepository {\n\t// create\n\tcreate(userId: string, teamId: string, image: Express.Multer.File | undefined, data: Partial<StatusPage>): Promise<StatusPage>;\n\t// single fetch\n\tfindByUrl(url: string): Promise<StatusPage>;\n\tfindByTeamId(teamId: string): Promise<StatusPage[]>;\n\t// collection fetch\n\t// update\n\tupdateById(id: string, teamId: string, image: Express.Multer.File | undefined, data: Partial<StatusPage>): Promise<StatusPage>;\n\t// delete\n\tdeleteById(id: string, teamId: string): Promise<StatusPage>;\n\t// other\n\tremoveMonitorFromStatusPages(monitorId: string): Promise<number>;\n}\n"
  },
  {
    "path": "server/src/repositories/status-pages/MongoStatusPagesRepository.ts",
    "content": "import { IStatusPagesRepository } from \"@/repositories/index.js\";\nimport { type StatusPageDocument, StatusPageModel } from \"@/db/models/StatusPage.js\";\nimport type { StatusPage, StatusPageLogo, StatusPageLogoDocument } from \"@/types/statusPage.js\";\nimport mongoose from \"mongoose\";\nimport { AppError } from \"@/utils/AppError.js\";\n\n// Type for update data that can include document-level fields (Buffer for logo)\ntype StatusPageUpdateData = Partial<Omit<StatusPage, \"id\" | \"userId\" | \"teamId\" | \"logo\" | \"createdAt\" | \"updatedAt\">> & {\n\tlogo?: StatusPageLogoDocument | null;\n};\nclass MongoStatusPagesRepository implements IStatusPagesRepository {\n\tprivate toStringId = (value?: mongoose.Types.ObjectId | string | null): string => {\n\t\tif (!value) {\n\t\t\treturn \"\";\n\t\t}\n\t\treturn value instanceof mongoose.Types.ObjectId ? value.toString() : String(value);\n\t};\n\n\tprivate toDateString = (value?: Date | string | null): string => {\n\t\tif (!value) {\n\t\t\treturn new Date(0).toISOString();\n\t\t}\n\t\treturn value instanceof Date ? value.toISOString() : new Date(value).toISOString();\n\t};\n\n\tprivate mapIdArray = (values?: Array<mongoose.Types.ObjectId | string>): string[] => {\n\t\treturn values?.map((value) => this.toStringId(value)) ?? [];\n\t};\n\n\tprivate mapLogo = (logo?: StatusPageLogoDocument | null): StatusPageLogo | undefined => {\n\t\tif (!logo) {\n\t\t\treturn undefined;\n\t\t}\n\t\t// Convert Buffer to base64 string for JSON serialization\n\t\tconst base64Data = Buffer.isBuffer(logo.data) ? logo.data.toString(\"base64\") : logo.data;\n\t\treturn {\n\t\t\tdata: base64Data,\n\t\t\tcontentType: logo.contentType,\n\t\t};\n\t};\n\n\tprivate toEntity = (doc: StatusPageDocument): StatusPage => {\n\t\treturn {\n\t\t\tid: this.toStringId(doc._id),\n\t\t\tuserId: this.toStringId(doc.userId),\n\t\t\tteamId: this.toStringId(doc.teamId),\n\t\t\ttype: doc.type,\n\t\t\tcompanyName: doc.companyName,\n\t\t\turl: doc.url,\n\t\t\ttimezone: doc.timezone ?? undefined,\n\t\t\tcolor: doc.color,\n\t\t\tmonitors: this.mapIdArray(doc.monitors),\n\t\t\tsubMonitors: this.mapIdArray(doc.subMonitors),\n\t\t\toriginalMonitors: this.mapIdArray(doc.originalMonitors),\n\t\t\tlogo: this.mapLogo(doc.logo),\n\t\t\tisPublished: doc.isPublished,\n\t\t\tshowCharts: doc.showCharts,\n\t\t\tshowUptimePercentage: doc.showUptimePercentage,\n\t\t\tshowAdminLoginLink: doc.showAdminLoginLink,\n\t\t\tshowInfrastructure: doc.showInfrastructure,\n\t\t\tcustomCSS: doc.customCSS,\n\t\t\tcreatedAt: this.toDateString(doc.createdAt),\n\t\t\tupdatedAt: this.toDateString(doc.updatedAt),\n\t\t};\n\t};\n\n\tprivate mapDocuments = (documents: StatusPageDocument[]): StatusPage[] => {\n\t\tif (!documents?.length) {\n\t\t\treturn [];\n\t\t}\n\t\treturn documents.map((doc) => this.toEntity(doc));\n\t};\n\n\tcreate = async (userId: string, teamId: string, image: Express.Multer.File | undefined, data: Partial<StatusPage>): Promise<StatusPage> => {\n\t\tconst { logo, ...restData } = data;\n\t\tvoid logo;\n\t\tconst statusPage = new StatusPageModel({\n\t\t\t...restData,\n\t\t\tuserId,\n\t\t\tteamId,\n\t\t});\n\t\tif (image) {\n\t\t\tstatusPage.logo = {\n\t\t\t\tdata: image.buffer as Buffer,\n\t\t\t\tcontentType: image.mimetype,\n\t\t\t};\n\t\t}\n\t\tawait statusPage.save();\n\t\treturn this.toEntity(statusPage);\n\t};\n\n\tfindByUrl = async (url: string): Promise<StatusPage> => {\n\t\tconst statusPage = await StatusPageModel.findOne({\n\t\t\turl,\n\t\t});\n\t\tif (!statusPage) {\n\t\t\tthrow new AppError({ message: \"Status page not found\", status: 404 });\n\t\t}\n\t\treturn this.toEntity(statusPage);\n\t\t// Get status page\n\t};\n\n\tfindByTeamId = async (teamId: string): Promise<StatusPage[]> => {\n\t\tconst statusPages = await StatusPageModel.find({ teamId });\n\t\treturn this.mapDocuments(statusPages);\n\t};\n\n\tupdateById = async (\n\t\tid: string,\n\t\tteamId: string,\n\t\timage: Express.Multer.File | undefined,\n\t\tpatch: Partial<StatusPage> & { removeLogo?: string }\n\t): Promise<StatusPage> => {\n\t\tconst { logo, removeLogo, ...restPatch } = patch;\n\t\tvoid logo;\n\t\tconst updateData: StatusPageUpdateData = { ...restPatch };\n\t\tif (image) {\n\t\t\tupdateData.logo = {\n\t\t\t\tdata: image.buffer as Buffer,\n\t\t\t\tcontentType: image.mimetype,\n\t\t\t};\n\t\t} else if (removeLogo === \"true\") {\n\t\t\tupdateData.logo = null;\n\t\t}\n\n\t\tconst statusPage = await StatusPageModel.findOneAndUpdate({ teamId, _id: id }, updateData, {\n\t\t\tnew: true,\n\t\t});\n\n\t\tif (!statusPage) {\n\t\t\tthrow new AppError({ message: \"Status page not found\", status: 404 });\n\t\t}\n\n\t\treturn this.toEntity(statusPage);\n\t};\n\n\tdeleteById = async (id: string, teamId: string): Promise<StatusPage> => {\n\t\tconst statusPage = await StatusPageModel.findOneAndDelete({ _id: id, teamId });\n\t\tif (!statusPage) {\n\t\t\tthrow new AppError({ message: \"Status page not found\", status: 404 });\n\t\t}\n\t\treturn this.toEntity(statusPage);\n\t};\n\n\tremoveMonitorFromStatusPages = async (monitorId: string): Promise<number> => {\n\t\tconst res = await StatusPageModel.updateMany({ monitors: monitorId }, { $pull: { monitors: monitorId } });\n\t\treturn res.modifiedCount;\n\t};\n}\n\nexport default MongoStatusPagesRepository;\n"
  },
  {
    "path": "server/src/repositories/teams/ITeamsRepository.ts",
    "content": "import type { Team } from \"@/types/index.js\";\nexport interface ITeamsRepository {\n\t// create\n\tcreate(email: string): Promise<Team>;\n\t// fetch\n\t// update\n\t// delete\n\t// other\n\tfindAllTeamIds(): Promise<string[]>;\n}\n"
  },
  {
    "path": "server/src/repositories/teams/MongoTeamsRepository.ts",
    "content": "import { Team } from \"@/types/index.js\";\nimport { TeamDocument, TeamModel } from \"@/db/models/index.js\";\nimport { ITeamsRepository } from \"@/repositories/index.js\";\nimport mongoose from \"mongoose\";\n\nclass MongoTeamsRepository implements ITeamsRepository {\n\tprivate toStringId = (value?: mongoose.Types.ObjectId | string | null): string => {\n\t\tif (!value) {\n\t\t\treturn \"\";\n\t\t}\n\t\treturn value instanceof mongoose.Types.ObjectId ? value.toString() : String(value);\n\t};\n\n\tprivate toDateString = (value?: Date | string | null): string => {\n\t\tif (!value) {\n\t\t\treturn new Date(0).toISOString();\n\t\t}\n\t\treturn value instanceof Date ? value.toISOString() : new Date(value).toISOString();\n\t};\n\n\tprivate toEntity = (doc: TeamDocument): Team => {\n\t\treturn {\n\t\t\tid: this.toStringId(doc._id),\n\t\t\temail: doc.email,\n\t\t\tcreatedAt: this.toDateString(doc.createdAt),\n\t\t\tupdatedAt: this.toDateString(doc.updatedAt),\n\t\t};\n\t};\n\n\tcreate = async (email: string) => {\n\t\tconst team = await TeamModel.create({ email });\n\t\treturn this.toEntity(team);\n\t};\n\n\tfindAllTeamIds = async (): Promise<string[]> => {\n\t\tconst teams = await TeamModel.find({}, { _id: 1 }).lean();\n\t\treturn teams.map((team) => this.toStringId(team._id));\n\t};\n}\n\nexport default MongoTeamsRepository;\n"
  },
  {
    "path": "server/src/repositories/users/IUsersRepository.ts",
    "content": "import type { User } from \"@/types/index.js\";\nexport interface IUsersRepository {\n\t// create\n\tcreate(user: Partial<User>, imageFile?: Express.Multer.File | null): Promise<User>;\n\t// fetch\n\tfindByEmail(email: string): Promise<User>;\n\tfindById(id: string): Promise<User>;\n\tfindAll(): Promise<User[]>;\n\t// update\n\tupdateById(id: string, patch: Partial<User>, file?: Express.Multer.File | null): Promise<User>;\n\t// delete\n\tdeleteById(id: string): Promise<User>;\n\t// other\n\tfindSuperAdmin(): Promise<boolean>;\n}\n"
  },
  {
    "path": "server/src/repositories/users/MongoUsersRepository.ts",
    "content": "import mongoose from \"mongoose\";\nimport { IUsersRepository } from \"@/repositories/index.js\";\nimport { UserModel, type UserDocument } from \"@/db/models/index.js\";\nimport type { User, UserProfileImage } from \"@/types/index.js\";\nimport { GenerateAvatarImage } from \"@/utils/imageProcessing.js\";\nimport { ParseBoolean } from \"@/utils/utils.js\";\nimport { AppError } from \"@/utils/AppError.js\";\nconst SERVICE_NAME = \"MongoUsersRepository\";\n\nclass MongoUsersRepository implements IUsersRepository {\n\tstatic SERVICE_NAME = SERVICE_NAME;\n\tprivate toStringId = (value?: mongoose.Types.ObjectId | string | null): string => {\n\t\tif (!value) {\n\t\t\treturn \"\";\n\t\t}\n\t\treturn value instanceof mongoose.Types.ObjectId ? value.toString() : String(value);\n\t};\n\n\tprivate toDateString = (value?: Date | string | null): string => {\n\t\tif (!value) {\n\t\t\treturn new Date(0).toISOString();\n\t\t}\n\t\treturn value instanceof Date ? value.toISOString() : new Date(value).toISOString();\n\t};\n\n\tprivate mapProfileImage = (image?: (UserProfileImage & { data?: Buffer }) | null) => {\n\t\tif (!image) {\n\t\t\treturn undefined;\n\t\t}\n\t\treturn {\n\t\t\tdata: image.data,\n\t\t\tcontentType: image.contentType,\n\t\t};\n\t};\n\n\tprotected toEntity = (doc: UserDocument): User => {\n\t\treturn {\n\t\t\tid: this.toStringId(doc._id),\n\t\t\tfirstName: doc.firstName,\n\t\t\tlastName: doc.lastName,\n\t\t\temail: doc.email,\n\t\t\tpassword: doc.password,\n\t\t\tavatarImage: doc.avatarImage ?? undefined,\n\t\t\tprofileImage: this.mapProfileImage(doc.profileImage),\n\t\t\tisActive: doc.isActive ?? false,\n\t\t\tisVerified: doc.isVerified ?? false,\n\t\t\trole: doc.role ?? [],\n\t\t\tteamId: this.toStringId(doc.teamId),\n\t\t\tcheckTTL: doc.checkTTL ?? undefined,\n\t\t\tcreatedAt: this.toDateString(doc.createdAt),\n\t\t\tupdatedAt: this.toDateString(doc.updatedAt),\n\t\t};\n\t};\n\n\tcreate = async (user: Partial<User>, imageFile: Express.Multer.File | null) => {\n\t\tif (imageFile) {\n\t\t\t// 1.  Save the full size image\n\t\t\tuser.profileImage = {\n\t\t\t\tdata: imageFile.buffer,\n\t\t\t\tcontentType: imageFile.mimetype,\n\t\t\t};\n\n\t\t\t// 2.  Get the avatar sized image\n\t\t\tconst avatar = await GenerateAvatarImage(imageFile);\n\t\t\tuser.avatarImage = avatar;\n\t\t}\n\n\t\tconst newUser = new UserModel(user);\n\t\tawait newUser.save();\n\t\tconst sanitizedUser = await UserModel.findOne({ _id: newUser._id }).select(\"-password\").select(\"-profileImage\");\n\t\tif (!sanitizedUser) {\n\t\t\tthrow new AppError({ message: \"Failed to create user\", service: SERVICE_NAME, status: 500 });\n\t\t}\n\t\treturn this.toEntity(sanitizedUser);\n\t};\n\n\tfindByEmail = async (email: string) => {\n\t\tconst user = await UserModel.findOne({ email: email }).select(\"-profileImage\");\n\t\tif (!user) {\n\t\t\tthrow new AppError({ message: \"User not found\", service: SERVICE_NAME, status: 404 });\n\t\t}\n\t\treturn this.toEntity(user);\n\t};\n\n\tfindById = async (id: string) => {\n\t\tconst user = await UserModel.findById(id).select(\"-password\").select(\"-profileImage\");\n\t\tif (!user) {\n\t\t\tthrow new Error(\"User not found\");\n\t\t}\n\n\t\treturn this.toEntity(user);\n\t};\n\n\tfindAll = async () => {\n\t\tconst users = await UserModel.find().select(\"-password\").select(\"-profileImage\");\n\t\treturn this.mapDocuments(users);\n\t};\n\n\tupdateById = async (id: string, patch: Partial<User & { deleteProfileImage?: boolean }>, file?: Express.Multer.File | null): Promise<User> => {\n\t\tconst candidateUser = { ...patch };\n\t\tlet unsetFields: Record<string, 1> | undefined;\n\n\t\tif (ParseBoolean(candidateUser.deleteProfileImage) === true) {\n\t\t\tunsetFields = { profileImage: 1, avatarImage: 1 };\n\t\t\tdelete candidateUser.deleteProfileImage;\n\t\t} else if (file) {\n\t\t\t// 1.  Save the full size image\n\t\t\tcandidateUser.profileImage = {\n\t\t\t\tdata: file.buffer,\n\t\t\t\tcontentType: file.mimetype,\n\t\t\t};\n\n\t\t\t// 2.  Get the avatar sized image\n\t\t\tconst avatar = await GenerateAvatarImage(file);\n\t\t\tcandidateUser.avatarImage = avatar;\n\t\t}\n\n\t\tdelete candidateUser.deleteProfileImage;\n\n\t\tconst updateQuery: Record<string, unknown> = { $set: candidateUser };\n\t\tif (unsetFields) {\n\t\t\tupdateQuery.$unset = unsetFields;\n\t\t}\n\n\t\tconst updatedUser = await UserModel.findOneAndUpdate({ _id: id }, updateQuery, { new: true }).select(\"-password\").select(\"-profileImage\");\n\t\tif (!updatedUser) {\n\t\t\tthrow new AppError({ message: \"User not found\", service: SERVICE_NAME, status: 404 });\n\t\t}\n\t\treturn this.toEntity(updatedUser);\n\t};\n\n\tdeleteById = async (id: string) => {\n\t\tconst deletedUser = await UserModel.findByIdAndDelete(id);\n\t\tif (!deletedUser) {\n\t\t\tthrow new AppError({ message: \"User not found\", service: SERVICE_NAME, status: 404 });\n\t\t}\n\t\treturn this.toEntity(deletedUser);\n\t};\n\n\tfindSuperAdmin = async () => {\n\t\tconst superAdmin = await UserModel.findOne({ role: \"superadmin\" });\n\t\tif (superAdmin !== null) {\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t};\n\n\tprivate mapDocuments = (documents: UserDocument[]): User[] => {\n\t\tif (!documents?.length) {\n\t\t\treturn [];\n\t\t}\n\t\treturn documents.map((doc) => this.toEntity(doc));\n\t};\n}\n\nexport default MongoUsersRepository;\n"
  },
  {
    "path": "server/src/routes/authRoute.ts",
    "content": "import { Router, RequestHandler } from \"express\";\nimport { isAllowed } from \"../middleware/isAllowed.js\";\nimport multer from \"multer\";\nimport { IAuthController } from \"@/controllers/authController.js\";\n\nconst upload = multer();\n\nclass AuthRoutes {\n\tprivate router: Router;\n\tprivate authController: IAuthController;\n\n\tconstructor(authController: IAuthController, verifyJWT: RequestHandler) {\n\t\tthis.router = Router();\n\t\tthis.authController = authController;\n\t\tthis.initRoutes(verifyJWT);\n\t}\n\n\tinitRoutes(verifyJWT: RequestHandler) {\n\t\tthis.router.post(\"/register\", upload.single(\"profileImage\"), this.authController.registerUser);\n\t\tthis.router.post(\"/login\", this.authController.loginUser);\n\n\t\tthis.router.post(\"/recovery/request\", this.authController.requestRecovery);\n\t\tthis.router.post(\"/recovery/validate\", this.authController.validateRecovery);\n\t\tthis.router.post(\"/recovery/reset/\", this.authController.resetPassword);\n\n\t\tthis.router.get(\"/users/superadmin\", this.authController.checkSuperadminExists);\n\n\t\tthis.router.get(\"/users\", verifyJWT, isAllowed([\"admin\", \"superadmin\"]), this.authController.getAllUsers);\n\t\tthis.router.post(\"/users\", verifyJWT, isAllowed([\"superadmin\"]), upload.single(\"profileImage\"), this.authController.createUser);\n\t\tthis.router.get(\"/users/:userId\", verifyJWT, isAllowed([\"admin\", \"superadmin\"]), this.authController.getUserById);\n\t\tthis.router.patch(\"/users/:userId\", verifyJWT, isAllowed([\"superadmin\"]), this.authController.editUserById);\n\t\tthis.router.patch(\"/users/:userId/password\", verifyJWT, isAllowed([\"superadmin\"]), this.authController.editUserPasswordById);\n\t\tthis.router.delete(\"/users/:userId\", verifyJWT, isAllowed([\"admin\", \"superadmin\"]), this.authController.deleteUserById);\n\n\t\tthis.router.patch(\"/user\", verifyJWT, upload.single(\"profileImage\"), this.authController.editUser);\n\t\tthis.router.delete(\"/user\", verifyJWT, this.authController.deleteUser);\n\t}\n\n\tgetRouter() {\n\t\treturn this.router;\n\t}\n}\n\nexport default AuthRoutes;\n"
  },
  {
    "path": "server/src/routes/checkRoute.ts",
    "content": "import { Router } from \"express\";\n\nimport { isAllowed } from \"../middleware/isAllowed.js\";\nimport { ICheckController } from \"@/controllers/checkController.js\";\n\nclass CheckRoutes {\n\tprivate router: Router;\n\tprivate checkController: ICheckController;\n\n\tconstructor(checkController: ICheckController) {\n\t\tthis.router = Router();\n\t\tthis.checkController = checkController;\n\t\tthis.initRoutes();\n\t}\n\n\tinitRoutes() {\n\t\tthis.router.get(\"/team/summary\", this.checkController.getChecksSummaryByTeamId);\n\t\tthis.router.get(\"/team\", this.checkController.getChecksByTeam);\n\t\tthis.router.delete(\"/team\", isAllowed([\"admin\", \"superadmin\"]), this.checkController.deleteChecksByTeamId);\n\t\tthis.router.get(\"/:monitorId\", this.checkController.getChecksByMonitor);\n\t\tthis.router.delete(\"/:monitorId\", this.checkController.deleteChecks);\n\t}\n\n\tgetRouter() {\n\t\treturn this.router;\n\t}\n}\n\nexport default CheckRoutes;\n"
  },
  {
    "path": "server/src/routes/diagnosticRoute.ts",
    "content": "import { RequestHandler, Router } from \"express\";\nimport { isAllowed } from \"../middleware/isAllowed.js\";\nimport { IDiagnosticController } from \"@/controllers/diagnosticController.js\";\n\nclass DiagnosticRoutes {\n\tprivate router: Router;\n\tprivate diagnosticController: IDiagnosticController;\n\n\tconstructor(diagnosticController: IDiagnosticController, verifyJWT: RequestHandler) {\n\t\tthis.router = Router();\n\t\tthis.diagnosticController = diagnosticController;\n\t\tthis.initRoutes(verifyJWT);\n\t}\n\n\tinitRoutes(verifyJWT: RequestHandler) {\n\t\tthis.router.get(\"/system\", verifyJWT, isAllowed([\"admin\", \"superadmin\"]), this.diagnosticController.getSystemStats);\n\t}\n\n\tgetRouter() {\n\t\treturn this.router;\n\t}\n}\n\nexport default DiagnosticRoutes;\n"
  },
  {
    "path": "server/src/routes/geoCheckRoutes.ts",
    "content": "import { IGeoCheckController } from \"@/controllers/geoCheckController.js\";\nimport { Router } from \"express\";\n\nclass GeoCheckRoutes {\n\tprivate router: Router;\n\tprivate geoCheckController: IGeoCheckController;\n\n\tconstructor(geoCheckController: IGeoCheckController) {\n\t\tthis.router = Router();\n\t\tthis.geoCheckController = geoCheckController;\n\t\tthis.initRoutes();\n\t}\n\n\tinitRoutes() {\n\t\tthis.router.get(\"/:monitorId\", this.geoCheckController.getGeoChecksByMonitor);\n\t}\n\n\tgetRouter() {\n\t\treturn this.router;\n\t}\n}\n\nexport default GeoCheckRoutes;\n"
  },
  {
    "path": "server/src/routes/incidentRoute.ts",
    "content": "import { Router } from \"express\";\nimport { isAllowed } from \"../middleware/isAllowed.js\";\nimport { IIncidentController } from \"@/controllers/incidentController.js\";\n\nclass IncidentRoutes {\n\tprivate router: Router;\n\tprivate incidentController: IIncidentController;\n\n\tconstructor(incidentController: IIncidentController) {\n\t\tthis.router = Router();\n\t\tthis.incidentController = incidentController;\n\t\tthis.initRoutes();\n\t}\n\n\tinitRoutes() {\n\t\t// Team routes\n\t\tthis.router.get(\"/team\", this.incidentController.getIncidentsByTeam);\n\t\tthis.router.get(\"/team/summary\", this.incidentController.getIncidentSummary);\n\n\t\t// Individual incident routes\n\t\tthis.router.get(\"/:incidentId\", this.incidentController.getIncidentById);\n\t\tthis.router.put(\"/:incidentId/resolve\", isAllowed([\"admin\", \"superadmin\"]), this.incidentController.resolveIncidentManually);\n\t}\n\n\tgetRouter() {\n\t\treturn this.router;\n\t}\n}\n\nexport default IncidentRoutes;\n"
  },
  {
    "path": "server/src/routes/inviteRoute.ts",
    "content": "import { RequestHandler, Router } from \"express\";\nimport { isAllowed } from \"../middleware/isAllowed.js\";\nimport { IInviteController } from \"@/controllers/inviteController.js\";\n\nclass InviteRoutes {\n\tprivate router: Router;\n\tprivate inviteController: IInviteController;\n\n\tconstructor(inviteController: IInviteController, verifyJWT: RequestHandler) {\n\t\tthis.router = Router();\n\t\tthis.inviteController = inviteController;\n\t\tthis.initRoutes(verifyJWT);\n\t}\n\n\tinitRoutes(verifyJWT: RequestHandler) {\n\t\tthis.router.post(\"/send\", verifyJWT, isAllowed([\"admin\", \"superadmin\"]), this.inviteController.sendInviteEmail);\n\t\tthis.router.post(\"/verify\", this.inviteController.verifyInviteToken);\n\t\tthis.router.post(\"/\", verifyJWT, isAllowed([\"admin\", \"superadmin\"]), this.inviteController.getInviteToken);\n\t}\n\n\tgetRouter() {\n\t\treturn this.router;\n\t}\n}\n\nexport default InviteRoutes;\n"
  },
  {
    "path": "server/src/routes/logRoutes.ts",
    "content": "import { Router } from \"express\";\nimport { isAllowed } from \"@/middleware/isAllowed.js\";\nimport { ILogController } from \"@/controllers/logController.js\";\nclass LogRoutes {\n\tprivate router: Router;\n\tprivate logController: ILogController;\n\n\tconstructor(logController: ILogController) {\n\t\tthis.router = Router();\n\t\tthis.logController = logController;\n\t\tthis.initRoutes();\n\t}\n\tinitRoutes() {\n\t\tthis.router.get(\"/\", isAllowed([\"admin\", \"superadmin\"]), this.logController.getLogs);\n\t}\n\n\tgetRouter() {\n\t\treturn this.router;\n\t}\n}\n\nexport default LogRoutes;\n"
  },
  {
    "path": "server/src/routes/maintenanceWindowRoute.ts",
    "content": "import { IMaintenanceWindowController } from \"@/controllers/maintenanceWindowController.js\";\nimport { Router } from \"express\";\n\nclass MaintenanceWindowRoutes {\n\tprivate router: Router;\n\tprivate mwController: IMaintenanceWindowController;\n\n\tconstructor(maintenanceWindowController: IMaintenanceWindowController) {\n\t\tthis.router = Router();\n\t\tthis.mwController = maintenanceWindowController;\n\t\tthis.initRoutes();\n\t}\n\tinitRoutes() {\n\t\tthis.router.post(\"/\", this.mwController.createMaintenanceWindows);\n\t\tthis.router.get(\"/team/\", this.mwController.getMaintenanceWindowsByTeamId);\n\n\t\tthis.router.get(\"/monitor/:monitorId\", this.mwController.getMaintenanceWindowsByMonitorId);\n\n\t\tthis.router.get(\"/:id\", this.mwController.getMaintenanceWindowById);\n\t\tthis.router.patch(\"/:id\", this.mwController.editMaintenanceWindow);\n\t\tthis.router.delete(\"/:id\", this.mwController.deleteMaintenanceWindow);\n\t}\n\n\tgetRouter() {\n\t\treturn this.router;\n\t}\n}\n\nexport default MaintenanceWindowRoutes;\n"
  },
  {
    "path": "server/src/routes/monitorRoute.ts",
    "content": "import { Router } from \"express\";\nimport { isAllowed } from \"@/middleware/isAllowed.js\";\nimport { IMonitorController } from \"@/controllers/monitorController.js\";\n\nclass MonitorRoutes {\n\tprivate router: Router;\n\tprivate monitorController: IMonitorController;\n\tconstructor(monitorController: IMonitorController) {\n\t\tthis.router = Router();\n\t\tthis.monitorController = monitorController;\n\t\tthis.initRoutes();\n\t}\n\n\tinitRoutes() {\n\t\t// Team routes\n\t\tthis.router.get(\"/team\", this.monitorController.getMonitorsByTeamId);\n\t\tthis.router.get(\"/team/with-checks\", this.monitorController.getMonitorsWithChecksByTeamId);\n\t\tthis.router.get(\"/team/groups\", this.monitorController.getGroupsByTeamId);\n\n\t\t// Uptime routes\n\t\tthis.router.get(\"/uptime/details/:monitorId\", this.monitorController.getUptimeDetailsById);\n\n\t\t// Hardware routes\n\t\tthis.router.get(\"/hardware/details/:monitorId\", this.monitorController.getHardwareDetailsById);\n\n\t\t// PageSpeed routes\n\t\tthis.router.get(\"/pagespeed/details/:monitorId\", this.monitorController.getPageSpeedDetailsById);\n\n\t\t// Geo checks routes\n\t\tthis.router.get(\"/:monitorId/geo-checks\", this.monitorController.getGeoChecksByMonitorId);\n\n\t\t// General monitor routes\n\t\tthis.router.post(\"/pause/:monitorId\", isAllowed([\"admin\", \"superadmin\"]), this.monitorController.pauseMonitor);\n\n\t\t// Util routes\n\t\tthis.router.get(\"/certificate/:monitorId\", (req, res, next) => {\n\t\t\tthis.monitorController.getMonitorCertificate(req, res, next);\n\t\t});\n\n\t\t// General monitor CRUD routes\n\t\tthis.router.post(\"/\", isAllowed([\"admin\", \"superadmin\"]), this.monitorController.createMonitor);\n\t\tthis.router.delete(\"/\", isAllowed([\"superadmin\"]), this.monitorController.deleteAllMonitors);\n\n\t\t// Other static routes\n\t\tthis.router.post(\"/demo\", isAllowed([\"admin\", \"superadmin\"]), this.monitorController.addDemoMonitors);\n\t\tthis.router.get(\"/export/json\", isAllowed([\"admin\", \"superadmin\"]), this.monitorController.exportMonitorsToJSON);\n\t\tthis.router.post(\"/import/json\", isAllowed([\"admin\", \"superadmin\"]), this.monitorController.importMonitorsFromJSON);\n\n\t\tthis.router.get(\"/games\", this.monitorController.getAllGames);\n\n\t\t// Individual monitor CRUD routes\n\t\tthis.router.get(\"/:monitorId\", this.monitorController.getMonitorById);\n\t\tthis.router.patch(\"/:monitorId\", isAllowed([\"admin\", \"superadmin\"]), this.monitorController.editMonitor);\n\t\tthis.router.delete(\"/:monitorId\", isAllowed([\"admin\", \"superadmin\"]), this.monitorController.deleteMonitor);\n\t}\n\n\tgetRouter() {\n\t\treturn this.router;\n\t}\n}\n\nexport default MonitorRoutes;\n"
  },
  {
    "path": "server/src/routes/notificationRoute.ts",
    "content": "import { INotificationController } from \"@/controllers/notificationController.js\";\nimport { Router } from \"express\";\nclass NotificationRoutes {\n\tprivate router: Router;\n\tprivate notificationController: INotificationController;\n\n\tconstructor(notificationController: INotificationController) {\n\t\tthis.router = Router();\n\t\tthis.notificationController = notificationController;\n\t\tthis.initializeRoutes();\n\t}\n\n\tinitializeRoutes() {\n\t\tthis.router.post(\"/\", this.notificationController.createNotification);\n\n\t\tthis.router.post(\"/test/all\", this.notificationController.testAllNotifications);\n\t\tthis.router.post(\"/test\", this.notificationController.testNotification);\n\n\t\tthis.router.get(\"/team\", this.notificationController.getNotificationsByTeamId);\n\n\t\tthis.router.get(\"/:id\", this.notificationController.getNotificationById);\n\t\tthis.router.delete(\"/:id\", this.notificationController.deleteNotification);\n\t\tthis.router.patch(\"/:id\", this.notificationController.editNotification);\n\t}\n\n\tgetRouter() {\n\t\treturn this.router;\n\t}\n}\n\nexport default NotificationRoutes;\n"
  },
  {
    "path": "server/src/routes/queueRoute.ts",
    "content": "import { Router } from \"express\";\nimport { isAllowed } from \"@/middleware/isAllowed.js\";\nimport { IJobQueueController } from \"@/controllers/queueController.js\";\nclass QueueRoutes {\n\tprivate router: Router;\n\tprivate queueController: IJobQueueController;\n\n\tconstructor(queueController: IJobQueueController) {\n\t\tthis.router = Router();\n\t\tthis.queueController = queueController;\n\t\tthis.initRoutes();\n\t}\n\tinitRoutes() {\n\t\tthis.router.get(\"/jobs\", isAllowed([\"admin\", \"superadmin\"]), this.queueController.getJobs);\n\n\t\tthis.router.get(\"/metrics\", isAllowed([\"admin\", \"superadmin\"]), this.queueController.getMetrics);\n\t\tthis.router.get(\"/all-metrics\", isAllowed([\"admin\", \"superadmin\"]), this.queueController.getAllMetrics);\n\t\tthis.router.post(\"/flush\", isAllowed([\"admin\", \"superadmin\"]), this.queueController.flushQueue);\n\t}\n\n\tgetRouter() {\n\t\treturn this.router;\n\t}\n}\n\nexport default QueueRoutes;\n"
  },
  {
    "path": "server/src/routes/settingsRoute.ts",
    "content": "import { Router } from \"express\";\nimport { isAllowed } from \"../middleware/isAllowed.js\";\nimport { ISettingsController } from \"@/controllers/settingsController.js\";\n\nclass SettingsRoutes {\n\tprivate router: Router;\n\tprivate settingsController: ISettingsController;\n\n\tconstructor(settingsController: ISettingsController) {\n\t\tthis.router = Router();\n\t\tthis.settingsController = settingsController;\n\t\tthis.initRoutes();\n\t}\n\n\tinitRoutes() {\n\t\tthis.router.get(\"/\", this.settingsController.getAppSettings);\n\t\tthis.router.patch(\"/\", isAllowed([\"admin\", \"superadmin\"]), this.settingsController.updateAppSettings);\n\t\tthis.router.post(\"/test-email\", isAllowed([\"admin\", \"superadmin\"]), this.settingsController.sendTestEmail);\n\t}\n\n\tgetRouter() {\n\t\treturn this.router;\n\t}\n}\n\nexport default SettingsRoutes;\n"
  },
  {
    "path": "server/src/routes/statusPageRoute.ts",
    "content": "import { IStatusPageController } from \"@/controllers/statusPageController.js\";\nimport { RequestHandler, Router } from \"express\";\nimport multer from \"multer\";\nconst upload = multer();\n\nclass StatusPageRoutes {\n\tprivate router: Router;\n\tprivate statusPageController: IStatusPageController;\n\n\tconstructor(statusPageController: IStatusPageController, verifyJWT: RequestHandler, verifyStatusPageAccess: RequestHandler) {\n\t\tthis.router = Router();\n\t\tthis.statusPageController = statusPageController;\n\t\tthis.initRoutes(verifyJWT, verifyStatusPageAccess);\n\t}\n\n\tinitRoutes(verifyJWT: RequestHandler, verifyStatusPageAccess: RequestHandler) {\n\t\tthis.router.get(\"/team\", verifyJWT, this.statusPageController.getStatusPagesByTeamId);\n\n\t\tthis.router.post(\"/\", upload.single(\"logo\"), verifyJWT, this.statusPageController.createStatusPage);\n\t\tthis.router.put(\"/:id\", upload.single(\"logo\"), verifyJWT, this.statusPageController.updateStatusPage);\n\n\t\tthis.router.get(\"/:url\", verifyStatusPageAccess, this.statusPageController.getStatusPageByUrl);\n\t\tthis.router.delete(\"/:id\", verifyJWT, this.statusPageController.deleteStatusPage);\n\t}\n\n\tgetRouter() {\n\t\treturn this.router;\n\t}\n}\n\nexport default StatusPageRoutes;\n"
  },
  {
    "path": "server/src/service/business/checkService.ts",
    "content": "import { Types } from \"mongoose\";\nimport { IChecksRepository, IMonitorsRepository } from \"@/repositories/index.js\";\nimport type {\n\tMonitorStatusResponse,\n\tCheckErrorInfo,\n\tCheck,\n\tILighthouseAudit,\n\tChecksQueryResult,\n\tChecksSummary,\n\tMonitorPayloadMap,\n} from \"@/types/index.js\";\nimport type { HardwareStatusPayload, PageSpeedStatusPayload } from \"@/types/network.js\";\nimport { AppError } from \"@/utils/AppError.js\";\nimport { ILogger } from \"@/utils/logger.js\";\n\nconst SERVICE_NAME = \"checkService\";\n\nexport interface ICheckService {\n\tcreateChecks(checks: Check[]): Promise<Check[]>;\n\tbuildCheck(statusResponse: MonitorStatusResponse<MonitorPayloadMap[keyof MonitorPayloadMap]>): Check | undefined;\n\tgetChecksByMonitor(params: {\n\t\tmonitorId: string;\n\t\tteamId: string;\n\t\tsortOrder: string;\n\t\tdateRange: string;\n\t\tpage: number;\n\t\trowsPerPage: number;\n\t\tfilter?: string;\n\t\tstatus?: boolean;\n\t}): Promise<ChecksQueryResult>;\n\tgetChecksByTeam(params: {\n\t\tteamId: string;\n\t\tsortOrder: string;\n\t\tdateRange: string;\n\t\tpage: number;\n\t\trowsPerPage: number;\n\t\tfilter?: string;\n\t}): Promise<ChecksQueryResult>;\n\tgetChecksSummaryByTeamId(params: { teamId: string; dateRange: string }): Promise<ChecksSummary>;\n\tdeleteChecks(params: { monitorId: string; teamId: string }): Promise<number>;\n\tdeleteChecksByTeamId(params: { teamId: string }): Promise<number>;\n\tdeleteOlderThan(date: Date): Promise<number>;\n}\n\nexport class CheckService implements ICheckService {\n\tstatic SERVICE_NAME = SERVICE_NAME;\n\n\tprivate monitorsRepository: IMonitorsRepository;\n\tprivate checksRepository: IChecksRepository;\n\tprivate logger: ILogger;\n\tconstructor(monitorsRepository: IMonitorsRepository, logger: ILogger, checksRepository: IChecksRepository) {\n\t\tthis.monitorsRepository = monitorsRepository;\n\t\tthis.logger = logger;\n\t\tthis.checksRepository = checksRepository;\n\t}\n\n\tget serviceName() {\n\t\treturn CheckService.SERVICE_NAME;\n\t}\n\n\tcreateChecks = async (checks: Check[]) => {\n\t\treturn this.checksRepository.createChecks(checks);\n\t};\n\n\tbuildCheck = (statusResponse: MonitorStatusResponse<MonitorPayloadMap[keyof MonitorPayloadMap]>): Check | undefined => {\n\t\tconst { monitorId, teamId, type, status, responseTime, code, message, payload, timings } = statusResponse;\n\n\t\tconst now = new Date().toISOString();\n\t\tconst check: Check = {\n\t\t\tid: new Types.ObjectId().toString(),\n\t\t\tcreatedAt: now,\n\t\t\tupdatedAt: now,\n\t\t\tmetadata: {\n\t\t\t\tmonitorId,\n\t\t\t\tteamId,\n\t\t\t\ttype,\n\t\t\t},\n\t\t\tstatus,\n\t\t\tstatusCode: code,\n\t\t\tresponseTime: responseTime || 0,\n\t\t\ttimings: timings,\n\t\t\tmessage,\n\t\t};\n\n\t\tif (type === \"pagespeed\") {\n\t\t\tconst pageSpeedPayload = payload as PageSpeedStatusPayload | undefined;\n\t\t\tif (!pageSpeedPayload) {\n\t\t\t\tthis.logger.warn({\n\t\t\t\t\tmessage: \"Failed to build check\",\n\t\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\t\tmethod: \"buildCheck\",\n\t\t\t\t});\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\tconst categories = pageSpeedPayload.lighthouseResult?.categories ?? {};\n\t\t\tconst audits = pageSpeedPayload.lighthouseResult?.audits ?? {};\n\t\t\tconst mapAudit = (audit: ILighthouseAudit | undefined) => {\n\t\t\t\tif (!audit || typeof audit !== \"object\") {\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\t\t\t\treturn {\n\t\t\t\t\tid: audit.id,\n\t\t\t\t\ttitle: audit.title,\n\t\t\t\t\tscore: typeof audit.score === \"number\" ? audit.score : (audit.score ?? null),\n\t\t\t\t\tdisplayValue: audit.displayValue,\n\t\t\t\t\tnumericValue: typeof audit.numericValue === \"number\" ? audit.numericValue : undefined,\n\t\t\t\t\tnumericUnit: audit.numericUnit,\n\t\t\t\t};\n\t\t\t};\n\t\t\tcheck.accessibility = (categories?.accessibility?.score || 0) * 100;\n\t\t\tcheck.bestPractices = (categories?.[\"best-practices\"]?.score || 0) * 100;\n\t\t\tcheck.seo = (categories?.seo?.score || 0) * 100;\n\t\t\tcheck.performance = (categories?.performance?.score || 0) * 100;\n\t\t\tcheck.audits = {\n\t\t\t\tcls: mapAudit(audits?.[\"cumulative-layout-shift\"]),\n\t\t\t\tsi: mapAudit(audits?.[\"speed-index\"]),\n\t\t\t\tfcp: mapAudit(audits?.[\"first-contentful-paint\"]),\n\t\t\t\tlcp: mapAudit(audits?.[\"largest-contentful-paint\"]),\n\t\t\t\ttbt: mapAudit(audits?.[\"total-blocking-time\"]),\n\t\t\t};\n\t\t}\n\n\t\tif (type === \"hardware\") {\n\t\t\tconst hardwarePayload = payload as HardwareStatusPayload | undefined;\n\t\t\tconst { cpu, memory, disk, host, net } = hardwarePayload?.data ?? {};\n\t\t\tconst errorsSource = Array.isArray(hardwarePayload?.errors)\n\t\t\t\t? hardwarePayload?.errors\n\t\t\t\t: (hardwarePayload?.errors as { errors?: CheckErrorInfo[] } | undefined)?.errors;\n\t\t\tcheck.cpu = cpu;\n\t\t\tcheck.memory = memory;\n\t\t\tcheck.disk = disk;\n\t\t\tcheck.host = host;\n\t\t\tcheck.errors = errorsSource;\n\t\t\tcheck.capture = hardwarePayload?.capture;\n\t\t\tcheck.net = net;\n\t\t}\n\t\treturn check;\n\t};\n\n\tgetChecksByMonitor = async ({\n\t\tmonitorId,\n\t\tteamId,\n\t\tsortOrder,\n\t\tdateRange,\n\t\tfilter,\n\t\tpage,\n\t\trowsPerPage,\n\t\tstatus,\n\t}: {\n\t\tmonitorId: string;\n\t\tteamId: string;\n\t\tsortOrder: string;\n\t\tdateRange: string;\n\t\tpage: number;\n\t\trowsPerPage: number;\n\t\tstatus?: boolean;\n\t\tfilter?: string;\n\t}) => {\n\t\tif (!monitorId) {\n\t\t\tthrow new AppError({ message: \"No monitor ID in request\", service: SERVICE_NAME, method: \"getChecksByMonitor\", status: 400 });\n\t\t}\n\t\tif (!teamId) {\n\t\t\tthrow new AppError({ message: \"No team ID in request\", service: SERVICE_NAME, method: \"getChecksByMonitor\", status: 400 });\n\t\t}\n\n\t\t// For verification, throws an error if monitor doesn't belong to team\n\t\tawait this.monitorsRepository.findById(monitorId, teamId);\n\n\t\tconst parsedPage = page ?? 0;\n\t\tconst parsedRowsPerPage = rowsPerPage ?? 5;\n\n\t\tconst result = await this.checksRepository.findByMonitorId(monitorId, sortOrder, dateRange, filter, parsedPage, parsedRowsPerPage, status);\n\n\t\treturn result;\n\t};\n\n\tgetChecksByTeam = async ({\n\t\tteamId,\n\t\tsortOrder,\n\t\tdateRange,\n\t\tfilter,\n\t\tpage,\n\t\trowsPerPage,\n\t}: {\n\t\tteamId: string;\n\t\tsortOrder: string;\n\t\tdateRange: string;\n\t\tpage: number;\n\t\trowsPerPage: number;\n\t\tfilter?: string;\n\t}) => {\n\t\tconst parsedPage = page ?? 0;\n\t\tconst parsedRowsPerPage = rowsPerPage ?? 5;\n\n\t\tconst checkData = await this.checksRepository.findByTeamId(sortOrder, dateRange, filter, parsedPage, parsedRowsPerPage, teamId);\n\t\treturn checkData;\n\t};\n\n\tgetChecksSummaryByTeamId = async ({ teamId, dateRange }: { teamId: string; dateRange: string }) => {\n\t\tconst summary = await this.checksRepository.findSummaryByTeamId(teamId, dateRange);\n\t\treturn summary;\n\t};\n\n\tdeleteChecks = async ({ monitorId, teamId }: { monitorId: string; teamId: string }) => {\n\t\tawait this.monitorsRepository.findById(monitorId, teamId);\n\n\t\tconst deletedCount = await this.checksRepository.deleteByMonitorId(monitorId);\n\t\treturn deletedCount;\n\t};\n\tdeleteChecksByTeamId = async ({ teamId }: { teamId: string }) => {\n\t\tconst deletedCount = await this.checksRepository.deleteByTeamId(teamId);\n\t\treturn deletedCount;\n\t};\n\n\tdeleteOlderThan = async (date: Date) => {\n\t\tconst deletedCount = await this.checksRepository.deleteOlderThan(date);\n\t\treturn deletedCount;\n\t};\n}\n"
  },
  {
    "path": "server/src/service/business/diagnosticService.ts",
    "content": "import v8 from \"v8\";\nimport os from \"os\";\n\nconst SERVICE_NAME = \"diagnosticService\";\n\nexport interface IDiagnosticService {\n\tgetCPUUsage(): Promise<{ userUsageMs: number; systemUsageMs: number; usagePercentage: number }>;\n\tgetSystemStats(): Promise<{\n\t\tosStats: { freeMemoryBytes: number; totalMemoryBytes: number };\n\t\tmemoryUsage: Record<keyof NodeJS.MemoryUsage, number>;\n\t\tcpuUsage: { userUsageMs: number; systemUsageMs: number; usagePercentage: number };\n\t\tv8HeapStats: { totalHeapSizeBytes: number; usedHeapSizeBytes: number; heapSizeLimitBytes: number };\n\t\teventLoopDelayMs: number;\n\t\tuptimeMs: number;\n\t}>;\n}\n\nexport class DiagnosticService implements IDiagnosticService {\n\tstatic SERVICE_NAME = SERVICE_NAME;\n\n\tconstructor() {\n\t\t/**\n\t\t * Performance Observer for monitoring system performance metrics.\n\t\t * Clears performance marks after each measurement to prevent memory leaks.\n\t\t */\n\t\tconst obs = new PerformanceObserver((items) => {\n\t\t\titems.getEntries();\n\t\t\tperformance.clearMarks();\n\t\t});\n\t\tobs.observe({ entryTypes: [\"measure\"] });\n\t}\n\n\tget serviceName() {\n\t\treturn DiagnosticService.SERVICE_NAME;\n\t}\n\n\tgetCPUUsage = async () => {\n\t\tconst startUsage = process.cpuUsage();\n\t\tconst timingPeriod = 1000; // measured in ms\n\t\tawait new Promise((resolve) => setTimeout(resolve, timingPeriod));\n\t\tconst endUsage = process.cpuUsage(startUsage);\n\t\tconst cpuUsage = {\n\t\t\tuserUsageMs: endUsage.user / 1000,\n\t\t\tsystemUsageMs: endUsage.system / 1000,\n\t\t\tusagePercentage: ((endUsage.user + endUsage.system) / 1000 / timingPeriod) * 100,\n\t\t};\n\t\treturn cpuUsage;\n\t};\n\n\tgetSystemStats = async () => {\n\t\t// Memory Usage\n\t\tconst totalMemory = os.totalmem();\n\t\tconst freeMemory = os.freemem();\n\n\t\tconst osStats = {\n\t\t\tfreeMemoryBytes: freeMemory, // bytes\n\t\t\ttotalMemoryBytes: totalMemory, // bytes\n\t\t};\n\n\t\tconst used = process.memoryUsage();\n\n\t\t// In MB\n\t\tconst memoryUsage: Record<keyof NodeJS.MemoryUsage, number> = {\n\t\t\trss: Math.round((used.rss / 1024 / 1024) * 100) / 100,\n\t\t\theapTotal: Math.round((used.heapTotal / 1024 / 1024) * 100) / 100,\n\t\t\theapUsed: Math.round((used.heapUsed / 1024 / 1024) * 100) / 100,\n\t\t\texternal: Math.round((used.external / 1024 / 1024) * 100) / 100,\n\t\t\tarrayBuffers: Math.round((used.arrayBuffers / 1024 / 1024) * 100) / 100,\n\t\t};\n\n\t\t// CPU Usage\n\t\tconst cpuMetrics = await this.getCPUUsage();\n\n\t\t// V8 Heap Statistics\n\t\tconst heapStats = v8.getHeapStatistics();\n\t\tconst v8Metrics = {\n\t\t\ttotalHeapSizeBytes: heapStats.total_heap_size, // bytes\n\t\t\tusedHeapSizeBytes: heapStats.used_heap_size, // bytes\n\t\t\theapSizeLimitBytes: heapStats.heap_size_limit, // bytes\n\t\t};\n\n\t\t// Event Loop Delay\n\t\tlet eventLoopDelay = 0;\n\t\tperformance.mark(\"start\");\n\t\tawait new Promise((resolve) => setTimeout(resolve, 0));\n\t\tperformance.mark(\"end\");\n\t\tperformance.measure(\"eventLoopDelay\", \"start\", \"end\");\n\t\tconst entries = performance.getEntriesByName(\"eventLoopDelay\");\n\t\tif (entries.length > 0 && entries[0] !== undefined) {\n\t\t\teventLoopDelay = entries[0].duration;\n\t\t}\n\n\t\t// Uptime\n\t\tconst uptimeMs = process.uptime() * 1000; // ms\n\n\t\t// Combine Metrics\n\t\tconst diagnostics = {\n\t\t\tosStats,\n\t\t\tmemoryUsage,\n\t\t\tcpuUsage: cpuMetrics,\n\t\t\tv8HeapStats: v8Metrics,\n\t\t\teventLoopDelayMs: eventLoopDelay,\n\t\t\tuptimeMs,\n\t\t};\n\n\t\treturn diagnostics;\n\t};\n}\n"
  },
  {
    "path": "server/src/service/business/geoChecksService.ts",
    "content": "import type { Monitor, GeoCheck } from \"@/types/index.js\";\nimport type { GeoCheckResult, GeoContinent } from \"@/types/geoCheck.js\";\nimport { Types } from \"mongoose\";\nimport type { FlatGeoChecksQueryResult, IGeoChecksRepository } from \"@/repositories/index.js\";\nimport type { IMonitorsRepository } from \"@/repositories/index.js\";\nimport type { IGlobalPingService } from \"@/service/infrastructure/globalPingService.js\";\nimport type { ILogger } from \"@/utils/logger.js\";\nimport { AppError } from \"@/utils/AppError.js\";\n\nconst SERVICE_NAME = \"GeoChecksService\";\n\nexport interface IGeoChecksService {\n\treadonly serviceName: string;\n\tbuildGeoCheck(monitor: Monitor): Promise<GeoCheck | null>;\n\tcreateGeoChecks(geoChecks: GeoCheck[]): Promise<GeoCheck[]>;\n\tgetGeoChecksByMonitor(args: {\n\t\tmonitorId: string;\n\t\tteamId: string;\n\t\tsortOrder: string;\n\t\tdateRange: string;\n\t\tpage?: number;\n\t\trowsPerPage?: number;\n\t\tcontinent: GeoContinent | GeoContinent[];\n\t}): Promise<FlatGeoChecksQueryResult>;\n}\n\nexport class GeoChecksService implements IGeoChecksService {\n\tstatic SERVICE_NAME = SERVICE_NAME;\n\n\tprivate logger: ILogger;\n\tprivate geoChecksRepository: IGeoChecksRepository;\n\tprivate globalPingService: IGlobalPingService;\n\tprivate monitorsRepository: IMonitorsRepository;\n\n\tconstructor({\n\t\tlogger,\n\t\tgeoChecksRepository,\n\t\tglobalPingService,\n\t\tmonitorsRepository,\n\t}: {\n\t\tlogger: ILogger;\n\t\tgeoChecksRepository: IGeoChecksRepository;\n\t\tglobalPingService: IGlobalPingService;\n\t\tmonitorsRepository: IMonitorsRepository;\n\t}) {\n\t\tthis.logger = logger;\n\t\tthis.geoChecksRepository = geoChecksRepository;\n\t\tthis.globalPingService = globalPingService;\n\t\tthis.monitorsRepository = monitorsRepository;\n\t}\n\n\tget serviceName() {\n\t\treturn GeoChecksService.SERVICE_NAME;\n\t}\n\n\tasync buildGeoCheck(monitor: Monitor): Promise<GeoCheck | null> {\n\t\ttry {\n\t\t\tif (!monitor.url) {\n\t\t\t\tthis.logger.warn({\n\t\t\t\t\tmessage: \"Monitor missing URL for geo check\",\n\t\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\t\tmethod: \"buildGeoCheck\",\n\t\t\t\t\tdetails: { monitorId: monitor.id },\n\t\t\t\t});\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tif (!monitor.geoCheckLocations || monitor.geoCheckLocations.length === 0) {\n\t\t\t\tthis.logger.warn({\n\t\t\t\t\tmessage: \"Monitor missing geo check locations\",\n\t\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\t\tmethod: \"buildGeoCheck\",\n\t\t\t\t\tdetails: { monitorId: monitor.id },\n\t\t\t\t});\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\t// Step 1: Create measurement request\n\t\t\tconst measurementId = await this.globalPingService.createMeasurement(monitor.type, monitor.url, monitor.geoCheckLocations);\n\n\t\t\tif (!measurementId) {\n\t\t\t\t// GlobalPing API is down, skip this check\n\t\t\t\tthis.logger.debug({\n\t\t\t\t\tmessage: \"Skipping geo check due to API unavailability\",\n\t\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\t\tmethod: \"buildGeoCheck\",\n\t\t\t\t});\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\t// Step 2: Poll for results\n\t\t\tconst results = await this.globalPingService.pollForResults(measurementId);\n\n\t\t\tif (results.length === 0) {\n\t\t\t\t// No successful results (all locations timed out or failed)\n\t\t\t\tthis.logger.debug({\n\t\t\t\t\tmessage: \"No successful geo check results\",\n\t\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\t\tmethod: \"buildGeoCheck\",\n\t\t\t\t});\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\t// Step 3: Build GeoCheck document\n\t\t\tconst geoCheck = this.createGeoCheckDocument(monitor, results);\n\n\t\t\tthis.logger.debug({\n\t\t\t\tmessage: `Geo check completed for monitor ${monitor.id}`,\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"buildGeoCheck\",\n\t\t\t});\n\n\t\t\treturn geoCheck;\n\t\t} catch (error: unknown) {\n\t\t\tthis.logger.error({\n\t\t\t\tmessage: \"Error executing geo check\",\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"buildGeoCheck\",\n\t\t\t\tdetails: { monitorId: monitor.id, error: error instanceof Error ? error.message : \"Unknown error\" },\n\t\t\t\tstack: error instanceof Error ? error.stack : undefined,\n\t\t\t});\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tprivate createGeoCheckDocument(monitor: Monitor, results: GeoCheckResult[]): GeoCheck {\n\t\tconst now = new Date();\n\t\tconst ttl = 90 * 24 * 60 * 60 * 1000; // 90 days in ms\n\t\tconst expiryDate = new Date(now.getTime() + ttl);\n\n\t\treturn {\n\t\t\tid: new Types.ObjectId().toString(),\n\t\t\tmetadata: {\n\t\t\t\tmonitorId: monitor.id,\n\t\t\t\tteamId: monitor.teamId,\n\t\t\t\ttype: monitor.type,\n\t\t\t},\n\t\t\tresults,\n\t\t\texpiry: expiryDate.toISOString(),\n\t\t\t__v: 0,\n\t\t\tcreatedAt: now.toISOString(),\n\t\t\tupdatedAt: now.toISOString(),\n\t\t};\n\t}\n\n\tcreateGeoChecks = async (geoChecks: GeoCheck[]) => {\n\t\treturn this.geoChecksRepository.createGeoChecks(geoChecks);\n\t};\n\n\tgetGeoChecksByMonitor = async ({\n\t\tmonitorId,\n\t\tteamId,\n\t\tsortOrder,\n\t\tdateRange,\n\t\tpage,\n\t\trowsPerPage,\n\t\tcontinent,\n\t}: {\n\t\tmonitorId: string;\n\t\tteamId: string;\n\t\tsortOrder: string;\n\t\tdateRange: string;\n\t\tpage?: number;\n\t\trowsPerPage?: number;\n\t\tcontinent: GeoContinent | GeoContinent[];\n\t}) => {\n\t\tif (!monitorId) {\n\t\t\tthrow new AppError({\n\t\t\t\tmessage: \"No monitor ID in request\",\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"getGeoChecksByMonitor\",\n\t\t\t\tstatus: 400,\n\t\t\t});\n\t\t}\n\t\tif (!teamId) {\n\t\t\tthrow new AppError({\n\t\t\t\tmessage: \"No team ID in request\",\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"getGeoChecksByMonitor\",\n\t\t\t\tstatus: 400,\n\t\t\t});\n\t\t}\n\n\t\tconst monitor = await this.monitorsRepository.findById(monitorId, teamId);\n\t\tif (!monitor) {\n\t\t\tthrow new AppError({\n\t\t\t\tmessage: `Monitor with ID ${monitorId} not found.`,\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"getGeoChecksByMonitor\",\n\t\t\t\tstatus: 404,\n\t\t\t});\n\t\t}\n\n\t\tconst continents = continent ? (Array.isArray(continent) ? continent : [continent]) : undefined;\n\t\tconst parsedPage = page || 0;\n\t\tconst parsedRowsPerPage = rowsPerPage || 5;\n\t\tconst result = await this.geoChecksRepository.findByMonitorId(monitorId, sortOrder, dateRange, parsedPage, parsedRowsPerPage, continents);\n\t\treturn result;\n\t};\n}\n"
  },
  {
    "path": "server/src/service/business/incidentService.ts",
    "content": "const SERVICE_NAME = \"incidentService\";\nimport type { Monitor } from \"@/types/monitor.js\";\nimport type { MonitorStatusResponse } from \"@/types/network.js\";\nimport { AppError } from \"@/utils/AppError.js\";\nimport { getDateForRange } from \"@/utils/dataUtils.js\";\nimport type { IIncidentsRepository, IMonitorsRepository, IUsersRepository } from \"@/repositories/index.js\";\nimport type { Incident, IncidentSummary, User } from \"@/types/index.js\";\nimport type { MonitorActionDecision } from \"@/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.js\";\nimport type { INotificationMessageBuilder } from \"@/service/infrastructure/notificationMessageBuilder.js\";\nimport type { ILogger } from \"@/utils/logger.js\";\n\nexport interface IIncidentService {\n\thandleIncident(\n\t\tmonitor: Monitor,\n\t\tcode: number,\n\t\tdecision: MonitorActionDecision,\n\t\tmonitorStatusResponse?: MonitorStatusResponse\n\t): Promise<Incident | null>;\n\tresolveIncident(incidentId: string, userId: string, teamId: string, comment?: string, userEmail?: string): Promise<Incident>;\n\tgetIncidentsByTeam(\n\t\tteamId: string,\n\t\tsortOrder: string,\n\t\tdateRange: string,\n\t\tpage: number,\n\t\trowsPerPage: number,\n\t\tstatus: boolean | undefined,\n\t\tmonitorId: string | undefined,\n\t\tresolutionType: string | undefined\n\t): Promise<{ incidents: Incident[]; count: number }>;\n\tgetIncidentSummary(teamId: string, limit?: number): Promise<IncidentSummary>;\n\tgetIncidentById(incidentId: string, teamId: string): Promise<{ incident: Incident; monitor: Monitor; user: User | null }>;\n}\n\nexport class IncidentService implements IIncidentService {\n\tstatic SERVICE_NAME = SERVICE_NAME;\n\n\tprivate logger: ILogger;\n\tprivate incidentsRepository: IIncidentsRepository;\n\tprivate monitorsRepository: IMonitorsRepository;\n\tprivate usersRepository: IUsersRepository;\n\tprivate notificationMessageBuilder: INotificationMessageBuilder;\n\n\tconstructor(\n\t\tlogger: ILogger,\n\t\tincidentsRepository: IIncidentsRepository,\n\t\tmonitorsRepository: IMonitorsRepository,\n\t\tusersRepository: IUsersRepository,\n\t\tnotificationMessageBuilder: INotificationMessageBuilder\n\t) {\n\t\tthis.logger = logger;\n\t\tthis.incidentsRepository = incidentsRepository;\n\t\tthis.monitorsRepository = monitorsRepository;\n\t\tthis.usersRepository = usersRepository;\n\t\tthis.notificationMessageBuilder = notificationMessageBuilder;\n\t}\n\n\tget serviceName() {\n\t\treturn IncidentService.SERVICE_NAME;\n\t}\n\n\thandleIncident = async (\n\t\tmonitor: Monitor,\n\t\tcode: number,\n\t\tdecision: MonitorActionDecision,\n\t\tmonitorStatusResponse?: MonitorStatusResponse\n\t): Promise<Incident | null> => {\n\t\tif (!decision.shouldCreateIncident && !decision.shouldResolveIncident) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst activeIncident = await this.incidentsRepository.findActiveByMonitorId(monitor.id, monitor.teamId);\n\n\t\tif (decision.shouldCreateIncident) {\n\t\t\tif (activeIncident) {\n\t\t\t\treturn activeIncident;\n\t\t\t} else {\n\t\t\t\tlet statusCode = code;\n\t\t\t\tlet message: string | undefined;\n\n\t\t\t\t// For threshold breaches, use 9999 status code and build descriptive message\n\t\t\t\tif (decision.incidentReason === \"threshold_breach\") {\n\t\t\t\t\tstatusCode = 9999;\n\t\t\t\t\tmessage = this.buildThresholdBreachMessage(monitor, monitorStatusResponse);\n\t\t\t\t}\n\n\t\t\t\tconst incident = {\n\t\t\t\t\tmonitorId: monitor.id,\n\t\t\t\t\tteamId: monitor.teamId,\n\t\t\t\t\tstartTime: Date.now().toString(),\n\t\t\t\t\tstatus: true,\n\t\t\t\t\tstatusCode,\n\t\t\t\t\tmessage,\n\t\t\t\t};\n\t\t\t\treturn await this.incidentsRepository.create(incident);\n\t\t\t}\n\t\t}\n\n\t\tif (decision.shouldResolveIncident) {\n\t\t\tif (!activeIncident) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tactiveIncident.status = false;\n\t\t\tactiveIncident.endTime = Date.now().toString();\n\t\t\tactiveIncident.resolutionType = \"automatic\";\n\t\t\treturn await this.incidentsRepository.updateById(activeIncident.id, activeIncident.teamId, activeIncident);\n\t\t}\n\n\t\treturn null;\n\t};\n\n\tprivate buildThresholdBreachMessage(monitor: Monitor, monitorStatusResponse?: MonitorStatusResponse): string {\n\t\tif (!monitorStatusResponse) {\n\t\t\treturn \"Threshold breach detected\";\n\t\t}\n\n\t\tconst breaches = this.notificationMessageBuilder.extractThresholdBreaches(monitor, monitorStatusResponse);\n\n\t\tif (breaches.length === 0) {\n\t\t\treturn \"Threshold breach detected\";\n\t\t}\n\n\t\treturn breaches.map((b) => `${b.metric.toUpperCase()}: ${b.formattedValue} (threshold: ${b.threshold}${b.unit})`).join(\", \");\n\t}\n\n\tresolveIncident = async (incidentId: string, userId: string, teamId: string, comment?: string, userEmail?: string) => {\n\t\ttry {\n\t\t\tif (!incidentId) {\n\t\t\t\tthrow new AppError({ message: \"No incident ID in request\", service: SERVICE_NAME, method: \"resolveIncident\" });\n\t\t\t}\n\n\t\t\tif (!userId) {\n\t\t\t\tthrow new AppError({ message: \"No user ID in request\", service: SERVICE_NAME, method: \"resolveIncident\" });\n\t\t\t}\n\n\t\t\tif (!teamId) {\n\t\t\t\tthrow new AppError({ message: \"No team ID in request\", service: SERVICE_NAME, method: \"resolveIncident\" });\n\t\t\t}\n\n\t\t\tconst incident = await this.incidentsRepository.findActiveByIncidentId(incidentId, teamId);\n\n\t\t\tif (!incident) {\n\t\t\t\tthrow new AppError({ message: \"Incident not found\", service: SERVICE_NAME, method: \"resolveIncident\" });\n\t\t\t}\n\n\t\t\tif (incident.status === false) {\n\t\t\t\tthrow new AppError({ message: \"Incident is already resolved\", service: SERVICE_NAME, method: \"resolveIncident\" });\n\t\t\t}\n\n\t\t\tincident.resolutionType = \"manual\";\n\t\t\tincident.status = false;\n\t\t\tincident.resolvedBy = userId;\n\t\t\tincident.resolvedByEmail = userEmail || null;\n\t\t\tincident.comment = comment || null;\n\t\t\tincident.endTime = Date.now().toString();\n\n\t\t\tconst resolvedIncident = await this.incidentsRepository.updateById(incident.id, teamId, incident);\n\n\t\t\tthis.logger.debug({\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"resolveIncidentManually\",\n\t\t\t\tmessage: `Incident manually resolved by user`,\n\t\t\t\tdetails: { incidentId: resolvedIncident.id },\n\t\t\t});\n\n\t\t\treturn resolvedIncident;\n\t\t} catch (error: unknown) {\n\t\t\tthis.logger.error({\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"resolveIncident\",\n\t\t\t\tmessage: error instanceof Error ? error.message : \"Unknown error\",\n\t\t\t\tdetails: { id: incidentId },\n\t\t\t\tstack: error instanceof Error ? error.stack : undefined,\n\t\t\t});\n\t\t\tthrow error;\n\t\t}\n\t};\n\n\tgetIncidentsByTeam = async (\n\t\tteamId: string,\n\t\tsortOrder: string,\n\t\tdateRange: string,\n\t\tpage: number,\n\t\trowsPerPage: number,\n\t\tstatus: boolean | undefined,\n\t\tmonitorId: string | undefined,\n\t\tresolutionType: string | undefined\n\t) => {\n\t\ttry {\n\t\t\tif (!teamId) {\n\t\t\t\tthrow new AppError({ message: \"No team ID in request\", service: SERVICE_NAME, method: \"getIncidentsByTeam\", status: 400 });\n\t\t\t}\n\n\t\t\tconst startDate = getDateForRange(dateRange);\n\n\t\t\tconst parsedPage = page ?? 0;\n\t\t\tconst parsedRowsPerPage = rowsPerPage ?? 20;\n\n\t\t\tconst incidents = await this.incidentsRepository.findByTeamId(\n\t\t\t\tteamId,\n\t\t\t\tstartDate,\n\t\t\t\tparsedPage,\n\t\t\t\tparsedRowsPerPage,\n\t\t\t\tsortOrder,\n\t\t\t\tstatus,\n\t\t\t\tmonitorId,\n\t\t\t\tresolutionType\n\t\t\t);\n\n\t\t\tconst count = await this.incidentsRepository.countByTeamId(teamId, startDate, status, monitorId, resolutionType);\n\n\t\t\treturn { incidents, count };\n\t\t} catch (error: unknown) {\n\t\t\tthis.logger.error({\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"getIncidentsByTeam\",\n\t\t\t\tmessage: error instanceof Error ? error.message : \"Unknown error\",\n\t\t\t\tdetails: { teamId },\n\t\t\t\tstack: error instanceof Error ? error.stack : undefined,\n\t\t\t});\n\t\t\tthrow error;\n\t\t}\n\t};\n\n\tgetIncidentSummary = async (teamId: string, limit?: number) => {\n\t\ttry {\n\t\t\tif (!teamId) {\n\t\t\t\tthrow new AppError({ message: \"No team ID in request\", service: SERVICE_NAME, method: \"getIncidentSummary\", status: 400 });\n\t\t\t}\n\n\t\t\tconst parsedLimit = limit ?? 10;\n\t\t\tconst summary = await this.incidentsRepository.findSummaryByTeamId(teamId, parsedLimit);\n\n\t\t\treturn summary;\n\t\t} catch (error: unknown) {\n\t\t\tthis.logger.error({\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"getIncidentSummary\",\n\t\t\t\tmessage: error instanceof Error ? error.message : \"Unknown error\",\n\t\t\t\tdetails: { teamId },\n\t\t\t\tstack: error instanceof Error ? error.stack : undefined,\n\t\t\t});\n\t\t\tthrow error;\n\t\t}\n\t};\n\n\tgetIncidentById = async (incidentId: string, teamId: string) => {\n\t\ttry {\n\t\t\tconst incident = await this.incidentsRepository.findById(incidentId, teamId);\n\t\t\tconst monitor = await this.monitorsRepository.findById(incident.monitorId, teamId);\n\t\t\tlet user = null;\n\t\t\tif (incident.resolvedBy) {\n\t\t\t\tuser = await this.usersRepository.findById(incident.resolvedBy);\n\t\t\t}\n\t\t\treturn { incident, monitor, user };\n\t\t} catch (error: unknown) {\n\t\t\tthis.logger.error({\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"getIncidentById\",\n\t\t\t\tmessage: error instanceof Error ? error.message : \"Unknown error\",\n\t\t\t\tdetails: { incidentId },\n\t\t\t\tstack: error instanceof Error ? error.stack : undefined,\n\t\t\t});\n\t\t\tthrow error;\n\t\t}\n\t};\n}\n"
  },
  {
    "path": "server/src/service/business/inviteService.ts",
    "content": "import type { Invite, UserRole } from \"@/types/index.js\";\nimport { canManageRole } from \"@/types/user.js\";\nimport type { IInvitesRepository } from \"@/repositories/index.js\";\nimport { AppError } from \"@/utils/AppError.js\";\nimport { ISettingsService } from \"../system/settingsService.js\";\nimport { IEmailService } from \"../infrastructure/emailService.js\";\n\nconst SERVICE_NAME = \"inviteService\";\n\nexport interface IInviteService {\n\tgetInviteToken(params: { invite: Partial<Invite>; teamId: string; userRoles: UserRole[] }): Promise<Invite>;\n\tsendInviteEmail(params: { invite: Partial<Invite>; firstName: string; userRoles: UserRole[] }): Promise<void>;\n\tverifyInviteToken(params: { inviteToken: string }): Promise<Invite>;\n}\n\nexport class InviteService implements IInviteService {\n\tstatic SERVICE_NAME = SERVICE_NAME;\n\n\tprivate settingsService: ISettingsService;\n\tprivate emailService: IEmailService;\n\tprivate invitesRepository: IInvitesRepository;\n\n\tconstructor({\n\t\tinvitesRepository,\n\t\tsettingsService,\n\t\temailService,\n\t}: {\n\t\tinvitesRepository: IInvitesRepository;\n\t\tsettingsService: ISettingsService;\n\t\temailService: IEmailService;\n\t}) {\n\t\tthis.invitesRepository = invitesRepository;\n\t\tthis.settingsService = settingsService;\n\t\tthis.emailService = emailService;\n\t}\n\n\tget serviceName() {\n\t\treturn InviteService.SERVICE_NAME;\n\t}\n\n\tgetInviteToken = async ({ invite, teamId, userRoles }: { invite: Partial<Invite>; teamId: string; userRoles: UserRole[] }) => {\n\t\tinvite.teamId = teamId;\n\n\t\tconst inviteRoles = invite.role ?? [];\n\n\t\tfor (const targetRole of inviteRoles) {\n\t\t\tconst canManage = userRoles.some((actorRole) => canManageRole(actorRole, targetRole));\n\t\t\tif (!canManage) {\n\t\t\t\tthrow new AppError({\n\t\t\t\t\tmessage: \"You do not have permission to create this invite\",\n\t\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\t\tmethod: \"getInviteToken\",\n\t\t\t\t\tstatus: 403,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tconst inviteToken = await this.invitesRepository.create(invite);\n\t\treturn inviteToken;\n\t};\n\n\tsendInviteEmail = async ({ invite, firstName, userRoles }: { invite: Partial<Invite>; firstName: string; userRoles: UserRole[] }) => {\n\t\tconst inviteRoles = invite.role ?? [];\n\t\tif (!invite.email) {\n\t\t\tthrow new AppError({\n\t\t\t\tmessage: \"Invite email is required to send an invite\",\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"sendInviteEmail\",\n\t\t\t\tstatus: 400,\n\t\t\t});\n\t\t}\n\n\t\tfor (const targetRole of inviteRoles) {\n\t\t\tconst canManage = userRoles.some((actorRole) => canManageRole(actorRole, targetRole));\n\t\t\tif (!canManage) {\n\t\t\t\tthrow new AppError({\n\t\t\t\t\tmessage: \"You do not have permission to create this invite\",\n\t\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\t\tmethod: \"sendInviteEmail\",\n\t\t\t\t\tstatus: 403,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tconst inviteToken = await this.invitesRepository.create(invite);\n\t\tconst { clientHost } = this.settingsService.getSettings();\n\n\t\tconst html = await this.emailService.buildEmail(\"employeeActivationTemplate\", {\n\t\t\tname: firstName,\n\t\t\tlink: `${clientHost}/register/${inviteToken.token}`,\n\t\t});\n\n\t\tif (!html) {\n\t\t\tthrow new AppError({\n\t\t\t\tmessage: \"Failed to build invite e-mail... Please verify your settings.\",\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"sendInviteEmail\",\n\t\t\t\tstatus: 500,\n\t\t\t});\n\t\t}\n\n\t\tconst result = await this.emailService.sendEmail(invite.email, \"Welcome to Uptime Monitor\", html);\n\t\tif (!result) {\n\t\t\tthrow new AppError({\n\t\t\t\tmessage: \"Failed to send invite e-mail... Please verify your settings.\",\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"sendInviteEmail\",\n\t\t\t\tstatus: 500,\n\t\t\t});\n\t\t}\n\t};\n\n\tverifyInviteToken = async ({ inviteToken }: { inviteToken: string }) => {\n\t\treturn await this.invitesRepository.findByToken(inviteToken);\n\t};\n}\n"
  },
  {
    "path": "server/src/service/business/maintenanceWindowService.ts",
    "content": "import { IMaintenanceWindowsRepository, IMonitorsRepository } from \"@/repositories/index.js\";\nimport type { DurationUnit, MaintenanceWindow } from \"@/types/index.js\";\nimport { AppError } from \"@/utils/AppError.js\";\n\nconst SERVICE_NAME = \"maintenanceWindowService\";\n\nexport interface IMaintenanceWindowService {\n\tcreateMaintenanceWindow(params: {\n\t\tteamId: string;\n\t\tmonitorIDs: string[];\n\t\tname: string;\n\t\tactive: boolean;\n\t\tduration: number;\n\t\tdurationUnit: DurationUnit;\n\t\trepeat: number;\n\t\tstart: string;\n\t\tend: string;\n\t}): Promise<void>;\n\tgetMaintenanceWindowById(params: { id: string; teamId: string }): Promise<MaintenanceWindow>;\n\tgetMaintenanceWindowsByTeamId(params: {\n\t\tteamId: string;\n\t\tactive?: boolean;\n\t\tpage?: number;\n\t\trowsPerPage?: number;\n\t\tfield?: string;\n\t\torder?: string;\n\t}): Promise<{ maintenanceWindows: MaintenanceWindow[]; maintenanceWindowCount: number }>;\n\tgetMaintenanceWindowsByMonitorId(params: { monitorId: string; teamId: string }): Promise<MaintenanceWindow[]>;\n\tdeleteMaintenanceWindow(params: { id: string; teamId: string }): Promise<MaintenanceWindow>;\n\teditMaintenanceWindow(params: { id: string; teamId: string; body: Partial<MaintenanceWindow> }): Promise<MaintenanceWindow>;\n}\n\nexport class MaintenanceWindowService implements IMaintenanceWindowService {\n\tstatic SERVICE_NAME = SERVICE_NAME;\n\tprivate monitorsRepository: IMonitorsRepository;\n\tprivate maintenanceWindowsRepository: IMaintenanceWindowsRepository;\n\n\tconstructor({\n\t\tmonitorsRepository,\n\t\tmaintenanceWindowsRepository,\n\t}: {\n\t\tmonitorsRepository: IMonitorsRepository;\n\t\tmaintenanceWindowsRepository: IMaintenanceWindowsRepository;\n\t}) {\n\t\tthis.monitorsRepository = monitorsRepository;\n\t\tthis.maintenanceWindowsRepository = maintenanceWindowsRepository;\n\t}\n\n\tget serviceName() {\n\t\treturn MaintenanceWindowService.SERVICE_NAME;\n\t}\n\n\tcreateMaintenanceWindow = async ({\n\t\tteamId,\n\t\tmonitorIDs,\n\t\tname,\n\t\tactive,\n\t\tduration,\n\t\tdurationUnit,\n\t\trepeat,\n\t\tstart,\n\t\tend,\n\t}: {\n\t\tteamId: string;\n\t\tmonitorIDs: string[];\n\t\tname: string;\n\t\tactive: boolean;\n\t\tduration: number;\n\t\tdurationUnit: DurationUnit;\n\t\trepeat: number;\n\t\tstart: string;\n\t\tend: string;\n\t}) => {\n\t\tconst monitors = await this.monitorsRepository.findByIds(monitorIDs);\n\n\t\tconst unauthorizedMonitors = monitors.filter((monitor) => monitor.teamId !== teamId);\n\n\t\tif (unauthorizedMonitors.length > 0) {\n\t\t\tthrow new AppError({\n\t\t\t\tmessage: \"Unauthorized to create maintenance window for one or more monitors\",\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"createMaintenanceWindow\",\n\t\t\t\tstatus: 403,\n\t\t\t});\n\t\t}\n\n\t\tconst dbTransactions = monitorIDs.map((monitorId: string) => {\n\t\t\treturn this.maintenanceWindowsRepository.create({\n\t\t\t\tteamId,\n\t\t\t\tmonitorId,\n\t\t\t\tname: name,\n\t\t\t\tactive: active,\n\t\t\t\tduration: duration,\n\t\t\t\tdurationUnit: durationUnit,\n\t\t\t\trepeat: repeat,\n\t\t\t\tstart: start,\n\t\t\t\tend: end,\n\t\t\t});\n\t\t});\n\t\tawait Promise.all(dbTransactions);\n\t};\n\n\tgetMaintenanceWindowById = async ({ id, teamId }: { id: string; teamId: string }) => {\n\t\treturn await this.maintenanceWindowsRepository.findById(id, teamId);\n\t};\n\n\tgetMaintenanceWindowsByTeamId = async ({\n\t\tteamId,\n\t\tactive,\n\t\tpage,\n\t\trowsPerPage,\n\t\tfield,\n\t\torder,\n\t}: {\n\t\tteamId: string;\n\t\tactive?: boolean;\n\t\tpage?: number;\n\t\trowsPerPage?: number;\n\t\tfield?: string;\n\t\torder?: string;\n\t}) => {\n\t\tpage = page ?? 0;\n\t\trowsPerPage = rowsPerPage ?? 10;\n\n\t\tconst maintenanceWindows = await this.maintenanceWindowsRepository.findByTeamId(teamId, page, rowsPerPage, field, order, active);\n\t\tconst maintenanceWindowCount = await this.maintenanceWindowsRepository.countByTeamId(teamId, active);\n\t\treturn { maintenanceWindows, maintenanceWindowCount };\n\t};\n\n\tgetMaintenanceWindowsByMonitorId = async ({ monitorId, teamId }: { monitorId: string; teamId: string }) => {\n\t\treturn await this.maintenanceWindowsRepository.findByMonitorId(monitorId, teamId);\n\t};\n\n\tdeleteMaintenanceWindow = async ({ id, teamId }: { id: string; teamId: string }) => {\n\t\treturn await this.maintenanceWindowsRepository.deleteById(id, teamId);\n\t};\n\n\teditMaintenanceWindow = async ({ id, teamId, body }: { id: string; teamId: string; body: Partial<MaintenanceWindow> }) => {\n\t\treturn await this.maintenanceWindowsRepository.updateById(id, teamId, body);\n\t};\n}\n"
  },
  {
    "path": "server/src/service/business/monitorService.ts",
    "content": "import { NormalizeData, NormalizeDataUptimeDetails } from \"@/utils/dataUtils.js\";\nimport { type Monitor } from \"@/types/index.js\";\nimport type {\n\tMonitorType,\n\tMonitorsWithChecksByTeamIdResult,\n\tUptimeDetailsResult,\n\tHardwareDetailsResult,\n\tPageSpeedDetailsResult,\n\tGamesMap,\n\tGroupedGeoCheckResult,\n} from \"@/types/monitor.js\";\nimport { supportsGeoCheck } from \"@/types/monitor.js\";\nimport type { GeoContinent } from \"@/types/geoCheck.js\";\nimport type {\n\tIChecksRepository,\n\tIGeoChecksRepository,\n\tIIncidentsRepository,\n\tIMonitorsRepository,\n\tIMonitorStatsRepository,\n\tIStatusPagesRepository,\n} from \"@/repositories/index.js\";\nimport demoMonitorsData from \"@/utils/demoMonitors.json\" with { type: \"json\" };\nimport { AppError } from \"@/utils/AppError.js\";\nimport type { ImportedMonitor } from \"@/validation/monitorValidation.js\";\nimport { ISuperSimpleQueue } from \"../infrastructure/SuperSimpleQueue/SuperSimpleQueue.js\";\nimport { IEmailService } from \"../infrastructure/emailService.js\";\nimport { ILogger } from \"@/utils/logger.js\";\n\nconst SERVICE_NAME = \"MonitorService\";\ntype DateRangeKey = \"recent\" | \"day\" | \"week\" | \"month\" | \"all\";\n\nexport interface IMonitorService {\n\treadonly serviceName: string;\n\n\t// create\n\tcreateMonitor(teamId: string, userId: string, body: Partial<Monitor>): Promise<void>;\n\tcreateMonitors(monitors: Array<Monitor>): Promise<Monitor[] | null>;\n\taddDemoMonitors(args: { userId: string; teamId: string }): Promise<Monitor[]>;\n\n\t// read\n\tgetUptimeDetailsById(args: { teamId: string; monitorId: string; dateRange: string }): Promise<UptimeDetailsResult>;\n\tgetHardwareDetailsById(args: { teamId: string; monitorId: string; dateRange: string }): Promise<HardwareDetailsResult>;\n\tgetPageSpeedDetailsById(args: { teamId: string; monitorId: string; dateRange: string }): Promise<PageSpeedDetailsResult>;\n\tgetGeoChecksByMonitorId(args: {\n\t\tteamId: string;\n\t\tmonitorId: string;\n\t\tdateRange: string;\n\t\tcontinents?: GeoContinent[];\n\t}): Promise<GroupedGeoCheckResult>;\n\tgetMonitorById(args: { teamId: string; monitorId: string }): Promise<Monitor>;\n\tgetMonitorsByTeamId(args: {\n\t\tteamId: string;\n\t\tlimit?: number;\n\t\ttype?: MonitorType | MonitorType[];\n\t\tpage?: number;\n\t\trowsPerPage?: number;\n\t\tfilter?: string;\n\t\tfield?: string;\n\t\torder?: \"asc\" | \"desc\";\n\t}): Promise<Monitor[] | null>;\n\tgetMonitorsWithChecksByTeamId(args: {\n\t\tteamId: string;\n\t\tlimit?: number;\n\t\ttype?: MonitorType | MonitorType[];\n\t\tpage?: number;\n\t\trowsPerPage?: number;\n\t\tfilter?: string;\n\t\tfield?: string;\n\t\torder?: \"asc\" | \"desc\";\n\t}): Promise<MonitorsWithChecksByTeamIdResult>;\n\tgetAllGames(): GamesMap;\n\tgetGroupsByTeamId(args: { teamId: string }): Promise<string[]>;\n\n\t// update\n\teditMonitor(args: { teamId: string; monitorId: string; body: Partial<Monitor> }): Promise<Monitor>;\n\tpauseMonitor(args: { teamId: string; monitorId: string }): Promise<Monitor>;\n\n\t// delete\n\tdeleteMonitor(args: { teamId: string; monitorId: string }): Promise<Monitor>;\n\tdeleteAllMonitors(args: { teamId: string }): Promise<number>;\n\n\t// other\n\texportMonitorsToJSON(args: { teamId: string }): Promise<Monitor[]>;\n\timportMonitorsFromJSON(args: { teamId: string; userId: string; monitors: ImportedMonitor[] }): Promise<{ imported: number; errors: string[] }>;\n}\n\nexport class MonitorService implements IMonitorService {\n\tstatic SERVICE_NAME = SERVICE_NAME;\n\n\tprivate jobQueue: ISuperSimpleQueue;\n\tprivate emailService: IEmailService;\n\tprivate logger: ILogger;\n\tprivate games: GamesMap;\n\tprivate monitorsRepository: IMonitorsRepository;\n\tprivate checksRepository: IChecksRepository;\n\tprivate geoChecksRepository: IGeoChecksRepository;\n\tprivate monitorStatsRepository: IMonitorStatsRepository;\n\tprivate statusPagesRepository: IStatusPagesRepository;\n\tprivate incidentsRepository: IIncidentsRepository;\n\n\tconstructor({\n\t\tjobQueue,\n\t\temailService,\n\t\tlogger,\n\t\tgames,\n\t\tmonitorsRepository,\n\t\tchecksRepository,\n\t\tgeoChecksRepository,\n\t\tmonitorStatsRepository,\n\t\tstatusPagesRepository,\n\t\tincidentsRepository,\n\t}: {\n\t\tjobQueue: ISuperSimpleQueue;\n\t\temailService: IEmailService;\n\t\tlogger: ILogger;\n\t\tgames: GamesMap;\n\t\tmonitorsRepository: IMonitorsRepository;\n\t\tchecksRepository: IChecksRepository;\n\t\tgeoChecksRepository: IGeoChecksRepository;\n\t\tmonitorStatsRepository: IMonitorStatsRepository;\n\t\tstatusPagesRepository: IStatusPagesRepository;\n\t\tincidentsRepository: IIncidentsRepository;\n\t}) {\n\t\tthis.jobQueue = jobQueue;\n\t\tthis.emailService = emailService;\n\t\tthis.logger = logger;\n\t\tthis.games = games;\n\t\tthis.monitorsRepository = monitorsRepository;\n\t\tthis.checksRepository = checksRepository;\n\t\tthis.geoChecksRepository = geoChecksRepository;\n\t\tthis.monitorStatsRepository = monitorStatsRepository;\n\t\tthis.statusPagesRepository = statusPagesRepository;\n\t\tthis.incidentsRepository = incidentsRepository;\n\t}\n\n\tget serviceName(): string {\n\t\treturn MonitorService.SERVICE_NAME;\n\t}\n\n\tprivate getDateRange = (dateRange: DateRangeKey) => {\n\t\tconst startDates = {\n\t\t\trecent: new Date(new Date().setHours(new Date().getHours() - 2)),\n\t\t\tday: new Date(new Date().setDate(new Date().getDate() - 1)),\n\t\t\tweek: new Date(new Date().setDate(new Date().getDate() - 7)),\n\t\t\tmonth: new Date(new Date().setMonth(new Date().getMonth() - 1)),\n\t\t\tall: new Date(0),\n\t\t};\n\t\treturn {\n\t\t\tstart: startDates[dateRange],\n\t\t\tend: new Date(),\n\t\t};\n\t};\n\n\tprivate getDateFormat = (dateRange: DateRangeKey): string => {\n\t\tconst formatLookup = {\n\t\t\trecent: \"%Y-%m-%dT%H:%M:00Z\",\n\t\t\tday: \"%Y-%m-%dT%H:00:00Z\",\n\t\t\tweek: \"%Y-%m-%dT00:00:00Z\",\n\t\t\tmonth: \"%Y-%m-%dT00:00:00Z\",\n\t\t\tall: \"%Y-%m-%dT00:00:00Z\",\n\t\t};\n\t\treturn formatLookup[dateRange];\n\t};\n\n\tcreateMonitor = async (teamId: string, userId: string, body: Monitor): Promise<void> => {\n\t\tconst monitor = await this.monitorsRepository.create(body, teamId, userId);\n\t\tif (!monitor) {\n\t\t\tthrow new AppError({ message: \"Failed to create monitor\", status: 500, service: SERVICE_NAME, method: \"createMonitor\" });\n\t\t}\n\n\t\tthis.jobQueue.addJob(monitor.id, monitor);\n\t};\n\n\tcreateMonitors = async (monitors: Array<Monitor>): Promise<Monitor[] | null> => {\n\t\tconst createdMonitors = await this.monitorsRepository.createMonitors(monitors);\n\t\tif (!monitors || monitors.length === 0) {\n\t\t\tthrow new AppError({ message: \"Failed to create monitors\", status: 500, service: SERVICE_NAME, method: \"createMonitors\" });\n\t\t}\n\n\t\tawait Promise.all(createdMonitors.map((monitor) => this.jobQueue.addJob(monitor.id, monitor)));\n\t\treturn createdMonitors;\n\t};\n\n\taddDemoMonitors = async ({ userId, teamId }: { userId: string; teamId: string }): Promise<Monitor[]> => {\n\t\tconst demoData = demoMonitorsData;\n\t\tconst monitors = demoData.map((monitor) => ({\n\t\t\tuserId,\n\t\t\tteamId,\n\t\t\tname: monitor.name,\n\t\t\tdescription: monitor.name,\n\t\t\ttype: \"http\" as const,\n\t\t\turl: monitor.url,\n\t\t\tinterval: 60000,\n\t\t}));\n\t\tconst demoMonitors = await this.monitorsRepository.createMonitors(monitors as unknown as Monitor[]);\n\n\t\tawait Promise.all(demoMonitors.map((monitor) => this.jobQueue.addJob(monitor.id, monitor)));\n\t\treturn demoMonitors;\n\t};\n\n\tgetUptimeDetailsById = async ({\n\t\tteamId,\n\t\tmonitorId,\n\t\tdateRange,\n\t}: {\n\t\tteamId: string;\n\t\tmonitorId: string;\n\t\tdateRange: string;\n\t}): Promise<UptimeDetailsResult> => {\n\t\tconst monitor = await this.monitorsRepository.findById(monitorId, teamId);\n\t\tif (!monitor) {\n\t\t\tthrow new AppError({ message: `Monitor with ID ${monitorId} not found.`, status: 404 });\n\t\t}\n\t\tconst rangeKey = (dateRange as DateRangeKey) ?? \"recent\";\n\t\tconst { start, end } = this.getDateRange(rangeKey);\n\t\tconst checksData = await this.checksRepository.findByDateRangeAndMonitorId(monitor.id, start, end, this.getDateFormat(rangeKey), {\n\t\t\ttype: monitor.type,\n\t\t});\n\t\tconst monitorStats = await this.monitorStatsRepository.findByMonitorId(monitor.id);\n\n\t\tif (\n\t\t\tchecksData.monitorType !== \"http\" &&\n\t\t\tchecksData.monitorType !== \"ping\" &&\n\t\t\tchecksData.monitorType !== \"docker\" &&\n\t\t\tchecksData.monitorType !== \"port\" &&\n\t\t\tchecksData.monitorType !== \"game\" &&\n\t\t\tchecksData.monitorType !== \"grpc\" &&\n\t\t\tchecksData.monitorType !== \"websocket\"\n\t\t) {\n\t\t\tthrow new AppError({ message: `${monitor.type} monitors are not supported for uptime details`, status: 400 });\n\t\t}\n\n\t\treturn {\n\t\t\tmonitorData: {\n\t\t\t\tmonitor,\n\t\t\t\tgroupedChecks: NormalizeDataUptimeDetails(checksData.groupedChecks, 10, 100),\n\t\t\t\tgroupedUpChecks: NormalizeDataUptimeDetails(checksData.groupedUpChecks, 10, 100),\n\t\t\t\tgroupedDownChecks: NormalizeDataUptimeDetails(checksData.groupedDownChecks, 10, 100),\n\t\t\t\tgroupedAvgResponseTime: checksData.avgResponseTime,\n\t\t\t\tgroupedUptimePercentage: checksData.uptimePercentage,\n\t\t\t},\n\t\t\tmonitorStats,\n\t\t};\n\t};\n\n\tgetHardwareDetailsById = async ({\n\t\tteamId,\n\t\tmonitorId,\n\t\tdateRange,\n\t}: {\n\t\tteamId: string;\n\t\tmonitorId: string;\n\t\tdateRange: string;\n\t}): Promise<HardwareDetailsResult> => {\n\t\tconst monitor = await this.monitorsRepository.findById(monitorId, teamId);\n\t\tif (!monitor) {\n\t\t\tthrow new AppError({ message: `Monitor with ID ${monitorId} not found.`, status: 404 });\n\t\t}\n\t\tif (monitor.type !== \"hardware\") {\n\t\t\tthrow new AppError({ message: `${monitor.type} monitors are not supported for hardware details`, status: 400 });\n\t\t}\n\n\t\tconst rangeKey = (dateRange as DateRangeKey) ?? \"recent\";\n\t\tconst { start, end } = this.getDateRange(rangeKey);\n\t\tconst checksData = await this.checksRepository.findByDateRangeAndMonitorId(monitor.id, start, end, this.getDateFormat(rangeKey), {\n\t\t\ttype: monitor.type,\n\t\t});\n\n\t\tif (checksData.monitorType !== \"hardware\") {\n\t\t\tthrow new AppError({ message: \"Unable to load hardware stats for this monitor\", status: 500 });\n\t\t}\n\n\t\tconst stats = {\n\t\t\taggregateData: checksData.aggregateData,\n\t\t\tupChecks: checksData.upChecks,\n\t\t\tchecks: checksData.checks,\n\t\t};\n\n\t\tconst monitorStats = await this.monitorStatsRepository.findByMonitorId(monitor.id);\n\n\t\treturn {\n\t\t\tmonitor,\n\t\t\tstats,\n\t\t\tmonitorStats,\n\t\t};\n\t};\n\n\tgetPageSpeedDetailsById = async ({\n\t\tteamId,\n\t\tmonitorId,\n\t\tdateRange,\n\t}: {\n\t\tteamId: string;\n\t\tmonitorId: string;\n\t\tdateRange: string;\n\t}): Promise<PageSpeedDetailsResult> => {\n\t\tconst monitor = await this.monitorsRepository.findById(monitorId, teamId);\n\t\tif (!monitor) {\n\t\t\tthrow new AppError({ message: `Monitor with ID ${monitorId} not found.`, status: 404 });\n\t\t}\n\t\tif (monitor.type !== \"pagespeed\") {\n\t\t\tthrow new AppError({ message: `${monitor.type} monitors are not supported for pagespeed details`, status: 400 });\n\t\t}\n\n\t\tconst rangeKey = (dateRange as DateRangeKey) ?? \"recent\";\n\t\tconst { start, end } = this.getDateRange(rangeKey);\n\t\tconst checksData = await this.checksRepository.findByDateRangeAndMonitorId(monitor.id, start, end, this.getDateFormat(rangeKey), {\n\t\t\ttype: monitor.type,\n\t\t});\n\n\t\tif (checksData.monitorType !== \"pagespeed\") {\n\t\t\tthrow new AppError({ message: \"Unable to load pagespeed stats for this monitor\", status: 500 });\n\t\t}\n\n\t\tconst monitorStats = await this.monitorStatsRepository.findByMonitorId(monitor.id);\n\n\t\treturn {\n\t\t\tmonitorData: {\n\t\t\t\tmonitor,\n\t\t\t\tgroupedChecks: checksData.groupedChecks,\n\t\t\t},\n\t\t\tmonitorStats,\n\t\t};\n\t};\n\n\tgetGeoChecksByMonitorId = async ({\n\t\tteamId,\n\t\tmonitorId,\n\t\tdateRange,\n\t\tcontinents,\n\t}: {\n\t\tteamId: string;\n\t\tmonitorId: string;\n\t\tdateRange: string;\n\t\tcontinents?: GeoContinent[];\n\t}): Promise<GroupedGeoCheckResult> => {\n\t\tconst monitor = await this.monitorsRepository.findById(monitorId, teamId);\n\t\tif (!monitor) {\n\t\t\tthrow new AppError({ message: `Monitor with ID ${monitorId} not found.`, status: 404 });\n\t\t}\n\n\t\tif (!supportsGeoCheck(monitor.type) || !monitor.geoCheckEnabled) {\n\t\t\treturn { groupedGeoChecks: [] };\n\t\t}\n\n\t\tconst rangeKey = (dateRange as DateRangeKey) ?? \"recent\";\n\t\tconst { start, end } = this.getDateRange(rangeKey);\n\t\tconst groupedGeoChecks = await this.geoChecksRepository.findGroupedByMonitorIdAndDateRange(\n\t\t\tmonitor.id,\n\t\t\tstart,\n\t\t\tend,\n\t\t\tthis.getDateFormat(rangeKey),\n\t\t\tcontinents\n\t\t);\n\n\t\treturn { groupedGeoChecks };\n\t};\n\n\tgetMonitorById = async ({ teamId, monitorId }: { teamId: string; monitorId: string }): Promise<Monitor> => {\n\t\tconst monitor = await this.monitorsRepository.findById(monitorId, teamId);\n\t\treturn monitor;\n\t};\n\n\tgetMonitorsByTeamId = async ({\n\t\tteamId,\n\t\ttype,\n\t\tfilter,\n\t}: {\n\t\tteamId: string;\n\t\ttype?: MonitorType | MonitorType[];\n\t\tfilter?: string;\n\t}): Promise<Monitor[] | null> => {\n\t\tconst monitors = await this.monitorsRepository.findByTeamId(teamId, {\n\t\t\ttype,\n\t\t\tfilter,\n\t\t});\n\t\treturn monitors;\n\t};\n\n\tgetMonitorsWithChecksByTeamId = async ({\n\t\tteamId,\n\t\tlimit,\n\t\ttype,\n\t\tpage,\n\t\trowsPerPage,\n\t\tfilter,\n\t\tfield,\n\t\torder,\n\t}: {\n\t\tteamId: string;\n\t\tlimit?: number;\n\t\ttype?: MonitorType | MonitorType[];\n\t\tpage?: number;\n\t\trowsPerPage?: number;\n\t\tfilter?: string;\n\t\tfield?: string;\n\t\torder?: \"asc\" | \"desc\";\n\t}): Promise<MonitorsWithChecksByTeamIdResult> => {\n\t\tconst summary = await this.monitorsRepository.findMonitorsSummaryByTeamId(teamId, { type });\n\t\tconst count = await this.monitorsRepository.findMonitorCountByTeamIdAndType(teamId, { type, filter });\n\t\tconst monitors = await this.monitorsRepository.findByTeamId(teamId, {\n\t\t\tlimit,\n\t\t\ttype,\n\t\t\tpage,\n\t\t\trowsPerPage,\n\t\t\tfilter,\n\t\t\tfield,\n\t\t\torder,\n\t\t});\n\n\t\tconst monitorsList = (monitors ?? []) as Monitor[];\n\t\tconst snapshotTypes: MonitorType[] = [\"hardware\"];\n\t\tconst requestedTypes = Array.isArray(type) ? type : type ? [type] : [];\n\t\tconst snapshotOnlyRequest =\n\t\t\trequestedTypes.length > 0 && requestedTypes.every((requestedType) => snapshotTypes.includes(requestedType as MonitorType));\n\n\t\tconst monitorsWithChecks = monitorsList.map((monitor: Monitor) => {\n\t\t\tconst rawChecks = monitor.recentChecks ?? [];\n\t\t\tconst isSnapshotType = snapshotOnlyRequest || snapshotTypes.includes(monitor.type);\n\t\t\tconst checks = isSnapshotType ? rawChecks.slice(0, 1) : NormalizeData(rawChecks, 10, 100);\n\t\t\tmonitor.recentChecks = checks;\n\t\t\treturn monitor;\n\t\t});\n\t\treturn { summary: summary ?? null, count, monitors: monitorsWithChecks };\n\t};\n\n\tgetAllGames = (): GamesMap => {\n\t\treturn this.games;\n\t};\n\n\tgetGroupsByTeamId = async ({ teamId }: { teamId: string }): Promise<string[]> => {\n\t\tconst groups = await this.monitorsRepository.findGroupsByTeamId(teamId);\n\t\treturn groups;\n\t};\n\n\teditMonitor = async ({ teamId, monitorId, body }: { teamId: string; monitorId: string; body: Partial<Monitor> }) => {\n\t\tconst editedMonitor = await this.monitorsRepository.updateById(monitorId, teamId, body);\n\t\tawait this.jobQueue.updateJob(editedMonitor);\n\t\treturn editedMonitor;\n\t};\n\n\tpauseMonitor = async ({ teamId, monitorId }: { teamId: string; monitorId: string }): Promise<Monitor> => {\n\t\tconst monitor = await this.monitorsRepository.togglePauseById(monitorId, teamId);\n\t\tif (monitor.isActive) {\n\t\t\tawait this.jobQueue.resumeJob(monitor);\n\t\t} else {\n\t\t\tawait this.jobQueue.pauseJob(monitor);\n\t\t}\n\t\treturn monitor;\n\t};\n\n\tdeleteMonitor = async ({ teamId, monitorId }: { teamId: string; monitorId: string }): Promise<Monitor> => {\n\t\tconst monitor = await this.monitorsRepository.deleteById(monitorId, teamId);\n\t\tawait this.monitorStatsRepository.deleteByMonitorId(monitor.id).catch((err: unknown) => {\n\t\t\tthis.logger.warn({\n\t\t\t\tmessage: `Error deleting monitor stats for monitor ${monitor.id} with name ${monitor.name}`,\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tstack: err instanceof Error ? err.stack : undefined,\n\t\t\t});\n\t\t});\n\t\tawait this.checksRepository.deleteByMonitorId(monitor.id).catch((err: unknown) => {\n\t\t\tthis.logger.warn({\n\t\t\t\tmessage: `Error deleting checks for monitor ${monitor.id} with name ${monitor.name}`,\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tstack: err instanceof Error ? err.stack : undefined,\n\t\t\t});\n\t\t});\n\t\tawait this.statusPagesRepository.removeMonitorFromStatusPages(monitor.id).catch((err: unknown) => {\n\t\t\tthis.logger.warn({\n\t\t\t\tmessage: `Error removing monitor ${monitor.id} with name ${monitor.name} from status pages`,\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tstack: err instanceof Error ? err.stack : undefined,\n\t\t\t});\n\t\t});\n\n\t\tawait this.incidentsRepository.deleteByMonitorId(monitor.id, teamId).catch((err: unknown) => {\n\t\t\tthis.logger.warn({\n\t\t\t\tmessage: `Error deleting incidents for monitor ${monitor.id} with name ${monitor.name}`,\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tstack: err instanceof Error ? err.stack : undefined,\n\t\t\t});\n\t\t});\n\n\t\tawait this.geoChecksRepository.deleteByMonitorId(monitor.id).catch((err: unknown) => {\n\t\t\tthis.logger.warn({\n\t\t\t\tmessage: `Error deleting geo checks for monitor ${monitor.id} with name ${monitor.name}`,\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tstack: err instanceof Error ? err.stack : undefined,\n\t\t\t});\n\t\t});\n\n\t\tawait this.jobQueue.deleteJob(monitor);\n\t\treturn monitor;\n\t};\n\n\tdeleteAllMonitors = async ({ teamId }: { teamId: string }): Promise<number> => {\n\t\tconst { monitors, deletedCount } = await this.monitorsRepository.deleteByTeamId(teamId);\n\t\tawait Promise.all(\n\t\t\tmonitors.map(async (monitor) => {\n\t\t\t\ttry {\n\t\t\t\t\tawait this.jobQueue.deleteJob(monitor);\n\t\t\t\t\tawait this.checksRepository.deleteByMonitorId(monitor.id);\n\t\t\t\t\tawait this.geoChecksRepository.deleteByMonitorId(monitor.id);\n\t\t\t\t\tawait this.statusPagesRepository.removeMonitorFromStatusPages(monitor.id);\n\t\t\t\t\tawait this.monitorStatsRepository.deleteByMonitorId(monitor.id);\n\t\t\t\t} catch (error: unknown) {\n\t\t\t\t\tthis.logger.warn({\n\t\t\t\t\t\tmessage: `Error deleting associated records for monitor ${monitor.id} with name ${monitor.name}`,\n\t\t\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\t\t\tmethod: \"deleteAllMonitors\",\n\t\t\t\t\t\tstack: error instanceof Error ? error.stack : undefined,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t})\n\t\t);\n\t\treturn deletedCount;\n\t};\n\n\texportMonitorsToJSON = async ({ teamId }: { teamId: string }): Promise<Monitor[]> => {\n\t\tconst monitors = await this.monitorsRepository.findByTeamId(teamId, {});\n\n\t\tif (!monitors || monitors.length === 0) {\n\t\t\tthrow new AppError({ message: \"No monitors found to export.\", service: SERVICE_NAME, method: \"exportMonitorsToJSON\", status: 400 });\n\t\t}\n\n\t\treturn monitors;\n\t};\n\n\timportMonitorsFromJSON = async ({\n\t\tteamId,\n\t\tuserId,\n\t\tmonitors,\n\t}: {\n\t\tteamId: string;\n\t\tuserId: string;\n\t\tmonitors: ImportedMonitor[];\n\t}): Promise<{ imported: number; errors: string[] }> => {\n\t\tconst errors: string[] = [];\n\n\t\tconst cleanedMonitors: Monitor[] = monitors.map((monitor) => ({\n\t\t\t...monitor,\n\t\t\tid: \"\",\n\t\t\tteamId,\n\t\t\tuserId,\n\t\t\trecentChecks: [],\n\t\t\tcreatedAt: \"\",\n\t\t\tupdatedAt: \"\",\n\t\t}));\n\n\t\tconst createdMonitors = await this.createMonitors(cleanedMonitors);\n\n\t\tif (!createdMonitors || createdMonitors.length === 0) {\n\t\t\tthrow new AppError({\n\t\t\t\tmessage: \"Failed to import any monitors. Please check the file format and try again.\",\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"importMonitorsFromJSON\",\n\t\t\t\tstatus: 400,\n\t\t\t});\n\t\t}\n\n\t\treturn { imported: createdMonitors.length, errors };\n\t};\n}\n"
  },
  {
    "path": "server/src/service/business/statusPageService.ts",
    "content": "import { type IStatusPagesRepository } from \"@/repositories/index.js\";\nimport { StatusPage } from \"@/types/index.js\";\nexport interface IStatusPageService {\n\tcreateStatusPage(userId: string, teamId: string, image: Express.Multer.File | undefined, data: Partial<StatusPage>): Promise<StatusPage>;\n\tgetStatusPageByUrl(url: string): Promise<StatusPage>;\n\tgetStatusPagesByTeamId(teamId: string): Promise<StatusPage[]>;\n\tupdateStatusPage(id: string, teamId: string, image: Express.Multer.File | undefined, data: Partial<StatusPage>): Promise<StatusPage>;\n\n\tdeleteStatusPage(statusPageId: string, teamId: string): Promise<StatusPage>;\n}\n\nexport class StatusPageService implements IStatusPageService {\n\tprivate statusPagesRepository: IStatusPagesRepository;\n\tconstructor(statusPagesRepository: IStatusPagesRepository) {\n\t\tthis.statusPagesRepository = statusPagesRepository;\n\t}\n\n\tcreateStatusPage = async (\n\t\tuserId: string,\n\t\tteamId: string,\n\t\timage: Express.Multer.File | undefined,\n\t\tdata: Partial<StatusPage>\n\t): Promise<StatusPage> => {\n\t\treturn await this.statusPagesRepository.create(userId, teamId, image, data);\n\t};\n\n\tgetStatusPageByUrl = async (url: string): Promise<StatusPage> => {\n\t\treturn await this.statusPagesRepository.findByUrl(url);\n\t};\n\n\tgetStatusPagesByTeamId = async (teamId: string): Promise<StatusPage[]> => {\n\t\treturn await this.statusPagesRepository.findByTeamId(teamId);\n\t};\n\n\tupdateStatusPage = async (id: string, teamId: string, image: Express.Multer.File | undefined, data: Partial<StatusPage>): Promise<StatusPage> => {\n\t\treturn await this.statusPagesRepository.updateById(id, teamId, image, data);\n\t};\n\n\tdeleteStatusPage = async (statusPageId: string, teamId: string): Promise<StatusPage> => {\n\t\treturn await this.statusPagesRepository.deleteById(statusPageId, teamId);\n\t};\n}\n"
  },
  {
    "path": "server/src/service/business/userService.ts",
    "content": "import {\n\tIInvitesRepository,\n\tIMonitorsRepository,\n\tIRecoveryTokensRepository,\n\tIUsersRepository,\n\tISettingsRepository,\n\tITeamsRepository,\n} from \"@/repositories/index.js\";\nimport type { User } from \"@/types/index.js\";\nimport { canManageRole, type UserRole } from \"@/types/user.js\";\nimport bcrypt from \"bcryptjs\";\nimport { AppError } from \"@/utils/AppError.js\";\nimport { ISuperSimpleQueue } from \"@/service/infrastructure/SuperSimpleQueue/SuperSimpleQueue.js\";\nimport { IEmailService } from \"@/service/infrastructure/emailService.js\";\nimport { EnvConfig, ISettingsService } from \"@/service/system/settingsService.js\";\nimport { ILogger } from \"@/utils/logger.js\";\nimport jwt from \"jsonwebtoken\";\nimport crypto from \"crypto\";\ntype CryptoType = typeof crypto;\ntype JwtType = typeof jwt;\nconst SERVICE_NAME = \"userService\";\n\nexport interface IUserService {\n\tissueToken(payload: Partial<User>, appSettings: EnvConfig): string;\n\tregisterUser(user: Partial<User>, inviteToken: string, file: Express.Multer.File | null): Promise<{ user: User; token: string }>;\n\tcreateUser(userData: Partial<User>, teamId: string, actorRoles: UserRole[], file: Express.Multer.File | null): Promise<User>;\n\tloginUser(email: string, password: string): Promise<{ user: User; token: string }>;\n\teditUser(\n\t\tupdates: Partial<User & { newPassword?: string }>,\n\t\tfile: Express.Multer.File | null,\n\t\tcurrentUserId: string,\n\t\tcurrentUserEmail: string\n\t): Promise<User>;\n\tcheckSuperadminExists(): Promise<boolean>;\n\trequestRecovery(email: string): Promise<string | false | undefined>;\n\tvalidateRecovery(recoveryToken: string): Promise<void>;\n\tresetPassword(password: string, recoveryToken: string): Promise<{ user: User; token: string }>;\n\tdeleteUser(params: { userId: string; teamId: string; roles: UserRole[] }): Promise<void>;\n\tdeleteUserById(params: { actorId: string; actorTeamId: string; actorRoles: UserRole[]; targetUserId: string }): Promise<void>;\n\tgetAllUsers(): Promise<User[]>;\n\tgetUserById(roles: UserRole[], userId: string): Promise<User>;\n\teditUserById(userId: string, patch: Partial<User>): Promise<void>;\n\tsetPasswordByUserId(userId: string, password: string): Promise<User>;\n}\n\nexport class UserService implements IUserService {\n\tstatic SERVICE_NAME = SERVICE_NAME;\n\n\tprivate hashPassword = (password: string): string => {\n\t\tconst salt = bcrypt.genSaltSync(10);\n\t\treturn bcrypt.hashSync(password, salt);\n\t};\n\n\tprivate emailService: IEmailService;\n\tprivate settingsService: ISettingsService;\n\tprivate logger: ILogger;\n\tprivate jwt: JwtType;\n\tprivate jobQueue: ISuperSimpleQueue;\n\tprivate crypto: CryptoType;\n\tprivate monitorsRepository: IMonitorsRepository;\n\tprivate usersRepository: IUsersRepository;\n\tprivate invitesRepository: IInvitesRepository;\n\tprivate recoveryTokensRepository: IRecoveryTokensRepository;\n\tprivate settingsRepository: ISettingsRepository;\n\tprivate teamsRepository: ITeamsRepository;\n\n\tconstructor({\n\t\tcrypto,\n\t\temailService,\n\t\tsettingsService,\n\t\tlogger,\n\t\tjwt,\n\t\tjobQueue,\n\t\tmonitorsRepository,\n\t\tusersRepository,\n\t\tinvitesRepository,\n\t\trecoveryTokensRepository,\n\t\tsettingsRepository,\n\t\tteamsRepository,\n\t}: {\n\t\tcrypto: CryptoType;\n\t\temailService: IEmailService;\n\t\tsettingsService: ISettingsService;\n\t\tlogger: ILogger;\n\t\tjwt: JwtType;\n\t\tjobQueue: ISuperSimpleQueue;\n\t\tmonitorsRepository: IMonitorsRepository;\n\t\tusersRepository: IUsersRepository;\n\t\tinvitesRepository: IInvitesRepository;\n\t\trecoveryTokensRepository: IRecoveryTokensRepository;\n\t\tsettingsRepository: ISettingsRepository;\n\t\tteamsRepository: ITeamsRepository;\n\t}) {\n\t\tthis.emailService = emailService;\n\t\tthis.settingsService = settingsService;\n\t\tthis.logger = logger;\n\t\tthis.jwt = jwt;\n\t\tthis.jobQueue = jobQueue;\n\t\tthis.crypto = crypto;\n\t\tthis.monitorsRepository = monitorsRepository;\n\t\tthis.usersRepository = usersRepository;\n\t\tthis.invitesRepository = invitesRepository;\n\t\tthis.recoveryTokensRepository = recoveryTokensRepository;\n\t\tthis.settingsRepository = settingsRepository;\n\t\tthis.teamsRepository = teamsRepository;\n\t}\n\n\tget serviceName() {\n\t\treturn UserService.SERVICE_NAME;\n\t}\n\n\tissueToken = (payload: Partial<User>, appSettings: EnvConfig) => {\n\t\tconst tokenTTL = appSettings?.jwtTTL ?? \"2h\";\n\t\tconst tokenSecret = appSettings?.jwtSecret;\n\t\tconst payloadData = payload;\n\t\treturn this.jwt.sign(payloadData, tokenSecret, { expiresIn: tokenTTL });\n\t};\n\n\tregisterUser = async (user: Partial<User>, inviteToken: string, file: Express.Multer.File | null) => {\n\t\t// Create a new user\n\t\t// If superAdmin exists, a token should be attached to all further register requests\n\t\tconst superAdminExists = await this.usersRepository.findSuperAdmin();\n\t\tif (superAdminExists) {\n\t\t\tconst invite = await this.invitesRepository.findByTokenAndDelete(inviteToken);\n\t\t\tuser.role = invite.role ?? [\"user\"];\n\t\t\tuser.teamId = invite.teamId;\n\t\t\tuser.email = invite.email;\n\t\t} else {\n\t\t\t// This is the first account, create JWT secret to use if one is not supplied by env\n\t\t\tconst jwtSecret = this.crypto.randomBytes(64).toString(\"hex\");\n\t\t\tawait this.settingsRepository.update({ jwtSecret });\n\t\t\t// Create a new team\n\t\t\tif (!user.email) {\n\t\t\t\tthrow new AppError({ message: \"Email is required for first user\", service: SERVICE_NAME, method: \"registerUser\", status: 400 });\n\t\t\t}\n\t\t\tconst team = await this.teamsRepository.create(user.email);\n\t\t\tuser.teamId = team.id;\n\t\t\tuser.role = [\"superadmin\"];\n\t\t}\n\n\t\t// Hash password before storing\n\t\tif (user.password) {\n\t\t\tuser.password = this.hashPassword(user.password);\n\t\t}\n\n\t\tconst newUser = await this.usersRepository.create(user, file);\n\n\t\tthis.logger.debug({\n\t\t\tmessage: \"New user created\",\n\t\t\tservice: SERVICE_NAME,\n\t\t\tmethod: \"registerUser\",\n\t\t\tdetails: { userId: newUser.id },\n\t\t});\n\n\t\tdelete newUser.profileImage;\n\t\tdelete newUser.avatarImage;\n\n\t\tconst appSettings = await this.settingsService.getSettings();\n\n\t\tconst token = this.issueToken(newUser, appSettings);\n\n\t\ttry {\n\t\t\tconst html = await this.emailService.buildEmail(\"welcomeEmailTemplate\", {\n\t\t\t\tname: newUser.firstName,\n\t\t\t});\n\t\t\tif (!html) {\n\t\t\t\tthrow new Error(\"Failed to build welcome email HTML\");\n\t\t\t}\n\t\t\tthis.emailService.sendEmail(newUser.email, \"Welcome to Uptime Monitor\", html).catch((error: unknown) => {\n\t\t\t\tthis.logger.warn({\n\t\t\t\t\tmessage: error instanceof Error ? error.message : \"Unknown error\",\n\t\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\t\tmethod: \"registerUser\",\n\t\t\t\t\tstack: error instanceof Error ? error.stack : undefined,\n\t\t\t\t});\n\t\t\t});\n\t\t} catch (error: unknown) {\n\t\t\tthis.logger.warn({\n\t\t\t\tmessage: error instanceof Error ? error.message : \"Unknown error\",\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"registerUser\",\n\t\t\t\tstack: error instanceof Error ? error.stack : undefined,\n\t\t\t});\n\t\t}\n\n\t\treturn { user: newUser, token };\n\t};\n\n\tcreateUser = async (userData: Partial<User>, teamId: string, actorRoles: UserRole[], file: Express.Multer.File | null) => {\n\t\t// Validate that the creator can assign the requested roles\n\t\tconst targetRoles = userData.role ?? [];\n\t\tfor (const targetRole of targetRoles) {\n\t\t\tconst canManage = actorRoles.some((actorRole) => canManageRole(actorRole, targetRole));\n\t\t\tif (!canManage) {\n\t\t\t\tthrow new AppError({\n\t\t\t\t\tmessage: \"You do not have permission to assign this role\",\n\t\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\t\tmethod: \"createUser\",\n\t\t\t\t\tstatus: 403,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tuserData.teamId = teamId;\n\n\t\tif (userData.password) {\n\t\t\tuserData.password = this.hashPassword(userData.password);\n\t\t}\n\n\t\tconst newUser = await this.usersRepository.create(userData, file);\n\n\t\tthis.logger.debug({\n\t\t\tmessage: \"New user created by superadmin\",\n\t\t\tservice: SERVICE_NAME,\n\t\t\tmethod: \"createUser\",\n\t\t\tdetails: { userId: newUser.id },\n\t\t});\n\n\t\tnewUser.profileImage = undefined;\n\t\tnewUser.avatarImage = undefined;\n\t\tnewUser.password = \"\";\n\n\t\treturn newUser;\n\t};\n\n\tloginUser = async (email: string, password: string) => {\n\t\t// Check if user exists\n\t\tconst user = await this.usersRepository.findByEmail(email);\n\t\t// Compare password\n\t\tconst match = await bcrypt.compare(password, user.password);\n\n\t\tif (match !== true) {\n\t\t\tthrow new AppError({ message: \"Incorrect password\", service: SERVICE_NAME, status: 401 });\n\t\t}\n\n\t\t// Remove password from user object.  Should this be abstracted to DB layer?\n\t\tconst userWithoutPassword = { ...user };\n\t\tuserWithoutPassword.password = \"\";\n\t\tuserWithoutPassword.avatarImage = \"\";\n\n\t\t// Happy path, return token\n\t\tconst appSettings = await this.settingsService.getSettings();\n\t\tconst token = this.issueToken(userWithoutPassword, appSettings);\n\t\t// reset avatar image\n\t\tuserWithoutPassword.avatarImage = user.avatarImage;\n\t\treturn { user: userWithoutPassword, token };\n\t};\n\n\teditUser = async (\n\t\tupdates: Partial<User & { newPassword?: string }>,\n\t\tfile: Express.Multer.File | null,\n\t\tcurrentUserId: string,\n\t\tcurrentUserEmail: string\n\t) => {\n\t\t// Change Password check\n\t\tif (updates?.password && updates?.newPassword) {\n\t\t\t// Get user's email\n\t\t\t// Add user email to body for DB operation\n\t\t\tupdates.email = currentUserEmail;\n\t\t\t// Get user\n\t\t\tconst user = await this.usersRepository.findByEmail(currentUserEmail);\n\t\t\t// Compare passwords\n\t\t\tconst match = await bcrypt.compare(updates?.password, user.password);\n\t\t\t// If not a match, throw a 403\n\t\t\t// 403 instead of 401 to avoid triggering axios interceptor\n\t\t\tif (!match) {\n\t\t\t\tthrow new AppError({ message: \"Incorrect current password\", service: SERVICE_NAME, status: 403 });\n\t\t\t}\n\t\t\t// If a match, update the password\n\t\t\tupdates.password = this.hashPassword(updates.newPassword);\n\t\t\tdelete updates.newPassword;\n\t\t}\n\n\t\treturn await this.usersRepository.updateById(currentUserId, updates, file);\n\t};\n\n\tcheckSuperadminExists = async () => {\n\t\treturn await this.usersRepository.findSuperAdmin();\n\t};\n\n\trequestRecovery = async (email: string) => {\n\t\tconst user = await this.usersRepository.findByEmail(email);\n\n\t\t// Delete existing tokens\n\t\tawait this.recoveryTokensRepository.deleteManyByEmail(email);\n\t\tconst recoveryToken = await this.recoveryTokensRepository.create(email);\n\t\tconst name = user.firstName;\n\t\tconst settings = this.settingsService.getSettings();\n\t\tconst url = `${settings.clientHost!}/set-new-password/${recoveryToken.token}`;\n\n\t\tconst html = await this.emailService.buildEmail(\"passwordResetTemplate\", {\n\t\t\tname,\n\t\t\temail,\n\t\t\turl,\n\t\t});\n\t\tif (!html) {\n\t\t\tthrow new AppError({\n\t\t\t\tmessage: \"Failed to build password reset email HTML\",\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"requestRecovery\",\n\t\t\t\tstatus: 500,\n\t\t\t});\n\t\t}\n\t\tconst msgId = await this.emailService.sendEmail(email, \"Checkmate Password Reset\", html);\n\t\treturn msgId;\n\t};\n\n\tvalidateRecovery = async (recoveryToken: string) => {\n\t\t// Throws if token not found, validating\n\t\tawait this.recoveryTokensRepository.findByToken(recoveryToken);\n\t};\n\n\tresetPassword = async (password: string, recoveryToken: string) => {\n\t\tconst existingToken = await this.recoveryTokensRepository.findByToken(recoveryToken);\n\t\tconst existingUser = await this.usersRepository.findByEmail(existingToken.email);\n\n\t\tconst match = await bcrypt.compare(password, existingUser.password);\n\t\tif (match === true) {\n\t\t\tthrow new AppError({ message: \"New password cannot be same as old password\", service: SERVICE_NAME, status: 400 });\n\t\t}\n\n\t\tconst hashedPassword = this.hashPassword(password);\n\t\tawait this.usersRepository.updateById(existingUser.id, { password: hashedPassword }, null);\n\t\tawait this.recoveryTokensRepository.deleteManyByEmail(existingUser.email);\n\n\t\texistingUser.password = \"\";\n\t\texistingUser.profileImage = undefined;\n\n\t\tconst token = this.issueToken(existingUser, await this.settingsService.getSettings());\n\n\t\treturn { user: existingUser, token };\n\t};\n\n\tdeleteUser = async ({ userId, teamId, roles }: { userId: string; teamId: string; roles: UserRole[] }) => {\n\t\tif (roles.includes(\"demo\")) {\n\t\t\tthrow new AppError({ message: \"Demo user cannot be deleted\", service: SERVICE_NAME, method: \"deleteUser\", status: 400 });\n\t\t}\n\n\t\t// 1. Find all the monitors associated with the team ID if superadmin\n\t\tconst res = await this.monitorsRepository.findByTeamId(teamId, {});\n\n\t\tif (roles.includes(\"superadmin\")) {\n\t\t\t// 2.  Remove all jobs, delete checks and alerts\n\t\t\tif (res && res.length > 0) {\n\t\t\t\tawait Promise.all(\n\t\t\t\t\tres.map(async (monitor) => {\n\t\t\t\t\t\tawait this.jobQueue.deleteJob(monitor);\n\t\t\t\t\t})\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\t// 6. Delete the user by id\n\t\tawait this.usersRepository.deleteById(userId);\n\t};\n\n\tdeleteUserById = async ({\n\t\tactorId,\n\t\tactorRoles,\n\t\tactorTeamId,\n\t\ttargetUserId,\n\t}: {\n\t\tactorId: string;\n\t\tactorTeamId: string;\n\t\tactorRoles: UserRole[];\n\t\ttargetUserId: string;\n\t}) => {\n\t\tif (actorId === targetUserId) {\n\t\t\tthrow new AppError({ message: \"Cannot delete your own account from here\", service: SERVICE_NAME, method: \"deleteUserById\", status: 400 });\n\t\t}\n\n\t\tconst targetUser = await this.usersRepository.findById(targetUserId);\n\n\t\tif (targetUser.teamId !== actorTeamId) {\n\t\t\tthrow new AppError({ message: \"User is not on your team\", service: SERVICE_NAME, method: \"deleteUserById\", status: 403 });\n\t\t}\n\n\t\tif (targetUser.role.includes(\"demo\")) {\n\t\t\tthrow new AppError({ message: \"Demo user cannot be deleted\", service: SERVICE_NAME, method: \"deleteUserById\", status: 400 });\n\t\t}\n\n\t\tconst targetRoles = targetUser.role;\n\n\t\t// Check actor can manage all of target's roles\n\t\tfor (const targetRole of targetRoles) {\n\t\t\tconst canManage = actorRoles.some((actorRole) => canManageRole(actorRole, targetRole));\n\t\t\tif (!canManage) {\n\t\t\t\tthrow new AppError({\n\t\t\t\t\tmessage: \"You do not have permission to remove this user\",\n\t\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\t\tmethod: \"deleteUserById\",\n\t\t\t\t\tstatus: 403,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tawait this.usersRepository.deleteById(targetUserId);\n\n\t\tthis.logger.info({\n\t\t\tmessage: `User ${targetUserId} deleted by ${actorId}`,\n\t\t\tservice: SERVICE_NAME,\n\t\t\tmethod: \"deleteUserById\",\n\t\t});\n\t};\n\n\tgetAllUsers = async () => {\n\t\treturn await this.usersRepository.findAll();\n\t};\n\n\tgetUserById = async (roles: UserRole[], userId: string) => {\n\t\tif (!roles.includes(\"superadmin\") && !roles.includes(\"admin\")) {\n\t\t\tthrow new AppError({ message: \"Insufficient permissions\", service: SERVICE_NAME, status: 403 });\n\t\t}\n\t\tconst user = await this.usersRepository.findById(userId);\n\n\t\treturn user;\n\t};\n\n\teditUserById = async (userId: string, patch: Partial<User>) => {\n\t\tawait this.usersRepository.updateById(userId, patch, null);\n\t};\n\n\tsetPasswordByUserId = async (userId: string, password: string) => {\n\t\tconst hashedPassword = this.hashPassword(password);\n\t\tconst updatedUser = await this.usersRepository.updateById(userId, { password: hashedPassword }, null);\n\t\treturn updatedUser;\n\t};\n}\n"
  },
  {
    "path": "server/src/service/index.ts",
    "content": "// Business services\nexport * from \"@/service/business/checkService.js\";\nexport * from \"@/service/business/diagnosticService.js\";\nexport * from \"@/service/business/geoChecksService.js\";\nexport * from \"@/service/business/incidentService.js\";\nexport * from \"@/service/business/inviteService.js\";\nexport * from \"@/service/business/maintenanceWindowService.js\";\nexport * from \"@/service/business/monitorService.js\";\nexport * from \"@/service/business/statusPageService.js\";\nexport * from \"@/service/business/userService.js\";\n\n// Infrastructure services\nexport * from \"@/service/infrastructure/SuperSimpleQueue/SuperSimpleQueue.js\";\nexport * from \"@/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.js\";\nexport * from \"@/service/infrastructure/notificationMessageBuilder.js\";\nexport * from \"@/service/infrastructure/bufferService.js\";\nexport * from \"@/service/infrastructure/emailService.js\";\nexport * from \"@/service/infrastructure/globalPingService.js\";\nexport * from \"@/service/infrastructure/networkService.js\";\nexport * from \"@/service/infrastructure/notificationsService.js\";\nexport * from \"@/service/infrastructure/statusService.js\";\n\n// Notification providers\nexport * from \"@/service/infrastructure/notificationProviders/discord.js\";\nexport * from \"@/service/infrastructure/notificationProviders/email.js\";\nexport * from \"@/service/infrastructure/notificationProviders/INotificationProvider.js\";\nexport * from \"@/service/infrastructure/notificationProviders/matrix.js\";\nexport * from \"@/service/infrastructure/notificationProviders/pagerduty.js\";\nexport * from \"@/service/infrastructure/notificationProviders/slack.js\";\nexport * from \"@/service/infrastructure/notificationProviders/teams.js\";\nexport * from \"@/service/infrastructure/notificationProviders/webhook.js\";\n\n// System services\nexport * from \"@/service/system/settingsService.js\";\n"
  },
  {
    "path": "server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueue.ts",
    "content": "import { IMonitorsRepository } from \"@/repositories/index.js\";\nimport { ILogger } from \"@/utils/logger.js\";\nimport Scheduler from \"super-simple-scheduler\";\nimport { ISuperSimpleQueueHelper } from \"@/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.js\";\nimport { Monitor, MonitorType, supportsGeoCheck } from \"@/types/monitor.js\";\nconst SERVICE_NAME = \"JobQueue\";\n\ntype QueueJobFailure = {\n\tmonitorId: string | number;\n\tmonitorUrl: string | null;\n\tmonitorType: string | null;\n\tfailedAt: number | null;\n\tfailCount: number;\n\tfailReason: string | null;\n};\n\ntype QueueMetrics = {\n\tjobs: number;\n\tactiveJobs: number;\n\tfailingJobs: number;\n\tjobsWithFailures: QueueJobFailure[];\n\ttotalRuns: number;\n\ttotalFailures: number;\n};\n\ntype QueueJobSummary = {\n\tmonitorId: string | number;\n\tmonitorUrl: string | null;\n\tmonitorType: string | null;\n\tmonitorInterval: number | null;\n\tactive: boolean;\n\tlockedAt: number | null;\n\trunCount: number;\n\tfailCount: number;\n\tfailReason: string | null;\n\tlastRunAt: number | null;\n\tlastFinishedAt: number | null;\n\tlastRunTook: number | null;\n\tlastFailedAt: number | null;\n};\n\nexport interface ISuperSimpleQueue {\n\treadonly serviceName: string;\n\tinit(): Promise<boolean>;\n\taddJob(monitorId: string, monitor: Monitor): Promise<void>;\n\tdeleteJob(monitor: Monitor): Promise<void>;\n\tpauseJob(monitor: Monitor): Promise<void>;\n\tresumeJob(monitor: Monitor): Promise<void>;\n\tupdateJob(monitor: Monitor): Promise<void>;\n\tshutdown(): Promise<void>;\n\tgetMetrics(): Promise<QueueMetrics>;\n\tgetJobs(): Promise<QueueJobSummary[]>;\n\tflushQueues(): Promise<{ success: boolean }>;\n\tobliterate(): Promise<void>;\n}\n\nexport class SuperSimpleQueue implements ISuperSimpleQueue {\n\tstatic SERVICE_NAME = SERVICE_NAME;\n\n\tprivate logger: ILogger;\n\tprivate helper: ISuperSimpleQueueHelper;\n\tprivate monitorsRepository: IMonitorsRepository;\n\tprivate readonly scheduler: Scheduler;\n\n\tconstructor(logger: ILogger, helper: ISuperSimpleQueueHelper, monitorsRepository: IMonitorsRepository, scheduler: Scheduler) {\n\t\tthis.logger = logger;\n\t\tthis.helper = helper;\n\t\tthis.monitorsRepository = monitorsRepository;\n\t\tthis.scheduler = scheduler;\n\t}\n\n\tget serviceName() {\n\t\treturn SuperSimpleQueue.SERVICE_NAME;\n\t}\n\n\tstatic async create(logger: ILogger, helper: ISuperSimpleQueueHelper, monitorsRepository: IMonitorsRepository) {\n\t\tconst scheduler = new Scheduler({\n\t\t\t// storeType: \"mongo\",\n\t\t\t// storeType: \"redis\",\n\t\t\tlogLevel: \"debug\",\n\t\t\t// dbUri: envSettings.dbConnectionString,\n\t\t});\n\t\tconst instance = new SuperSimpleQueue(logger, helper, monitorsRepository, scheduler);\n\t\tawait instance.init();\n\t\treturn instance;\n\t}\n\n\tinit = async () => {\n\t\ttry {\n\t\t\tthis.scheduler.start();\n\n\t\t\tthis.scheduler.addTemplate(\"monitor-job\", this.helper.getHeartbeatJob());\n\t\t\tthis.scheduler.addTemplate(\"geo-check-job\", this.helper.getHeartbeatGeoJob());\n\t\t\tthis.scheduler.addTemplate(\"cleanup-orphaned\", this.helper.getCleanupOrphanedJob());\n\t\t\tthis.scheduler.addTemplate(\"cleanup-retention-job\", this.helper.getCleanupRetentionJob());\n\t\t\tconst monitors = await this.monitorsRepository.findAll();\n\t\t\tif (!monitors) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tfor (const monitor of monitors) {\n\t\t\t\tconst randomOffset = Math.floor(Math.random() * 100);\n\t\t\t\tsetTimeout(() => {\n\t\t\t\t\tthis.addJob(monitor.id, monitor);\n\t\t\t\t}, randomOffset);\n\t\t\t}\n\n\t\t\tthis.scheduler.addJob({ id: \"cleanup-orphaned\", template: \"cleanup-orphaned\", active: true });\n\t\t\tthis.scheduler.addJob({ id: \"cleanup-retention\", template: \"cleanup-retention-job\", active: true, repeat: 24 * 60 * 60 * 1000 });\n\n\t\t\treturn true;\n\t\t} catch (error: unknown) {\n\t\t\tthis.logger.error({\n\t\t\t\tmessage: `Failed to initialize SuperSimpleQueue: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"init\",\n\t\t\t});\n\t\t\treturn false;\n\t\t}\n\t};\n\n\taddJob = async (monitorId: string, monitor: Monitor) => {\n\t\tthis.scheduler.addJob({\n\t\t\tid: monitorId,\n\t\t\ttemplate: \"monitor-job\",\n\t\t\trepeat: monitor.interval,\n\t\t\tactive: monitor.isActive,\n\t\t\tdata: monitor,\n\t\t});\n\n\t\t// Return early if we don't need geo checks\n\t\tif (!supportsGeoCheck(monitor.type)) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Add geo check job if enabled for HTTP monitors\n\t\tif (monitor.geoCheckEnabled) {\n\t\t\tthis.scheduler.addJob({\n\t\t\t\tid: `${monitorId}-geo`,\n\t\t\t\ttemplate: \"geo-check-job\",\n\t\t\t\trepeat: monitor.geoCheckInterval,\n\t\t\t\tactive: monitor.isActive,\n\t\t\t\tdata: monitor,\n\t\t\t});\n\t\t}\n\t};\n\n\tdeleteJob = async (monitor: Monitor) => {\n\t\tthis.scheduler.removeJob(monitor.id);\n\t\tthis.scheduler.removeJob(`${monitor.id}-geo`);\n\t};\n\n\tpauseJob = async (monitor: Monitor) => {\n\t\tconst result = await this.scheduler.pauseJob(monitor.id);\n\t\tif (result === false) {\n\t\t\tthrow new Error(\"Failed to pause monitor\");\n\t\t}\n\t\tawait this.scheduler.pauseJob(`${monitor.id}-geo`);\n\t\tthis.logger.debug({\n\t\t\tmessage: `Paused monitor ${monitor.id}`,\n\t\t\tservice: SERVICE_NAME,\n\t\t\tmethod: \"pauseJob\",\n\t\t});\n\t};\n\n\tresumeJob = async (monitor: Monitor) => {\n\t\tconst result = await this.scheduler.resumeJob(monitor.id);\n\t\tif (result === false) {\n\t\t\tthrow new Error(\"Failed to resume monitor\");\n\t\t}\n\n\t\tawait this.scheduler.resumeJob(`${monitor.id}-geo`);\n\n\t\tthis.logger.debug({\n\t\t\tmessage: `Resumed monitor ${monitor.id}`,\n\t\t\tservice: SERVICE_NAME,\n\t\t\tmethod: \"resumeJob\",\n\t\t});\n\t};\n\n\tupdateJob = async (monitor: Monitor) => {\n\t\tthis.scheduler.updateJob(monitor.id, { repeat: monitor.interval, data: monitor });\n\n\t\t// Handle geo check job lifecycle\n\t\tconst geoJobId = `${monitor.id}-geo`;\n\t\tif (monitor.geoCheckEnabled && supportsGeoCheck(monitor.type)) {\n\t\t\t// Check if geo job exists\n\t\t\tconst existingGeoJob = await this.scheduler.getJob(geoJobId);\n\t\t\tif (existingGeoJob) {\n\t\t\t\t// Update existing geo job\n\t\t\t\tthis.scheduler.updateJob(geoJobId, { repeat: monitor.geoCheckInterval, active: monitor.isActive, data: monitor });\n\t\t\t} else {\n\t\t\t\t// Create new geo job\n\t\t\t\tthis.scheduler.addJob({\n\t\t\t\t\tid: geoJobId,\n\t\t\t\t\ttemplate: \"geo-check-job\",\n\t\t\t\t\trepeat: monitor.geoCheckInterval,\n\t\t\t\t\tactive: monitor.isActive,\n\t\t\t\t\tdata: monitor,\n\t\t\t\t});\n\t\t\t}\n\t\t} else {\n\t\t\t// Remove geo job if disabled or monitor type changed\n\t\t\tthis.scheduler.removeJob(geoJobId);\n\t\t}\n\t};\n\n\tshutdown = async () => {\n\t\tthis.scheduler.stop();\n\t};\n\n\tgetMetrics = async () => {\n\t\tconst jobs = await this.scheduler.getJobs();\n\t\tconst metrics = jobs.reduce(\n\t\t\t(acc, job) => {\n\t\t\t\tconst runCount = job.runCount ?? 0;\n\t\t\t\tconst failCount = job.failCount ?? 0;\n\t\t\t\tconst lastFailedAt = job.lastFailedAt ?? 0;\n\t\t\t\tconst lastRunAt = job.lastRunAt ?? 0;\n\t\t\t\tacc.totalRuns += runCount;\n\t\t\t\tacc.totalFailures += failCount;\n\t\t\t\tacc.jobs++;\n\t\t\t\tif (failCount > 0 && lastFailedAt >= lastRunAt) {\n\t\t\t\t\tacc.failingJobs++;\n\t\t\t\t}\n\n\t\t\t\tif (job.lockedAt) {\n\t\t\t\t\tacc.activeJobs++;\n\t\t\t\t}\n\n\t\t\t\tif (failCount > 0) {\n\t\t\t\t\tacc.jobsWithFailures.push({\n\t\t\t\t\t\tmonitorId: job.id,\n\t\t\t\t\t\tmonitorUrl: job?.data?.url || null,\n\t\t\t\t\t\tmonitorType: job?.data?.type || null,\n\t\t\t\t\t\tfailedAt: job.lastFailedAt ?? null,\n\t\t\t\t\t\tfailCount,\n\t\t\t\t\t\tfailReason: job.lastFailReason ?? null,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\treturn acc;\n\t\t\t},\n\t\t\t{\n\t\t\t\tjobs: 0,\n\t\t\t\tactiveJobs: 0,\n\t\t\t\tfailingJobs: 0,\n\t\t\t\tjobsWithFailures: [] as Array<{\n\t\t\t\t\tmonitorId: string | number;\n\t\t\t\t\tmonitorUrl: string;\n\t\t\t\t\tmonitorType: MonitorType;\n\t\t\t\t\tfailedAt: number | null;\n\t\t\t\t\tfailCount: number;\n\t\t\t\t\tfailReason: string | null;\n\t\t\t\t}>,\n\t\t\t\ttotalRuns: 0,\n\t\t\t\ttotalFailures: 0,\n\t\t\t}\n\t\t);\n\t\treturn metrics;\n\t};\n\n\tgetJobs = async () => {\n\t\tconst jobs = await this.scheduler.getJobs();\n\t\treturn jobs.map((job) => {\n\t\t\treturn {\n\t\t\t\tmonitorId: job.id,\n\t\t\t\tmonitorUrl: job?.data?.url || null,\n\t\t\t\tmonitorType: job?.data?.type || null,\n\t\t\t\tmonitorInterval: job?.data?.interval || null,\n\t\t\t\tactive: job.active,\n\t\t\t\tlockedAt: job.lockedAt ?? null,\n\t\t\t\trunCount: job.runCount ?? 0,\n\t\t\t\tfailCount: job.failCount ?? 0,\n\t\t\t\tfailReason: job.lastFailReason ?? null,\n\t\t\t\tlastRunAt: job.lastRunAt ?? null,\n\t\t\t\tlastFinishedAt: job.lastFinishedAt ?? null,\n\t\t\t\tlastRunTook: job.lockedAt ? null : (job.lastFinishedAt ?? 0) - (job.lastRunAt ?? 0),\n\t\t\t\tlastFailedAt: job.lastFailedAt ?? null,\n\t\t\t};\n\t\t});\n\t};\n\n\tflushQueues = async () => {\n\t\tconst stopRes = await this.scheduler.stop();\n\t\tconst flushRes = await this.scheduler.flushJobs();\n\t\tconst initRes = await this.init();\n\t\treturn {\n\t\t\tsuccess: Boolean(stopRes && flushRes && initRes),\n\t\t};\n\t};\n\n\tobliterate = async () => {\n\t\tthis.logger.warn({\n\t\t\tmessage: \"obliterate method not implemented\",\n\t\t\tservice: SERVICE_NAME,\n\t\t\tmethod: \"obliterate\",\n\t\t});\n\t};\n}\n"
  },
  {
    "path": "server/src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts",
    "content": "const SERVICE_NAME = \"JobQueueHelper\";\nimport type { Monitor } from \"@/types/monitor.js\";\nimport { supportsGeoCheck } from \"@/types/monitor.js\";\nimport { AppError } from \"@/utils/AppError.js\";\nimport {\n\tICheckService,\n\tINetworkService,\n\tINotificationsService,\n\tISettingsService,\n\tIStatusService,\n\tIncidentService,\n\ttype IGeoChecksService,\n} from \"@/service/index.js\";\nimport { CHECK_TTL_SENTINEL, type MaintenanceWindow, type StatusChangeResult } from \"@/types/index.js\";\nimport {\n\tIMaintenanceWindowsRepository,\n\tIMonitorsRepository,\n\tITeamsRepository,\n\tIMonitorStatsRepository,\n\tIChecksRepository,\n\tIIncidentsRepository,\n\tIGeoChecksRepository,\n} from \"@/repositories/index.js\";\nimport { ILogger } from \"@/utils/logger.js\";\nimport { IBufferService } from \"@/service/index.js\";\n\nexport interface ISuperSimpleQueueHelper {\n\treadonly serviceName: string;\n\tgetHeartbeatJob(): (monitor: Monitor) => Promise<void>;\n\tgetHeartbeatGeoJob(): (monitor: Monitor) => Promise<void>;\n\tgetCleanupOrphanedJob(): () => Promise<void>;\n\tgetCleanupRetentionJob(): () => Promise<void>;\n\tisInMaintenanceWindow(monitorId: string, teamId: string): Promise<boolean>;\n}\n\nexport interface MonitorActionDecision {\n\tshouldCreateIncident: boolean;\n\tshouldResolveIncident: boolean;\n\tshouldSendNotification: boolean;\n\tincidentReason: \"status_down\" | \"threshold_breach\" | null;\n\tnotificationReason: \"status_change\" | \"threshold_breach\" | null;\n\tthresholdBreaches?: {\n\t\tcpu?: boolean;\n\t\tmemory?: boolean;\n\t\tdisk?: boolean;\n\t\ttemp?: boolean;\n\t};\n}\n\nexport class SuperSimpleQueueHelper implements ISuperSimpleQueueHelper {\n\tstatic SERVICE_NAME = SERVICE_NAME;\n\n\tprivate logger: ILogger;\n\tprivate networkService: INetworkService;\n\tprivate statusService: IStatusService;\n\tprivate notificationsService: INotificationsService;\n\tprivate checkService: ICheckService;\n\tprivate settingsService: ISettingsService;\n\tprivate buffer: IBufferService;\n\tprivate incidentService: IncidentService;\n\tprivate maintenanceWindowsRepository: IMaintenanceWindowsRepository;\n\tprivate monitorsRepository: IMonitorsRepository;\n\tprivate teamsRepository: ITeamsRepository;\n\tprivate monitorStatsRepository: IMonitorStatsRepository;\n\tprivate checksRepository: IChecksRepository;\n\tprivate incidentsRepository: IIncidentsRepository;\n\tprivate geoChecksService: IGeoChecksService;\n\tprivate geoChecksRepository: IGeoChecksRepository;\n\n\tconstructor(\n\t\tlogger: ILogger,\n\t\tnetworkService: INetworkService,\n\t\tstatusService: IStatusService,\n\t\tnotificationsService: INotificationsService,\n\t\tcheckService: ICheckService,\n\t\tsettingsService: ISettingsService,\n\t\tbuffer: IBufferService,\n\t\tincidentService: IncidentService,\n\t\tmaintenanceWindowsRepository: IMaintenanceWindowsRepository,\n\t\tmonitorsRepository: IMonitorsRepository,\n\t\tteamsRepository: ITeamsRepository,\n\t\tmonitorStatsRepository: IMonitorStatsRepository,\n\t\tchecksRepository: IChecksRepository,\n\t\tincidentsRepository: IIncidentsRepository,\n\t\tgeoChecksService: IGeoChecksService,\n\t\tgeoChecksRepository: IGeoChecksRepository\n\t) {\n\t\tthis.logger = logger;\n\t\tthis.networkService = networkService;\n\t\tthis.statusService = statusService;\n\t\tthis.checkService = checkService;\n\t\tthis.settingsService = settingsService;\n\t\tthis.buffer = buffer;\n\t\tthis.notificationsService = notificationsService;\n\t\tthis.incidentService = incidentService;\n\t\tthis.maintenanceWindowsRepository = maintenanceWindowsRepository;\n\t\tthis.monitorsRepository = monitorsRepository;\n\t\tthis.teamsRepository = teamsRepository;\n\t\tthis.monitorStatsRepository = monitorStatsRepository;\n\t\tthis.checksRepository = checksRepository;\n\t\tthis.incidentsRepository = incidentsRepository;\n\t\tthis.geoChecksService = geoChecksService;\n\t\tthis.geoChecksRepository = geoChecksRepository;\n\t}\n\n\tget serviceName() {\n\t\treturn SuperSimpleQueueHelper.SERVICE_NAME;\n\t}\n\n\tgetHeartbeatJob = () => {\n\t\treturn async (monitor: Monitor) => {\n\t\t\ttry {\n\t\t\t\tconst monitorId = monitor.id;\n\t\t\t\tconst teamId = monitor.teamId;\n\t\t\t\tif (!monitorId) {\n\t\t\t\t\tthrow new AppError({ message: \"No monitor id\", service: SERVICE_NAME, method: \"getMonitorJob\" });\n\t\t\t\t}\n\n\t\t\t\t// Step 1.  Check for maintenance window, if found, skip the check\n\n\t\t\t\tconst maintenanceWindowActive = await this.isInMaintenanceWindow(monitorId, teamId);\n\t\t\t\tif (maintenanceWindowActive) {\n\t\t\t\t\tthis.logger.debug({\n\t\t\t\t\t\tmessage: `Monitor ${monitorId} is in maintenance window`,\n\t\t\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\t\t\tmethod: \"getMonitorJob\",\n\t\t\t\t\t});\n\t\t\t\t\tif (monitor.status !== \"maintenance\") {\n\t\t\t\t\t\tawait this.monitorsRepository.updateById(monitorId, teamId, { status: \"maintenance\" });\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Step 2.  Request monitor status\n\t\t\t\tconst status = await this.networkService.requestStatus(monitor);\n\t\t\t\tif (!status) {\n\t\t\t\t\tthrow new Error(\"No network response\");\n\t\t\t\t}\n\n\t\t\t\t// Step 3.  Build check\n\t\t\t\tconst check = this.checkService.buildCheck(status);\n\t\t\t\tif (!check) {\n\t\t\t\t\tthis.logger.warn({\n\t\t\t\t\t\tmessage: `No check could be built for monitor ${monitorId}`,\n\t\t\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\t\t\tmethod: \"getMonitorJob\",\n\t\t\t\t\t\tdetails: { code: status.code, message: status.message },\n\t\t\t\t\t});\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t// Step 4 Add check to buffer\n\t\t\t\tthis.buffer.addToBuffer(check);\n\t\t\t\t// Step 4.  Update monitor status\n\t\t\t\tconst statusChangeResult = await this.statusService.updateMonitorStatus(status, check);\n\n\t\t\t\t// Step 5.  Get decisions\n\t\t\t\tconst decision = this.evaluateMonitorAction(statusChangeResult);\n\n\t\t\t\t// Step 6. Handle notifications (best effort, continue even in event of failure, don't wait)\n\t\t\t\tif (decision.shouldSendNotification) {\n\t\t\t\t\tthis.notificationsService.handleNotifications(statusChangeResult.monitor, status, decision).catch((error: unknown) => {\n\t\t\t\t\t\tthis.logger.error({\n\t\t\t\t\t\t\tmessage: `Error sending notifications for job ${statusChangeResult.monitor.id}: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n\t\t\t\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\t\t\t\tmethod: \"getMonitorJob\",\n\t\t\t\t\t\t\tstack: error instanceof Error ? error.stack : undefined,\n\t\t\t\t\t\t});\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\t// Step 7. Handle incidents (best effort, don't wait)\n\t\t\t\tthis.incidentService.handleIncident(statusChangeResult.monitor, statusChangeResult.code, decision, status).catch((error: unknown) => {\n\t\t\t\t\tthis.logger.warn({\n\t\t\t\t\t\tmessage: `Error handling incident for job ${monitor.id}: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n\t\t\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\t\t\tmethod: \"getMonitorJob\",\n\t\t\t\t\t\tstack: error instanceof Error ? error.stack : undefined,\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t} catch (error: unknown) {\n\t\t\t\tthis.logger.warn({\n\t\t\t\t\tmessage: error instanceof Error ? error.message : \"Unknown error\",\n\t\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\t\tmethod: \"getMonitorJob\",\n\t\t\t\t\tstack: error instanceof Error ? error.stack : undefined,\n\t\t\t\t});\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t};\n\t};\n\n\tgetCleanupOrphanedJob = () => {\n\t\treturn async () => {\n\t\t\ttry {\n\t\t\t\tthis.logger.info({\n\t\t\t\t\tmessage: \"Starting cleanup of orphaned data\",\n\t\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\t\tmethod: \"getCleanupOrphanedJob\",\n\t\t\t\t});\n\n\t\t\t\t// Get all valid team IDs\n\t\t\t\tconst validTeamIds = await this.teamsRepository.findAllTeamIds();\n\t\t\t\tthis.logger.debug({\n\t\t\t\t\tmessage: `Found ${validTeamIds.length} valid teams`,\n\t\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\t\tmethod: \"getCleanupOrphanedJob\",\n\t\t\t\t});\n\n\t\t\t\t// Remove orphaned monitors (monitors without a valid team)\n\t\t\t\tconst deletedMonitorCount = await this.monitorsRepository.deleteByTeamIdsNotIn(validTeamIds);\n\t\t\t\tif (deletedMonitorCount > 0) {\n\t\t\t\t\tthis.logger.info({\n\t\t\t\t\t\tmessage: `Deleted ${deletedMonitorCount} orphaned monitors`,\n\t\t\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\t\t\tmethod: \"getCleanupOrphanedJob\",\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\t// Remove orphaned monitorStats (stats without a valid monitor)\n\t\t\t\tconst allMonitorIds = await this.monitorsRepository.findAllMonitorIds();\n\t\t\t\tthis.logger.debug({\n\t\t\t\t\tmessage: `Found ${allMonitorIds.length} valid monitors`,\n\t\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\t\tmethod: \"getCleanupOrphanedJob\",\n\t\t\t\t});\n\n\t\t\t\tconst deletedStatsCount = await this.monitorStatsRepository.deleteByMonitorIdsNotIn(allMonitorIds);\n\t\t\t\tif (deletedStatsCount > 0) {\n\t\t\t\t\tthis.logger.info({\n\t\t\t\t\t\tmessage: `Deleted ${deletedStatsCount} orphaned monitor stats`,\n\t\t\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\t\t\tmethod: \"getCleanupOrphanedJob\",\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\t// Remove orphaned checks\n\t\t\t\tconst deletedChecksCount = await this.checksRepository.deleteByMonitorIdsNotIn(allMonitorIds);\n\t\t\t\tif (deletedChecksCount > 0) {\n\t\t\t\t\tthis.logger.info({\n\t\t\t\t\t\tmessage: `Deleted ${deletedChecksCount} orphaned checks`,\n\t\t\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\t\t\tmethod: \"getCleanupOrphanedJob\",\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\t// Remove orphaned incidents\n\t\t\t\tconst deletedIncidentsCount = await this.incidentsRepository.deleteByMonitorIdsNotIn(allMonitorIds);\n\t\t\t\tif (deletedIncidentsCount > 0) {\n\t\t\t\t\tthis.logger.info({\n\t\t\t\t\t\tmessage: `Deleted ${deletedIncidentsCount} orphaned incidents`,\n\t\t\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\t\t\tmethod: \"getCleanupOrphanedJob\",\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\t// Remove orphaned geo checks\n\t\t\t\tconst deletedGeoChecksCount = await this.geoChecksRepository.deleteByMonitorIdsNotIn(allMonitorIds);\n\t\t\t\tif (deletedGeoChecksCount > 0) {\n\t\t\t\t\tthis.logger.info({\n\t\t\t\t\t\tmessage: `Deleted ${deletedGeoChecksCount} orphaned geo checks`,\n\t\t\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\t\t\tmethod: \"getCleanupOrphanedJob\",\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tthis.logger.info({\n\t\t\t\t\tmessage: \"Cleanup of orphaned data completed\",\n\t\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\t\tmethod: \"getCleanupOrphanedJob\",\n\t\t\t\t});\n\t\t\t} catch (error: unknown) {\n\t\t\t\tthis.logger.warn({\n\t\t\t\t\tmessage: error instanceof Error ? error.message : \"Unknown error\",\n\t\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\t\tmethod: \"getCleanupOrphanedJob\",\n\t\t\t\t\tstack: error instanceof Error ? error.stack : undefined,\n\t\t\t\t});\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t};\n\t};\n\n\tgetHeartbeatGeoJob = () => {\n\t\treturn async (monitor: Monitor) => {\n\t\t\ttry {\n\t\t\t\tconst monitorId = monitor.id;\n\t\t\t\tconst teamId = monitor.teamId;\n\n\t\t\t\t// Step 1: Validate monitor eligibility\n\t\t\t\tif (!monitorId) {\n\t\t\t\t\tthrow new AppError({ message: \"No monitor id\", service: SERVICE_NAME, method: \"getHeartbeatGeoJob\" });\n\t\t\t\t}\n\n\t\t\t\tif (!monitor.geoCheckEnabled) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (!supportsGeoCheck(monitor.type)) {\n\t\t\t\t\tthis.logger.debug({\n\t\t\t\t\t\tmessage: `Monitor ${monitorId} type does not support geo checks, skipping`,\n\t\t\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\t\t\tmethod: \"getHeartbeatGeoJob\",\n\t\t\t\t\t});\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (!monitor.geoCheckLocations || monitor.geoCheckLocations.length === 0) {\n\t\t\t\t\tthis.logger.warn({\n\t\t\t\t\t\tmessage: `No geo check locations configured for monitor ${monitorId}`,\n\t\t\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\t\t\tmethod: \"getHeartbeatGeoJob\",\n\t\t\t\t\t});\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Step 2: Check for maintenance window\n\t\t\t\tconst maintenanceWindowActive = await this.isInMaintenanceWindow(monitorId, teamId);\n\t\t\t\tif (maintenanceWindowActive) {\n\t\t\t\t\tthis.logger.debug({\n\t\t\t\t\t\tmessage: `Monitor ${monitorId} is in maintenance window, skipping geo check`,\n\t\t\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\t\t\tmethod: \"getHeartbeatGeoJob\",\n\t\t\t\t\t});\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Step 3: Build geo check (handles API calls and polling)\n\t\t\t\tconst geoCheck = await this.geoChecksService.buildGeoCheck(monitor);\n\t\t\t\tif (!geoCheck) {\n\t\t\t\t\tthis.logger.warn({\n\t\t\t\t\t\tmessage: `No geo check could be built for monitor ${monitorId}`,\n\t\t\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\t\t\tmethod: \"getHeartbeatGeoJob\",\n\t\t\t\t\t});\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Step 4: Add geo check to buffer\n\t\t\t\tthis.buffer.addGeoCheckToBuffer(geoCheck);\n\n\t\t\t\tthis.logger.debug({\n\t\t\t\t\tmessage: `Geo check job executed for monitor ${monitorId}`,\n\t\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\t\tmethod: \"getHeartbeatGeoJob\",\n\t\t\t\t});\n\t\t\t} catch (error: unknown) {\n\t\t\t\tthis.logger.error({\n\t\t\t\t\tmessage: error instanceof Error ? error.message : \"Unknown error\",\n\t\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\t\tmethod: \"getHeartbeatGeoJob\",\n\t\t\t\t\tstack: error instanceof Error ? error.stack : undefined,\n\t\t\t\t});\n\t\t\t\t// Don't throw - geo check failures shouldn't crash the job scheduler\n\t\t\t}\n\t\t};\n\t};\n\n\tasync isInMaintenanceWindow(monitorId: string, teamId: string) {\n\t\tconst maintenanceWindows = await this.maintenanceWindowsRepository.findByMonitorId(monitorId, teamId);\n\t\t// Check for active maintenance window:\n\t\tconst maintenanceWindowIsActive = maintenanceWindows.reduce((acc: boolean, window: MaintenanceWindow) => {\n\t\t\tif (window.active) {\n\t\t\t\tconst start = new Date(window.start);\n\t\t\t\tconst end = new Date(window.end);\n\t\t\t\tconst now = new Date();\n\t\t\t\tconst repeatInterval = window.repeat || 0;\n\n\t\t\t\t// If start is < now and end > now, we're in maintenance\n\t\t\t\tif (start <= now && end >= now) return true;\n\n\t\t\t\t// If maintenance window was set in the past with a repeat,\n\t\t\t\t// we need to advance start and end to see if we are in range\n\n\t\t\t\twhile (start < now && repeatInterval !== 0) {\n\t\t\t\t\tstart.setTime(start.getTime() + repeatInterval);\n\t\t\t\t\tend.setTime(end.getTime() + repeatInterval);\n\t\t\t\t\tif (start <= now && end >= now) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn acc;\n\t\t}, false);\n\t\treturn maintenanceWindowIsActive;\n\t}\n\n\tgetCleanupRetentionJob = () => {\n\t\treturn async () => {\n\t\t\ttry {\n\t\t\t\tconst settings = await this.settingsService.getDBSettings();\n\n\t\t\t\tconst checkTTL = settings.checkTTL; // Check TTL is in DAYS, not MS\n\n\t\t\t\tif (checkTTL === CHECK_TTL_SENTINEL) {\n\t\t\t\t\tthis.logger.info({\n\t\t\t\t\t\tmessage: `Check TTL is set to unlimited, skipping cleanup`,\n\t\t\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\t\t\tmethod: \"getCleanupRetentionJob\",\n\t\t\t\t\t});\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst checkTTLInMs = checkTTL * 24 * 60 * 60 * 1000;\n\t\t\t\tconst cutoffDate = new Date(Date.now() - checkTTLInMs);\n\t\t\t\tconst deleteCount = await this.checkService.deleteOlderThan(cutoffDate);\n\t\t\t\tthis.logger.info({\n\t\t\t\t\tmessage: `Deleted ${deleteCount} checks older than ${cutoffDate.toISOString()}`,\n\t\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\t\tmethod: \"getCleanupRetentionJob\",\n\t\t\t\t});\n\t\t\t} catch (error: unknown) {\n\t\t\t\tthis.logger.error({\n\t\t\t\t\tmessage: error instanceof Error ? error.message : \"Unknown error\",\n\t\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\t\tmethod: \"getCleanupRetentionJob\",\n\t\t\t\t\tstack: error instanceof Error ? error.stack : undefined,\n\t\t\t\t});\n\t\t\t}\n\t\t};\n\t};\n\n\tprivate evaluateMonitorAction(statusChangeResult: StatusChangeResult): MonitorActionDecision {\n\t\tconst { monitor, statusChanged, prevStatus } = statusChangeResult;\n\n\t\t// Initialize result\n\t\tconst decision: MonitorActionDecision = {\n\t\t\tshouldCreateIncident: false,\n\t\t\tshouldResolveIncident: false,\n\t\t\tshouldSendNotification: false,\n\t\t\tincidentReason: null,\n\t\t\tnotificationReason: null,\n\t\t};\n\n\t\tif (!statusChanged) {\n\t\t\treturn decision;\n\t\t}\n\n\t\tif (monitor.status === \"down\") {\n\t\t\t// Monitor went down (unreachable)\n\t\t\tdecision.shouldCreateIncident = true;\n\t\t\tdecision.shouldSendNotification = true;\n\t\t\tdecision.incidentReason = \"status_down\";\n\t\t\tdecision.notificationReason = \"status_change\";\n\t\t} else if (monitor.status === \"breached\") {\n\t\t\t// Hardware monitor exceeded thresholds\n\t\t\tdecision.shouldCreateIncident = true;\n\t\t\tdecision.shouldSendNotification = true;\n\t\t\tdecision.incidentReason = \"threshold_breach\";\n\t\t\tdecision.notificationReason = \"threshold_breach\";\n\t\t} else if (monitor.status === \"up\" && (prevStatus === \"down\" || prevStatus === \"breached\")) {\n\t\t\t// Monitor recovered from down or breached state\n\t\t\tdecision.shouldResolveIncident = true;\n\t\t\tdecision.shouldSendNotification = true;\n\t\t\tdecision.notificationReason = \"status_change\";\n\t\t}\n\n\t\treturn decision;\n\t}\n}\n"
  },
  {
    "path": "server/src/service/infrastructure/bufferService.ts",
    "content": "import type { Check } from \"@/types/index.js\";\nimport type { GeoCheck } from \"@/types/index.js\";\nimport type { IGeoChecksService } from \"../business/geoChecksService.js\";\nimport type { ILogger } from \"@/utils/logger.js\";\nimport type { ISettingsService } from \"@/service/system/settingsService.js\";\nimport { ICheckService } from \"../business/checkService.js\";\nconst SERVICE_NAME = \"BufferService\";\n\nexport interface IBufferService {\n\taddToBuffer(check: Check): void;\n\taddGeoCheckToBuffer(geoCheck: GeoCheck): void;\n\tremoveCheckFromBuffer(check: Check): boolean;\n\tscheduleNextFlush(): void;\n\tflushBuffer(): Promise<void>;\n\tflushGeoBuffer(): Promise<void>;\n}\n\nexport class BufferService implements IBufferService {\n\tstatic SERVICE_NAME = SERVICE_NAME;\n\tprivate BUFFER_TIMEOUT: number;\n\tprivate logger: ILogger;\n\tprivate SERVICE_NAME: string;\n\tprivate buffer: Check[];\n\tprivate geoBuffer: GeoCheck[];\n\tprivate bufferTimer: NodeJS.Timeout | null = null;\n\tprivate checksService: ICheckService;\n\tprivate geoChecksService: IGeoChecksService;\n\n\tconstructor(logger: ILogger, checkService: ICheckService, geoChecksService: IGeoChecksService, settingsService: ISettingsService) {\n\t\tthis.BUFFER_TIMEOUT = settingsService.getSettings().nodeEnv === \"development\" ? 10 : 1000 * 60 * 1; // 1 minute\n\t\tthis.logger = logger;\n\t\tthis.checksService = checkService;\n\t\tthis.geoChecksService = geoChecksService;\n\t\tthis.SERVICE_NAME = SERVICE_NAME;\n\t\tthis.buffer = [];\n\t\tthis.geoBuffer = [];\n\t\tthis.scheduleNextFlush();\n\t\tthis.logger.info({\n\t\t\tmessage: `Buffer service initialized, flushing every ${this.BUFFER_TIMEOUT / 1000}s`,\n\t\t\tservice: this.SERVICE_NAME,\n\t\t\tmethod: \"constructor\",\n\t\t});\n\t}\n\n\tget serviceName() {\n\t\treturn BufferService.SERVICE_NAME;\n\t}\n\n\taddToBuffer(check: Check) {\n\t\ttry {\n\t\t\tthis.buffer.push(check);\n\t\t} catch (error: unknown) {\n\t\t\tthis.logger.error({\n\t\t\t\tmessage: error instanceof Error ? error.message : \"Unknown error\",\n\t\t\t\tservice: this.SERVICE_NAME,\n\t\t\t\tmethod: \"addToBuffer\",\n\t\t\t\tstack: error instanceof Error ? error.stack : undefined,\n\t\t\t});\n\t\t}\n\t}\n\n\taddGeoCheckToBuffer(geoCheck: GeoCheck) {\n\t\ttry {\n\t\t\tthis.geoBuffer.push(geoCheck);\n\t\t} catch (error: unknown) {\n\t\t\tthis.logger.error({\n\t\t\t\tmessage: error instanceof Error ? error.message : \"Unknown error\",\n\t\t\t\tservice: this.SERVICE_NAME,\n\t\t\t\tmethod: \"addGeoCheckToBuffer\",\n\t\t\t\tstack: error instanceof Error ? error.stack : undefined,\n\t\t\t});\n\t\t}\n\t}\n\n\tremoveCheckFromBuffer(checkToRemove: Check) {\n\t\ttry {\n\t\t\tif (!checkToRemove) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tconst index = this.buffer.findIndex((check) => {\n\t\t\t\tif (checkToRemove.id && check.id) {\n\t\t\t\t\treturn check.id.toString() === checkToRemove.id.toString();\n\t\t\t\t}\n\t\t\t\treturn (\n\t\t\t\t\tcheck.metadata.monitorId?.toString() === checkToRemove.metadata.monitorId &&\n\t\t\t\t\tcheck.metadata.teamId?.toString() === checkToRemove.metadata.teamId &&\n\t\t\t\t\tcheck.metadata.type === checkToRemove.metadata.type &&\n\t\t\t\t\tcheck.status === checkToRemove.status &&\n\t\t\t\t\tcheck.statusCode === checkToRemove.statusCode &&\n\t\t\t\t\tcheck.responseTime === checkToRemove.responseTime &&\n\t\t\t\t\tcheck.message === checkToRemove.message\n\t\t\t\t);\n\t\t\t});\n\n\t\t\tif (index !== -1) {\n\t\t\t\tthis.buffer.splice(index, 1);\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\treturn false;\n\t\t} catch (error: unknown) {\n\t\t\tthis.logger.error({\n\t\t\t\tmessage: error instanceof Error ? error.message : \"Unknown error\",\n\t\t\t\tservice: this.SERVICE_NAME,\n\t\t\t\tmethod: \"removeCheckFromBuffer\",\n\t\t\t\tstack: error instanceof Error ? error.stack : undefined,\n\t\t\t});\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tscheduleNextFlush() {\n\t\tif (this.bufferTimer) {\n\t\t\tclearTimeout(this.bufferTimer);\n\t\t}\n\t\tthis.bufferTimer = setTimeout(async () => {\n\t\t\ttry {\n\t\t\t\tawait this.flushBuffer();\n\t\t\t\tawait this.flushGeoBuffer();\n\t\t\t} catch (error: unknown) {\n\t\t\t\tthis.logger.error({\n\t\t\t\t\tmessage: error instanceof Error ? error.message : \"Unknown error\",\n\t\t\t\t\tservice: this.SERVICE_NAME,\n\t\t\t\t\tmethod: \"scheduleNextFlush\",\n\t\t\t\t\tstack: error instanceof Error ? error.stack : undefined,\n\t\t\t\t});\n\t\t\t} finally {\n\t\t\t\t// Schedule the next flush only after the current one completes\n\t\t\t\tthis.scheduleNextFlush();\n\t\t\t}\n\t\t}, this.BUFFER_TIMEOUT);\n\t}\n\tasync flushBuffer() {\n\t\ttry {\n\t\t\tif (this.buffer.length > 0) {\n\t\t\t\tthis.logger.debug({\n\t\t\t\t\tmessage: `Flushing ${this.buffer.length} checks to database`,\n\t\t\t\t\tservice: this.SERVICE_NAME,\n\t\t\t\t\tmethod: \"flushBuffer\",\n\t\t\t\t});\n\t\t\t\tawait this.checksService.createChecks(this.buffer);\n\t\t\t\tthis.buffer = [];\n\t\t\t}\n\t\t} catch (error: unknown) {\n\t\t\tthis.logger.error({\n\t\t\t\tmessage: error instanceof Error ? error.message : \"Unknown error\",\n\t\t\t\tservice: this.SERVICE_NAME,\n\t\t\t\tmethod: \"flushBuffer\",\n\t\t\t\tstack: error instanceof Error ? error.stack : undefined,\n\t\t\t});\n\t\t\t// Clear buffer even on error to prevent infinite retry loops\n\t\t\tthis.buffer = [];\n\t\t}\n\t}\n\n\tasync flushGeoBuffer() {\n\t\ttry {\n\t\t\tif (this.geoBuffer.length > 0) {\n\t\t\t\tthis.logger.debug({\n\t\t\t\t\tmessage: `Flushing ${this.geoBuffer.length} geo checks to database`,\n\t\t\t\t\tservice: this.SERVICE_NAME,\n\t\t\t\t\tmethod: \"flushGeoBuffer\",\n\t\t\t\t});\n\t\t\t\tawait this.geoChecksService.createGeoChecks(this.geoBuffer);\n\t\t\t\tthis.geoBuffer = [];\n\t\t\t}\n\t\t} catch (error: unknown) {\n\t\t\tthis.logger.error({\n\t\t\t\tmessage: error instanceof Error ? error.message : \"Unknown error\",\n\t\t\t\tservice: this.SERVICE_NAME,\n\t\t\t\tmethod: \"flushGeoBuffer\",\n\t\t\t\tstack: error instanceof Error ? error.stack : undefined,\n\t\t\t});\n\t\t\t// Clear buffer even on error to prevent infinite retry loops\n\t\t\tthis.geoBuffer = [];\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "server/src/service/infrastructure/emailService.ts",
    "content": "import { fileURLToPath } from \"url\";\nimport { EmailTransportConfig } from \"@/types/index.js\";\nimport { ISettingsService } from \"@/service/system/settingsService.js\";\nimport { ILogger } from \"@/utils/logger.js\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport nodemailer from \"nodemailer\";\nimport mjml2html from \"mjml\";\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\nconst SERVICE_NAME = \"EmailService\";\ntype MjmlFn = typeof mjml2html;\ntype FileSystem = typeof fs;\ntype PathModule = typeof path;\ntype Mailer = typeof nodemailer;\ntype TemplateCompiler = (template: string) => (context: Record<string, unknown>) => string;\n\nexport interface IEmailService {\n\tinit(): void;\n\tbuildEmail(template: string, context: Record<string, unknown>): Promise<string | undefined>;\n\tsendEmail(to: string, subject: string, html: string, transportConfig?: EmailTransportConfig): Promise<string | false | undefined>;\n}\n\nexport class EmailService implements IEmailService {\n\tstatic SERVICE_NAME = SERVICE_NAME;\n\n\tprivate settingsService: ISettingsService;\n\tprivate fs: FileSystem;\n\tprivate path: PathModule;\n\tprivate compile: TemplateCompiler;\n\tprivate mjml2html: MjmlFn;\n\tprivate nodemailer: Mailer;\n\tprivate logger: ILogger;\n\tprivate transporter: ReturnType<typeof import(\"nodemailer\").createTransport> | null = null;\n\tprivate templateLookup: Record<string, ((context: Record<string, unknown>) => string) | undefined>;\n\tprivate loadTemplate: (templateName: string) => ((context: Record<string, unknown>) => string) | undefined;\n\n\tconstructor(\n\t\tsettingsService: ISettingsService,\n\t\tfs: FileSystem,\n\t\tpath: PathModule,\n\t\tcompile: TemplateCompiler,\n\t\tmjml2html: MjmlFn,\n\t\tnodemailer: Mailer,\n\t\tlogger: ILogger\n\t) {\n\t\tthis.settingsService = settingsService;\n\t\tthis.fs = fs;\n\t\tthis.path = path;\n\t\tthis.compile = compile;\n\t\tthis.mjml2html = mjml2html;\n\t\tthis.nodemailer = nodemailer;\n\t\tthis.logger = logger;\n\t\tthis.templateLookup = {};\n\t\tthis.loadTemplate = () => undefined;\n\t\tthis.init();\n\t}\n\n\tget serviceName() {\n\t\treturn EmailService.SERVICE_NAME;\n\t}\n\n\tinit = () => {\n\t\tthis.loadTemplate = (templateName) => {\n\t\t\ttry {\n\t\t\t\tconst templatePath = this.path.join(__dirname, `../../templates/${templateName}.mjml`);\n\t\t\t\tconst templateContent = this.fs.readFileSync(templatePath, \"utf8\");\n\t\t\t\treturn this.compile(templateContent);\n\t\t\t} catch (error: unknown) {\n\t\t\t\tthis.logger.error({\n\t\t\t\t\tmessage: error instanceof Error ? error.message : \"Unknown error\",\n\t\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\t\tmethod: \"loadTemplate\",\n\t\t\t\t\tstack: error instanceof Error ? error.stack : undefined,\n\t\t\t\t});\n\t\t\t}\n\t\t};\n\n\t\tthis.templateLookup = {\n\t\t\twelcomeEmailTemplate: this.loadTemplate(\"welcomeEmail\"),\n\t\t\temployeeActivationTemplate: this.loadTemplate(\"employeeActivation\"),\n\t\t\tnoIncidentsThisWeekTemplate: this.loadTemplate(\"noIncidentsThisWeek\"),\n\t\t\tpasswordResetTemplate: this.loadTemplate(\"passwordReset\"),\n\t\t\ttestEmailTemplate: this.loadTemplate(\"testEmailTemplate\"),\n\t\t\tunifiedNotificationTemplate: this.loadTemplate(\"unifiedNotification\"),\n\t\t};\n\t};\n\n\tbuildEmail = async (template: string, context: Record<string, unknown>) => {\n\t\ttry {\n\t\t\tconst mjml = this.templateLookup[template]?.(context);\n\t\t\tif (!mjml) {\n\t\t\t\tthrow new Error(`Template ${template} not found`);\n\t\t\t}\n\t\t\tconst html = await this.mjml2html(mjml);\n\t\t\treturn html.html;\n\t\t} catch (error: unknown) {\n\t\t\tthis.logger.error({\n\t\t\t\tmessage: error instanceof Error ? error.message : \"Unknown error\",\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"buildEmail\",\n\t\t\t\tstack: error instanceof Error ? error.stack : undefined,\n\t\t\t});\n\t\t}\n\t};\n\n\tsendEmail = async (to: string, subject: string, html: string, transportConfig?: EmailTransportConfig) => {\n\t\tlet config: EmailTransportConfig;\n\t\tif (typeof transportConfig !== \"undefined\") {\n\t\t\tconfig = transportConfig;\n\t\t} else {\n\t\t\tconfig = await this.settingsService.getDBSettings();\n\t\t}\n\t\tconst {\n\t\t\tsystemEmailHost,\n\t\t\tsystemEmailPort,\n\t\t\tsystemEmailSecure,\n\t\t\tsystemEmailPool,\n\t\t\tsystemEmailUser,\n\t\t\tsystemEmailAddress,\n\t\t\tsystemEmailPassword,\n\t\t\tsystemEmailConnectionHost,\n\t\t\tsystemEmailTLSServername,\n\t\t\tsystemEmailIgnoreTLS,\n\t\t\tsystemEmailRequireTLS,\n\t\t\tsystemEmailRejectUnauthorized,\n\t\t} = config;\n\n\t\tconst emailConfig = {\n\t\t\thost: systemEmailHost,\n\t\t\tport: Number(systemEmailPort),\n\t\t\tsecure: systemEmailSecure,\n\t\t\tauth: {\n\t\t\t\tuser: systemEmailUser || systemEmailAddress,\n\t\t\t\tpass: systemEmailPassword,\n\t\t\t},\n\t\t\tname: systemEmailConnectionHost || \"localhost\",\n\t\t\tconnectionTimeout: 5000,\n\t\t\tpool: systemEmailPool,\n\t\t\ttls: {\n\t\t\t\trejectUnauthorized: systemEmailRejectUnauthorized,\n\t\t\t\tignoreTLS: systemEmailIgnoreTLS,\n\t\t\t\trequireTLS: systemEmailRequireTLS,\n\t\t\t\tservername: systemEmailTLSServername,\n\t\t\t},\n\t\t};\n\t\tthis.transporter = this.nodemailer.createTransport(emailConfig);\n\n\t\ttry {\n\t\t\tawait this.transporter.verify();\n\t\t} catch (error: unknown) {\n\t\t\tthis.logger.warn({\n\t\t\t\tmessage: \"Email transporter verification failed\",\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"verifyTransporter\",\n\t\t\t\tstack: error instanceof Error ? error.stack : undefined,\n\t\t\t});\n\t\t\treturn false;\n\t\t}\n\n\t\ttry {\n\t\t\tconst info = await this.transporter.sendMail({\n\t\t\t\tto: to,\n\t\t\t\tfrom: systemEmailAddress,\n\t\t\t\tsubject: subject,\n\t\t\t\thtml: html,\n\t\t\t});\n\t\t\treturn info?.messageId;\n\t\t} catch (error: unknown) {\n\t\t\tthis.logger.error({\n\t\t\t\tmessage: error instanceof Error ? error.message : \"Unknown error\",\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"sendEmail\",\n\t\t\t\tstack: error instanceof Error ? error.stack : undefined,\n\t\t\t});\n\t\t}\n\t};\n}\n"
  },
  {
    "path": "server/src/service/infrastructure/globalPingService.ts",
    "content": "import type { GeoContinent, GeoCheckResult, GeoCheckTimings, GeoCheckLocation } from \"@/types/geoCheck.js\";\nimport { supportsGeoCheck } from \"@/types/monitor.js\";\nimport { MonitorType } from \"@/types/index.js\";\nimport type { ILogger } from \"@/utils/logger.js\";\nimport got from \"got\";\n\nconst SERVICE_NAME = \"GlobalPingService\";\nconst GLOBAL_PING_API_BASE = \"https://api.globalping.io/v1\";\nconst POLL_INTERVAL_MS = 2000;\nconst MAX_POLL_TIMEOUT_MS = 30000;\n\ninterface GlobalPingMeasurementRequest {\n\ttype: MonitorType;\n\ttarget: string;\n\tlocations: Array<{ continent: GeoContinent }>;\n\tlimit: number;\n}\n\ninterface GlobalPingMeasurementResponse {\n\tid: string;\n\ttype: string;\n\tstatus: \"in-progress\" | \"finished\" | \"failed\";\n\tprobesCount: number;\n\tresults?: GlobalPingProbeResult[];\n}\n\ninterface GlobalPingProbeResult {\n\tprobe: {\n\t\tcontinent: GeoContinent;\n\t\tregion: string;\n\t\tcountry: string;\n\t\tstate: string | null;\n\t\tcity: string;\n\t\tlongitude: number;\n\t\tlatitude: number;\n\t};\n\tresult: {\n\t\tstatus: \"finished\" | \"failed\" | \"timeout\";\n\t\tstatusCode?: number;\n\t\tstatusCodeName?: string;\n\t\ttimings?: {\n\t\t\ttotal: number;\n\t\t\tdns: number;\n\t\t\ttcp: number;\n\t\t\ttls: number;\n\t\t\tfirstByte: number;\n\t\t\tdownload: number;\n\t\t};\n\t\tstats?: {\n\t\t\tmin: number;\n\t\t\tmax: number;\n\t\t\tavg: number;\n\t\t\ttotal: number;\n\t\t\tloss: number;\n\t\t\trcv: number;\n\t\t\tdrop: number;\n\t\t};\n\t\trawOutput?: string;\n\t};\n}\n\nexport interface IGlobalPingService {\n\treadonly serviceName: string;\n\tcreateMeasurement(monitorType: MonitorType, url: string, locations: GeoContinent[]): Promise<string | null>;\n\tpollForResults(measurementId: string, timeoutMs?: number): Promise<GeoCheckResult[]>;\n}\n\nexport class GlobalPingService implements IGlobalPingService {\n\tstatic SERVICE_NAME = SERVICE_NAME;\n\n\tprivate logger: ILogger;\n\n\tconstructor(logger: ILogger) {\n\t\tthis.logger = logger;\n\t}\n\n\tget serviceName() {\n\t\treturn GlobalPingService.SERVICE_NAME;\n\t}\n\n\tasync createMeasurement(monitorType: MonitorType, url: string, locations: GeoContinent[]): Promise<string | null> {\n\t\ttry {\n\t\t\tif (!supportsGeoCheck(monitorType)) {\n\t\t\t\tthrow new Error(`Unsupported monitor type for GlobalPing: ${monitorType}`);\n\t\t\t}\n\t\t\t// GlobalPing API expects target without protocol (http:// or https://)\n\t\t\tconst cleanTarget = url.replace(/^https?:\\/\\//, \"\");\n\n\t\t\tconst requestBody: GlobalPingMeasurementRequest = {\n\t\t\t\ttype: monitorType,\n\t\t\t\ttarget: cleanTarget,\n\t\t\t\tlocations: locations.map((continent) => ({ continent })),\n\t\t\t\tlimit: locations.length,\n\t\t\t};\n\n\t\t\tconst response = await got.post<GlobalPingMeasurementResponse>(`${GLOBAL_PING_API_BASE}/measurements`, {\n\t\t\t\tjson: requestBody,\n\t\t\t\tresponseType: \"json\",\n\t\t\t\ttimeout: { request: 10000 },\n\t\t\t});\n\n\t\t\tconst measurementId = response.body.id;\n\n\t\t\tthis.logger.debug({\n\t\t\t\tmessage: `Created GlobalPing measurement: ${measurementId} for target: ${cleanTarget}`,\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"createMeasurement\",\n\t\t\t});\n\n\t\t\treturn measurementId;\n\t\t} catch (error: unknown) {\n\t\t\tthis.logger.error({\n\t\t\t\tmessage: \"GlobalPing API unavailable, skipping geo check\",\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"createMeasurement\",\n\t\t\t\tstack: error instanceof Error ? error.stack : undefined,\n\t\t\t});\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tasync pollForResults(measurementId: string, timeoutMs: number = MAX_POLL_TIMEOUT_MS): Promise<GeoCheckResult[]> {\n\t\tconst startTime = Date.now();\n\n\t\twhile (Date.now() - startTime < timeoutMs) {\n\t\t\ttry {\n\t\t\t\tconst response = await got.get<GlobalPingMeasurementResponse>(`${GLOBAL_PING_API_BASE}/measurements/${measurementId}`, {\n\t\t\t\t\tresponseType: \"json\",\n\t\t\t\t\ttimeout: { request: 5000 },\n\t\t\t\t});\n\n\t\t\t\tconst measurement = response.body;\n\n\t\t\t\tif (measurement.status === \"finished\") {\n\t\t\t\t\tconst results = this.transformResults(measurement.results || []);\n\t\t\t\t\tthis.logger.debug({\n\t\t\t\t\t\tmessage: `GlobalPing measurement completed: ${measurementId}`,\n\t\t\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\t\t\tmethod: \"pollForResults\",\n\t\t\t\t\t\tdetails: { measurementId, resultsCount: results.length },\n\t\t\t\t\t});\n\t\t\t\t\treturn results;\n\t\t\t\t}\n\n\t\t\t\tif (measurement.status === \"failed\") {\n\t\t\t\t\tthis.logger.warn({\n\t\t\t\t\t\tmessage: `GlobalPing measurement failed: ${measurementId}`,\n\t\t\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\t\t\tmethod: \"pollForResults\",\n\t\t\t\t\t});\n\t\t\t\t\treturn [];\n\t\t\t\t}\n\n\t\t\t\t// Still in-progress, wait and poll again\n\t\t\t\tawait this.sleep(POLL_INTERVAL_MS);\n\t\t\t} catch (error: unknown) {\n\t\t\t\tthis.logger.error({\n\t\t\t\t\tmessage: \"Error polling GlobalPing API\",\n\t\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\t\tmethod: \"pollForResults\",\n\t\t\t\t\tstack: error instanceof Error ? error.stack : undefined,\n\t\t\t\t});\n\t\t\t\treturn [];\n\t\t\t}\n\t\t}\n\n\t\t// Timeout reached\n\t\tthis.logger.warn({\n\t\t\tmessage: `GlobalPing measurement polling timeout: ${measurementId}`,\n\t\t\tservice: SERVICE_NAME,\n\t\t\tmethod: \"pollForResults\",\n\t\t\tdetails: { measurementId, timeoutMs },\n\t\t});\n\t\treturn [];\n\t}\n\n\tprivate transformResults(probeResults: GlobalPingProbeResult[]): GeoCheckResult[] {\n\t\tconst successfulResults: GeoCheckResult[] = [];\n\n\t\tfor (const probeResult of probeResults) {\n\t\t\tif (probeResult.result.status !== \"finished\") {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst location: GeoCheckLocation = {\n\t\t\t\tcontinent: probeResult.probe.continent,\n\t\t\t\tregion: probeResult.probe.region,\n\t\t\t\tcountry: probeResult.probe.country,\n\t\t\t\tstate: probeResult.probe.state || \"\",\n\t\t\t\tcity: probeResult.probe.city,\n\t\t\t\tlongitude: probeResult.probe.longitude,\n\t\t\t\tlatitude: probeResult.probe.latitude,\n\t\t\t};\n\n\t\t\t// HTTP results have statusCode and timings, ping results have stats\n\t\t\tif (probeResult.result.statusCode && probeResult.result.timings) {\n\t\t\t\tconst timings: GeoCheckTimings = {\n\t\t\t\t\ttotal: probeResult.result.timings.total,\n\t\t\t\t\tdns: probeResult.result.timings.dns,\n\t\t\t\t\ttcp: probeResult.result.timings.tcp,\n\t\t\t\t\ttls: probeResult.result.timings.tls,\n\t\t\t\t\tfirstByte: probeResult.result.timings.firstByte,\n\t\t\t\t\tdownload: probeResult.result.timings.download,\n\t\t\t\t};\n\n\t\t\t\tsuccessfulResults.push({\n\t\t\t\t\tlocation,\n\t\t\t\t\tstatus: probeResult.result.statusCode >= 200 && probeResult.result.statusCode < 300,\n\t\t\t\t\tstatusCode: probeResult.result.statusCode,\n\t\t\t\t\ttimings,\n\t\t\t\t});\n\t\t\t} else if (probeResult.result.stats) {\n\t\t\t\tsuccessfulResults.push({\n\t\t\t\t\tlocation,\n\t\t\t\t\tstatus: probeResult.result.stats.loss === 0,\n\t\t\t\t\tstatusCode: probeResult.result.stats.loss === 0 ? 200 : 5000,\n\t\t\t\t\ttimings: {\n\t\t\t\t\t\ttotal: probeResult.result.stats.avg,\n\t\t\t\t\t\tdns: 0,\n\t\t\t\t\t\ttcp: 0,\n\t\t\t\t\t\ttls: 0,\n\t\t\t\t\t\tfirstByte: 0,\n\t\t\t\t\t\tdownload: 0,\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\treturn successfulResults;\n\t}\n\n\tprivate sleep(ms: number): Promise<void> {\n\t\treturn new Promise((resolve) => setTimeout(resolve, ms));\n\t}\n}\n"
  },
  {
    "path": "server/src/service/infrastructure/network/AdvancedMatcher.ts",
    "content": "import { Monitor } from \"@/types/monitor.js\";\nimport jmespath from \"jmespath\";\ntype JmesPath = typeof jmespath;\n\nexport interface IAdvancedMatcher {\n\tvalidate<T>(payload: T, monitor: Monitor): { ok: boolean; message: string; extracted?: T | undefined };\n}\n\nexport class AdvancedMatcher implements IAdvancedMatcher {\n\tconstructor(private jmespath: JmesPath) {}\n\n\tprivate compare(actual: unknown, expected: string, method?: string): boolean {\n\t\tif (method === \"equal\") return String(actual) === expected;\n\t\tif (method === \"include\") return String(actual).includes(expected);\n\t\tif (method === \"regex\") return new RegExp(expected).test(String(actual));\n\t\treturn String(actual) === expected; // Default\n\t}\n\n\tvalidate<T>(payload: T, monitor: Monitor): { ok: boolean; message: string; extracted?: T | undefined } {\n\t\tconst { useAdvancedMatching, jsonPath, matchMethod, expectedValue } = monitor;\n\t\tif (!useAdvancedMatching) return { ok: true, message: \"Success\" };\n\n\t\tlet dataToValidate = payload;\n\n\t\tif (jsonPath) {\n\t\t\ttry {\n\t\t\t\tdataToValidate = this.jmespath.search(payload, jsonPath);\n\t\t\t} catch {\n\t\t\t\treturn { ok: false, message: \"Error evaluating JSON path\" };\n\t\t\t}\n\t\t}\n\n\t\tif (expectedValue) {\n\t\t\tconst ok = this.compare(dataToValidate, expectedValue, matchMethod);\n\t\t\treturn {\n\t\t\t\tok,\n\t\t\t\tmessage: ok ? \"Success\" : \"Expected value did not match\",\n\t\t\t\textracted: dataToValidate,\n\t\t\t};\n\t\t}\n\n\t\tconst isFalsy = dataToValidate === false || dataToValidate === \"false\" || dataToValidate === undefined || dataToValidate === null;\n\t\treturn {\n\t\t\tok: !isFalsy,\n\t\t\tmessage: !isFalsy ? \"Success\" : \"Extracted value is falsy\",\n\t\t\textracted: dataToValidate,\n\t\t};\n\t}\n}\n"
  },
  {
    "path": "server/src/service/infrastructure/network/DockerProvider.ts",
    "content": "import { IStatusProvider } from \"@/service/infrastructure/network/IStatusProvider.js\";\nimport { DockerStatusPayload, MonitorStatusResponse } from \"@/types/network.js\";\nimport { Monitor, MonitorType } from \"@/types/monitor.js\";\nimport { ILogger } from \"@/utils/logger.js\";\nimport { AppError } from \"@/utils/AppError.js\";\nimport Dockerode from \"dockerode\";\nimport { NETWORK_ERROR, timeRequest } from \"@/service/infrastructure/network/utils.js\";\n\ntype DockerodeType = typeof Dockerode;\n\nconst SERVICE_NAME = \"DockerProvider\";\n\nexport interface DockerError extends Error {\n\tstatusCode?: number;\n\treason?: string;\n\tjson?: { message?: string };\n}\n\nexport class DockerProvider implements IStatusProvider<DockerStatusPayload> {\n\treadonly type = \"docker\";\n\tprivate docker: Dockerode;\n\tconstructor(\n\t\tprivate logger: ILogger,\n\t\tprivate DockerLib: DockerodeType\n\t) {\n\t\tthis.docker = new this.DockerLib();\n\t}\n\n\tsupports(type: MonitorType): boolean {\n\t\treturn type === \"docker\";\n\t}\n\n\tprivate isDockerError(error: unknown): error is DockerError {\n\t\treturn error instanceof Error && (\"statusCode\" in error || \"reason\" in error || \"json\" in error);\n\t}\n\n\tasync handle(monitor: Monitor): Promise<MonitorStatusResponse<DockerStatusPayload>> {\n\t\tconst { url: containerInput } = monitor;\n\t\ttry {\n\t\t\tif (!containerInput) {\n\t\t\t\tthrow new Error(\"Container name or ID is required for Docker monitor\");\n\t\t\t}\n\n\t\t\tconst containers = await this.docker.listContainers({ all: true });\n\t\t\tconst normalizedInput = containerInput.replace(/^\\/+/, \"\").toLowerCase();\n\n\t\t\t// Priority-based matching to avoid ambiguity:\n\t\t\t// 1. Exact full ID match (64-char)\n\t\t\tconst exactIdMatch = containers.find((c) => c.Id.toLowerCase() === normalizedInput);\n\n\t\t\t// 2. Exact container name match (case-insensitive)\n\t\t\tconst exactNameMatch = containers.find((c) =>\n\t\t\t\tc.Names.some((name: string) => {\n\t\t\t\t\tconst cleanName = name.replace(/^\\/+/, \"\").toLowerCase();\n\t\t\t\t\treturn cleanName === normalizedInput;\n\t\t\t\t})\n\t\t\t);\n\n\t\t\t// 3. Partial ID match (fallback for backwards compatibility)\n\t\t\tconst partialIdMatch = containers.find((c) => c.Id.toLowerCase().startsWith(normalizedInput));\n\n\t\t\t// Select container based on priority\n\t\t\tconst targetContainer = exactIdMatch || exactNameMatch || partialIdMatch;\n\n\t\t\t// Handle no match\n\t\t\tif (!targetContainer) {\n\t\t\t\tthis.logger.warn({\n\t\t\t\t\tmessage: `No container found for \"${monitor.url}\".`,\n\t\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\t\tmethod: \"handle\",\n\t\t\t\t\tdetails: { url: monitor.url },\n\t\t\t\t});\n\n\t\t\t\treturn {\n\t\t\t\t\tmonitorId: monitor.id,\n\t\t\t\t\tteamId: monitor.teamId,\n\t\t\t\t\ttype: monitor.type,\n\t\t\t\t\tstatus: false,\n\t\t\t\t\tcode: 404,\n\t\t\t\t\tmessage: \"Docker container not found\",\n\t\t\t\t\tresponseTime: 0,\n\t\t\t\t\tpayload: null,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\t// 5. Handle Ambiguity Check\n\t\t\tconst matchTypes: string[] = [];\n\t\t\tif (exactIdMatch) matchTypes.push(\"exact ID\");\n\t\t\tif (exactNameMatch) matchTypes.push(\"exact name\");\n\t\t\tif (partialIdMatch && !exactIdMatch) matchTypes.push(\"partial ID\");\n\n\t\t\tif (matchTypes.length > 1) {\n\t\t\t\tconst message = `Ambiguous container match for \"${containerInput}\". Matched by: ${matchTypes.join(\", \")}. Using ${exactIdMatch ? \"exact ID\" : exactNameMatch ? \"exact name\" : \"partial ID\"} match.`;\n\n\t\t\t\tthis.logger.warn({\n\t\t\t\t\tmessage,\n\t\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\t\tmethod: \"handle\",\n\t\t\t\t\tdetails: { url: containerInput },\n\t\t\t\t});\n\n\t\t\t\treturn {\n\t\t\t\t\tmonitorId: monitor.id,\n\t\t\t\t\tteamId: monitor.teamId,\n\t\t\t\t\ttype: monitor.type,\n\t\t\t\t\tstatus: false,\n\t\t\t\t\tcode: NETWORK_ERROR,\n\t\t\t\t\tmessage,\n\t\t\t\t\tresponseTime: 0,\n\t\t\t\t\tpayload: null,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\t// 6. Inspect Container Status\n\t\t\tconst container = this.docker.getContainer(targetContainer.Id);\n\t\t\tconst { response, responseTime, error } = await timeRequest(() => container.inspect());\n\n\t\t\tif (error) {\n\t\t\t\tlet message = \"Failed to fetch Docker container information\";\n\t\t\t\tlet code = NETWORK_ERROR;\n\n\t\t\t\tif (this.isDockerError(error)) {\n\t\t\t\t\tcode = error.statusCode ?? NETWORK_ERROR;\n\t\t\t\t\tmessage = error.json?.message ?? error.reason ?? error.message;\n\t\t\t\t} else if (error instanceof Error) {\n\t\t\t\t\tmessage = error.message;\n\t\t\t\t}\n\n\t\t\t\treturn {\n\t\t\t\t\tmonitorId: monitor.id,\n\t\t\t\t\tteamId: monitor.teamId,\n\t\t\t\t\ttype: monitor.type,\n\t\t\t\t\tstatus: false,\n\t\t\t\t\tcode: code,\n\t\t\t\t\tmessage: message,\n\t\t\t\t\tresponseTime,\n\t\t\t\t\tpayload: null,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tmonitorId: monitor.id,\n\t\t\t\tteamId: monitor.teamId,\n\t\t\t\ttype: monitor.type,\n\t\t\t\tstatus: response?.State?.Status === \"running\",\n\t\t\t\tcode: 200,\n\t\t\t\tmessage: \"Docker container status fetched successfully\",\n\t\t\t\tresponseTime,\n\t\t\t\tpayload: response as unknown as DockerStatusPayload,\n\t\t\t};\n\t\t} catch (err: unknown) {\n\t\t\tthrow new AppError({\n\t\t\t\tmessage: err instanceof Error ? err.message : \"Error performing Docker request\",\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"handle\",\n\t\t\t\tdetails: { url: containerInput },\n\t\t\t});\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "server/src/service/infrastructure/network/GameProvider.ts",
    "content": "import { IStatusProvider } from \"@/service/infrastructure/network/IStatusProvider.js\";\nimport { GameStatusPayload, MonitorStatusResponse } from \"@/types/network.js\";\nimport { Monitor, MonitorType } from \"@/types/monitor.js\";\nimport { GameDig } from \"gamedig\";\nimport { AppError } from \"@/utils/AppError.js\";\nimport { NETWORK_ERROR } from \"@/service/infrastructure/network/utils.js\";\nimport { ILogger } from \"@/utils/logger.js\";\n\ntype GameDigType = typeof GameDig;\n\nconst SERVICE_NAME = \"GameProvider\";\nexport class GameProvider implements IStatusProvider<GameStatusPayload> {\n\treadonly type = \"game\";\n\tconstructor(\n\t\tprivate logger: ILogger,\n\t\tprivate gameDig: GameDigType\n\t) {}\n\n\tsupports(type: MonitorType): boolean {\n\t\treturn type === \"game\";\n\t}\n\n\tasync handle(monitor: Monitor): Promise<MonitorStatusResponse<GameStatusPayload>> {\n\t\tconst { url, port, gameId, id, teamId, type } = monitor;\n\n\t\t// Clean the host in case a full URL was passed\n\t\tconst host = url?.replace(/^https?:\\/\\//, \"\").split(/[/?#:]/)[0] || \"\";\n\t\ttry {\n\t\t\tconst state = await this.gameDig\n\t\t\t\t.query({\n\t\t\t\t\ttype: gameId ?? \"unknown\",\n\t\t\t\t\thost: host,\n\t\t\t\t\tport: port ?? 0,\n\t\t\t\t})\n\t\t\t\t.catch((error: unknown) => {\n\t\t\t\t\tthis.logger.warn({\n\t\t\t\t\t\tmessage: error instanceof Error ? error.message : String(error),\n\t\t\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\t\t\tmethod: \"handle\",\n\t\t\t\t\t\tdetails: { host, port, gameId },\n\t\t\t\t\t});\n\t\t\t\t\treturn undefined;\n\t\t\t\t});\n\n\t\t\tif (!state) {\n\t\t\t\treturn {\n\t\t\t\t\tmonitorId: id,\n\t\t\t\t\tteamId: teamId,\n\t\t\t\t\ttype: type,\n\t\t\t\t\tstatus: false,\n\t\t\t\t\tcode: NETWORK_ERROR,\n\t\t\t\t\tmessage: \"No response from game server\",\n\t\t\t\t\tresponseTime: 0,\n\t\t\t\t\tpayload: null,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tmonitorId: id,\n\t\t\t\tteamId: teamId,\n\t\t\t\ttype: type,\n\t\t\t\tstatus: true,\n\t\t\t\tcode: 200,\n\t\t\t\tmessage: \"Success\",\n\t\t\t\tresponseTime: state.ping ?? 0,\n\t\t\t\tpayload: state,\n\t\t\t};\n\t\t} catch (err: unknown) {\n\t\t\tconst originalMessage = err instanceof Error ? err.message : String(err);\n\t\t\tthrow new AppError({\n\t\t\t\tmessage: originalMessage || \"Error performing game server check\",\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"handle\",\n\t\t\t\tdetails: { url: monitor.url, port: monitor.port, gameId: monitor.gameId },\n\t\t\t});\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "server/src/service/infrastructure/network/GrpcProvider.ts",
    "content": "import { IStatusProvider } from \"@/service/infrastructure/network/IStatusProvider.js\";\nimport { GrpcStatusPayload, MonitorStatusResponse } from \"@/types/network.js\";\nimport { Monitor, MonitorType } from \"@/types/monitor.js\";\nimport { AppError } from \"@/utils/AppError.js\";\nimport { timeRequest } from \"@/service/infrastructure/network/utils.js\";\nimport * as grpc from \"@grpc/grpc-js\";\nimport * as protoLoader from \"@grpc/proto-loader\";\n\nimport path from \"path\";\nimport { fileURLToPath } from \"url\";\n\ntype GrpcType = typeof grpc;\ntype ProtoLoaderType = typeof protoLoader;\n\nconst SERVICE_NAME = \"GrpcProvider\";\n\nexport class GrpcProvider implements IStatusProvider<GrpcStatusPayload> {\n\treadonly type = \"grpc\";\n\tconstructor(\n\t\tprivate grpc: GrpcType,\n\t\tprivate protoLoader: ProtoLoaderType\n\t) {}\n\n\tsupports(type: MonitorType): boolean {\n\t\treturn type === \"grpc\";\n\t}\n\n\tprivate getGrpcStatusName(code: number): string {\n\t\tconst statusNames: Record<number, string> = {\n\t\t\t0: \"OK\",\n\t\t\t1: \"CANCELLED\",\n\t\t\t2: \"UNKNOWN\",\n\t\t\t3: \"INVALID_ARGUMENT\",\n\t\t\t4: \"DEADLINE_EXCEEDED\",\n\t\t\t5: \"NOT_FOUND\",\n\t\t\t6: \"ALREADY_EXISTS\",\n\t\t\t7: \"PERMISSION_DENIED\",\n\t\t\t8: \"RESOURCE_EXHAUSTED\",\n\t\t\t9: \"FAILED_PRECONDITION\",\n\t\t\t10: \"ABORTED\",\n\t\t\t11: \"OUT_OF_RANGE\",\n\t\t\t12: \"UNIMPLEMENTED\",\n\t\t\t13: \"INTERNAL\",\n\t\t\t14: \"UNAVAILABLE\",\n\t\t\t15: \"DATA_LOSS\",\n\t\t\t16: \"UNAUTHENTICATED\",\n\t\t};\n\t\treturn statusNames[code] || \"UNKNOWN\";\n\t}\n\n\tasync handle(monitor: Monitor): Promise<MonitorStatusResponse<GrpcStatusPayload>> {\n\t\ttry {\n\t\t\tconst { id, teamId, type, url, port, ignoreTlsErrors } = monitor;\n\t\t\tconst grpcServiceName = monitor.grpcServiceName || \"\";\n\n\t\t\tif (!url) {\n\t\t\t\tthrow new AppError({ message: \"Monitor host is required\", service: SERVICE_NAME, method: \"handle\" });\n\t\t\t}\n\t\t\tif (!port) {\n\t\t\t\tthrow new AppError({ message: \"Monitor port is required\", service: SERVICE_NAME, method: \"handle\" });\n\t\t\t}\n\n\t\t\tconst host = url?.replace(/^https?:\\/\\//, \"\").split(/[/?#:]/)[0];\n\t\t\tconst target = `${host}:${port}`;\n\n\t\t\tconst currentFilePath = fileURLToPath(import.meta.url);\n\t\t\tconst protoPath = path.join(path.dirname(currentFilePath), \"protos\", \"health.proto\");\n\t\t\tconst packageDefinition = this.protoLoader.loadSync(protoPath, {\n\t\t\t\tkeepCase: true,\n\t\t\t\tlongs: String,\n\t\t\t\tenums: String,\n\t\t\t\tdefaults: true,\n\t\t\t\toneofs: true,\n\t\t\t});\n\t\t\tconst grpcObject = this.grpc.loadPackageDefinition(packageDefinition) as unknown as {\n\t\t\t\tgrpc: {\n\t\t\t\t\thealth: {\n\t\t\t\t\t\tv1: {\n\t\t\t\t\t\t\tHealth: new (\n\t\t\t\t\t\t\t\ttarget: string,\n\t\t\t\t\t\t\t\tcredentials: unknown\n\t\t\t\t\t\t\t) => {\n\t\t\t\t\t\t\t\tCheck: (request: { service: string }, options: { deadline: Date }, callback: (err: unknown, response: unknown) => void) => void;\n\t\t\t\t\t\t\t\tclose: () => void;\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t};\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tconst healthService = grpcObject.grpc.health.v1.Health;\n\n\t\t\tlet credentials;\n\t\t\tif (ignoreTlsErrors) {\n\t\t\t\tcredentials = this.grpc.credentials.createSsl(null, null, null, {\n\t\t\t\t\tcheckServerIdentity: () => undefined,\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tcredentials = this.grpc.credentials.createInsecure();\n\t\t\t}\n\n\t\t\tconst client = new healthService(target, credentials);\n\n\t\t\tconst TIMEOUT_MS = 10000;\n\t\t\tconst deadline = new Date(Date.now() + TIMEOUT_MS);\n\n\t\t\tconst { response, responseTime, error } = await timeRequest<GrpcStatusPayload>(() => {\n\t\t\t\treturn new Promise<GrpcStatusPayload>((resolve, reject) => {\n\t\t\t\t\tclient.Check({ service: grpcServiceName }, { deadline }, (err: unknown, response: unknown) => {\n\t\t\t\t\t\tclient.close();\n\n\t\t\t\t\t\tif (err) {\n\t\t\t\t\t\t\tconst grpcErr = err as { code?: number; details?: string; message?: string };\n\t\t\t\t\t\t\tconst payload: GrpcStatusPayload = {\n\t\t\t\t\t\t\t\tgrpcStatusCode: grpcErr.code ?? -1,\n\t\t\t\t\t\t\t\tgrpcStatusName: this.getGrpcStatusName(grpcErr.code ?? -1),\n\t\t\t\t\t\t\t\tserviceName: grpcServiceName,\n\t\t\t\t\t\t\t\tservingStatus: \"UNKNOWN\",\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\tconst grpcError = new AppError({\n\t\t\t\t\t\t\t\tmessage: grpcErr.details || grpcErr.message || \"gRPC error\",\n\t\t\t\t\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\t\t\t\t\tmethod: \"handle\",\n\t\t\t\t\t\t\t}) as AppError & { grpcPayload?: GrpcStatusPayload; grpcCode?: number };\n\t\t\t\t\t\t\tgrpcError.grpcPayload = payload;\n\t\t\t\t\t\t\tgrpcError.grpcCode = grpcErr.code;\n\t\t\t\t\t\t\treject(grpcError);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst resp = response as { status?: string } | undefined;\n\t\t\t\t\t\tconst servingStatus = resp?.status ?? \"UNKNOWN\";\n\t\t\t\t\t\tresolve({\n\t\t\t\t\t\t\tgrpcStatusCode: 0,\n\t\t\t\t\t\t\tgrpcStatusName: \"OK\",\n\t\t\t\t\t\t\tserviceName: grpcServiceName,\n\t\t\t\t\t\t\tservingStatus,\n\t\t\t\t\t\t});\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t});\n\n\t\t\tif (error) {\n\t\t\t\tconst grpcError = error as AppError & { grpcPayload?: GrpcStatusPayload; grpcCode?: number };\n\t\t\t\tconst payload = grpcError.grpcPayload;\n\t\t\t\treturn {\n\t\t\t\t\tmonitorId: id,\n\t\t\t\t\tteamId: teamId,\n\t\t\t\t\ttype: type,\n\t\t\t\t\tstatus: false,\n\t\t\t\t\tcode: grpcError.grpcCode ?? 5000,\n\t\t\t\t\tmessage: grpcError.message ?? \"gRPC health check failed\",\n\t\t\t\t\tresponseTime,\n\t\t\t\t\tpayload: payload ?? null,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tconst grpcPayload = response as GrpcStatusPayload;\n\t\t\tconst isServing = grpcPayload.servingStatus === \"SERVING\";\n\n\t\t\treturn {\n\t\t\t\tmonitorId: id,\n\t\t\t\tteamId: teamId,\n\t\t\t\ttype: type,\n\t\t\t\tstatus: isServing,\n\t\t\t\tcode: isServing ? 200 : 5000,\n\t\t\t\tmessage: isServing ? `gRPC service healthy (${grpcPayload.servingStatus})` : `gRPC service unhealthy (${grpcPayload.servingStatus})`,\n\t\t\t\tresponseTime,\n\t\t\t\tpayload: grpcPayload,\n\t\t\t};\n\t\t} catch (err: unknown) {\n\t\t\tconst originalMessage = err instanceof Error ? err.message : String(err);\n\t\t\tthrow new AppError({\n\t\t\t\tmessage: originalMessage || \"Error performing gRPC health check\",\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"handle\",\n\t\t\t\tdetails: { url: monitor.url, port: monitor.port, grpcServiceName: monitor.grpcServiceName },\n\t\t\t});\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "server/src/service/infrastructure/network/HardwareProvider.ts",
    "content": "import { IStatusProvider } from \"@/service/infrastructure/network/IStatusProvider.js\";\nimport { HardwareStatusPayload, MonitorStatusResponse } from \"@/types/network.js\";\nimport { Monitor, MonitorType } from \"@/types/monitor.js\";\nimport { HttpProvider } from \"@/service/infrastructure/network/HttpProvider.js\";\nimport { AppError } from \"@/utils/AppError.js\";\n\nexport class HardwareProvider implements IStatusProvider<HardwareStatusPayload> {\n\treadonly type = \"hardware\";\n\tconstructor(private httpProvider: HttpProvider) {}\n\n\tsupports(type: MonitorType) {\n\t\treturn type === \"hardware\";\n\t}\n\n\tasync handle(monitor: Monitor): Promise<MonitorStatusResponse<HardwareStatusPayload>> {\n\t\tconst { url } = monitor;\n\t\ttry {\n\t\t\tif (!url) throw new Error(\"URL is required for Hardware monitor\");\n\t\t\treturn await this.httpProvider.handle<HardwareStatusPayload>(monitor);\n\t\t} catch (err: unknown) {\n\t\t\tthrow new AppError({\n\t\t\t\tmessage: err instanceof Error ? err.message : \"Error performing Hardware request\",\n\t\t\t\tservice: \"HardwareProvider\",\n\t\t\t\tmethod: \"handle\",\n\t\t\t\tdetails: { url: monitor.url },\n\t\t\t});\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "server/src/service/infrastructure/network/HttpProvider.ts",
    "content": "import { type Got, HTTPError, RequestError } from \"got\";\nimport { IAdvancedMatcher } from \"@/service/infrastructure/network/AdvancedMatcher.js\";\nimport { IStatusProvider } from \"@/service/infrastructure/network/IStatusProvider.js\";\nimport { HttpStatusPayload } from \"@/types/network.js\";\nimport { MonitorStatusResponse } from \"@/types/network.js\";\nimport { Agent as HttpsAgent } from \"https\";\nimport { Monitor, MonitorType } from \"@/types/monitor.js\";\nimport { NETWORK_ERROR } from \"@/service/infrastructure/network/utils.js\";\nimport CacheableLookup from \"cacheable-lookup\";\n\nexport class HttpProvider implements IStatusProvider<HttpStatusPayload> {\n\treadonly type = \"http\";\n\n\tconstructor(\n\t\tprivate got: Got,\n\t\tprivate advancedMatcher: IAdvancedMatcher\n\t) {\n\t\tconst cacheable = new CacheableLookup({ maxTtl: 300, errorTtl: 30 });\n\t\tthis.got = got.extend({\n\t\t\tdnsCache: cacheable,\n\t\t\ttimeout: {\n\t\t\t\trequest: 30000,\n\t\t\t},\n\t\t\tretry: { limit: 1 },\n\t\t});\n\t}\n\n\tsupports(type: MonitorType) {\n\t\treturn type === \"http\";\n\t}\n\n\tprivate handleHttpError<T>(error: unknown, monitor: Monitor): MonitorStatusResponse<T> {\n\t\tif (error instanceof HTTPError || error instanceof RequestError) {\n\t\t\treturn {\n\t\t\t\tmonitorId: monitor.id,\n\t\t\t\tteamId: monitor.teamId,\n\t\t\t\ttype: monitor.type,\n\t\t\t\tstatus: false,\n\t\t\t\tcode: error.response?.statusCode ?? NETWORK_ERROR,\n\t\t\t\tmessage: error.message,\n\t\t\t\tresponseTime: error.timings?.phases?.total ?? 0,\n\t\t\t\ttimings: error.timings,\n\t\t\t\tpayload: null as T,\n\t\t\t};\n\t\t}\n\n\t\treturn {\n\t\t\tmonitorId: monitor.id,\n\t\t\tteamId: monitor.teamId,\n\t\t\ttype: monitor.type,\n\t\t\tstatus: false,\n\t\t\tcode: NETWORK_ERROR,\n\t\t\tmessage: error instanceof Error ? error.message : String(error),\n\t\t\tresponseTime: 0,\n\t\t\tpayload: null as T,\n\t\t};\n\t}\n\n\tasync handle<T>(monitor: Monitor): Promise<MonitorStatusResponse<T>> {\n\t\tconst { url, secret, jsonPath, ignoreTlsErrors } = monitor;\n\n\t\tif (!url) {\n\t\t\tthrow new Error(\"URL is required for HTTP monitor\");\n\t\t}\n\n\t\tconst options: Record<string, unknown> = {\n\t\t\theaders: monitor.secret ? { Authorization: `Bearer ${secret}` } : undefined,\n\t\t};\n\n\t\toptions.agent = {\n\t\t\thttps: new HttpsAgent({ rejectUnauthorized: !ignoreTlsErrors }),\n\t\t};\n\n\t\ttry {\n\t\t\tconst response = await this.got<string>(url, options);\n\t\t\tconst contentType = response.headers[\"content-type\"] || \"\";\n\t\t\tconst isJson = contentType.includes(\"application/json\");\n\n\t\t\tif (jsonPath && !isJson) {\n\t\t\t\treturn {\n\t\t\t\t\tmonitorId: monitor.id,\n\t\t\t\t\tteamId: monitor.teamId,\n\t\t\t\t\ttype: monitor.type,\n\t\t\t\t\tstatus: false,\n\t\t\t\t\tcode: response.statusCode,\n\t\t\t\t\tmessage: \"Response is not JSON\",\n\t\t\t\t\tresponseTime: response.timings.phases.total ?? 0,\n\t\t\t\t\ttimings: response.timings,\n\t\t\t\t\tpayload: response.body as unknown as T,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tlet payload: T;\n\t\t\tif (isJson) {\n\t\t\t\ttry {\n\t\t\t\t\tpayload = JSON.parse(response.body) as T;\n\t\t\t\t} catch {\n\t\t\t\t\tpayload = response.body as unknown as T;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tpayload = response.body as unknown as T;\n\t\t\t}\n\n\t\t\tconst matchResult = this.advancedMatcher.validate<T>(payload, monitor);\n\t\t\treturn {\n\t\t\t\tmonitorId: monitor.id,\n\t\t\t\tteamId: monitor.teamId,\n\t\t\t\ttype: monitor.type,\n\t\t\t\tstatus: response.ok && matchResult.ok,\n\t\t\t\tcode: response.statusCode,\n\t\t\t\tmessage: matchResult.ok ? (response.statusMessage ?? \"OK\") : matchResult.message,\n\t\t\t\tresponseTime: response.timings.phases.total ?? 0,\n\t\t\t\ttimings: response.timings,\n\t\t\t\tpayload,\n\t\t\t\textracted: matchResult.extracted,\n\t\t\t};\n\t\t} catch (error: unknown) {\n\t\t\treturn this.handleHttpError(error, monitor);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "server/src/service/infrastructure/network/IStatusProvider.ts",
    "content": "import { Monitor, MonitorType } from \"@/types/monitor.js\";\nimport { MonitorStatusResponse } from \"@/types/network.js\";\n\nexport interface IStatusProvider<T> {\n\ttype: string;\n\tsupports: (type: MonitorType) => boolean;\n\thandle(monitor: Monitor): Promise<MonitorStatusResponse<T>>;\n}\n"
  },
  {
    "path": "server/src/service/infrastructure/network/PageSpeedProvider.ts",
    "content": "import { IStatusProvider } from \"@/service/infrastructure/network/IStatusProvider.js\";\nimport { MonitorStatusResponse, PageSpeedStatusPayload } from \"@/types/network.js\";\nimport { Monitor, MonitorType } from \"@/types/monitor.js\";\nimport { HttpProvider } from \"@/service/infrastructure/network/HttpProvider.js\";\nimport { ISettingsService } from \"@/service/system/settingsService.js\";\nimport { ILogger } from \"@/utils/logger.js\";\nimport { AppError } from \"@/utils/AppError.js\";\n\nexport class PageSpeedProvider implements IStatusProvider<PageSpeedStatusPayload> {\n\treadonly type = \"pagespeed\";\n\tconstructor(\n\t\tprivate httpProvider: HttpProvider,\n\t\tprivate settingsService: ISettingsService,\n\t\tprivate logger: ILogger\n\t) {}\n\n\tsupports(type: MonitorType) {\n\t\treturn type === \"pagespeed\";\n\t}\n\n\tasync handle(monitor: Monitor): Promise<MonitorStatusResponse<PageSpeedStatusPayload>> {\n\t\tconst { url } = monitor;\n\t\ttry {\n\t\t\tif (!url) throw new Error(\"URL is required for PageSpeed monitor\");\n\t\t\tconst dbSettings = await this.settingsService.getDBSettings();\n\t\t\tconst apiKey = dbSettings?.pagespeedApiKey;\n\t\t\tlet pageSpeedUrl = `https://pagespeedonline.googleapis.com/pagespeedonline/v5/runPagespeed?url=${encodeURIComponent(\n\t\t\t\turl\n\t\t\t)}&category=seo&category=accessibility&category=best-practices&category=performance`;\n\n\t\t\tif (apiKey) {\n\t\t\t\tpageSpeedUrl += `&key=${apiKey}`;\n\t\t\t} else {\n\t\t\t\tthis.logger.warn({\n\t\t\t\t\tmessage: \"PageSpeed API key not found, performance may be throttled\",\n\t\t\t\t\tservice: \"PageSpeedProvider\",\n\t\t\t\t\tmethod: \"handle\",\n\t\t\t\t\tdetails: { url },\n\t\t\t\t});\n\t\t\t}\n\n\t\t\treturn await this.httpProvider.handle<PageSpeedStatusPayload>({\n\t\t\t\t...monitor,\n\t\t\t\turl: pageSpeedUrl,\n\t\t\t});\n\t\t} catch (err: unknown) {\n\t\t\tthrow new AppError({\n\t\t\t\tmessage: err instanceof Error ? err.message : \"Error performing PageSpeed request\",\n\t\t\t\tservice: \"PageSpeedProvider\",\n\t\t\t\tmethod: \"handle\",\n\t\t\t\tdetails: { url: monitor.url },\n\t\t\t});\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "server/src/service/infrastructure/network/PingProvider.ts",
    "content": "import { PingStatusPayload } from \"@/types/network.js\";\nimport { IStatusProvider } from \"./IStatusProvider.js\";\nimport { MonitorType, Monitor } from \"@/types/monitor.js\";\nimport { MonitorStatusResponse } from \"@/types/network.js\";\nimport { AppError } from \"@/utils/AppError.js\";\nimport ping from \"ping\";\nimport { timeRequest } from \"@/service/infrastructure/network/utils.js\";\nconst SERVICE_NAME = \"PingProvider\";\n\ntype Ping = typeof ping;\n\nexport class PingProvider implements IStatusProvider<PingStatusPayload> {\n\treadonly type = \"ping\";\n\n\tconstructor(private ping: Ping) {}\n\n\tsupports(type: MonitorType): boolean {\n\t\treturn type === \"ping\";\n\t}\n\n\tprivate sanitizeHost(url: string): string {\n\t\treturn url\n\t\t\t.replace(/^https?:\\/\\//, \"\")\n\t\t\t.replace(/\\/.*$/, \"\")\n\t\t\t.replace(/:.*/, \"\");\n\t}\n\n\tasync handle(monitor: Monitor): Promise<MonitorStatusResponse<PingStatusPayload>> {\n\t\ttry {\n\t\t\tif (!monitor.url) {\n\t\t\t\tthrow new Error(\"URL is required for ping monitor\");\n\t\t\t}\n\n\t\t\tconst sanitizedHost = this.sanitizeHost(monitor.url);\n\t\t\tconst { response, error } = await timeRequest<PingStatusPayload>(() => this.ping.promise.probe(sanitizedHost));\n\n\t\t\tif (error) {\n\t\t\t\tthrow error;\n\t\t\t}\n\n\t\t\tif (!response) {\n\t\t\t\tthrow new Error(`No response from ping for host: ${sanitizedHost}`);\n\t\t\t}\n\n\t\t\tconst responseTime = typeof response.time === \"number\" ? response.time : parseFloat(String(response.time)) || 0;\n\n\t\t\treturn {\n\t\t\t\tmonitorId: monitor.id,\n\t\t\t\tteamId: monitor.teamId,\n\t\t\t\ttype: monitor.type,\n\t\t\t\tstatus: response.alive ?? false,\n\t\t\t\tcode: response.alive ? 200 : 5000,\n\t\t\t\tmessage: response.alive ? \"Success\" : \"Ping failed\",\n\t\t\t\tresponseTime,\n\t\t\t\tpayload: response,\n\t\t\t};\n\t\t} catch (err: unknown) {\n\t\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\t\tthrow new AppError({\n\t\t\t\tmessage,\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"handle\",\n\t\t\t});\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "server/src/service/infrastructure/network/PortProvider.ts",
    "content": "import { IStatusProvider } from \"@/service/infrastructure/network/IStatusProvider.js\";\nimport { PortStatusPayload, MonitorStatusResponse } from \"@/types/network.js\";\nimport { Monitor, MonitorType } from \"@/types/monitor.js\";\nimport { AppError } from \"@/utils/AppError.js\";\nimport { NETWORK_ERROR, timeRequest } from \"@/service/infrastructure/network/utils.js\";\nimport * as net from \"net\";\ntype NetType = typeof net;\n\nconst SERVICE_NAME = \"PortProvider\";\n\nexport class PortProvider implements IStatusProvider<PortStatusPayload> {\n\treadonly type = \"port\";\n\n\tconstructor(private net: NetType) {}\n\n\tsupports(type: MonitorType): boolean {\n\t\treturn type === \"port\";\n\t}\n\n\tasync handle(monitor: Monitor): Promise<MonitorStatusResponse<PortStatusPayload>> {\n\t\ttry {\n\t\t\tconst { url, port } = monitor;\n\t\t\tif (!url || !port) {\n\t\t\t\tthrow new Error(\"URL and port are required for port monitoring\");\n\t\t\t}\n\n\t\t\tconst { responseTime, error } = await timeRequest(async () => {\n\t\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\t\tconst socket = this.net.createConnection(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\thost: url,\n\t\t\t\t\t\t\tport,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t() => {\n\t\t\t\t\t\t\tsocket.end();\n\t\t\t\t\t\t\tsocket.destroy();\n\t\t\t\t\t\t\tresolve({ success: true });\n\t\t\t\t\t\t}\n\t\t\t\t\t);\n\n\t\t\t\t\tsocket.setTimeout(5000);\n\t\t\t\t\tsocket.on(\"timeout\", () => {\n\t\t\t\t\t\tsocket.destroy();\n\t\t\t\t\t\treject(new Error(\"Connection timeout\"));\n\t\t\t\t\t});\n\n\t\t\t\t\tsocket.on(\"error\", (err: unknown) => {\n\t\t\t\t\t\tsocket.destroy();\n\t\t\t\t\t\treject(err);\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t});\n\t\t\tif (error) {\n\t\t\t\tconst errorMessage = error instanceof Error ? error.message : \"Port check failed\";\n\t\t\t\treturn {\n\t\t\t\t\tmonitorId: monitor.id,\n\t\t\t\t\tteamId: monitor.teamId,\n\t\t\t\t\ttype: monitor.type,\n\t\t\t\t\tstatus: false,\n\t\t\t\t\tcode: NETWORK_ERROR,\n\t\t\t\t\tmessage: errorMessage,\n\t\t\t\t\tresponseTime: responseTime,\n\t\t\t\t\ttimings: undefined,\n\t\t\t\t\tpayload: { success: false },\n\t\t\t\t};\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tmonitorId: monitor.id,\n\t\t\t\tteamId: monitor.teamId,\n\t\t\t\ttype: monitor.type,\n\t\t\t\tstatus: true,\n\t\t\t\tcode: 200,\n\t\t\t\tmessage: \"Port check successful\",\n\t\t\t\tresponseTime: responseTime,\n\t\t\t\ttimings: undefined,\n\t\t\t\tpayload: { success: true },\n\t\t\t};\n\t\t} catch (err: unknown) {\n\t\t\tconst originalMessage = err instanceof Error ? err.message : String(err);\n\t\t\tthrow new AppError({\n\t\t\t\tmessage: originalMessage || \"Error performing port check\",\n\t\t\t\tstatus: 500,\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"handle\",\n\t\t\t\tdetails: { url: monitor.url, port: monitor.port },\n\t\t\t});\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "server/src/service/infrastructure/network/WebSocketProvider.ts",
    "content": "import { IStatusProvider } from \"@/service/infrastructure/network/IStatusProvider.js\";\nimport { WebSocketStatusPayload, MonitorStatusResponse } from \"@/types/network.js\";\nimport { Monitor, MonitorType } from \"@/types/monitor.js\";\nimport { AppError } from \"@/utils/AppError.js\";\nimport { NETWORK_ERROR, timeRequest } from \"@/service/infrastructure/network/utils.js\";\nimport type WebSocket from \"ws\";\n\ntype WebSocketConstructor = typeof WebSocket;\n\nconst SERVICE_NAME = \"WebSocketProvider\";\nconst TIMEOUT_MS = 10000;\n\nexport class WebSocketProvider implements IStatusProvider<WebSocketStatusPayload> {\n\treadonly type = \"websocket\";\n\n\tconstructor(private WS: WebSocketConstructor) {}\n\n\tsupports(type: MonitorType): boolean {\n\t\treturn type === \"websocket\";\n\t}\n\n\tasync handle(monitor: Monitor): Promise<MonitorStatusResponse<WebSocketStatusPayload>> {\n\t\ttry {\n\t\t\tconst { url } = monitor;\n\t\t\tif (!url) {\n\t\t\t\tthrow new Error(\"URL is required for WebSocket monitoring\");\n\t\t\t}\n\n\t\t\tconst { responseTime, error } = await timeRequest(async () => {\n\t\t\t\treturn new Promise<{ connected: boolean }>((resolve, reject) => {\n\t\t\t\t\tconst options: WebSocket.ClientOptions = {};\n\t\t\t\t\tif (monitor.ignoreTlsErrors) {\n\t\t\t\t\t\toptions.rejectUnauthorized = false;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst ws = new this.WS(url, options);\n\n\t\t\t\t\tconst timeout = setTimeout(() => {\n\t\t\t\t\t\tws.close();\n\t\t\t\t\t\treject(new Error(\"WebSocket connection timeout\"));\n\t\t\t\t\t}, TIMEOUT_MS);\n\n\t\t\t\t\tws.on(\"open\", () => {\n\t\t\t\t\t\tclearTimeout(timeout);\n\t\t\t\t\t\tws.close();\n\t\t\t\t\t\tresolve({ connected: true });\n\t\t\t\t\t});\n\n\t\t\t\t\tws.on(\"error\", (err: unknown) => {\n\t\t\t\t\t\tclearTimeout(timeout);\n\t\t\t\t\t\tws.close();\n\t\t\t\t\t\treject(err);\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t});\n\n\t\t\tif (error) {\n\t\t\t\tconst errorMessage = error instanceof Error ? error.message : \"WebSocket check failed\";\n\t\t\t\treturn {\n\t\t\t\t\tmonitorId: monitor.id,\n\t\t\t\t\tteamId: monitor.teamId,\n\t\t\t\t\ttype: monitor.type,\n\t\t\t\t\tstatus: false,\n\t\t\t\t\tcode: NETWORK_ERROR,\n\t\t\t\t\tmessage: errorMessage,\n\t\t\t\t\tresponseTime: responseTime,\n\t\t\t\t\ttimings: undefined,\n\t\t\t\t\tpayload: { connected: false },\n\t\t\t\t};\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tmonitorId: monitor.id,\n\t\t\t\tteamId: monitor.teamId,\n\t\t\t\ttype: monitor.type,\n\t\t\t\tstatus: true,\n\t\t\t\tcode: 200,\n\t\t\t\tmessage: \"WebSocket check successful\",\n\t\t\t\tresponseTime: responseTime,\n\t\t\t\ttimings: undefined,\n\t\t\t\tpayload: { connected: true },\n\t\t\t};\n\t\t} catch (err: unknown) {\n\t\t\tconst originalMessage = err instanceof Error ? err.message : String(err);\n\t\t\tthrow new AppError({\n\t\t\t\tmessage: originalMessage || \"Error performing WebSocket check\",\n\t\t\t\tstatus: 500,\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"handle\",\n\t\t\t\tdetails: { url: monitor.url },\n\t\t\t});\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "server/src/service/infrastructure/network/utils.ts",
    "content": "export const timeRequest = async <T>(operation: () => Promise<T>): Promise<{ response: T | null; responseTime: number; error: unknown }> => {\n\tconst start = process.hrtime.bigint();\n\ttry {\n\t\tconst response = await operation();\n\t\tconst elapsedMs = Math.round(Number(process.hrtime.bigint() - start) / 1_000_000);\n\t\treturn { response, responseTime: elapsedMs, error: null };\n\t} catch (error) {\n\t\tconst elapsedMs = Math.round(Number(process.hrtime.bigint() - start) / 1_000_000);\n\t\treturn { response: null, responseTime: elapsedMs, error };\n\t}\n};\n\nexport const NETWORK_ERROR = 5000;\nexport const PING_ERROR = 5001;\n"
  },
  {
    "path": "server/src/service/infrastructure/networkService.ts",
    "content": "import type { Monitor, MonitorStatusResponse, MonitorPayloadMap, MonitorType } from \"@/types/index.js\";\nimport type { AxiosStatic } from \"axios\";\nimport { AppError } from \"@/utils/AppError.js\";\nimport { NETWORK_ERROR } from \"@/service/infrastructure/network/utils.js\";\nimport { ILogger } from \"@/utils/logger.js\";\nimport { IStatusProvider } from \"./network/IStatusProvider.js\";\nconst SERVICE_NAME = \"NetworkService\";\n\nexport interface INetworkService {\n\treadonly serviceName: string;\n\trequestStatus<T extends MonitorType>(monitor: Monitor & { type: T }): Promise<MonitorStatusResponse<MonitorPayloadMap[T]>>;\n\trequestWebhook(\n\t\ttype: string,\n\t\turl: string,\n\t\tbody: unknown\n\t): Promise<{ type: string; status: boolean; code: number; message: string; payload?: unknown }>;\n\trequestPagerDuty(args: { message: string; routingKey: string; monitorUrl: string }): Promise<boolean>;\n\trequestMatrix(args: { homeserverUrl: string; accessToken: string; roomId: string; message: string }): Promise<{\n\t\tstatus: boolean;\n\t\tcode: number;\n\t\tmessage: string;\n\t\tpayload?: unknown;\n\t}>;\n}\n\nexport class NetworkService implements INetworkService {\n\tstatic SERVICE_NAME = SERVICE_NAME;\n\n\tprivate axios: AxiosStatic;\n\tprivate logger: ILogger;\n\n\tconstructor(\n\t\taxios: AxiosStatic,\n\t\tlogger: ILogger,\n\t\tprivate providers: IStatusProvider<unknown>[]\n\t) {\n\t\tthis.axios = axios;\n\t\tthis.logger = logger;\n\t}\n\n\tget serviceName(): string {\n\t\treturn NetworkService.SERVICE_NAME;\n\t}\n\n\t// Main entry point\n\tasync requestStatus<T extends MonitorType>(monitor: Monitor & { type: T }): Promise<MonitorStatusResponse<MonitorPayloadMap[T]>> {\n\t\tconst provider = this.providers.find((p) => p.supports(monitor.type));\n\t\tif (!provider) {\n\t\t\treturn this.handleUnsupportedType(monitor.type) as Promise<MonitorStatusResponse<MonitorPayloadMap[T]>>;\n\t\t}\n\t\treturn provider.handle(monitor) as Promise<MonitorStatusResponse<MonitorPayloadMap[T]>>;\n\t}\n\n\tprivate async handleUnsupportedType(type: string): Promise<MonitorStatusResponse> {\n\t\treturn {\n\t\t\tmonitorId: \"unknown\",\n\t\t\tteamId: \"unknown\",\n\t\t\ttype: \"unknown\",\n\t\t\tstatus: false,\n\t\t\tcode: NETWORK_ERROR,\n\t\t\tmessage: `Unsupported type: ${type}`,\n\t\t};\n\t}\n\n\t// Other network requests unrelated to monitoring:\n\tasync requestWebhook(type: string, url: string, body: unknown) {\n\t\ttry {\n\t\t\tconst response = await this.axios.post(url, body, {\n\t\t\t\theaders: {\n\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t},\n\t\t\t});\n\n\t\t\treturn {\n\t\t\t\ttype: \"webhook\",\n\t\t\t\tstatus: true,\n\t\t\t\tcode: response.status,\n\t\t\t\tmessage: `Successfully sent ${type} notification`,\n\t\t\t\tpayload: response.data,\n\t\t\t};\n\t\t} catch (err: unknown) {\n\t\t\tthis.logger.warn({\n\t\t\t\tmessage: err instanceof Error ? err.message : String(err),\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"requestWebhook\",\n\t\t\t});\n\n\t\t\tif (err && typeof err === \"object\" && \"response\" in err) {\n\t\t\t\tconst axiosError = err as { response?: { status?: number; data?: unknown } };\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"webhook\",\n\t\t\t\t\tstatus: false,\n\t\t\t\t\tcode: axiosError.response?.status ?? NETWORK_ERROR,\n\t\t\t\t\tmessage: `Failed to send ${type} notification`,\n\t\t\t\t\tpayload: axiosError.response?.data,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\ttype: \"webhook\",\n\t\t\t\tstatus: false,\n\t\t\t\tcode: NETWORK_ERROR,\n\t\t\t\tmessage: `Failed to send ${type} notification`,\n\t\t\t};\n\t\t}\n\t}\n\n\tasync requestPagerDuty({ message, routingKey, monitorUrl }: { message: string; routingKey: string; monitorUrl: string }) {\n\t\ttry {\n\t\t\tconst response = await this.axios.post(`https://events.pagerduty.com/v2/enqueue`, {\n\t\t\t\trouting_key: routingKey,\n\t\t\t\tevent_action: \"trigger\",\n\t\t\t\tpayload: {\n\t\t\t\t\tsummary: message,\n\t\t\t\t\tseverity: \"critical\",\n\t\t\t\t\tsource: monitorUrl,\n\t\t\t\t\ttimestamp: new Date().toISOString(),\n\t\t\t\t},\n\t\t\t});\n\n\t\t\tif (response?.data?.status !== \"success\") return false;\n\t\t\treturn true;\n\t\t} catch (err: unknown) {\n\t\t\tconst originalMessage = err instanceof Error ? err.message : String(err);\n\n\t\t\tthrow new AppError({\n\t\t\t\tmessage: originalMessage || \"Error sending PagerDuty notification\",\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"requestPagerDuty\",\n\t\t\t\tdetails: {\n\t\t\t\t\tresponseData: err && typeof err === \"object\" && \"response\" in err ? (err as { response?: { data?: unknown } }).response?.data : undefined,\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\t}\n\n\tasync requestMatrix({\n\t\thomeserverUrl,\n\t\taccessToken,\n\t\troomId,\n\t\tmessage,\n\t}: {\n\t\thomeserverUrl: string;\n\t\taccessToken: string;\n\t\troomId: string;\n\t\tmessage: string;\n\t}) {\n\t\ttry {\n\t\t\tconst url = `${homeserverUrl}/_matrix/client/v3/rooms/${roomId}/send/m.room.message?access_token=${accessToken}`;\n\t\t\tconst body = {\n\t\t\t\tmsgtype: \"m.text\",\n\t\t\t\tbody: message,\n\t\t\t\tformat: \"org.matrix.custom.html\",\n\t\t\t\tformatted_body: message,\n\t\t\t};\n\t\t\tconst response = await this.axios.post(url, body, {\n\t\t\t\theaders: {\n\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t},\n\t\t\t});\n\n\t\t\treturn {\n\t\t\t\tstatus: true,\n\t\t\t\tcode: response.status,\n\t\t\t\tmessage: \"Successfully sent Matrix notification\",\n\t\t\t};\n\t\t} catch (err: unknown) {\n\t\t\tif (err instanceof Error) {\n\t\t\t\tthis.logger.warn({\n\t\t\t\t\tmessage: err.message,\n\t\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\t\tmethod: \"requestMatrix\",\n\t\t\t\t});\n\n\t\t\t\tif (err && typeof err === \"object\" && \"response\" in err) {\n\t\t\t\t\tconst axiosError = err as { response?: { status?: number; data?: unknown } };\n\t\t\t\t\treturn {\n\t\t\t\t\t\tstatus: false,\n\t\t\t\t\t\tcode: axiosError.response?.status || NETWORK_ERROR,\n\t\t\t\t\t\tmessage: \"Failed to send Matrix notification\",\n\t\t\t\t\t\tpayload: axiosError.response?.data,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.logger.warn({\n\t\t\t\tmessage: String(err),\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"requestMatrix\",\n\t\t\t});\n\n\t\t\treturn {\n\t\t\t\tstatus: false,\n\t\t\t\tcode: NETWORK_ERROR,\n\t\t\t\tmessage: \"Failed to send Matrix notification\",\n\t\t\t};\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "server/src/service/infrastructure/notificationMessageBuilder.ts",
    "content": "import type { HardwareStatusPayload, Monitor, MonitorStatusResponse } from \"@/types/index.js\";\nimport type { MonitorActionDecision } from \"@/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.js\";\nimport type {\n\tNotificationMessage,\n\tNotificationType,\n\tNotificationSeverity,\n\tThresholdBreach,\n\tNotificationContent,\n} from \"@/types/notificationMessage.js\";\n\nexport interface INotificationMessageBuilder {\n\tbuildMessage(\n\t\tmonitor: Monitor,\n\t\tmonitorStatusResponse: MonitorStatusResponse,\n\t\tdecision: MonitorActionDecision,\n\t\tclientHost: string\n\t): NotificationMessage;\n\textractThresholdBreaches(monitor: Monitor, monitorStatusResponse: MonitorStatusResponse): ThresholdBreach[];\n}\n\nconst SERVICE_NAME = \"NotificationMessageBuilder\";\n\nexport class NotificationMessageBuilder implements INotificationMessageBuilder {\n\tstatic SERVICE_NAME = SERVICE_NAME;\n\n\tbuildMessage(\n\t\tmonitor: Monitor,\n\t\tmonitorStatusResponse: MonitorStatusResponse,\n\t\tdecision: MonitorActionDecision,\n\t\tclientHost: string\n\t): NotificationMessage {\n\t\tconst type = this.determineNotificationType(decision, monitor);\n\t\tconst severity = this.determineSeverity(type);\n\t\tconst content = this.buildContent(type, monitor, monitorStatusResponse);\n\n\t\treturn {\n\t\t\ttype,\n\t\t\tseverity,\n\t\t\tmonitor: {\n\t\t\t\tid: monitor.id,\n\t\t\t\tname: monitor.name,\n\t\t\t\turl: monitor.url,\n\t\t\t\ttype: monitor.type,\n\t\t\t\tstatus: monitor.status,\n\t\t\t},\n\t\t\tcontent,\n\t\t\tclientHost,\n\t\t\tmetadata: {\n\t\t\t\tteamId: monitor.teamId,\n\t\t\t\tnotificationReason: decision.notificationReason || \"status_change\",\n\t\t\t},\n\t\t};\n\t}\n\n\tprivate determineNotificationType(decision: MonitorActionDecision, monitor: Monitor): NotificationType {\n\t\t// Down status has highest priority (critical)\n\t\tif (monitor.status === \"down\") {\n\t\t\treturn \"monitor_down\";\n\t\t}\n\n\t\t// Threshold breach (only if not down)\n\t\tif (decision.notificationReason === \"threshold_breach\") {\n\t\t\treturn \"threshold_breach\";\n\t\t}\n\n\t\t// Recovery from threshold breach (only for hardware monitors)\n\t\tif (decision.notificationReason === \"status_change\" && monitor.status === \"up\" && monitor.type === \"hardware\") {\n\t\t\treturn \"threshold_resolved\";\n\t\t}\n\n\t\t// Standard recovery (up)\n\t\tif (monitor.status === \"up\") {\n\t\t\treturn \"monitor_up\";\n\t\t}\n\n\t\t// Default to monitor_up for any other case\n\t\treturn \"monitor_up\";\n\t}\n\n\tprivate determineSeverity(type: NotificationType): NotificationSeverity {\n\t\tswitch (type) {\n\t\t\tcase \"monitor_down\":\n\t\t\t\treturn \"critical\";\n\t\t\tcase \"threshold_breach\":\n\t\t\t\treturn \"warning\";\n\t\t\tcase \"monitor_up\":\n\t\t\tcase \"threshold_resolved\":\n\t\t\t\treturn \"success\";\n\t\t\tcase \"test\":\n\t\t\t\treturn \"info\";\n\t\t\tdefault:\n\t\t\t\treturn \"info\";\n\t\t}\n\t}\n\n\tprivate buildContent(type: NotificationType, monitor: Monitor, monitorStatusResponse: MonitorStatusResponse): NotificationContent {\n\t\tswitch (type) {\n\t\t\tcase \"monitor_down\":\n\t\t\t\treturn this.buildMonitorDownContent(monitor, monitorStatusResponse);\n\t\t\tcase \"monitor_up\":\n\t\t\t\treturn this.buildMonitorUpContent(monitor);\n\t\t\tcase \"threshold_breach\":\n\t\t\t\treturn this.buildThresholdBreachContent(monitor, monitorStatusResponse as MonitorStatusResponse<HardwareStatusPayload>);\n\t\t\tcase \"threshold_resolved\":\n\t\t\t\treturn this.buildThresholdResolvedContent(monitor);\n\t\t\tdefault:\n\t\t\t\treturn this.buildDefaultContent(monitor);\n\t\t}\n\t}\n\n\tprivate buildMonitorDownContent(monitor: Monitor, monitorStatusResponse: MonitorStatusResponse): NotificationContent {\n\t\tconst title = `Monitor Down: ${monitor.name}`;\n\t\tconst summary = `Monitor \"${monitor.name}\" is currently down and unreachable.`;\n\t\tconst details = [`URL: ${monitor.url}`, `Status: Down`, `Type: ${monitor.type}`];\n\n\t\t// Add response code if available\n\t\tif (monitorStatusResponse.code) {\n\t\t\tdetails.push(`Response Code: ${monitorStatusResponse.code}`);\n\t\t}\n\n\t\t// Add error message if available\n\t\tif (monitorStatusResponse.message) {\n\t\t\tdetails.push(`Error: ${monitorStatusResponse.message}`);\n\t\t}\n\n\t\treturn {\n\t\t\ttitle,\n\t\t\tsummary,\n\t\t\tdetails,\n\t\t\ttimestamp: new Date(),\n\t\t};\n\t}\n\n\tprivate buildMonitorUpContent(monitor: Monitor): NotificationContent {\n\t\tconst title = `Monitor Recovered: ${monitor.name}`;\n\t\tconst summary = `Monitor \"${monitor.name}\" is back up and operational.`;\n\t\tconst details = [`URL: ${monitor.url}`, `Status: Up`, `Type: ${monitor.type}`];\n\n\t\treturn {\n\t\t\ttitle,\n\t\t\tsummary,\n\t\t\tdetails,\n\t\t\ttimestamp: new Date(),\n\t\t};\n\t}\n\n\tprivate buildThresholdBreachContent(monitor: Monitor, monitorStatusResponse: MonitorStatusResponse<HardwareStatusPayload>): NotificationContent {\n\t\tconst title = `Threshold Exceeded: ${monitor.name}`;\n\t\tconst summary = `Monitor \"${monitor.name}\" has exceeded one or more thresholds.`;\n\t\tconst details = [`URL: ${monitor.url}`, `Status: Threshold exceeded`, `Type: ${monitor.type}`];\n\n\t\tconst thresholds = this.extractThresholdBreaches(monitor, monitorStatusResponse);\n\n\t\treturn {\n\t\t\ttitle,\n\t\t\tsummary,\n\t\t\tdetails,\n\t\t\tthresholds,\n\t\t\ttimestamp: new Date(),\n\t\t};\n\t}\n\n\tprivate buildThresholdResolvedContent(monitor: Monitor): NotificationContent {\n\t\tconst title = `Thresholds Resolved: ${monitor.name}`;\n\t\tconst summary = `Monitor \"${monitor.name}\" thresholds have returned to normal.`;\n\t\tconst details = [`URL: ${monitor.url}`, `Status: Up`, `Type: ${monitor.type}`];\n\n\t\treturn {\n\t\t\ttitle,\n\t\t\tsummary,\n\t\t\tdetails,\n\t\t\ttimestamp: new Date(),\n\t\t};\n\t}\n\n\tprivate buildDefaultContent(monitor: Monitor): NotificationContent {\n\t\treturn {\n\t\t\ttitle: `Monitor: ${monitor.name}`,\n\t\t\tsummary: `Status update for monitor \"${monitor.name}\".`,\n\t\t\tdetails: [`URL: ${monitor.url}`, `Status: ${monitor.status}`, `Type: ${monitor.type}`],\n\t\t\ttimestamp: new Date(),\n\t\t};\n\t}\n\n\tpublic extractThresholdBreaches(monitor: Monitor, monitorStatusResponse: MonitorStatusResponse<HardwareStatusPayload>): ThresholdBreach[] {\n\t\tconst breaches: ThresholdBreach[] = [];\n\n\t\t// Check if this is a hardware monitor with threshold data\n\t\tif (monitor.type !== \"hardware\" || !monitorStatusResponse.payload) {\n\t\t\treturn breaches;\n\t\t}\n\n\t\t// Cast to HardwareStatusPayload type\n\t\tconst payload = monitorStatusResponse.payload;\n\t\tconst hardware = payload.data;\n\n\t\tif (!hardware) {\n\t\t\treturn breaches;\n\t\t}\n\n\t\t// Note: usage_percent values in hardware payload are decimals (0-1)\n\t\tif (monitor.cpuAlertThreshold !== undefined && monitor.cpuAlertThreshold !== null && hardware.cpu?.usage_percent !== undefined) {\n\t\t\tconst cpuUsageDecimal = hardware.cpu.usage_percent;\n\t\t\tconst cpuPercent = cpuUsageDecimal * 100;\n\t\t\tconst threshold = monitor.cpuAlertThreshold;\n\t\t\tif (cpuPercent > threshold) {\n\t\t\t\tbreaches.push({\n\t\t\t\t\tmetric: \"cpu\",\n\t\t\t\t\tcurrentValue: cpuPercent,\n\t\t\t\t\tthreshold,\n\t\t\t\t\tunit: \"%\",\n\t\t\t\t\tformattedValue: `${cpuPercent.toFixed(1)}%`,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\t// Memory threshold breach\n\t\tif (monitor.memoryAlertThreshold !== undefined && monitor.memoryAlertThreshold !== null && hardware.memory?.usage_percent !== undefined) {\n\t\t\tconst memoryUsageDecimal = hardware.memory.usage_percent;\n\t\t\tconst memoryPercent = memoryUsageDecimal * 100;\n\t\t\tconst threshold = monitor.memoryAlertThreshold;\n\t\t\tif (memoryPercent > threshold) {\n\t\t\t\tbreaches.push({\n\t\t\t\t\tmetric: \"memory\",\n\t\t\t\t\tcurrentValue: memoryPercent,\n\t\t\t\t\tthreshold,\n\t\t\t\t\tunit: \"%\",\n\t\t\t\t\tformattedValue: `${memoryPercent.toFixed(1)}%`,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\t// Disk threshold breach\n\t\tif (monitor.diskAlertThreshold !== undefined && monitor.diskAlertThreshold !== null && Array.isArray(hardware.disk)) {\n\t\t\t// Find the highest disk usage\n\t\t\tlet maxDiskUsageDecimal = 0;\n\t\t\tfor (const disk of hardware.disk) {\n\t\t\t\tif (disk.usage_percent !== undefined && disk.usage_percent > maxDiskUsageDecimal) {\n\t\t\t\t\tmaxDiskUsageDecimal = disk.usage_percent;\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst maxDiskPercent = maxDiskUsageDecimal * 100;\n\t\t\tconst threshold = monitor.diskAlertThreshold;\n\t\t\tif (maxDiskPercent > threshold) {\n\t\t\t\tbreaches.push({\n\t\t\t\t\tmetric: \"disk\",\n\t\t\t\t\tcurrentValue: maxDiskPercent,\n\t\t\t\t\tthreshold,\n\t\t\t\t\tunit: \"%\",\n\t\t\t\t\tformattedValue: `${maxDiskPercent.toFixed(1)}%`,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\t// Temperature threshold breach\n\t\tif (monitor.tempAlertThreshold !== undefined && monitor.tempAlertThreshold !== null && hardware.cpu?.temperature) {\n\t\t\t// Temperature is an array in cpu.temperature\n\t\t\tconst temps = Array.isArray(hardware.cpu.temperature) ? hardware.cpu.temperature : [hardware.cpu.temperature];\n\t\t\tconst maxTemp = Math.max(...temps.filter((t: number) => !isNaN(t)));\n\t\t\tconst threshold = monitor.tempAlertThreshold;\n\t\t\tif (maxTemp >= threshold) {\n\t\t\t\tbreaches.push({\n\t\t\t\t\tmetric: \"temp\",\n\t\t\t\t\tcurrentValue: maxTemp,\n\t\t\t\t\tthreshold,\n\t\t\t\t\tunit: \"°C\",\n\t\t\t\t\tformattedValue: `${maxTemp.toFixed(1)}°C`,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\treturn breaches;\n\t}\n}\n"
  },
  {
    "path": "server/src/service/infrastructure/notificationProviders/INotificationProvider.ts",
    "content": "import type { Notification } from \"@/types/index.js\";\nimport type { NotificationMessage } from \"@/types/notificationMessage.js\";\n\nexport interface INotificationProvider {\n\tsendMessage: (notification: Notification, message: NotificationMessage) => Promise<boolean>;\n\tsendTestAlert(notification: Partial<Notification>): Promise<boolean>;\n}\n"
  },
  {
    "path": "server/src/service/infrastructure/notificationProviders/discord.ts",
    "content": "const SERVICE_NAME = \"DiscordProvider\";\nimport type { AlertDiscordPayload, DiscordEmbedField, Notification } from \"@/types/index.js\";\nimport { INotificationProvider } from \"@/service/index.js\";\nimport { getTestMessage } from \"@/service/infrastructure/notificationProviders/utils.js\";\nimport type { NotificationMessage, NotificationSeverity } from \"@/types/notificationMessage.js\";\nimport got from \"got\";\nimport { ILogger } from \"@/utils/logger.js\";\n\nexport class DiscordProvider implements INotificationProvider {\n\tprivate logger: ILogger;\n\n\tconstructor(logger: ILogger) {\n\t\tthis.logger = logger;\n\t}\n\n\tsendTestAlert = async (notification: Partial<Notification>) => {\n\t\tif (!notification.address) {\n\t\t\treturn false;\n\t\t}\n\t\ttry {\n\t\t\tawait got.post(notification.address, {\n\t\t\t\tjson: { content: getTestMessage() },\n\t\t\t\theaders: {\n\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t},\n\t\t\t});\n\t\t\treturn true;\n\t\t} catch (error) {\n\t\t\tconst err = error as Error;\n\t\t\tthis.logger.warn({\n\t\t\t\tmessage: \"Discord test alert failed\",\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"sendTestAlert\",\n\t\t\t\tstack: err?.stack,\n\t\t\t});\n\t\t\treturn false;\n\t\t}\n\t};\n\n\tasync sendMessage(notification: Notification, message: NotificationMessage): Promise<boolean> {\n\t\tif (!notification.address) {\n\t\t\tthis.logger.warn({\n\t\t\t\tmessage: \"Discord notification missing webhook URL\",\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"sendMessage\",\n\t\t\t});\n\t\t\treturn false;\n\t\t}\n\n\t\tconst embed = this.buildDiscordEmbed(message);\n\n\t\ttry {\n\t\t\tawait got.post(notification.address, {\n\t\t\t\tjson: { embeds: [embed] },\n\t\t\t\theaders: {\n\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t},\n\t\t\t});\n\t\t\treturn true;\n\t\t} catch (error) {\n\t\t\tconst err = error as Error;\n\t\t\tthis.logger.warn({\n\t\t\t\tmessage: \"Discord notification failed\",\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"sendMessage\",\n\t\t\t\tstack: err?.stack,\n\t\t\t});\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tprivate buildDiscordEmbed(message: NotificationMessage): AlertDiscordPayload {\n\t\tconst colorMap: Record<NotificationSeverity, number> = {\n\t\t\tcritical: 0xdc2626, // red-600\n\t\t\twarning: 0xf59e0b, // amber-500\n\t\t\tinfo: 0x3b82f6, // blue-500\n\t\t\tsuccess: 0x10b981, // green-500\n\t\t};\n\n\t\tconst color = colorMap[message.severity] ?? colorMap.info;\n\n\t\tconst fields: Array<DiscordEmbedField> = [];\n\n\t\t// Add monitor details\n\t\tfields.push({\n\t\t\tname: \"Monitor\",\n\t\t\tvalue: message.monitor.name,\n\t\t\tinline: true,\n\t\t});\n\n\t\tfields.push({\n\t\t\tname: \"Type\",\n\t\t\tvalue: message.monitor.type.toUpperCase(),\n\t\t\tinline: true,\n\t\t});\n\n\t\tfields.push({\n\t\t\tname: \"Status\",\n\t\t\tvalue: message.monitor.status.charAt(0).toUpperCase() + message.monitor.status.slice(1),\n\t\t\tinline: true,\n\t\t});\n\n\t\t// Add monitor URL\n\t\tfields.push({\n\t\t\tname: \"URL\",\n\t\t\tvalue: message.monitor.url,\n\t\t\tinline: false,\n\t\t});\n\n\t\t// Add threshold breaches if present\n\t\tif (message.content.thresholds && message.content.thresholds.length > 0) {\n\t\t\tconst thresholdLines = message.content.thresholds\n\t\t\t\t.map((t) => `• **${t.metric.toUpperCase()}**: ${t.formattedValue} (threshold: ${t.threshold}${t.unit})`)\n\t\t\t\t.join(\"\\n\");\n\n\t\t\tfields.push({\n\t\t\t\tname: \"Threshold Breaches\",\n\t\t\t\tvalue: thresholdLines,\n\t\t\t\tinline: false,\n\t\t\t});\n\t\t}\n\n\t\t// Add details if present\n\t\tif (message.content.details && message.content.details.length > 0) {\n\t\t\tconst detailsText = message.content.details.join(\"\\n\");\n\t\t\tfields.push({\n\t\t\t\tname: \"Details\",\n\t\t\t\tvalue: detailsText,\n\t\t\t\tinline: false,\n\t\t\t});\n\t\t}\n\n\t\treturn {\n\t\t\ttitle: message.content.title,\n\t\t\tdescription: message.content.summary,\n\t\t\tcolor,\n\t\t\tfields,\n\t\t\ttimestamp: message.content.timestamp.toISOString(),\n\t\t};\n\t}\n}\n"
  },
  {
    "path": "server/src/service/infrastructure/notificationProviders/email.ts",
    "content": "const SERVICE_NAME = \"EmailProvider\";\nimport type { Notification } from \"@/types/index.js\";\nimport { INotificationProvider } from \"@/service/index.js\";\nimport { buildTestEmail } from \"@/service/infrastructure/notificationProviders/utils.js\";\nimport type { NotificationMessage } from \"@/types/notificationMessage.js\";\nimport type { ILogger } from \"@/utils/logger.js\";\nimport { IEmailService } from \"@/service/infrastructure/emailService.js\";\nexport class EmailProvider implements INotificationProvider {\n\tprivate emailService: IEmailService;\n\tprivate logger: ILogger;\n\n\tconstructor(emailService: IEmailService, logger: ILogger) {\n\t\tthis.emailService = emailService;\n\t\tthis.logger = logger;\n\t}\n\n\tasync sendTestAlert(notification: Partial<Notification>): Promise<boolean> {\n\t\tconst subject = \"Test notification\";\n\t\tconst html = await buildTestEmail(this.emailService);\n\n\t\tif (!notification.address) {\n\t\t\tthis.logger.warn({\n\t\t\t\tmessage: \"Missing address\",\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"sendTestAlert\",\n\t\t\t});\n\t\t\treturn false;\n\t\t}\n\n\t\tif (!html) {\n\t\t\tthis.logger.warn({\n\t\t\t\tmessage: \"Failed to build test email content\",\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"sendTestAlert\",\n\t\t\t});\n\t\t\treturn false;\n\t\t}\n\n\t\tconst messageId = await this.emailService.sendEmail(notification.address, subject, html);\n\t\tif (!messageId) {\n\t\t\tthis.logger.warn({\n\t\t\t\tmessage: \"Email test alert failed\",\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"sendTestAlert\",\n\t\t\t});\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n\tasync sendMessage(notification: Notification, message: NotificationMessage): Promise<boolean> {\n\t\tif (!notification.address) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst subject = this.buildSubject(message);\n\t\tconst html = await this.buildEmailFromMessage(message);\n\n\t\tif (!html) {\n\t\t\tthis.logger.warn({\n\t\t\t\tmessage: \"Failed to build email content\",\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"sendMessage\",\n\t\t\t});\n\t\t\treturn false;\n\t\t}\n\n\t\tconst messageId = await this.emailService.sendEmail(notification.address, subject, html);\n\t\tif (!messageId) {\n\t\t\tthis.logger.warn({\n\t\t\t\tmessage: \"Email notification failed\",\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"sendMessage\",\n\t\t\t});\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n\tprivate buildSubject(message: NotificationMessage): string {\n\t\tswitch (message.type) {\n\t\t\tcase \"monitor_down\":\n\t\t\t\treturn `Monitor ${message.monitor.name} is down`;\n\t\t\tcase \"monitor_up\":\n\t\t\t\treturn `Monitor ${message.monitor.name} is back up`;\n\t\t\tcase \"threshold_breach\":\n\t\t\t\treturn `Monitor ${message.monitor.name} threshold exceeded`;\n\t\t\tcase \"threshold_resolved\":\n\t\t\t\treturn `Monitor ${message.monitor.name} thresholds resolved`;\n\t\t\tdefault:\n\t\t\t\treturn `Alert: ${message.monitor.name}`;\n\t\t}\n\t}\n\n\tprivate async buildEmailFromMessage(message: NotificationMessage): Promise<string | undefined> {\n\t\tconst context = {\n\t\t\ttitle: message.content.title,\n\t\t\tsummary: message.content.summary,\n\t\t\tmonitorName: message.monitor.name,\n\t\t\tmonitorUrl: message.monitor.url,\n\t\t\tmonitorType: message.monitor.type,\n\t\t\tmonitorStatus: message.monitor.status,\n\t\t\theaderColor: this.getColorForSeverity(message.severity),\n\t\t\tthresholds: message.content.thresholds,\n\t\t\tdetails: message.content.details,\n\t\t\tincidentUrl: message.content.incident?.url,\n\t\t};\n\n\t\tthis.logger.info({\n\t\t\tmessage: \"[DEBUG] Building email from message\",\n\t\t\tservice: SERVICE_NAME,\n\t\t\tmethod: \"buildEmailFromMessage\",\n\t\t\tdetails: { context },\n\t\t});\n\n\t\tconst html = await this.emailService.buildEmail(\"unifiedNotificationTemplate\", context);\n\n\t\treturn html;\n\t}\n\n\tprivate getColorForSeverity(severity: string): string {\n\t\tconst colorMap: Record<string, string> = {\n\t\t\tcritical: \"red\",\n\t\t\twarning: \"#f59e0b\",\n\t\t\tinfo: \"#3b82f6\",\n\t\t\tsuccess: \"green\",\n\t\t};\n\t\treturn colorMap[severity] ?? \"#3b82f6\";\n\t}\n}\n"
  },
  {
    "path": "server/src/service/infrastructure/notificationProviders/matrix.ts",
    "content": "const SERVICE_NAME = \"MatrixProvider\";\nimport got from \"got\";\nimport type { INotificationProvider } from \"@/service/index.js\";\nimport type { AlertMatrixPayload, Notification } from \"@/types/index.js\";\nimport type { NotificationMessage } from \"@/types/notificationMessage.js\";\nimport { getTestMessage } from \"@/service/infrastructure/notificationProviders/utils.js\";\nimport { ILogger } from \"@/utils/logger.js\";\n\nexport class MatrixProvider implements INotificationProvider {\n\tprivate logger: ILogger;\n\n\tconstructor(logger: ILogger) {\n\t\tthis.logger = logger;\n\t}\n\n\tsendTestAlert = async (notification: Partial<Notification>) => {\n\t\tconst { homeserverUrl, accessToken, roomId } = notification;\n\t\tif (!homeserverUrl || !accessToken || !roomId) {\n\t\t\treturn false;\n\t\t}\n\t\tconst url = `${homeserverUrl}/_matrix/client/v3/rooms/${roomId}/send/m.room.message?access_token=${accessToken}`;\n\t\tconst body = {\n\t\t\tmsgtype: \"m.text\",\n\t\t\tbody: getTestMessage(),\n\t\t};\n\t\ttry {\n\t\t\tawait got.post(url, {\n\t\t\t\tjson: body,\n\t\t\t\theaders: {\n\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t},\n\t\t\t});\n\t\t\treturn true;\n\t\t} catch (error) {\n\t\t\tconst err = error as Error;\n\t\t\tthis.logger.warn({\n\t\t\t\tmessage: \"Matrix test alert failed\",\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"sendTestAlert\",\n\t\t\t\tstack: err?.stack,\n\t\t\t});\n\t\t\treturn false;\n\t\t}\n\t};\n\n\tsendMessage = async (notification: Notification, message: NotificationMessage): Promise<boolean> => {\n\t\tconst { homeserverUrl, accessToken, roomId } = notification;\n\n\t\tif (!homeserverUrl || !accessToken || !roomId) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst { plainText, htmlText } = this.buildMatrixMessage(message);\n\n\t\tconst url = `${homeserverUrl}/_matrix/client/v3/rooms/${roomId}/send/m.room.message?access_token=${accessToken}`;\n\t\tconst body = {\n\t\t\tmsgtype: \"m.text\",\n\t\t\tbody: plainText,\n\t\t\tformat: \"org.matrix.custom.html\",\n\t\t\tformatted_body: htmlText,\n\t\t};\n\n\t\ttry {\n\t\t\tawait got.post(url, {\n\t\t\t\tjson: body,\n\t\t\t\theaders: {\n\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t},\n\t\t\t});\n\t\t\treturn true;\n\t\t} catch (error) {\n\t\t\tconst err = error as Error;\n\t\t\tthis.logger.warn({\n\t\t\t\tmessage: \"Matrix notification failed\",\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"sendMessage\",\n\t\t\t\tstack: err?.stack,\n\t\t\t});\n\t\t\treturn false;\n\t\t}\n\t};\n\n\t/**\n\t * Build Matrix message from NotificationMessage\n\t * Returns both plain text and HTML formatted versions\n\t * Matrix supports HTML subset for rich formatting\n\t */\n\tprivate buildMatrixMessage(message: NotificationMessage): AlertMatrixPayload {\n\t\tconst plainLines: string[] = [];\n\t\tconst htmlLines: string[] = [];\n\n\t\t// Determine color based on severity\n\t\tconst colorMap = {\n\t\t\tcritical: \"#FF0000\", // Red\n\t\t\twarning: \"#FFA500\", // Orange\n\t\t\tsuccess: \"#00FF00\", // Green\n\t\t\tinfo: \"#0000FF\", // Blue\n\t\t};\n\t\tconst color = colorMap[message.severity] || \"#808080\";\n\n\t\t// Title\n\t\tplainLines.push(`# ${message.content.title}`);\n\t\thtmlLines.push(`<h2 style=\"color: ${color};\">${this.escapeHtml(message.content.title)}</h2>`);\n\n\t\t// Summary\n\t\tplainLines.push(\"\");\n\t\tplainLines.push(message.content.summary);\n\t\thtmlLines.push(`<p>${this.escapeHtml(message.content.summary)}</p>`);\n\n\t\t// Monitor details\n\t\tplainLines.push(\"\");\n\t\tplainLines.push(\"## Monitor Details\");\n\t\tplainLines.push(`- Name: ${message.monitor.name}`);\n\t\tplainLines.push(`- URL: ${message.monitor.url}`);\n\t\tplainLines.push(`- Type: ${message.monitor.type}`);\n\t\tplainLines.push(`- Status: ${message.monitor.status}`);\n\n\t\thtmlLines.push(`<h3>Monitor Details</h3>`);\n\t\thtmlLines.push(`<ul>`);\n\t\thtmlLines.push(`<li><strong>Name:</strong> ${this.escapeHtml(message.monitor.name)}</li>`);\n\t\thtmlLines.push(`<li><strong>URL:</strong> <a href=\"${this.escapeHtml(message.monitor.url)}\">${this.escapeHtml(message.monitor.url)}</a></li>`);\n\t\thtmlLines.push(`<li><strong>Type:</strong> ${this.escapeHtml(message.monitor.type)}</li>`);\n\t\thtmlLines.push(`<li><strong>Status:</strong> ${this.escapeHtml(message.monitor.status)}</li>`);\n\t\thtmlLines.push(`</ul>`);\n\n\t\t// Threshold breaches (if any)\n\t\tif (message.content.thresholds && message.content.thresholds.length > 0) {\n\t\t\tplainLines.push(\"\");\n\t\t\tplainLines.push(\"## Threshold Breaches\");\n\t\t\thtmlLines.push(`<h3>Threshold Breaches</h3>`);\n\t\t\thtmlLines.push(`<ul>`);\n\n\t\t\tmessage.content.thresholds.forEach((breach) => {\n\t\t\t\tplainLines.push(`- ${breach.metric.toUpperCase()}: ${breach.formattedValue} (threshold: ${breach.threshold}${breach.unit})`);\n\t\t\t\thtmlLines.push(\n\t\t\t\t\t`<li><strong>${this.escapeHtml(breach.metric.toUpperCase())}:</strong> ${this.escapeHtml(breach.formattedValue)} (threshold: ${breach.threshold}${this.escapeHtml(breach.unit)})</li>`\n\t\t\t\t);\n\t\t\t});\n\n\t\t\thtmlLines.push(`</ul>`);\n\t\t}\n\n\t\t// Additional details (if any)\n\t\tif (message.content.details && message.content.details.length > 0) {\n\t\t\tplainLines.push(\"\");\n\t\t\tplainLines.push(\"## Additional Information\");\n\t\t\thtmlLines.push(`<h3>Additional Information</h3>`);\n\t\t\thtmlLines.push(`<ul>`);\n\n\t\t\tmessage.content.details.forEach((detail) => {\n\t\t\t\tplainLines.push(`- ${detail}`);\n\t\t\t\thtmlLines.push(`<li>${this.escapeHtml(detail)}</li>`);\n\t\t\t});\n\n\t\t\thtmlLines.push(`</ul>`);\n\t\t}\n\n\t\t// Incident link (if incident exists)\n\t\tif (message.content.incident) {\n\t\t\tconst incidentUrl = `${message.clientHost}/infrastructure/${message.monitor.id}`;\n\t\t\tplainLines.push(\"\");\n\t\t\tplainLines.push(`View Incident: ${incidentUrl}`);\n\t\t\thtmlLines.push(`<p><a href=\"${this.escapeHtml(incidentUrl)}\">View Incident</a></p>`);\n\t\t}\n\n\t\t// Footer with timestamp\n\t\tplainLines.push(\"\");\n\t\tplainLines.push(`Checkmate | ${new Date(message.content.timestamp).toUTCString()}`);\n\t\thtmlLines.push(`<hr>`);\n\t\thtmlLines.push(`<p><small>Checkmate | ${new Date(message.content.timestamp).toUTCString()}</small></p>`);\n\n\t\treturn {\n\t\t\tplainText: plainLines.join(\"\\n\"),\n\t\t\thtmlText: htmlLines.join(\"\"),\n\t\t};\n\t}\n\n\t/**\n\t * Escape HTML special characters for safe rendering\n\t */\n\tprivate escapeHtml(text: string): string {\n\t\treturn text.replace(/&/g, \"&amp;\").replace(/</g, \"&lt;\").replace(/>/g, \"&gt;\").replace(/\"/g, \"&quot;\").replace(/'/g, \"&#039;\");\n\t}\n}\n"
  },
  {
    "path": "server/src/service/infrastructure/notificationProviders/pagerduty.ts",
    "content": "const SERVICE_NAME = \"PagerDutyProvider\";\nimport got from \"got\";\nimport type { Notification } from \"@/types/index.js\";\nimport { INotificationProvider } from \"@/service/index.js\";\nimport type { NotificationMessage } from \"@/types/notificationMessage.js\";\nimport { getTestMessage } from \"@/service/infrastructure/notificationProviders/utils.js\";\nimport { ILogger } from \"@/utils/logger.js\";\nimport { AlertPagerDutyPayload } from \"@/types/index.js\";\n\nexport class PagerDutyProvider implements INotificationProvider {\n\tprivate logger: ILogger;\n\n\tconstructor(logger: ILogger) {\n\t\tthis.logger = logger;\n\t}\n\n\tasync sendTestAlert(notification: Partial<Notification>): Promise<boolean> {\n\t\ttry {\n\t\t\tawait got.post(\"https://events.pagerduty.com/v2/enqueue\", {\n\t\t\t\tjson: {\n\t\t\t\t\trouting_key: notification.address,\n\t\t\t\t\tevent_action: \"trigger\",\n\t\t\t\t\tpayload: {\n\t\t\t\t\t\tsummary: getTestMessage(),\n\t\t\t\t\t\tseverity: \"info\",\n\t\t\t\t\t\tsource: \"checkmate\",\n\t\t\t\t\t\ttimestamp: new Date().toISOString(),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tresponseType: \"json\",\n\t\t\t});\n\t\t\treturn true;\n\t\t} catch (error) {\n\t\t\tconst err = error as Error;\n\t\t\tthis.logger.warn({\n\t\t\t\tmessage: \"PagerDuty test alert failed\",\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"sendTestAlert\",\n\t\t\t\tstack: err?.stack,\n\t\t\t});\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * New unified message format implementation\n\t */\n\tasync sendMessage(notification: Notification, message: NotificationMessage): Promise<boolean> {\n\t\tif (!notification.address) {\n\t\t\tthis.logger.warn({\n\t\t\t\tmessage: \"PagerDuty notification missing routing key\",\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"sendMessage\",\n\t\t\t});\n\t\t\treturn false;\n\t\t}\n\n\t\ttry {\n\t\t\tconst payload = this.buildPagerDutyPayload(notification, message);\n\t\t\tawait got.post(\"https://events.pagerduty.com/v2/enqueue\", {\n\t\t\t\tjson: payload,\n\t\t\t});\n\t\t\tthis.logger.info({\n\t\t\t\tmessage: \"[NEW] PagerDuty notification sent via sendMessage\",\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"sendMessage\",\n\t\t\t});\n\t\t\treturn true;\n\t\t} catch (error) {\n\t\t\tconst err = error as Error;\n\t\t\tthis.logger.warn({\n\t\t\t\tmessage: \"PagerDuty notification failed\",\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"sendMessage\",\n\t\t\t\tstack: err?.stack,\n\t\t\t});\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tprivate buildPagerDutyPayload(notification: Notification, message: NotificationMessage): AlertPagerDutyPayload {\n\t\t// Map our notification type to PagerDuty event_action\n\t\tconst eventAction = message.type === \"monitor_up\" || message.type === \"threshold_resolved\" ? \"resolve\" : \"trigger\";\n\n\t\t// Map severity to PagerDuty severity levels\n\t\tconst severityMap: Record<string, string> = {\n\t\t\tcritical: \"critical\",\n\t\t\twarning: \"warning\",\n\t\t\tinfo: \"info\",\n\t\t\tsuccess: \"info\",\n\t\t};\n\n\t\tconst severity = severityMap[message.severity] || \"error\";\n\n\t\t// Build deduplication key based on monitor ID for event grouping\n\t\tconst dedupKey = `checkmate-${message.monitor.id}`;\n\n\t\t// Build summary\n\t\tlet summary = `${message.content.title} - ${message.content.summary}`;\n\n\t\t// Add threshold details to summary if present\n\t\tif (message.content.thresholds && message.content.thresholds.length > 0) {\n\t\t\tconst thresholdInfo = message.content.thresholds\n\t\t\t\t.map((t) => `${t.metric.toUpperCase()}: ${t.formattedValue}/${t.threshold}${t.unit}`)\n\t\t\t\t.join(\", \");\n\t\t\tsummary += ` [${thresholdInfo}]`;\n\t\t}\n\n\t\t// Build custom details\n\t\tconst customDetails: Record<string, unknown> = {\n\t\t\tmonitor_name: message.monitor.name,\n\t\t\tmonitor_url: message.monitor.url,\n\t\t\tmonitor_type: message.monitor.type,\n\t\t\tmonitor_status: message.monitor.status,\n\t\t\tnotification_type: message.type,\n\t\t};\n\n\t\tif (message.content.thresholds && message.content.thresholds.length > 0) {\n\t\t\tcustomDetails.threshold_breaches = message.content.thresholds.map((t) => ({\n\t\t\t\tmetric: t.metric,\n\t\t\t\tcurrent: t.formattedValue,\n\t\t\t\tthreshold: `${t.threshold}${t.unit}`,\n\t\t\t}));\n\t\t}\n\n\t\tif (message.content.details && message.content.details.length > 0) {\n\t\t\tcustomDetails.details = message.content.details;\n\t\t}\n\n\t\treturn {\n\t\t\trouting_key: notification.address,\n\t\t\tdedup_key: dedupKey,\n\t\t\tevent_action: eventAction,\n\t\t\tpayload: {\n\t\t\t\tsummary,\n\t\t\t\tseverity,\n\t\t\t\tsource: message.monitor.url,\n\t\t\t\ttimestamp: message.content.timestamp.toISOString(),\n\t\t\t\tcustom_details: customDetails,\n\t\t\t},\n\t\t};\n\t}\n}\n"
  },
  {
    "path": "server/src/service/infrastructure/notificationProviders/slack.ts",
    "content": "const SERVICE_NAME = \"SlackProvider\";\nimport type { Notification } from \"@/types/index.js\";\nimport { INotificationProvider } from \"@/service/index.js\";\nimport type { NotificationMessage } from \"@/types/notificationMessage.js\";\nimport { getTestMessage } from \"@/service/infrastructure/notificationProviders/utils.js\";\nimport got, { HTTPError } from \"got\";\nimport { ILogger } from \"@/utils/logger.js\";\n\nexport class SlackProvider implements INotificationProvider {\n\tprivate logger: ILogger;\n\n\tconstructor(logger: ILogger) {\n\t\tthis.logger = logger;\n\t}\n\n\tasync sendTestAlert(notification: Partial<Notification>): Promise<boolean> {\n\t\tif (!notification.address) {\n\t\t\treturn false;\n\t\t}\n\n\t\ttry {\n\t\t\tawait got.post(notification.address, {\n\t\t\t\tjson: { text: getTestMessage() },\n\t\t\t\theaders: {\n\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t},\n\t\t\t});\n\t\t\treturn true;\n\t\t} catch (error) {\n\t\t\tconst err = error as HTTPError;\n\t\t\tthis.logger.warn({\n\t\t\t\tmessage: \"Slack test alert failed\",\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"sendTestAlert\",\n\t\t\t\tstack: err?.stack,\n\t\t\t});\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * New unified message format - builds Slack Block Kit payload from NotificationMessage\n\t */\n\tasync sendMessage(notification: Notification, message: NotificationMessage): Promise<boolean> {\n\t\tif (!notification.address) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst payload = this.buildSlackPayload(message);\n\n\t\ttry {\n\t\t\tawait got.post(notification.address, {\n\t\t\t\tjson: payload,\n\t\t\t\theaders: {\n\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t},\n\t\t\t});\n\t\t\tthis.logger.info({\n\t\t\t\tmessage: \"[NEW] Slack notification sent via sendMessage\",\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"sendMessage\",\n\t\t\t});\n\t\t\treturn true;\n\t\t} catch (error) {\n\t\t\tconst err = error as Error;\n\t\t\tthis.logger.warn({\n\t\t\t\tmessage: \"[NEW] Slack alert failed via sendMessage\",\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"sendMessage\",\n\t\t\t\tstack: err?.stack,\n\t\t\t});\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * Build Slack Block Kit payload from NotificationMessage\n\t * Uses Slack's rich formatting with sections, fields, and context blocks\n\t */\n\tprivate buildSlackPayload(message: NotificationMessage): object {\n\t\tconst blocks: unknown[] = [];\n\n\t\t// Determine color based on severity\n\t\tconst colorMap = {\n\t\t\tcritical: \"#FF0000\", // Red\n\t\t\twarning: \"#FFA500\", // Orange\n\t\t\tsuccess: \"#00FF00\", // Green\n\t\t\tinfo: \"#0000FF\", // Blue\n\t\t};\n\t\tconst color = colorMap[message.severity] || \"#808080\";\n\n\t\t// Header block with title\n\t\tblocks.push({\n\t\t\ttype: \"header\",\n\t\t\ttext: {\n\t\t\t\ttype: \"plain_text\",\n\t\t\t\ttext: message.content.title,\n\t\t\t\temoji: true,\n\t\t\t},\n\t\t});\n\n\t\t// Summary section\n\t\tblocks.push({\n\t\t\ttype: \"section\",\n\t\t\ttext: {\n\t\t\t\ttype: \"mrkdwn\",\n\t\t\t\ttext: message.content.summary,\n\t\t\t},\n\t\t});\n\n\t\t// Monitor details as fields\n\t\tconst monitorFields = [\n\t\t\t{ type: \"mrkdwn\", text: `*Name:*\\n${message.monitor.name}` },\n\t\t\t{ type: \"mrkdwn\", text: `*Type:*\\n${message.monitor.type}` },\n\t\t\t{ type: \"mrkdwn\", text: `*Status:*\\n${message.monitor.status}` },\n\t\t\t{ type: \"mrkdwn\", text: `*URL:*\\n${message.monitor.url}` },\n\t\t];\n\n\t\tblocks.push({\n\t\t\ttype: \"section\",\n\t\t\tfields: monitorFields,\n\t\t});\n\n\t\t// Divider\n\t\tblocks.push({ type: \"divider\" });\n\n\t\t// Threshold breaches (if any)\n\t\tif (message.content.thresholds && message.content.thresholds.length > 0) {\n\t\t\tconst thresholdText = message.content.thresholds\n\t\t\t\t.map((breach) => `• *${breach.metric.toUpperCase()}:* ${breach.formattedValue} (threshold: ${breach.threshold}${breach.unit})`)\n\t\t\t\t.join(\"\\n\");\n\n\t\t\tblocks.push({\n\t\t\t\ttype: \"section\",\n\t\t\t\ttext: {\n\t\t\t\t\ttype: \"mrkdwn\",\n\t\t\t\t\ttext: `*Threshold Breaches:*\\n${thresholdText}`,\n\t\t\t\t},\n\t\t\t});\n\n\t\t\tblocks.push({ type: \"divider\" });\n\t\t}\n\n\t\t// Additional details (if any)\n\t\tif (message.content.details && message.content.details.length > 0) {\n\t\t\tconst detailsText = message.content.details.map((detail) => `• ${detail}`).join(\"\\n\");\n\n\t\t\tblocks.push({\n\t\t\t\ttype: \"section\",\n\t\t\t\ttext: {\n\t\t\t\t\ttype: \"mrkdwn\",\n\t\t\t\t\ttext: `*Additional Information:*\\n${detailsText}`,\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\n\t\t// Incident link button (if incident exists)\n\t\tif (message.content.incident) {\n\t\t\tblocks.push({\n\t\t\t\ttype: \"actions\",\n\t\t\t\telements: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: \"button\",\n\t\t\t\t\t\ttext: {\n\t\t\t\t\t\t\ttype: \"plain_text\",\n\t\t\t\t\t\t\ttext: \"View Incident\",\n\t\t\t\t\t\t\temoji: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\turl: `${message.clientHost}/infrastructure/${message.monitor.id}`,\n\t\t\t\t\t\tstyle: \"primary\",\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t});\n\t\t}\n\n\t\t// Context footer with timestamp\n\t\tblocks.push({\n\t\t\ttype: \"context\",\n\t\t\telements: [\n\t\t\t\t{\n\t\t\t\t\ttype: \"mrkdwn\",\n\t\t\t\t\ttext: `Checkmate | ${new Date(message.content.timestamp).toUTCString()}`,\n\t\t\t\t},\n\t\t\t],\n\t\t});\n\n\t\t// Return Slack payload with blocks and attachment color\n\t\treturn {\n\t\t\tblocks,\n\t\t\tattachments: [\n\t\t\t\t{\n\t\t\t\t\tcolor,\n\t\t\t\t\tblocks: [], // Empty blocks in attachment for color bar\n\t\t\t\t},\n\t\t\t],\n\t\t};\n\t}\n}\n"
  },
  {
    "path": "server/src/service/infrastructure/notificationProviders/teams.ts",
    "content": "const SERVICE_NAME = \"TeamsProvider\";\nimport type { Notification } from \"@/types/index.js\";\nimport { INotificationProvider } from \"@/service/index.js\";\nimport type { NotificationMessage } from \"@/types/notificationMessage.js\";\nimport { getTestMessage } from \"@/service/infrastructure/notificationProviders/utils.js\";\nimport type { ILogger } from \"@/utils/logger.js\";\nimport got, { HTTPError } from \"got\";\n\n// Types for Adaptive Card elements\ntype TextBlock = {\n\ttype: \"TextBlock\";\n\ttext: string;\n\tweight?: \"Bolder\" | \"Normal\" | \"Lighter\";\n\tsize?: \"Small\" | \"Medium\" | \"Large\" | \"ExtraLarge\";\n\tcolor?: \"Default\" | \"Dark\" | \"Light\" | \"Accent\" | \"Good\" | \"Warning\" | \"Attention\";\n\twrap?: boolean;\n\tspacing?: \"None\" | \"Small\" | \"Medium\" | \"Large\" | \"ExtraLarge\" | \"Auto\";\n\tisSubtle?: boolean;\n};\n\ntype ColumnSet = {\n\ttype: \"ColumnSet\";\n\tseparator?: boolean;\n\tspacing?: \"None\" | \"Small\" | \"Medium\" | \"Large\" | \"ExtraLarge\" | \"Auto\";\n\tcolumns: unknown[];\n};\n\ntype Fact = {\n\ttitle: string;\n\tvalue: string;\n};\n\ntype FactSet = {\n\ttype: \"FactSet\";\n\tfacts: Fact[];\n};\n\ntype Action = {\n\ttype: string;\n\ttitle: string;\n\turl?: string;\n};\n\ntype AdaptiveCard = {\n\ttype: \"AdaptiveCard\";\n\t$schema: \"http://adaptivecards.io/schemas/adaptive-card.json\";\n\tversion: \"1.4\";\n\tbody: (TextBlock | ColumnSet | FactSet)[];\n\tactions?: Action[];\n};\n\ntype TeamsMessage = {\n\ttype: \"message\";\n\tattachments: Array<{\n\t\tcontentType: \"application/vnd.microsoft.card.adaptive\";\n\t\tcontentUrl: null;\n\t\tcontent: AdaptiveCard;\n\t}>;\n};\n\nexport class TeamsProvider implements INotificationProvider {\n\tprivate logger: ILogger;\n\n\tconstructor(logger: ILogger) {\n\t\tthis.logger = logger;\n\t}\n\n\tasync sendTestAlert(notification: Partial<Notification>): Promise<boolean> {\n\t\tif (!notification.address) {\n\t\t\treturn false;\n\t\t}\n\n\t\ttry {\n\t\t\tconst payload = this.wrapAdaptiveCard({\n\t\t\t\ttype: \"AdaptiveCard\",\n\t\t\t\t$schema: \"http://adaptivecards.io/schemas/adaptive-card.json\",\n\t\t\t\tversion: \"1.4\",\n\t\t\t\tbody: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: \"TextBlock\",\n\t\t\t\t\t\ttext: getTestMessage(),\n\t\t\t\t\t\tweight: \"Bolder\",\n\t\t\t\t\t\tsize: \"Medium\",\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t});\n\n\t\t\tawait got.post(notification.address, {\n\t\t\t\tjson: payload,\n\t\t\t\theaders: {\n\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t},\n\t\t\t});\n\t\t\treturn true;\n\t\t} catch (error) {\n\t\t\tconst err = error as HTTPError;\n\t\t\tthis.logger.warn({\n\t\t\t\tmessage: \"Teams test alert failed\",\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"sendTestAlert\",\n\t\t\t\tstack: err?.stack,\n\t\t\t});\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tasync sendMessage(notification: Notification, message: NotificationMessage): Promise<boolean> {\n\t\tif (!notification.address) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst payload = this.wrapAdaptiveCard(this.buildAdaptiveCard(message));\n\n\t\ttry {\n\t\t\tawait got.post(notification.address, {\n\t\t\t\tjson: payload,\n\t\t\t\theaders: {\n\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t},\n\t\t\t});\n\t\t\tthis.logger.info({\n\t\t\t\tmessage: \"Teams notification sent via sendMessage\",\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"sendMessage\",\n\t\t\t});\n\t\t\treturn true;\n\t\t} catch (error) {\n\t\t\tconst err = error as HTTPError;\n\t\t\tthis.logger.warn({\n\t\t\t\tmessage: \"Teams alert failed via sendMessage\",\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"sendMessage\",\n\t\t\t\tstack: err?.stack,\n\t\t\t});\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * Wrap an Adaptive Card in the Teams webhook envelope format\n\t */\n\tprivate wrapAdaptiveCard(card: AdaptiveCard): TeamsMessage {\n\t\treturn {\n\t\t\ttype: \"message\",\n\t\t\tattachments: [\n\t\t\t\t{\n\t\t\t\t\tcontentType: \"application/vnd.microsoft.card.adaptive\",\n\t\t\t\t\tcontentUrl: null,\n\t\t\t\t\tcontent: card,\n\t\t\t\t},\n\t\t\t],\n\t\t};\n\t}\n\n\t/**\n\t * Build an Adaptive Card from NotificationMessage\n\t */\n\tprivate buildAdaptiveCard(message: NotificationMessage): AdaptiveCard {\n\t\tconst colorMap: Record<string, string> = {\n\t\t\tcritical: \"attention\",\n\t\t\twarning: \"warning\",\n\t\t\tsuccess: \"good\",\n\t\t\tinfo: \"accent\",\n\t\t};\n\t\tconst color = (colorMap[message.severity] || \"default\") as \"Default\" | \"Dark\" | \"Light\" | \"Accent\" | \"Good\" | \"Warning\" | \"Attention\" | undefined;\n\n\t\tconst body: (TextBlock | ColumnSet | FactSet)[] = [];\n\n\t\t// Header with colored status indicator\n\t\tbody.push({\n\t\t\ttype: \"TextBlock\",\n\t\t\ttext: message.content.title,\n\t\t\tweight: \"Bolder\",\n\t\t\tsize: \"Large\",\n\t\t\tcolor,\n\t\t\twrap: true,\n\t\t});\n\n\t\t// Summary\n\t\tbody.push({\n\t\t\ttype: \"TextBlock\",\n\t\t\ttext: message.content.summary,\n\t\t\twrap: true,\n\t\t\tspacing: \"Small\",\n\t\t});\n\n\t\t// Separator\n\t\tbody.push({\n\t\t\ttype: \"ColumnSet\",\n\t\t\tseparator: true,\n\t\t\tspacing: \"Medium\",\n\t\t\tcolumns: [],\n\t\t});\n\n\t\t// Monitor details as a FactSet\n\t\tbody.push({\n\t\t\ttype: \"FactSet\",\n\t\t\tfacts: [\n\t\t\t\t{ title: \"Name\", value: message.monitor.name },\n\t\t\t\t{ title: \"Type\", value: message.monitor.type },\n\t\t\t\t{ title: \"Status\", value: message.monitor.status },\n\t\t\t\t{ title: \"URL\", value: message.monitor.url },\n\t\t\t],\n\t\t});\n\n\t\t// Threshold breaches\n\t\tif (message.content.thresholds && message.content.thresholds.length > 0) {\n\t\t\tbody.push({\n\t\t\t\ttype: \"TextBlock\",\n\t\t\t\ttext: \"**Threshold Breaches**\",\n\t\t\t\tweight: \"Bolder\",\n\t\t\t\tspacing: \"Medium\",\n\t\t\t\twrap: true,\n\t\t\t});\n\n\t\t\tfor (const breach of message.content.thresholds) {\n\t\t\t\tbody.push({\n\t\t\t\t\ttype: \"TextBlock\",\n\t\t\t\t\ttext: `• **${breach.metric.toUpperCase()}**: ${breach.formattedValue} (threshold: ${breach.threshold}${breach.unit})`,\n\t\t\t\t\twrap: true,\n\t\t\t\t\tspacing: \"Small\",\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\t// Additional details\n\t\tif (message.content.details && message.content.details.length > 0) {\n\t\t\tbody.push({\n\t\t\t\ttype: \"TextBlock\",\n\t\t\t\ttext: \"**Additional Information**\",\n\t\t\t\tweight: \"Bolder\",\n\t\t\t\tspacing: \"Medium\",\n\t\t\t\twrap: true,\n\t\t\t});\n\n\t\t\tfor (const detail of message.content.details) {\n\t\t\t\tbody.push({\n\t\t\t\t\ttype: \"TextBlock\",\n\t\t\t\t\ttext: `• ${detail}`,\n\t\t\t\t\twrap: true,\n\t\t\t\t\tspacing: \"Small\",\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\t// Timestamp footer\n\t\tbody.push({\n\t\t\ttype: \"TextBlock\",\n\t\t\ttext: `Checkmate | ${new Date(message.content.timestamp).toUTCString()}`,\n\t\t\tsize: \"Small\",\n\t\t\tisSubtle: true,\n\t\t\tspacing: \"Medium\",\n\t\t\twrap: true,\n\t\t});\n\n\t\t// Actions (incident link)\n\t\tconst actions: Action[] = [];\n\t\tif (message.content.incident) {\n\t\t\tactions.push({\n\t\t\t\ttype: \"Action.OpenUrl\",\n\t\t\t\ttitle: \"View Incident\",\n\t\t\t\turl: `${message.clientHost}/incidents/${message.content.incident.id}`,\n\t\t\t});\n\t\t}\n\n\t\treturn {\n\t\t\ttype: \"AdaptiveCard\",\n\t\t\t$schema: \"http://adaptivecards.io/schemas/adaptive-card.json\",\n\t\t\tversion: \"1.4\",\n\t\t\tbody,\n\t\t\t...(actions.length > 0 ? { actions } : {}),\n\t\t};\n\t}\n}\n"
  },
  {
    "path": "server/src/service/infrastructure/notificationProviders/utils.ts",
    "content": "import { IEmailService } from \"@/service/infrastructure/emailService.js\";\nexport const buildTestEmail = async (emailService: IEmailService) => {\n\tconst context = { testName: \"Monitoring System\" };\n\tconst html = await emailService.buildEmail(\"testEmailTemplate\", context);\n\treturn html;\n};\n\nexport const getTestMessage = () => {\n\treturn \"This is a test notification from Checkmate\";\n};\n"
  },
  {
    "path": "server/src/service/infrastructure/notificationProviders/webhook.ts",
    "content": "const SERVICE_NAME = \"WebhookProvider\";\nimport type { Notification } from \"@/types/index.js\";\nimport { INotificationProvider } from \"@/service/index.js\";\nimport type { NotificationMessage } from \"@/types/notificationMessage.js\";\nimport { getTestMessage } from \"@/service/infrastructure/notificationProviders/utils.js\";\nimport got from \"got\";\nimport { ILogger } from \"@/utils/logger.js\";\n\nexport class WebhookProvider implements INotificationProvider {\n\tprivate logger: ILogger;\n\n\tconstructor(logger: ILogger) {\n\t\tthis.logger = logger;\n\t}\n\n\tsendMessage = async (notification: Notification, message: NotificationMessage): Promise<boolean> => {\n\t\tif (!notification.address) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Build webhook payload from unified message\n\t\tconst payload = this.buildWebhookPayload(message);\n\n\t\ttry {\n\t\t\tawait got.post(notification.address, {\n\t\t\t\tjson: payload,\n\t\t\t\theaders: {\n\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t},\n\t\t\t});\n\t\t\tthis.logger.info({\n\t\t\t\tmessage: \"Webhook notification sent\",\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"sendMessage\",\n\t\t\t});\n\t\t\treturn true;\n\t\t} catch (error) {\n\t\t\tconst err = error as Error;\n\t\t\tthis.logger.warn({\n\t\t\t\tmessage: \"Webhook alert failed\",\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"sendMessage\",\n\t\t\t\tstack: err?.stack,\n\t\t\t});\n\t\t\treturn false;\n\t\t}\n\t};\n\n\tprivate buildWebhookPayload(message: NotificationMessage): object {\n\t\tconst lines: string[] = [];\n\n\t\t// Title and summary\n\t\tlines.push(`**${message.content.title}**`);\n\t\tlines.push(message.content.summary);\n\t\tlines.push(\"\");\n\n\t\t// Monitor information\n\t\tlines.push(\"**Monitor Details:**\");\n\t\tlines.push(`- Name: ${message.monitor.name}`);\n\t\tlines.push(`- URL: ${message.monitor.url}`);\n\t\tlines.push(`- Type: ${message.monitor.type}`);\n\t\tlines.push(`- Status: ${message.monitor.status}`);\n\t\tlines.push(\"\");\n\n\t\t// Additional details\n\t\tif (message.content.details && message.content.details.length > 0) {\n\t\t\tlines.push(\"**Additional Information:**\");\n\t\t\tmessage.content.details.forEach((detail) => lines.push(`- ${detail}`));\n\t\t\tlines.push(\"\");\n\t\t}\n\n\t\t// Threshold breaches (for hardware monitors)\n\t\tif (message.content.thresholds && message.content.thresholds.length > 0) {\n\t\t\tlines.push(\"**Threshold Breaches:**\");\n\t\t\tmessage.content.thresholds.forEach((breach) => {\n\t\t\t\tlines.push(`- ${breach.metric.toUpperCase()}: ${breach.formattedValue} (threshold: ${breach.threshold}${breach.unit})`);\n\t\t\t});\n\t\t\tlines.push(\"\");\n\t\t}\n\n\t\t// Incident link\n\t\tif (message.content.incident) {\n\t\t\tlines.push(`[View Incident](${message.clientHost}/infrastructure/${message.monitor.id})`);\n\t\t}\n\n\t\t// Return webhook payload with both text and structured data\n\t\treturn {\n\t\t\ttext: lines.join(\"\\n\"),\n\t\t\tseverity: message.severity,\n\t\t\ttype: message.type,\n\t\t\tmonitor: {\n\t\t\t\tid: message.monitor.id,\n\t\t\t\tname: message.monitor.name,\n\t\t\t\turl: message.monitor.url,\n\t\t\t\tstatus: message.monitor.status,\n\t\t\t},\n\t\t\ttimestamp: message.content.timestamp,\n\t\t};\n\t}\n\n\tsendTestAlert = async (notification: Partial<Notification>) => {\n\t\tif (!notification.address) {\n\t\t\treturn false;\n\t\t}\n\t\ttry {\n\t\t\tawait got.post(notification.address, {\n\t\t\t\tjson: { text: getTestMessage() },\n\t\t\t\theaders: {\n\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t},\n\t\t\t});\n\t\t\treturn true;\n\t\t} catch (error) {\n\t\t\tconst err = error as Error;\n\t\t\tthis.logger.warn({\n\t\t\t\tmessage: \"Webhook test alert failed\",\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"sendTestAlert\",\n\t\t\t\tstack: err?.stack,\n\t\t\t});\n\t\t\treturn false;\n\t\t}\n\t};\n}\n"
  },
  {
    "path": "server/src/service/infrastructure/notificationsService.ts",
    "content": "import type { Monitor, MonitorStatusResponse, Notification } from \"@/types/index.js\";\nimport type { NotificationMessage } from \"@/types/notificationMessage.js\";\nimport { IMonitorsRepository, INotificationsRepository } from \"@/repositories/index.js\";\nimport { INotificationProvider } from \"./notificationProviders/INotificationProvider.js\";\nimport type { MonitorActionDecision } from \"@/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.js\";\nimport type { ISettingsService } from \"@/service/system/settingsService.js\";\nimport { ILogger } from \"@/utils/logger.js\";\nimport type { INotificationMessageBuilder } from \"@/service/infrastructure/notificationMessageBuilder.js\";\n\nexport interface INotificationsService {\n\tcreateNotification: (notificationData: Partial<Notification>, userId: string, teamId: string) => Promise<Notification>;\n\tfindById: (id: string, teamId: string) => Promise<Notification>;\n\tfindNotificationsByTeamId: (teamId: string) => Promise<Notification[]>;\n\tupdateById(id: string, teamId: string, updateData: Partial<Notification>): Promise<Notification>;\n\tdeleteById: (id: string, teamId: string) => Promise<Notification>;\n\thandleNotifications: (monitor: Monitor, monitorStatusResponse: MonitorStatusResponse, decision: MonitorActionDecision) => Promise<boolean>;\n\n\tsendTestNotification: (notification: Partial<Notification>) => Promise<boolean>;\n\ttestAllNotifications: (notificationIds: string[]) => Promise<boolean>;\n}\n\nconst SERVICE_NAME = \"NotificationsService\";\n\nexport class NotificationsService implements INotificationsService {\n\tstatic SERVICE_NAME = SERVICE_NAME;\n\n\tprivate notificationsRepository: INotificationsRepository;\n\tprivate monitorsRepository: IMonitorsRepository;\n\tprivate webhookProvider: INotificationProvider;\n\tprivate emailProvider: INotificationProvider;\n\tprivate slackProvider: INotificationProvider;\n\tprivate discordProvider: INotificationProvider;\n\tprivate pagerDutyProvider: INotificationProvider;\n\tprivate matrixProvider: INotificationProvider;\n\tprivate teamsProvider: INotificationProvider;\n\tprivate logger: ILogger;\n\tprivate settingsService: ISettingsService;\n\tprivate notificationMessageBuilder: INotificationMessageBuilder;\n\n\tconstructor(\n\t\tnotificationsRepository: INotificationsRepository,\n\t\tmonitorsRepository: IMonitorsRepository,\n\t\twebhookProvider: INotificationProvider,\n\t\temailProvider: INotificationProvider,\n\t\tslackProvider: INotificationProvider,\n\t\tdiscordProvider: INotificationProvider,\n\t\tpagerDutyProvider: INotificationProvider,\n\t\tmatrixProvider: INotificationProvider,\n\t\tteamsProvider: INotificationProvider,\n\t\tsettingsService: ISettingsService,\n\t\tlogger: ILogger,\n\t\tnotificationMessageBuilder: INotificationMessageBuilder\n\t) {\n\t\tthis.notificationsRepository = notificationsRepository;\n\t\tthis.monitorsRepository = monitorsRepository;\n\t\tthis.webhookProvider = webhookProvider;\n\t\tthis.emailProvider = emailProvider;\n\t\tthis.slackProvider = slackProvider;\n\t\tthis.discordProvider = discordProvider;\n\t\tthis.pagerDutyProvider = pagerDutyProvider;\n\t\tthis.matrixProvider = matrixProvider;\n\t\tthis.teamsProvider = teamsProvider;\n\t\tthis.settingsService = settingsService;\n\t\tthis.logger = logger;\n\t\tthis.notificationMessageBuilder = notificationMessageBuilder;\n\t}\n\n\tprivate send = async (\n\t\tnotification: Notification,\n\t\tmonitor: Monitor,\n\t\tmonitorStatusResponse: MonitorStatusResponse,\n\t\tdecision: MonitorActionDecision,\n\t\tnotificationMessage: NotificationMessage | undefined\n\t): Promise<boolean> => {\n\t\tif (!notificationMessage) {\n\t\t\tthis.logger.warn({\n\t\t\t\tmessage: \"Notification message not provided\",\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"send\",\n\t\t\t});\n\t\t\treturn false;\n\t\t}\n\n\t\t// Route to provider based on notification type\n\t\tswitch (notification.type) {\n\t\t\tcase \"webhook\":\n\t\t\t\treturn await this.webhookProvider.sendMessage!(notification, notificationMessage);\n\t\t\tcase \"slack\":\n\t\t\t\treturn await this.slackProvider.sendMessage!(notification, notificationMessage);\n\t\t\tcase \"matrix\":\n\t\t\t\treturn await this.matrixProvider.sendMessage!(notification, notificationMessage);\n\t\t\tcase \"pager_duty\":\n\t\t\t\treturn await this.pagerDutyProvider.sendMessage!(notification, notificationMessage);\n\t\t\tcase \"discord\":\n\t\t\t\treturn await this.discordProvider.sendMessage!(notification, notificationMessage);\n\t\t\tcase \"email\":\n\t\t\t\treturn await this.emailProvider.sendMessage!(notification, notificationMessage);\n\t\t\tcase \"teams\":\n\t\t\t\treturn await this.teamsProvider.sendMessage!(notification, notificationMessage);\n\t\t\tdefault:\n\t\t\t\tthis.logger.warn({\n\t\t\t\t\tmessage: `Unknown notification type: ${notification.type}`,\n\t\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\t\tmethod: \"send\",\n\t\t\t\t});\n\t\t\t\treturn false;\n\t\t}\n\t};\n\n\tprivate sendNotifications = async (monitor: Monitor, monitorStatusResponse: MonitorStatusResponse, decision: MonitorActionDecision) => {\n\t\tconst notificationIds = monitor.notifications ?? [];\n\t\tconst notifications = await this.notificationsRepository.findNotificationsByIds(notificationIds);\n\n\t\t// Build notification message once for all notifications\n\t\tconst settings = this.settingsService.getSettings();\n\t\tconst clientHost = settings.clientHost || \"Host not defined\";\n\t\tconst notificationMessage = this.notificationMessageBuilder.buildMessage(monitor, monitorStatusResponse, decision, clientHost);\n\n\t\tconst tasks = notifications.map((notification) => this.send(notification, monitor, monitorStatusResponse, decision, notificationMessage));\n\n\t\tconst outcomes = await Promise.all(tasks);\n\t\tconst succeeded = outcomes.filter(Boolean).length;\n\t\tconst failed = outcomes.length - succeeded;\n\t\tif (failed > 0) {\n\t\t\tthis.logger.warn({\n\t\t\t\tmessage: `Notification send completed with ${succeeded} success, ${failed} failure(s)`,\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"sendNotifications\",\n\t\t\t});\n\t\t}\n\t\t// Return true if all notifications succeeded\n\t\treturn succeeded === notifications.length;\n\t};\n\n\thandleNotifications = async (monitor: Monitor, monitorStatusResponse: MonitorStatusResponse, decision: MonitorActionDecision) => {\n\t\tif (!decision.shouldSendNotification) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Send notifications based on decision\n\t\treturn await this.sendNotifications(monitor, monitorStatusResponse, decision);\n\t};\n\n\tsendTestNotification = async (notification: Partial<Notification>) => {\n\t\tswitch (notification.type) {\n\t\t\tcase \"email\":\n\t\t\t\treturn await this.emailProvider.sendTestAlert(notification);\n\t\t\tcase \"slack\":\n\t\t\t\treturn await this.slackProvider.sendTestAlert(notification);\n\t\t\tcase \"discord\":\n\t\t\t\treturn await this.discordProvider.sendTestAlert(notification);\n\t\t\tcase \"pager_duty\":\n\t\t\t\treturn await this.pagerDutyProvider.sendTestAlert(notification);\n\t\t\tcase \"matrix\":\n\t\t\t\treturn await this.matrixProvider.sendTestAlert(notification);\n\t\t\tcase \"webhook\":\n\t\t\t\treturn await this.webhookProvider.sendTestAlert(notification);\n\t\t\tcase \"teams\":\n\t\t\t\treturn await this.teamsProvider.sendTestAlert(notification);\n\t\t\tdefault:\n\t\t\t\treturn false;\n\t\t}\n\t};\n\n\ttestAllNotifications = async (notificationIds: string[]) => {\n\t\tconst notifications = await this.notificationsRepository.findNotificationsByIds(notificationIds);\n\t\tconst tasks = notifications.map((notification) => this.sendTestNotification(notification));\n\t\tconst outcomes = await Promise.all(tasks);\n\t\tconst succeeded = outcomes.filter(Boolean).length;\n\t\tconst failed = outcomes.length - succeeded;\n\t\tif (failed > 0) {\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t};\n\n\tcreateNotification = async (notificationData: Partial<Notification>, userId: string, teamId: string): Promise<Notification> => {\n\t\tnotificationData.userId = userId;\n\t\tnotificationData.teamId = teamId;\n\t\treturn await this.notificationsRepository.create(notificationData);\n\t};\n\n\tfindById = async (id: string, teamId: string): Promise<Notification> => {\n\t\treturn await this.notificationsRepository.findById(id, teamId);\n\t};\n\n\tfindNotificationsByTeamId = async (teamId: string): Promise<Notification[]> => {\n\t\treturn await this.notificationsRepository.findByTeamId(teamId);\n\t};\n\n\tupdateById = async (id: string, teamId: string, updateData: Partial<Notification>): Promise<Notification> => {\n\t\treturn await this.notificationsRepository.updateById(id, teamId, updateData);\n\t};\n\n\tdeleteById = async (id: string, teamId: string): Promise<Notification> => {\n\t\tconst deleted = await this.notificationsRepository.deleteById(id, teamId);\n\t\tawait this.monitorsRepository.removeNotificationFromMonitors(id);\n\t\treturn deleted;\n\t};\n}\n"
  },
  {
    "path": "server/src/service/infrastructure/protos/health.proto",
    "content": "syntax = \"proto3\";\n\npackage grpc.health.v1;\n\nmessage HealthCheckRequest {\n\tstring service = 1;\n}\n\nmessage HealthCheckResponse {\n\tenum ServingStatus {\n\t\tUNKNOWN = 0;\n\t\tSERVING = 1;\n\t\tNOT_SERVING = 2;\n\t\tSERVICE_UNKNOWN = 3;\n\t}\n\tServingStatus status = 1;\n}\n\nservice Health {\n\trpc Check(HealthCheckRequest) returns (HealthCheckResponse);\n}\n"
  },
  {
    "path": "server/src/service/infrastructure/statusService.ts",
    "content": "import { IChecksRepository, IMonitorsRepository, IMonitorStatsRepository } from \"@/repositories/index.js\";\nimport type {\n\tMonitor,\n\tMonitorStatus,\n\tMonitorStatusResponse,\n\tStatusChangeResult,\n\tCheck,\n\tHardwareStatusPayload,\n\tPageSpeedStatusPayload,\n\tPingStatusPayload,\n\tHttpStatusPayload,\n\tDockerStatusPayload,\n\tPortStatusPayload,\n\tGameStatusPayload,\n\tGrpcStatusPayload,\n\tCheckSnapshot,\n\tMonitorStats,\n\tCheckDiskInfo,\n} from \"@/types/index.js\";\nimport { AppError } from \"@/utils/AppError.js\";\nimport { ILogger } from \"@/utils/logger.js\";\nimport { IBufferService } from \"./bufferService.js\";\nconst SERVICE_NAME = \"StatusService\";\n\nexport interface IStatusService {\n\tupdateRunningStats(monitor: Monitor, networkResponse: MonitorStatusResponse): Promise<boolean>;\n\tupdateMonitorStatus(\n\t\tstatusResponse: MonitorStatusResponse<\n\t\t\t| PingStatusPayload\n\t\t\t| HttpStatusPayload\n\t\t\t| PageSpeedStatusPayload\n\t\t\t| HardwareStatusPayload\n\t\t\t| DockerStatusPayload\n\t\t\t| PortStatusPayload\n\t\t\t| GameStatusPayload\n\t\t\t| GrpcStatusPayload\n\t\t\t| undefined\n\t\t>,\n\t\tcheck: Check\n\t): Promise<StatusChangeResult>;\n}\n\nexport class StatusService implements IStatusService {\n\tstatic SERVICE_NAME = SERVICE_NAME;\n\tprivate logger: ILogger;\n\tprivate buffer: IBufferService;\n\tprivate monitorsRepository: IMonitorsRepository;\n\tprivate monitorStatsRepository: IMonitorStatsRepository;\n\tprivate checksRepository: IChecksRepository;\n\n\tconstructor(\n\t\tlogger: ILogger,\n\t\tbuffer: IBufferService,\n\t\tmonitorsRepository: IMonitorsRepository,\n\t\tmonitorStatsRepository: IMonitorStatsRepository,\n\t\tchecksRepository: IChecksRepository\n\t) {\n\t\tthis.logger = logger;\n\t\tthis.buffer = buffer;\n\t\tthis.monitorsRepository = monitorsRepository;\n\t\tthis.monitorStatsRepository = monitorStatsRepository;\n\t\tthis.checksRepository = checksRepository;\n\t}\n\n\tget serviceName() {\n\t\treturn StatusService.SERVICE_NAME;\n\t}\n\n\tasync updateRunningStats(monitor: Monitor, networkResponse: MonitorStatusResponse) {\n\t\ttry {\n\t\t\tconst monitorId = monitor.id;\n\t\t\tconst { responseTime, status } = networkResponse;\n\t\t\tlet existingStats: MonitorStats | null = null;\n\t\t\texistingStats = await this.monitorStatsRepository\n\t\t\t\t.findByMonitorId(monitorId)\n\t\t\t\t.then((result) => result)\n\t\t\t\t.catch(() => {\n\t\t\t\t\tthis.logger.debug({\n\t\t\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\t\t\tmethod: \"updateRunningStats\",\n\t\t\t\t\t\tmessage: `No existing stats found for monitor ${monitorId}, initializing new stats.`,\n\t\t\t\t\t});\n\t\t\t\t\treturn null;\n\t\t\t\t});\n\n\t\t\tlet stats: Omit<MonitorStats, \"id\" | \"monitorId\" | \"createdAt\" | \"updatedAt\">;\n\n\t\t\tif (!existingStats) {\n\t\t\t\t// Initialize new stats\n\t\t\t\tstats = {\n\t\t\t\t\tavgResponseTime: 0,\n\t\t\t\t\tmaxResponseTime: 0,\n\t\t\t\t\ttotalChecks: 0,\n\t\t\t\t\ttotalUpChecks: 0,\n\t\t\t\t\ttotalDownChecks: 0,\n\t\t\t\t\tuptimePercentage: 0,\n\t\t\t\t\tlastResponseTime: 0,\n\t\t\t\t\tlastCheckTimestamp: 0,\n\t\t\t\t};\n\t\t\t} else {\n\t\t\t\t// Use existing stats (omit id, monitorId, createdAt, updatedAt)\n\t\t\t\tstats = {\n\t\t\t\t\tavgResponseTime: existingStats.avgResponseTime,\n\t\t\t\t\tmaxResponseTime: existingStats.maxResponseTime,\n\t\t\t\t\ttotalChecks: existingStats.totalChecks,\n\t\t\t\t\ttotalUpChecks: existingStats.totalUpChecks,\n\t\t\t\t\ttotalDownChecks: existingStats.totalDownChecks,\n\t\t\t\t\tuptimePercentage: existingStats.uptimePercentage,\n\t\t\t\t\tlastResponseTime: existingStats.lastResponseTime,\n\t\t\t\t\tlastCheckTimestamp: existingStats.lastCheckTimestamp,\n\t\t\t\t\ttimeOfLastFailure: existingStats.timeOfLastFailure,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\t// Update stats\n\t\t\tstats.totalChecks++;\n\n\t\t\t// Last response time\n\t\t\tstats.lastResponseTime = responseTime ?? 0;\n\n\t\t\t// Max response time\n\t\t\tif (responseTime && responseTime > stats.maxResponseTime) {\n\t\t\t\tstats.maxResponseTime = responseTime;\n\t\t\t}\n\n\t\t\t// Avg response time:\n\t\t\tlet avgResponseTime = stats.avgResponseTime;\n\t\t\tif (typeof responseTime !== \"undefined\" && responseTime !== null) {\n\t\t\t\tif (avgResponseTime === 0) {\n\t\t\t\t\tavgResponseTime = responseTime;\n\t\t\t\t} else {\n\t\t\t\t\tavgResponseTime = (avgResponseTime * (stats.totalChecks - 1) + responseTime) / stats.totalChecks;\n\t\t\t\t}\n\t\t\t}\n\t\t\tstats.avgResponseTime = avgResponseTime;\n\n\t\t\t// Total checks\n\t\t\tif (status === true) {\n\t\t\t\tstats.totalUpChecks++;\n\t\t\t\t// Update the timeSinceLastFailure if needed\n\t\t\t\tif (stats.timeOfLastFailure === 0) {\n\t\t\t\t\tstats.timeOfLastFailure = new Date().getTime();\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tstats.totalDownChecks++;\n\t\t\t\tstats.timeOfLastFailure = 0;\n\t\t\t}\n\n\t\t\t// Calculate uptime percentage\n\t\t\tlet uptimePercentage;\n\t\t\tif (stats.totalChecks > 0) {\n\t\t\t\tuptimePercentage = stats.totalUpChecks / stats.totalChecks;\n\t\t\t} else {\n\t\t\t\tuptimePercentage = status === true ? 100 : 0;\n\t\t\t}\n\t\t\tstats.uptimePercentage = uptimePercentage;\n\n\t\t\t// latest check\n\t\t\tstats.lastCheckTimestamp = new Date().getTime();\n\n\t\t\t// Create or update\n\t\t\tif (!existingStats) {\n\t\t\t\tawait this.monitorStatsRepository.create({ monitorId, ...stats });\n\t\t\t} else {\n\t\t\t\tawait this.monitorStatsRepository.updateByMonitorId(monitorId, stats);\n\t\t\t}\n\n\t\t\treturn true;\n\t\t} catch (error: unknown) {\n\t\t\tthis.logger.error({\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmessage: error instanceof Error ? error.message : \"Unknown error\",\n\t\t\t\tmethod: \"updateRunningStats\",\n\t\t\t\tstack: error instanceof Error ? error.stack : undefined,\n\t\t\t});\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tupdateMonitorStatus = async (\n\t\tstatusResponse: MonitorStatusResponse<\n\t\t\t| PingStatusPayload\n\t\t\t| HttpStatusPayload\n\t\t\t| PageSpeedStatusPayload\n\t\t\t| HardwareStatusPayload\n\t\t\t| DockerStatusPayload\n\t\t\t| PortStatusPayload\n\t\t\t| GameStatusPayload\n\t\t\t| GrpcStatusPayload\n\t\t\t| undefined\n\t\t>,\n\t\tcheck: Check\n\t): Promise<StatusChangeResult> => {\n\t\ttry {\n\t\t\tconst { monitorId, teamId, status, code } = statusResponse;\n\t\t\tconst monitor = await this.monitorsRepository.findById(monitorId, teamId);\n\n\t\t\t// Update running stats\n\t\t\tthis.updateRunningStats(monitor, statusResponse);\n\n\t\t\tmonitor.statusWindow = monitor.statusWindow || [];\n\t\t\tmonitor.statusWindow.push(status);\n\t\t\twhile (monitor.statusWindow.length > monitor.statusWindowSize) {\n\t\t\t\tmonitor.statusWindow.shift();\n\t\t\t}\n\n\t\t\tconst checkSnapshot: CheckSnapshot = {\n\t\t\t\tid: check.id,\n\t\t\t\tstatus: check.status,\n\t\t\t\tresponseTime: check.responseTime,\n\t\t\t\ttimings: check.timings,\n\t\t\t\tstatusCode: check.statusCode,\n\t\t\t\tmessage: check.message,\n\t\t\t\tcpu: check.cpu,\n\t\t\t\tmemory: check.memory,\n\t\t\t\tdisk: check.disk,\n\t\t\t\thost: check.host,\n\t\t\t\terrors: check.errors,\n\t\t\t\tcapture: check.capture,\n\t\t\t\tnet: check.net,\n\t\t\t\taccessibility: check.accessibility,\n\t\t\t\tbestPractices: check.bestPractices,\n\t\t\t\tseo: check.seo,\n\t\t\t\tperformance: check.performance,\n\t\t\t\taudits: check.audits,\n\t\t\t\tcreatedAt: check.createdAt,\n\t\t\t};\n\t\t\tmonitor.recentChecks = monitor.recentChecks || [];\n\t\t\tmonitor.recentChecks.push(checkSnapshot);\n\t\t\tconst maxRecentChecks = 25;\n\t\t\twhile (monitor.recentChecks.length > maxRecentChecks) {\n\t\t\t\tmonitor.recentChecks.shift();\n\t\t\t}\n\n\t\t\tconst prevStatus = monitor.status;\n\t\t\tlet newStatus: MonitorStatus = status === true ? \"up\" : \"down\";\n\t\t\tlet statusChanged = false;\n\n\t\t\t// Return early if not enough data points\n\t\t\tif (monitor.statusWindow.length < monitor.statusWindowSize) {\n\t\t\t\tmonitor.status = newStatus;\n\t\t\t\tconst updated = await this.monitorsRepository.updateById(monitor.id, monitor.teamId, monitor);\n\t\t\t\treturn {\n\t\t\t\t\tmonitor: updated,\n\t\t\t\t\tstatusChanged: false,\n\t\t\t\t\tprevStatus,\n\t\t\t\t\tcode,\n\t\t\t\t\ttimestamp: Date.now(),\n\t\t\t\t};\n\t\t\t}\n\n\t\t\t// Check if threshold has been met\n\t\t\tconst failures = monitor.statusWindow.filter((s) => s === false).length;\n\t\t\tconst failureRate = (failures / monitor.statusWindow.length) * 100;\n\n\t\t\t// If threshold has been met and the monitor is not already down, mark down:\n\t\t\tif (failureRate >= monitor.statusWindowThreshold && monitor.status !== \"down\") {\n\t\t\t\tnewStatus = \"down\";\n\t\t\t\tstatusChanged = true;\n\t\t\t}\n\t\t\t// If the failure rate is below the threshold and the monitor is down, recover:\n\t\t\telse if (failureRate < monitor.statusWindowThreshold && monitor.status === \"down\") {\n\t\t\t\tnewStatus = \"up\";\n\t\t\t\tstatusChanged = true;\n\t\t\t}\n\n\t\t\t// Evaluate hardware threshold breaches (only for hardware monitors)\n\t\t\tlet thresholdBreaches: { cpu: boolean; memory: boolean; disk: boolean; temp: boolean } | undefined;\n\t\t\tif (monitor.type === \"hardware\" && statusResponse.payload) {\n\t\t\t\tconst payload = statusResponse.payload as HardwareStatusPayload;\n\t\t\t\tconst metrics = payload?.data;\n\n\t\t\t\tif (metrics) {\n\t\t\t\t\t// Evaluate threshold breaches\n\t\t\t\t\tconst cpuUsage = metrics.cpu?.usage_percent ?? -1;\n\t\t\t\t\tconst cpuBreach = cpuUsage !== -1 && cpuUsage > monitor.cpuAlertThreshold / 100;\n\n\t\t\t\t\tconst memoryUsage = metrics.memory?.usage_percent ?? -1;\n\t\t\t\t\tconst memoryBreach = memoryUsage !== -1 && memoryUsage > monitor.memoryAlertThreshold / 100;\n\n\t\t\t\t\tconst diskBreach =\n\t\t\t\t\t\tmetrics.disk?.some((d: CheckDiskInfo) => typeof d?.usage_percent === \"number\" && d.usage_percent > monitor.diskAlertThreshold / 100) ??\n\t\t\t\t\t\tfalse;\n\n\t\t\t\t\tconst temps = metrics.cpu?.temperature ?? [];\n\t\t\t\t\tconst tempBreach = temps.some((temp: number) => temp > monitor.tempAlertThreshold);\n\n\t\t\t\t\tthresholdBreaches = {\n\t\t\t\t\t\tcpu: cpuBreach,\n\t\t\t\t\t\tmemory: memoryBreach,\n\t\t\t\t\t\tdisk: diskBreach,\n\t\t\t\t\t\ttemp: tempBreach,\n\t\t\t\t\t};\n\n\t\t\t\t\t// Update counters: decrement if breached, reset to 5 if not breached\n\t\t\t\t\tif (cpuBreach) {\n\t\t\t\t\t\tmonitor.cpuAlertCounter = Math.max(0, monitor.cpuAlertCounter - 1);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tmonitor.cpuAlertCounter = 5;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (memoryBreach) {\n\t\t\t\t\t\tmonitor.memoryAlertCounter = Math.max(0, monitor.memoryAlertCounter - 1);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tmonitor.memoryAlertCounter = 5;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (diskBreach) {\n\t\t\t\t\t\tmonitor.diskAlertCounter = Math.max(0, monitor.diskAlertCounter - 1);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tmonitor.diskAlertCounter = 5;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (tempBreach) {\n\t\t\t\t\t\tmonitor.tempAlertCounter = Math.max(0, monitor.tempAlertCounter - 1);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tmonitor.tempAlertCounter = 5;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Check if any counter has reached zero (initial breach)\n\t\t\t\t\tconst anyCounterZero =\n\t\t\t\t\t\tmonitor.cpuAlertCounter === 0 || monitor.memoryAlertCounter === 0 || monitor.diskAlertCounter === 0 || monitor.tempAlertCounter === 0;\n\n\t\t\t\t\tconst anyThresholdBreached = cpuBreach || memoryBreach || diskBreach || tempBreach;\n\t\t\t\t\tconst allThresholdsNormal = !cpuBreach && !memoryBreach && !diskBreach && !tempBreach;\n\n\t\t\t\t\t// Update monitor status based on threshold breach state\n\t\t\t\t\tif (newStatus !== \"down\") {\n\t\t\t\t\t\t// Don't override \"down\" status - service unreachable takes precedence\n\t\t\t\t\t\t// Check current monitor status, not newStatus for comparison\n\t\t\t\t\t\tif (anyCounterZero && anyThresholdBreached && monitor.status !== \"breached\") {\n\t\t\t\t\t\t\t// Initial breach: counter hit zero, change status to breached\n\t\t\t\t\t\t\tnewStatus = \"breached\";\n\t\t\t\t\t\t\tstatusChanged = true;\n\t\t\t\t\t\t} else if (anyCounterZero && anyThresholdBreached && monitor.status === \"breached\") {\n\t\t\t\t\t\t\t// Already breached, keep status but don't mark as changed\n\t\t\t\t\t\t\tnewStatus = \"breached\";\n\t\t\t\t\t\t\t// statusChanged remains false\n\t\t\t\t\t\t} else if (allThresholdsNormal && monitor.status === \"breached\") {\n\t\t\t\t\t\t\t// All thresholds returned to normal, recover from breached state\n\t\t\t\t\t\t\tnewStatus = \"up\";\n\t\t\t\t\t\t\tstatusChanged = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Apply the final status\n\t\t\tmonitor.status = newStatus;\n\n\t\t\tconst updated = await this.monitorsRepository.updateById(monitor.id, monitor.teamId, monitor);\n\n\t\t\treturn {\n\t\t\t\tmonitor: updated,\n\t\t\t\tstatusChanged,\n\t\t\t\tprevStatus,\n\t\t\t\tcode,\n\t\t\t\ttimestamp: new Date().getTime(),\n\t\t\t\tthresholdBreaches,\n\t\t\t};\n\t\t} catch (error: unknown) {\n\t\t\tthrow new AppError({\n\t\t\t\tmessage: `Failed to update monitor with id ${check.metadata.monitorId} with status: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"updateMonitorStatus\",\n\t\t\t});\n\t\t}\n\t};\n\n\tinsertCheck = async (check: Check) => {\n\t\ttry {\n\t\t\tif (typeof check === \"undefined\") {\n\t\t\t\tthis.logger.warn({\n\t\t\t\t\tmessage: \"Failed to build check\",\n\t\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\t\tmethod: \"insertCheck\",\n\t\t\t\t});\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tthis.buffer.addToBuffer(check);\n\t\t\treturn true;\n\t\t} catch (error: unknown) {\n\t\t\tthis.logger.error({\n\t\t\t\tmessage: error instanceof Error ? error.message : \"Unknown error\",\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"insertCheck\",\n\t\t\t\tdetails: { msg: `Error inserting check for monitor: ${check?.metadata.monitorId}` },\n\t\t\t\tstack: error instanceof Error ? error.stack : undefined,\n\t\t\t});\n\t\t}\n\t};\n}\n"
  },
  {
    "path": "server/src/service/system/settingsService.ts",
    "content": "import { ISettingsRepository } from \"@/repositories/index.js\";\nimport { Settings, SettingsUpdate } from \"@/types/index.js\";\nimport { AppError } from \"@/utils/AppError.js\";\nimport { ValidatedEnv } from \"@/validation/envValidation.js\";\nimport type { StringValue } from \"ms\";\nconst SERVICE_NAME = \"SettingsService\";\n\nexport type EnvConfig = {\n\tjwtSecret: string;\n\tjwtTTL: StringValue;\n\tnodeEnv: string;\n\tlogLevel: string;\n\tclientHost: string;\n\tdbConnectionString: string;\n};\n\nexport interface ISettingsService {\n\treadonly serviceName: string;\n\tloadSettings(): EnvConfig;\n\tgetSettings(): EnvConfig;\n\tgetDBSettings(): Promise<Settings>;\n\tupdateDbSettings(newSettings: SettingsUpdate): Promise<Settings>;\n}\n\nexport class SettingsService implements ISettingsService {\n\tstatic SERVICE_NAME = SERVICE_NAME;\n\tprivate settings: EnvConfig;\n\tprivate settingsRepository: ISettingsRepository;\n\n\tconstructor(settingsRepository: ISettingsRepository, env: ValidatedEnv) {\n\t\tthis.settingsRepository = settingsRepository;\n\t\tthis.settings = {\n\t\t\tjwtSecret: env.JWT_SECRET,\n\t\t\tjwtTTL: env.TOKEN_TTL as StringValue,\n\t\t\tnodeEnv: env.NODE_ENV,\n\t\t\tlogLevel: env.LOG_LEVEL,\n\t\t\tclientHost: env.CLIENT_HOST,\n\t\t\tdbConnectionString: env.DB_CONNECTION_STRING,\n\t\t};\n\t}\n\n\tget serviceName() {\n\t\treturn SettingsService.SERVICE_NAME;\n\t}\n\n\tloadSettings() {\n\t\treturn this.settings;\n\t}\n\n\tgetSettings() {\n\t\tif (!this.settings) {\n\t\t\tthrow new Error(\"Settings have not been loaded\");\n\t\t}\n\t\treturn this.settings;\n\t}\n\n\tupdateDbSettings = async (newSettings: SettingsUpdate) => {\n\t\treturn await this.settingsRepository.update(newSettings);\n\t};\n\n\tgetDBSettings = async () => {\n\t\t// Remove any old settings\n\t\tawait this.settingsRepository.deleteLegacy();\n\n\t\tlet settings = await this.settingsRepository.findSingleton();\n\t\tif (settings === null) {\n\t\t\tawait this.settingsRepository.create({});\n\t\t\tsettings = await this.settingsRepository.findSingleton();\n\t\t}\n\n\t\tif (!settings) {\n\t\t\tthrow new AppError({ message: \"Settings not found\", status: 500 });\n\t\t}\n\n\t\treturn settings;\n\t};\n}\n"
  },
  {
    "path": "server/src/shutdown.ts",
    "content": "import { InitializedServices } from \"./config/services.js\";\nimport { logger } from \"./utils/logger.js\";\nimport type { Server } from \"http\";\n\nexport const initShutdownListener = (server: Server, services: InitializedServices) => {\n\tconst SERVICE_NAME = \"Server\";\n\n\tlet isShuttingDown = false;\n\n\tconst shutdown = async () => {\n\t\tif (isShuttingDown) {\n\t\t\treturn;\n\t\t}\n\t\tisShuttingDown = true;\n\t\tlogger.info({ message: \"Attempting graceful shutdown\" });\n\n\t\ttry {\n\t\t\tserver.close();\n\t\t\tawait services.jobQueue.shutdown();\n\t\t\tawait services.db.disconnect();\n\t\t\tlogger.info({ message: \"Graceful shutdown complete\" });\n\t\t\tprocess.exit(0);\n\t\t} catch (error) {\n\t\t\tconst err = error as Error;\n\t\t\tlogger.error({\n\t\t\t\tmessage: err.message,\n\t\t\t\tservice: SERVICE_NAME,\n\t\t\t\tmethod: \"shutdown\",\n\t\t\t\tstack: err.stack,\n\t\t\t});\n\t\t\tprocess.exit(1);\n\t\t}\n\t};\n\tprocess.on(\"SIGUSR2\", shutdown);\n\tprocess.on(\"SIGINT\", shutdown);\n\tprocess.on(\"SIGTERM\", shutdown);\n};\n"
  },
  {
    "path": "server/src/templates/addReview.mjml",
    "content": "<!-- name -->\n<mjml>\n\t<mj-head>\n\t\t<mj-font\n\t\t\tname=\"Roboto\"\n\t\t\thref=\"https://fonts.googleapis.com/css?family=Roboto:300,500\"\n\t\t></mj-font>\n\t\t<mj-attributes>\n\t\t\t<mj-all font-family=\"Roboto, Helvetica, sans-serif\"></mj-all>\n\t\t\t<mj-text\n\t\t\t\tfont-weight=\"300\"\n\t\t\t\tfont-size=\"16px\"\n\t\t\t\tcolor=\"#616161\"\n\t\t\t\tline-height=\"24px\"\n\t\t\t></mj-text>\n\t\t\t<mj-section padding=\"0px\"></mj-section>\n\t\t</mj-attributes>\n\t</mj-head>\n\t<mj-body>\n\t\t<mj-section padding=\"20px 0\">\n\t\t\t<mj-column width=\"100%\">\n\t\t\t\t<mj-text\n\t\t\t\t\talign=\"left\"\n\t\t\t\t\tfont-size=\"10px\"\n\t\t\t\t>\n\t\t\t\t\tMessage from Checkmate Service\n\t\t\t\t</mj-text>\n\t\t\t</mj-column>\n\t\t</mj-section>\n\t\t<mj-section>\n\t\t\t<mj-column width=\"100%\">\n\t\t\t\t<mj-text>\n\t\t\t\t\t<p>Hello {{ name }}!</p>\n\t\t\t\t\t<p>\n\t\t\t\t\t\tWe hope you’re finding Checkmate helpful in monitoring your infrastructure. Your support means a lot to us, and we\n\t\t\t\t\t\t<b>truly appreciate</b> having you as part of our community.\n\t\t\t\t\t</p>\n\t\t\t\t\t<p>\n\t\t\t\t\t\tIf you’re happy with Checkmate, we’d love to hear about your experience! Leaving a review on G2 helps others discover Checkmate and\n\t\t\t\t\t\tsupports our ongoing improvements.\n\t\t\t\t\t</p>\n\t\t\t\t\tG2 Link: TBD\n\t\t\t\t\t<p>Thank you for taking the time to share your thoughts - we greatly appreciate it!</p>\n\t\t\t\t\tCheckmate Team\n\t\t\t\t</mj-text>\n\t\t\t</mj-column>\n\t\t\t<mj-column width=\"100%\">\n\t\t\t\t<mj-divider\n\t\t\t\t\tborder-width=\"1px\"\n\t\t\t\t\tborder-color=\"#E0E0E0\"\n\t\t\t\t></mj-divider>\n\t\t\t\t<mj-text font-size=\"12px\">\n\t\t\t\t\t<p>This email was sent by Checkmate.</p>\n\t\t\t\t</mj-text>\n\t\t\t</mj-column>\n\t\t</mj-section>\n\t</mj-body>\n</mjml>\n"
  },
  {
    "path": "server/src/templates/employeeActivation.mjml",
    "content": "<!-- name, link -->\n<mjml>\n\t<mj-head>\n\t\t<mj-font\n\t\t\tname=\"Roboto\"\n\t\t\thref=\"https://fonts.googleapis.com/css?family=Roboto:300,500\"\n\t\t></mj-font>\n\t\t<mj-attributes>\n\t\t\t<mj-all font-family=\"Roboto, Helvetica, sans-serif\"></mj-all>\n\t\t\t<mj-text\n\t\t\t\tfont-weight=\"300\"\n\t\t\t\tfont-size=\"16px\"\n\t\t\t\tcolor=\"#616161\"\n\t\t\t\tline-height=\"24px\"\n\t\t\t></mj-text>\n\t\t\t<mj-section padding=\"0px\"></mj-section>\n\t\t</mj-attributes>\n\t</mj-head>\n\t<mj-body>\n\t\t<mj-section padding=\"20px 0\">\n\t\t\t<mj-column width=\"100%\">\n\t\t\t\t<mj-text\n\t\t\t\t\talign=\"left\"\n\t\t\t\t\tfont-size=\"10px\"\n\t\t\t\t\t>Message from Checkmate Service</mj-text\n\t\t\t\t>\n\t\t\t</mj-column>\n\t\t</mj-section>\n\t\t<mj-section>\n\t\t\t<mj-column width=\"100%\">\n\t\t\t\t<mj-text>\n\t\t\t\t\t<p>Hello {{ name }}!</p>\n\t\t\t\t\t<p>One of the admins created an account for you on the Checkmate server.</p>\n\t\t\t\t\t<p>You can go ahead and create your account using this link.</p>\n\t\t\t\t\t<p>\n\t\t\t\t\t\t<a href=\"{{link}}\">{{ link }}</a>\n\t\t\t\t\t</p>\n\t\t\t\t\t<p>Thank you.</p>\n\t\t\t\t</mj-text>\n\t\t\t</mj-column>\n\t\t\t<mj-column width=\"100%\">\n\t\t\t\t<mj-divider\n\t\t\t\t\tborder-width=\"1px\"\n\t\t\t\t\tborder-color=\"#E0E0E0\"\n\t\t\t\t></mj-divider>\n\t\t\t\t<mj-text font-size=\"12px\">\n\t\t\t\t\t<p>This email was sent by Checkmate.</p>\n\t\t\t\t</mj-text>\n\t\t\t</mj-column>\n\t\t</mj-section>\n\t</mj-body>\n</mjml>\n"
  },
  {
    "path": "server/src/templates/noIncidentsThisWeek.mjml",
    "content": "<mjml>\n\t<mj-head>\n\t\t<mj-font\n\t\t\tname=\"Roboto\"\n\t\t\thref=\"https://fonts.googleapis.com/css?family=Roboto:300,500\"\n\t\t></mj-font>\n\t\t<mj-attributes>\n\t\t\t<mj-all font-family=\"Roboto, Helvetica, sans-serif\"></mj-all>\n\t\t\t<mj-text\n\t\t\t\tfont-weight=\"300\"\n\t\t\t\tfont-size=\"16px\"\n\t\t\t\tcolor=\"#616161\"\n\t\t\t\tline-height=\"24px\"\n\t\t\t></mj-text>\n\t\t\t<mj-section padding=\"0px\"></mj-section>\n\t\t</mj-attributes>\n\t</mj-head>\n\t<mj-body>\n\t\t<mj-section padding=\"20px 0\">\n\t\t\t<mj-column width=\"100%\">\n\t\t\t\t<mj-text\n\t\t\t\t\talign=\"left\"\n\t\t\t\t\tfont-size=\"10px\"\n\t\t\t\t\t>Message from Checkmate Service</mj-text\n\t\t\t\t>\n\t\t\t</mj-column>\n\t\t\t<mj-column\n\t\t\t\twidth=\"45%\"\n\t\t\t\tpadding-top=\"20px\"\n\t\t\t>\n\t\t\t\t<mj-text\n\t\t\t\t\talign=\"center\"\n\t\t\t\t\tfont-weight=\"500\"\n\t\t\t\t\tpadding=\"0px\"\n\t\t\t\t\tfont-size=\"18px\"\n\t\t\t\t\tcolor=\"green\"\n\t\t\t\t\t>No incidents this week!</mj-text\n\t\t\t\t>\n\t\t\t\t<mj-divider\n\t\t\t\t\tborder-width=\"2px\"\n\t\t\t\t\tborder-color=\"#616161\"\n\t\t\t\t></mj-divider>\n\t\t\t</mj-column>\n\t\t</mj-section>\n\t\t<mj-section>\n\t\t\t<mj-column width=\"100%\">\n\t\t\t\t<mj-text>\n\t\t\t\t\t<p>Hello {{ name }}!</p>\n\t\t\t\t\t<p>There were no incidents this week. Good job!</p>\n\t\t\t\t\t<p><b>Current monitors:</b></p>\n\t\t\t\t\t<p><b>Google:</b> 100% availability</p>\n\t\t\t\t\t<p><b>Canada.ca:</b>100% availability</p>\n\t\t\t\t</mj-text>\n\t\t\t</mj-column>\n\t\t\t<mj-column width=\"100%\">\n\t\t\t\t<mj-divider\n\t\t\t\t\tborder-width=\"1px\"\n\t\t\t\t\tborder-color=\"#E0E0E0\"\n\t\t\t\t></mj-divider>\n\t\t\t\t<mj-text font-size=\"12px\">\n\t\t\t\t\t<p>This email was sent by Checkmate.</p>\n\t\t\t\t</mj-text>\n\t\t\t</mj-column>\n\t\t</mj-section>\n\t</mj-body>\n</mjml>\n"
  },
  {
    "path": "server/src/templates/passwordReset.mjml",
    "content": "<!-- name, email, url -->\n\n<mjml>\n\t<mj-head>\n\t\t<mj-font\n\t\t\tname=\"Roboto\"\n\t\t\thref=\"https://fonts.googleapis.com/css?family=Roboto:300,500\"\n\t\t></mj-font>\n\t\t<mj-attributes>\n\t\t\t<mj-all font-family=\"Roboto, Helvetica, sans-serif\"></mj-all>\n\t\t\t<mj-text\n\t\t\t\tfont-weight=\"300\"\n\t\t\t\tfont-size=\"16px\"\n\t\t\t\tcolor=\"#616161\"\n\t\t\t\tline-height=\"24px\"\n\t\t\t></mj-text>\n\t\t\t<mj-section padding=\"0px\"></mj-section>\n\t\t</mj-attributes>\n\t</mj-head>\n\t<mj-body>\n\t\t<mj-section padding=\"20px 0\">\n\t\t\t<mj-column width=\"100%\">\n\t\t\t\t<mj-text\n\t\t\t\t\talign=\"left\"\n\t\t\t\t\tfont-size=\"10px\"\n\t\t\t\t>\n\t\t\t\t\tMessage from Checkmate Service\n\t\t\t\t</mj-text>\n\t\t\t</mj-column>\n\t\t</mj-section>\n\t\t<mj-section>\n\t\t\t<mj-column width=\"100%\">\n\t\t\t\t<mj-text>\n\t\t\t\t\t<p>Hello {{ name }}!</p>\n\t\t\t\t\t<p>\n\t\t\t\t\t\tYou are receiving this email because a password reset request has been made for {{ email }}. Please use the link below on the site to\n\t\t\t\t\t\treset your password.\n\t\t\t\t\t</p>\n\t\t\t\t\t<a href=\"{{url}}\">Reset Password</a>\n\t\t\t\t\t<p>If you didn't request this, please ignore this email.</p>\n\n\t\t\t\t\t<p>Thank you.</p>\n\t\t\t\t</mj-text>\n\t\t\t</mj-column>\n\t\t\t<mj-column width=\"100%\">\n\t\t\t\t<mj-divider\n\t\t\t\t\tborder-width=\"1px\"\n\t\t\t\t\tborder-color=\"#E0E0E0\"\n\t\t\t\t></mj-divider>\n\t\t\t\t<mj-text font-size=\"12px\">\n\t\t\t\t\t<p>This email was sent by Checkmate.</p>\n\t\t\t\t</mj-text>\n\t\t\t</mj-column>\n\t\t</mj-section>\n\t</mj-body>\n</mjml>\n"
  },
  {
    "path": "server/src/templates/testEmailTemplate.mjml",
    "content": "<mjml>\n\t<mj-body>\n\t\t<mj-section>\n\t\t\t<mj-column>\n\t\t\t\t<mj-text\n\t\t\t\t\tfont-size=\"20px\"\n\t\t\t\t\tfont-family=\"Helvetica Neue\"\n\t\t\t\t>\n\t\t\t\t\tHello!\n\t\t\t\t</mj-text>\n\t\t\t\t<mj-text\n\t\t\t\t\tfont-size=\"16px\"\n\t\t\t\t\tfont-family=\"Helvetica Neue\"\n\t\t\t\t>\n\t\t\t\t\tThis is a test email from the Monitoring System.\n\t\t\t\t</mj-text>\n\t\t\t\t<mj-text\n\t\t\t\t\tfont-size=\"14px\"\n\t\t\t\t\tfont-family=\"Helvetica Neue\"\n\t\t\t\t>\n\t\t\t\t\tIf you're receiving this, your email configuration is working correctly.\n\t\t\t\t</mj-text>\n\t\t\t</mj-column>\n\t\t</mj-section>\n\t</mj-body>\n</mjml>\n"
  },
  {
    "path": "server/src/templates/unifiedNotification.mjml",
    "content": "<mjml>\n\t<mj-head>\n\t\t<mj-font\n\t\t\tname=\"Roboto\"\n\t\t\thref=\"https://fonts.googleapis.com/css?family=Roboto:300,500\"\n\t\t></mj-font>\n\t\t<mj-attributes>\n\t\t\t<mj-all font-family=\"Roboto, Helvetica, sans-serif\"></mj-all>\n\t\t\t<mj-text\n\t\t\t\tfont-weight=\"300\"\n\t\t\t\tfont-size=\"16px\"\n\t\t\t\tcolor=\"#616161\"\n\t\t\t\tline-height=\"24px\"\n\t\t\t></mj-text>\n\t\t\t<mj-section padding=\"0px\"></mj-section>\n\t\t</mj-attributes>\n\t</mj-head>\n\t<mj-body>\n\t\t<mj-section padding=\"20px 0\">\n\t\t\t<mj-column width=\"100%\">\n\t\t\t\t<mj-text\n\t\t\t\t\talign=\"left\"\n\t\t\t\t\tfont-size=\"10px\"\n\t\t\t\t>\n\t\t\t\t\tMessage from Checkmate Service\n\t\t\t\t</mj-text>\n\t\t\t</mj-column>\n\t\t\t<mj-column\n\t\t\t\twidth=\"45%\"\n\t\t\t\tpadding-top=\"20px\"\n\t\t\t>\n\t\t\t\t<mj-text\n\t\t\t\t\talign=\"center\"\n\t\t\t\t\tfont-weight=\"500\"\n\t\t\t\t\tpadding=\"0px\"\n\t\t\t\t\tfont-size=\"18px\"\n\t\t\t\t\tcolor=\"{{headerColor}}\"\n\t\t\t\t>\n\t\t\t\t\t{{ title }}\n\t\t\t\t</mj-text>\n\t\t\t\t<mj-divider\n\t\t\t\t\tborder-width=\"2px\"\n\t\t\t\t\tborder-color=\"#616161\"\n\t\t\t\t></mj-divider>\n\t\t\t</mj-column>\n\t\t</mj-section>\n\t\t<mj-section>\n\t\t\t<mj-column width=\"100%\">\n\t\t\t\t<mj-text>\n\t\t\t\t\t<p>Hello!</p>\n\t\t\t\t\t<p>{{ summary }}</p>\n\t\t\t\t\t<p><b>Monitor name:</b> {{ monitorName }}</p>\n\t\t\t\t\t<p><b>URL:</b> {{ monitorUrl }}</p>\n\t\t\t\t\t<p><b>Type:</b> {{ monitorType }}</p>\n\t\t\t\t\t<p><b>Status:</b> {{ monitorStatus }}</p>\n\t\t\t\t\t{{#if thresholds}}\n\t\t\t\t\t<p><b>Threshold Breaches:</b></p>\n\t\t\t\t\t<ul>\n\t\t\t\t\t\t{{#each thresholds}}\n\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t<b>{{ metric }}:</b> {{ formattedValue }} (threshold: {{ threshold }}{{ unit }})\n\t\t\t\t\t\t</li>\n\t\t\t\t\t\t{{/each}}\n\t\t\t\t\t</ul>\n\t\t\t\t\t{{/if}}\n\t\t\t\t\t{{#if details}}\n\t\t\t\t\t<p><b>Additional Details:</b></p>\n\t\t\t\t\t<ul>\n\t\t\t\t\t\t{{#each details}}\n\t\t\t\t\t\t<li>{{ this }}</li>\n\t\t\t\t\t\t{{/each}}\n\t\t\t\t\t</ul>\n\t\t\t\t\t{{/if}}\n\t\t\t\t</mj-text>\n\t\t\t</mj-column>\n\t\t\t<mj-column width=\"100%\">\n\t\t\t\t<mj-divider\n\t\t\t\t\tborder-width=\"1px\"\n\t\t\t\t\tborder-color=\"#E0E0E0\"\n\t\t\t\t></mj-divider>\n\t\t\t\t{{#if incidentUrl}}\n\t\t\t\t<mj-button\n\t\t\t\t\tbackground-color=\"#1570EF\"\n\t\t\t\t\thref=\"{{incidentUrl}}\"\n\t\t\t\t>\n\t\t\t\t\tView incident details\n\t\t\t\t</mj-button>\n\t\t\t\t{{/if}}\n\t\t\t\t<mj-text font-size=\"12px\">\n\t\t\t\t\t<p>This email was sent by Checkmate.</p>\n\t\t\t\t</mj-text>\n\t\t\t</mj-column>\n\t\t</mj-section>\n\t</mj-body>\n</mjml>\n"
  },
  {
    "path": "server/src/templates/welcomeEmail.mjml",
    "content": "<!-- name -->\n<mjml>\n\t<mj-head>\n\t\t<mj-font\n\t\t\tname=\"Roboto\"\n\t\t\thref=\"https://fonts.googleapis.com/css?family=Roboto:300,500\"\n\t\t></mj-font>\n\t\t<mj-attributes>\n\t\t\t<mj-all font-family=\"Roboto, Helvetica, sans-serif\"></mj-all>\n\t\t\t<mj-text\n\t\t\t\tfont-weight=\"300\"\n\t\t\t\tfont-size=\"16px\"\n\t\t\t\tcolor=\"#616161\"\n\t\t\t\tline-height=\"24px\"\n\t\t\t></mj-text>\n\t\t\t<mj-section padding=\"0px\"></mj-section>\n\t\t</mj-attributes>\n\t</mj-head>\n\t<mj-body>\n\t\t<mj-section padding=\"20px 0\">\n\t\t\t<mj-column width=\"100%\">\n\t\t\t\t<mj-text\n\t\t\t\t\talign=\"left\"\n\t\t\t\t\tfont-size=\"10px\"\n\t\t\t\t>\n\t\t\t\t\tMessage from Checkmate Service\n\t\t\t\t</mj-text>\n\t\t\t</mj-column>\n\t\t</mj-section>\n\t\t<mj-section>\n\t\t\t<mj-column width=\"100%\">\n\t\t\t\t<mj-text>\n\t\t\t\t\t<p>Hello {{ name }}!</p>\n\t\t\t\t\t<p>Thank you for trying out Checkmate! We developed it with great care to meet our own needs, and we're excited to share it with you.</p>\n\t\t\t\t\t<p>Checkmate is an automated way of checking whether a service such as a website or an application is available or not.</p>\n\t\t\t\t\t<p>We hope you find our service as valuable as we do.</p>\n\t\t\t\t\t<p>Thank you.</p>\n\t\t\t\t</mj-text>\n\t\t\t</mj-column>\n\t\t\t<mj-column width=\"100%\">\n\t\t\t\t<mj-divider\n\t\t\t\t\tborder-width=\"1px\"\n\t\t\t\t\tborder-color=\"#E0E0E0\"\n\t\t\t\t></mj-divider>\n\t\t\t\t<mj-text font-size=\"12px\">\n\t\t\t\t\t<p>This email was sent by Checkmate.</p>\n\t\t\t\t</mj-text>\n\t\t\t</mj-column>\n\t\t</mj-section>\n\t</mj-body>\n</mjml>\n"
  },
  {
    "path": "server/src/types/alert.ts",
    "content": "import { NotificationChannel } from \"@/types/index.js\";\nexport interface AlertWebhookPayload {\n\tbody: Record<string, unknown>;\n}\n\nexport interface AlertPagerDutyPayload {\n\trouting_key?: string;\n\tdedup_key?: string;\n\tevent_action?: \"trigger\" | \"resolve\";\n\tpayload: Record<string, unknown>;\n}\n\nexport interface AlertMatrixPayload {\n\tplainText: string;\n\thtmlText: string;\n}\n\nexport interface DiscordEmbedField {\n\tname: string;\n\tvalue: string;\n\tinline?: boolean;\n}\n\nexport interface AlertDiscordPayload {\n\ttitle: string;\n\tdescription: string;\n\tcolor: number;\n\tfields: DiscordEmbedField[];\n\ttimestamp: string;\n}\n\nexport interface Alert {\n\tchannel: NotificationChannel;\n\taddress?: string;\n\tsubject: string;\n\tmessage: string;\n\thtml?: string;\n\tdiscordContent?: Record<string, unknown> | null;\n\twebhook?: AlertWebhookPayload | null;\n\tpagerDuty?: AlertPagerDutyPayload | null;\n\tmatrix?: AlertMatrixPayload | null;\n}\n"
  },
  {
    "path": "server/src/types/check.ts",
    "content": "import type { MonitorType } from \"@/types/index.js\";\nimport type { Response } from \"got\";\n\nexport const CHECK_TTL_SENTINEL = 366;\n\nexport type GotTimings = Response[\"timings\"];\n\nexport interface CheckMetadata {\n\tmonitorId: string;\n\tteamId: string;\n\ttype: MonitorType;\n}\n\nexport interface CheckCpuInfo {\n\tphysical_core?: number;\n\tlogical_core?: number;\n\tfrequency?: number;\n\tcurrent_frequency?: number;\n\ttemperature?: number[];\n\tfree_percent?: number;\n\tusage_percent?: number;\n}\n\nexport interface CheckMemoryInfo {\n\ttotal_bytes?: number;\n\tavailable_bytes?: number;\n\tused_bytes?: number;\n\tusage_percent?: number;\n}\n\nexport interface CheckHostInfo {\n\tos?: string;\n\tplatform?: string;\n\tkernel_version?: string;\n\tpretty_name?: string;\n}\n\nexport interface CheckCaptureInfo {\n\tversion?: string;\n\tmode?: string;\n}\n\nexport interface CheckDiskInfo {\n\tdevice?: string;\n\tmountpoint?: string;\n\ttotal_bytes?: number;\n\tfree_bytes?: number;\n\tused_bytes?: number;\n\tusage_percent?: number;\n\ttotal_inodes?: number;\n\tfree_inodes?: number;\n\tused_inodes?: number;\n\tinodes_usage_percent?: number;\n\tread_bytes?: number;\n\twrite_bytes?: number;\n\tread_time?: number;\n\twrite_time?: number;\n}\n\nexport interface CheckErrorInfo {\n\tmetric: string[];\n\terr: string;\n}\n\nexport interface CheckNetworkInterfaceInfo {\n\tname: string;\n\tbytes_sent: number;\n\tbytes_recv: number;\n\tpackets_sent: number;\n\tpackets_recv: number;\n\terr_in: number;\n\terr_out: number;\n\tdrop_in: number;\n\tdrop_out: number;\n\tfifo_in: number;\n\tfifo_out: number;\n}\n\nexport interface CheckAudits {\n\tcls?: ILighthouseAudit;\n\tsi?: ILighthouseAudit;\n\tfcp?: ILighthouseAudit;\n\tlcp?: ILighthouseAudit;\n\ttbt?: ILighthouseAudit;\n}\n\nexport interface ILighthouseAudit {\n\tid?: string;\n\ttitle?: string;\n\tscore?: number | null;\n\tdisplayValue?: string;\n\tnumericValue?: number;\n\tnumericUnit?: string;\n}\n\nexport interface Check {\n\tid: string;\n\tmetadata: CheckMetadata;\n\tstatus: boolean;\n\tresponseTime: number;\n\ttimings?: GotTimings;\n\tstatusCode: number;\n\tmessage: string;\n\tcpu?: CheckCpuInfo;\n\tmemory?: CheckMemoryInfo;\n\tdisk?: CheckDiskInfo[];\n\thost?: CheckHostInfo;\n\terrors?: CheckErrorInfo[];\n\tcapture?: CheckCaptureInfo;\n\tnet?: CheckNetworkInterfaceInfo[];\n\taccessibility?: number;\n\tbestPractices?: number;\n\tseo?: number;\n\tperformance?: number;\n\taudits?: CheckAudits;\n\tcreatedAt: string;\n\tupdatedAt: string;\n}\nexport interface ChecksQueryResult {\n\tchecksCount: number;\n\tchecks: Check[];\n}\n\nexport interface PageSpeedChecksResult {\n\tmonitorType: \"pagespeed\";\n\tgroupedChecks: PageSpeedGroupedCheck[];\n}\n\nexport interface HardwareChecksResult {\n\tmonitorType: \"hardware\";\n\taggregateData: {\n\t\ttotalChecks: number;\n\t};\n\tupChecks: {\n\t\ttotalChecks: number;\n\t};\n\tchecks: Array<{\n\t\tbucketDate: string;\n\t\tavgCpuUsage: number;\n\t\tavgMemoryUsage: number;\n\t\tavgTemperature: number[];\n\t\tdisks: Array<{\n\t\t\tname: string;\n\t\t\treadSpeed: number;\n\t\t\twriteSpeed: number;\n\t\t\ttotalBytes: number;\n\t\t\tfreeBytes: number;\n\t\t\tusagePercent: number;\n\t\t}>;\n\t\tnet: Array<{\n\t\t\tname: string;\n\t\t\tbytesSentPerSecond: number;\n\t\t\tdeltaBytesRecv: number;\n\t\t\tdeltaPacketsSent: number;\n\t\t\tdeltaPacketsRecv: number;\n\t\t\tdeltaErrIn: number;\n\t\t\tdeltaErrOut: number;\n\t\t\tdeltaDropIn: number;\n\t\t\tdeltaDropOut: number;\n\t\t\tdeltaFifoIn: number;\n\t\t\tdeltaFifoOut: number;\n\t\t}>;\n\t}>;\n}\n\nexport interface GroupedCheck {\n\tbucketDate: string;\n\tavgResponseTime: number;\n\ttotalChecks: number;\n}\n\nexport interface PageSpeedGroupedCheck {\n\tbucketDate: string;\n\tperformance: number;\n\taccessibility: number;\n\tbestPractices: number;\n\tseo: number;\n\ttotalChecks: number;\n}\n\nexport interface UptimeChecksResult {\n\tmonitorType: Exclude<MonitorType, \"hardware\" | \"pagespeed\">;\n\tgroupedChecks: GroupedCheck[];\n\tgroupedUpChecks: GroupedCheck[];\n\tgroupedDownChecks: GroupedCheck[];\n\tuptimePercentage: number;\n\tavgResponseTime: number;\n}\n\nexport interface ChecksSummary {\n\ttotalChecks: number;\n\tdownChecks: number;\n}\n\nexport interface HasResponseTime {\n\tresponseTime: number;\n}\n\nexport type NormalizedCheck<T extends HasResponseTime = Check> = T & {\n\toriginalResponseTime: number;\n};\n\nexport type NormalizedUptimeCheck<T extends GroupedCheck = GroupedCheck> = T & {\n\toriginalAvgResponseTime: number;\n};\n\nexport type CheckSnapshot = Omit<Check, \"metadata\" | \"updatedAt\">;\n"
  },
  {
    "path": "server/src/types/email.ts",
    "content": "import { Settings } from \"./settings.js\";\n\nexport type EmailTransportConfig = Pick<\n\tSettings,\n\t| \"systemEmailHost\"\n\t| \"systemEmailPort\"\n\t| \"systemEmailAddress\"\n\t| \"systemEmailPassword\"\n\t| \"systemEmailUser\"\n\t| \"systemEmailConnectionHost\"\n\t| \"systemEmailTLSServername\"\n\t| \"systemEmailSecure\"\n\t| \"systemEmailPool\"\n\t| \"systemEmailIgnoreTLS\"\n\t| \"systemEmailRequireTLS\"\n\t| \"systemEmailRejectUnauthorized\"\n>;\n"
  },
  {
    "path": "server/src/types/express.d.ts",
    "content": "import type { User } from \"@/types/index.js\";\n\ndeclare global {\n\tnamespace Express {\n\t\tinterface Request {\n\t\t\tfile?: Multer.File;\n\t\t\tuser?: User | undefined;\n\t\t\tresource?: unknown;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "server/src/types/geoCheck.ts",
    "content": "import type { MonitorType } from \"@/types/index.js\";\n\nexport const GeoContinents = [\"EU\", \"NA\", \"AS\", \"SA\", \"AF\", \"OC\"] as const;\nexport type GeoContinent = (typeof GeoContinents)[number];\n\nexport interface GeoCheckMetadata {\n\tmonitorId: string;\n\tteamId: string;\n\ttype: MonitorType;\n}\n\nexport interface GeoCheckTimings {\n\ttotal: number;\n\tdns: number;\n\ttcp: number;\n\ttls: number;\n\tfirstByte: number;\n\tdownload: number;\n}\n\nexport interface GeoCheckLocation {\n\tcontinent: GeoContinent;\n\tregion: string;\n\tcountry: string;\n\tstate: string;\n\tcity: string;\n\tlongitude: number;\n\tlatitude: number;\n}\n\nexport interface GeoCheckResult {\n\tlocation: GeoCheckLocation;\n\tstatus: boolean;\n\tstatusCode: number;\n\ttimings: GeoCheckTimings;\n}\n\nexport interface GeoCheck {\n\tid: string;\n\tmetadata: GeoCheckMetadata;\n\tresults: GeoCheckResult[];\n\texpiry: string;\n\t__v: number;\n\tcreatedAt: string;\n\tupdatedAt: string;\n}\n\nexport interface FlatGeoCheck {\n\tid: string;\n\tmonitorId: string;\n\tteamId: string;\n\ttype: string;\n\tlocation: GeoCheckLocation;\n\tstatus: boolean;\n\tstatusCode: number;\n\ttimings: GeoCheckTimings;\n\tcreatedAt: string;\n\tupdatedAt: string;\n}\n\nexport interface GroupedGeoCheck {\n\tbucketDate: string;\n\tcontinent: GeoContinent;\n\tavgResponseTime: number;\n\ttotalChecks: number;\n\tuptimePercentage: number;\n}\n\nexport interface GeoChecksResult {\n\tmonitorType: Exclude<MonitorType, \"hardware\" | \"pagespeed\">;\n\tgroupedGeoChecks: GroupedGeoCheck[];\n}\n"
  },
  {
    "path": "server/src/types/incident.ts",
    "content": "// export type IncidentResolutionType = \"automatic\" | \"manual\" | null;\n\nexport const IncidentResolutionTypes = [\"automatic\", \"manual\", null] as const;\nexport type IncidentResolutionType = (typeof IncidentResolutionTypes)[number];\n\nexport interface Incident {\n\tid: string;\n\tmonitorId: string;\n\tteamId: string;\n\tstartTime: string;\n\tendTime: string | null;\n\tstatus: boolean;\n\tmessage?: string | null;\n\tstatusCode?: number | null;\n\tresolutionType: IncidentResolutionType;\n\tresolvedBy?: string | null;\n\tresolvedByEmail?: string | null;\n\tcomment?: string | null;\n\tcreatedAt: string;\n\tupdatedAt: string;\n}\n\nexport interface IncidentSummaryTopMonitor {\n\tmonitorId: string;\n\tmonitorName: string | null;\n\tincidentCount: number;\n}\n\nexport interface IncidentSummaryItem {\n\tid: string;\n\tmonitorId: string;\n\tmonitorName: string | null;\n\tstatus: boolean;\n\tstartTime: string;\n\tendTime: string | null;\n\tresolutionType: IncidentResolutionType;\n\tmessage: string | null;\n\tstatusCode: number | null;\n\tcreatedAt: string;\n}\n\nexport interface IncidentSummary {\n\ttotal: number;\n\ttotalActive: number;\n\ttotalManualResolutions: number;\n\ttotalAutomaticResolutions: number;\n\tavgResolutionTimeHours: number;\n\ttopMonitor: IncidentSummaryTopMonitor | null;\n\tlatestIncidents: IncidentSummaryItem[];\n}\n"
  },
  {
    "path": "server/src/types/index.ts",
    "content": "export * from \"@/types/check.js\";\nexport * from \"@/types/geoCheck.js\";\nexport * from \"@/types/monitor.js\";\nexport * from \"@/types/monitorStats.js\";\nexport * from \"@/types/statusPage.js\";\nexport * from \"@/types/network.js\";\nexport * from \"@/types/user.js\";\nexport * from \"@/types/invite.js\";\nexport * from \"@/types/recoveryToken.js\";\nexport * from \"@/types/settings.js\";\nexport * from \"@/types/notification.js\";\nexport * from \"@/types/alert.js\";\nexport * from \"@/types/incident.js\";\nexport * from \"@/types/email.js\";\nexport * from \"@/types/team.js\";\nexport * from \"@/types/maintenanceWindow.js\";\n"
  },
  {
    "path": "server/src/types/invite.ts",
    "content": "import type { UserRole } from \"@/types/user.js\";\n\nexport interface Invite {\n\tid: string;\n\temail: string;\n\tteamId: string;\n\trole: UserRole[];\n\ttoken: string;\n\texpiry: string;\n\tcreatedAt: string;\n\tupdatedAt: string;\n}\n"
  },
  {
    "path": "server/src/types/maintenanceWindow.ts",
    "content": "export type DurationUnit = \"seconds\" | \"minutes\" | \"hours\" | \"days\";\n\nexport interface MaintenanceWindow {\n\tid: string;\n\tmonitorId: string;\n\tteamId: string;\n\tactive: boolean;\n\tname: string;\n\tduration: number;\n\tdurationUnit: DurationUnit;\n\trepeat: number;\n\tstart: string;\n\tend: string;\n\tcreatedAt: string;\n\tupdatedAt: string;\n}\n"
  },
  {
    "path": "server/src/types/monitor.ts",
    "content": "import type { CheckSnapshot } from \"@/types/check.js\";\nexport type { CheckSnapshot } from \"@/types/check.js\";\nimport type { GeoContinent, GroupedGeoCheck } from \"@/types/geoCheck.js\";\nexport type { GeoContinent } from \"@/types/geoCheck.js\";\n\nexport const MonitorTypes = [\"http\", \"ping\", \"pagespeed\", \"hardware\", \"docker\", \"port\", \"game\", \"grpc\", \"websocket\", \"unknown\"] as const;\nexport type MonitorType = (typeof MonitorTypes)[number];\n\nexport const GeoCheckSupportedTypes: readonly MonitorType[] = [\"http\", \"ping\"] as const;\nexport const supportsGeoCheck = (type: MonitorType): boolean => GeoCheckSupportedTypes.includes(type);\n\nexport const MonitorStatuses = [\"up\", \"down\", \"paused\", \"initializing\", \"maintenance\", \"breached\"] as const;\nexport type MonitorStatus = (typeof MonitorStatuses)[number];\n\nexport const MonitorMatchMethods = [\"equal\", \"include\", \"regex\"] as const;\nexport type MonitorMatchMethod = (typeof MonitorMatchMethods)[number] | \"\";\n\nexport interface Monitor {\n\tid: string;\n\tuserId: string;\n\tteamId: string;\n\tname: string;\n\tdescription?: string;\n\tstatus: MonitorStatus;\n\tstatusWindow: boolean[];\n\tstatusWindowSize: number;\n\tstatusWindowThreshold: number;\n\ttype: MonitorType;\n\tignoreTlsErrors: boolean;\n\tuseAdvancedMatching: boolean;\n\tjsonPath?: string;\n\texpectedValue?: string;\n\tmatchMethod?: MonitorMatchMethod;\n\turl: string;\n\tport?: number;\n\tisActive: boolean;\n\tinterval: number;\n\tuptimePercentage?: number;\n\tnotifications: string[];\n\tsecret?: string;\n\tcpuAlertThreshold: number;\n\tcpuAlertCounter: number;\n\tmemoryAlertThreshold: number;\n\tmemoryAlertCounter: number;\n\tdiskAlertThreshold: number;\n\tdiskAlertCounter: number;\n\ttempAlertThreshold: number;\n\ttempAlertCounter: number;\n\tselectedDisks: string[];\n\tgameId?: string;\n\tgrpcServiceName?: string;\n\tgroup: string | null;\n\tgeoCheckEnabled?: boolean;\n\tgeoCheckLocations?: GeoContinent[];\n\tgeoCheckInterval?: number;\n\trecentChecks: CheckSnapshot[];\n\tcreatedAt: string;\n\tupdatedAt: string;\n}\n\nexport interface MonitorsSummary {\n\ttotalMonitors: number;\n\tupMonitors: number;\n\tdownMonitors: number;\n\tpausedMonitors: number;\n\tinitializingMonitors: number;\n\tmaintenanceMonitors: number;\n\tbreachedMonitors: number;\n}\n\nexport interface MonitorsWithChecksByTeamIdResult {\n\tsummary: MonitorsSummary | null;\n\tcount: number;\n\tmonitors: Monitor[];\n}\n\nexport interface GroupedGeoCheckResult {\n\tgroupedGeoChecks: GroupedGeoCheck[];\n}\n\nexport interface UptimeDetailsResult {\n\tmonitorData: {\n\t\tmonitor: Monitor;\n\t\tgroupedChecks: import(\"./check.js\").GroupedCheck[];\n\t\tgroupedUpChecks: import(\"./check.js\").GroupedCheck[];\n\t\tgroupedDownChecks: import(\"./check.js\").GroupedCheck[];\n\t\tgroupedAvgResponseTime: number;\n\t\tgroupedUptimePercentage: number;\n\t};\n\tmonitorStats: import(\"./monitorStats.js\").MonitorStats | null;\n}\n\nexport interface HardwareDiskStats {\n\tname: string;\n\treadSpeed: number;\n\twriteSpeed: number;\n\ttotalBytes: number;\n\tfreeBytes: number;\n\tusagePercent: number;\n}\n\nexport interface HardwareNetStats {\n\tname: string;\n\tbytesSentPerSecond: number;\n\tdeltaBytesRecv: number;\n\tdeltaPacketsSent: number;\n\tdeltaPacketsRecv: number;\n\tdeltaErrIn: number;\n\tdeltaErrOut: number;\n\tdeltaDropIn: number;\n\tdeltaDropOut: number;\n\tdeltaFifoIn: number;\n\tdeltaFifoOut: number;\n}\n\nexport interface HardwareCheckStats {\n\tbucketDate: string;\n\tavgCpuUsage: number;\n\tavgMemoryUsage: number;\n\tavgTemperature: number[];\n\tdisks: HardwareDiskStats[];\n\tnet: HardwareNetStats[];\n}\n\nexport interface HardwareStats {\n\taggregateData: {\n\t\ttotalChecks: number;\n\t};\n\tupChecks: {\n\t\ttotalChecks: number;\n\t};\n\tchecks: HardwareCheckStats[];\n}\n\nexport interface HardwareDetailsResult {\n\tmonitor: Monitor;\n\tstats: HardwareStats;\n\tmonitorStats: import(\"./monitorStats.js\").MonitorStats | null;\n}\n\nexport interface PageSpeedDetailsResult {\n\tmonitorData: {\n\t\tmonitor: Monitor;\n\t\tgroupedChecks: import(\"./check.js\").PageSpeedGroupedCheck[];\n\t};\n\tmonitorStats: import(\"./monitorStats.js\").MonitorStats | null;\n}\n\nexport interface Game {\n\tname: string;\n\trelease_year?: number;\n\toptions?: {\n\t\tport?: number;\n\t\tport_query?: number;\n\t\tprotocol?: string;\n\t};\n\textra?: {\n\t\told_id?: string;\n\t};\n}\n\nexport type GamesMap = Record<string, Game>;\n"
  },
  {
    "path": "server/src/types/monitorStats.ts",
    "content": "export interface MonitorStats {\n\tid: string;\n\tmonitorId: string;\n\tavgResponseTime: number;\n\tmaxResponseTime: number;\n\ttotalChecks: number;\n\ttotalUpChecks: number;\n\ttotalDownChecks: number;\n\tuptimePercentage: number;\n\tlastCheckTimestamp: number;\n\tlastResponseTime: number;\n\ttimeOfLastFailure?: number;\n\tcreatedAt: string;\n\tupdatedAt: string;\n}\n"
  },
  {
    "path": "server/src/types/network.ts",
    "content": "import type {\n\tCheckCaptureInfo,\n\tCheckCpuInfo,\n\tCheckDiskInfo,\n\tCheckErrorInfo,\n\tCheckHostInfo,\n\tCheckMemoryInfo,\n\tCheckNetworkInterfaceInfo,\n\tGotTimings,\n\tILighthouseAudit,\n\tMonitor,\n\tMonitorMatchMethod,\n\tMonitorType,\n\tMonitorStatus,\n} from \"@/types/index.js\";\n\nimport type { QueryResult } from \"gamedig\";\n\nexport interface MonitorStatusResponse<\n\tT =\n\t\t| HttpStatusPayload\n\t\t| PingStatusPayload\n\t\t| PageSpeedStatusPayload\n\t\t| HardwareStatusPayload\n\t\t| DockerStatusPayload\n\t\t| GameStatusPayload\n\t\t| GrpcStatusPayload\n\t\t| WebSocketStatusPayload,\n> {\n\tmonitorId: string;\n\tteamId: string;\n\ttype: MonitorType;\n\tstatus: boolean;\n\tcode: number;\n\tmessage: string;\n\tresponseTime?: number;\n\tpayload?: T | null;\n\ttimings?: GotTimings;\n\tfirst_byte_took?: number;\n\tbody_read_took?: number;\n\tdns_took?: number;\n\tconn_took?: number;\n\tconnect_took?: number;\n\ttls_took?: number;\n\tjsonPath?: string;\n\tmatchMethod?: MonitorMatchMethod;\n\texpectedValue?: string;\n\textracted?: unknown;\n}\n\nexport interface PingStatusPayload {\n\thost: string;\n\tnumeric_host?: string;\n\talive: boolean;\n\ttime: number | unknown;\n\ttimes?: number[];\n\toutput?: string;\n\tmin?: string;\n\tmax?: string;\n\tavg?: string;\n\tstddev?: string;\n\tpacketLoss?: string;\n}\n\nexport type HttpStatusPayload = unknown;\n\nexport interface PageSpeedCategoryScore {\n\tscore?: number | null;\n}\n\nexport interface PageSpeedStatusPayload {\n\tlighthouseResult?: {\n\t\tcategories?: {\n\t\t\taccessibility?: PageSpeedCategoryScore;\n\t\t\t\"best-practices\"?: PageSpeedCategoryScore;\n\t\t\tperformance?: PageSpeedCategoryScore;\n\t\t\tseo?: PageSpeedCategoryScore;\n\t\t\t[key: string]: PageSpeedCategoryScore | undefined;\n\t\t};\n\t\taudits?: Record<string, ILighthouseAudit | undefined>;\n\t};\n\t[key: string]: unknown;\n}\n\nexport interface HardwareStatusMetrics {\n\tcpu?: CheckCpuInfo;\n\tmemory?: CheckMemoryInfo;\n\tdisk?: CheckDiskInfo[];\n\thost?: CheckHostInfo;\n\tnet?: CheckNetworkInterfaceInfo[];\n}\n\nexport interface HardwareStatusPayload {\n\tdata?: HardwareStatusMetrics;\n\terrors?: CheckErrorInfo[] | { errors?: CheckErrorInfo[] };\n\tcapture?: CheckCaptureInfo;\n\t[key: string]: unknown;\n}\n\nexport type DockerStatusPayload = Record<string, unknown>;\n\nexport interface PortStatusPayload {\n\tsuccess: boolean;\n}\n\nexport type GameStatusPayload = QueryResult;\n\nexport interface GrpcStatusPayload {\n\tgrpcStatusCode: number;\n\tgrpcStatusName: string;\n\tserviceName: string;\n\tservingStatus: string;\n}\n\nexport interface WebSocketStatusPayload {\n\tconnected: boolean;\n}\n\nexport interface MonitorPayloadMap {\n\tping: PingStatusPayload;\n\thttp: HttpStatusPayload;\n\tpagespeed: PageSpeedStatusPayload;\n\thardware: HardwareStatusPayload;\n\tdocker: DockerStatusPayload;\n\tport: PortStatusPayload;\n\tgame: GameStatusPayload;\n\tgrpc: GrpcStatusPayload;\n\twebsocket: WebSocketStatusPayload;\n\tunknown: unknown;\n}\n\nexport type StatusChangeResult = {\n\tmonitor: Monitor;\n\tstatusChanged: boolean;\n\tprevStatus: MonitorStatus;\n\tcode: number;\n\ttimestamp: number;\n\tthresholdBreaches?: {\n\t\tcpu: boolean;\n\t\tmemory: boolean;\n\t\tdisk: boolean;\n\t\ttemp: boolean;\n\t};\n};\n\nexport type MonitorStatusResponseOverrides<T> = Partial<Omit<MonitorStatusResponse<T>, \"monitorId\" | \"teamId\" | \"type\">>;\n"
  },
  {
    "path": "server/src/types/notification.ts",
    "content": "export const NotificationChannels = [\"email\", \"slack\", \"discord\", \"webhook\", \"pager_duty\", \"matrix\", \"teams\"] as const;\nexport type NotificationChannel = (typeof NotificationChannels)[number];\n\nexport interface Notification {\n\tid: string;\n\tuserId: string;\n\tteamId: string;\n\ttype: NotificationChannel;\n\tnotificationName: string;\n\taddress?: string;\n\tphone?: string;\n\thomeserverUrl?: string;\n\troomId?: string;\n\taccessToken?: string;\n\tcreatedAt: string;\n\tupdatedAt: string;\n}\n"
  },
  {
    "path": "server/src/types/notificationMessage.ts",
    "content": "/**\n * Unified notification message types for cross-provider consistency\n * Part of notification system unification effort\n */\n\nexport type NotificationType = \"monitor_down\" | \"monitor_up\" | \"threshold_breach\" | \"threshold_resolved\" | \"test\";\n\nexport type NotificationSeverity = \"critical\" | \"warning\" | \"info\" | \"success\";\n\nexport interface MonitorInfo {\n\tid: string;\n\tname: string;\n\turl: string;\n\ttype: string;\n\tstatus: string;\n}\n\nexport interface ThresholdBreach {\n\tmetric: \"cpu\" | \"memory\" | \"disk\" | \"temp\";\n\tcurrentValue: number;\n\tthreshold: number;\n\tunit: string;\n\tformattedValue: string; // e.g., \"85%\" or \"72°C\"\n}\n\nexport interface IncidentInfo {\n\tid: string;\n\turl: string;\n\tcreatedAt: Date;\n\tresolvedAt?: Date;\n\tduration?: string;\n}\n\nexport interface NotificationContent {\n\ttitle: string;\n\tsummary: string;\n\tdetails?: string[];\n\tthresholds?: ThresholdBreach[];\n\tincident?: IncidentInfo;\n\ttimestamp: Date;\n}\n\nexport interface NotificationMessage {\n\ttype: NotificationType;\n\tseverity: NotificationSeverity;\n\tmonitor: MonitorInfo;\n\tcontent: NotificationContent;\n\tclientHost: string;\n\tmetadata: {\n\t\tteamId: string;\n\t\tnotificationReason: string;\n\t};\n}\n"
  },
  {
    "path": "server/src/types/recoveryToken.ts",
    "content": "export interface RecoveryToken {\n\tid: string;\n\temail: string;\n\ttoken: string;\n\texpiry: string;\n\tcreatedAt: string;\n\tupdatedAt: string;\n}\n"
  },
  {
    "path": "server/src/types/settings.ts",
    "content": "export interface SettingsThresholds {\n\tcpu?: number;\n\tmemory?: number;\n\tdisk?: number;\n\ttemperature?: number;\n}\n\nexport type SettingsUpdate = {\n\t[K in keyof Settings]?: Settings[K] | null;\n};\n\nexport interface Settings {\n\tid: string;\n\tcheckTTL: number;\n\tlanguage: string;\n\tjwtSecret?: string;\n\tpagespeedApiKey?: string;\n\tsystemEmailHost?: string;\n\tsystemEmailPort?: number;\n\tsystemEmailAddress?: string;\n\tsystemEmailPassword?: string;\n\tsystemEmailUser?: string;\n\tsystemEmailConnectionHost?: string;\n\tsystemEmailTLSServername?: string;\n\tsystemEmailSecure: boolean;\n\tsystemEmailPool: boolean;\n\tsystemEmailIgnoreTLS: boolean;\n\tsystemEmailRequireTLS: boolean;\n\tsystemEmailRejectUnauthorized: boolean;\n\tshowURL: boolean;\n\tsingleton: boolean;\n\tversion: number;\n\tglobalThresholds?: SettingsThresholds;\n\tcreatedAt: string;\n\tupdatedAt: string;\n}\n"
  },
  {
    "path": "server/src/types/ssl-checker.d.ts",
    "content": "declare module \"ssl-checker\" {\n\timport { Agent } from \"https\";\n\n\texport interface SSLDetails {\n\t\tdaysRemaining: number;\n\t\tvalid: boolean;\n\t\tvalidFrom: string;\n\t\tvalidTo: string;\n\t\tvalidFor: string[];\n\t}\n\n\texport interface SSLOptions {\n\t\tmethod?: \"GET\" | \"HEAD\";\n\t\tport?: number;\n\t\tagent?: Agent;\n\t\trejectUnauthorized?: boolean;\n\t\tvalidateSubjectAltName?: boolean;\n\t}\n\n\tfunction sslChecker(hostname: string, options?: SSLOptions): Promise<SSLDetails>;\n\n\t// Change 'export default' to 'export =' to allow it to be callable\n\texport = sslChecker;\n}\n"
  },
  {
    "path": "server/src/types/statusPage.ts",
    "content": "export const StatusPageTypes = [\"uptime\", \"infrastructure\"] as const;\nexport type StatusPageType = (typeof StatusPageTypes)[number];\n\nexport interface StatusPageLogo {\n\tdata: string;\n\tcontentType: string;\n}\n\nexport interface StatusPageLogoDocument {\n\tdata: Buffer;\n\tcontentType: string;\n}\n\nexport interface StatusPage {\n\tid: string;\n\tuserId: string;\n\tteamId: string;\n\ttype: StatusPageType[];\n\tcompanyName: string;\n\turl: string;\n\ttimezone?: string;\n\tcolor: string;\n\tmonitors: string[];\n\tsubMonitors: string[];\n\toriginalMonitors?: string[];\n\tlogo?: StatusPageLogo | null;\n\tisPublished: boolean;\n\tshowCharts: boolean;\n\tshowUptimePercentage: boolean;\n\tshowAdminLoginLink: boolean;\n\tshowInfrastructure: boolean;\n\tcustomCSS: string;\n\tcreatedAt: string;\n\tupdatedAt: string;\n}\n"
  },
  {
    "path": "server/src/types/team.ts",
    "content": "export interface Team {\n\tid: string;\n\temail: string;\n\tcreatedAt: string;\n\tupdatedAt: string;\n}\n"
  },
  {
    "path": "server/src/types/user.ts",
    "content": "export const UserRoles = [\"user\", \"admin\", \"superadmin\", \"demo\"] as const;\nexport type UserRole = (typeof UserRoles)[number];\n\nexport const RoleHierarchy: Record<UserRole, number> = {\n\tdemo: 0,\n\tuser: 1,\n\tadmin: 2,\n\tsuperadmin: 3,\n};\n\nexport const canManageRole = (actorRole: UserRole, targetRole: UserRole): boolean => {\n\treturn RoleHierarchy[actorRole] > RoleHierarchy[targetRole];\n};\n\nexport interface UserProfileImage {\n\tdata?: Buffer;\n\tcontentType?: string;\n}\n\nexport interface User {\n\tid: string;\n\tfirstName: string;\n\tlastName: string;\n\temail: string;\n\tpassword: string;\n\tavatarImage?: string;\n\tprofileImage?: UserProfileImage;\n\tisActive: boolean;\n\tisVerified: boolean;\n\trole: UserRole[];\n\tteamId: string;\n\tcheckTTL?: number;\n\tcreatedAt: string;\n\tupdatedAt: string;\n}\n"
  },
  {
    "path": "server/src/utils/AppError.ts",
    "content": "export interface AppErrorConfig {\n\tmessage?: string;\n\tstatus?: number;\n\tservice?: string;\n\tmethod?: string;\n\tdetails?: Record<string, unknown> | undefined;\n}\n\nexport class AppError extends Error {\n\treadonly status: number;\n\treadonly service: string;\n\treadonly method: string;\n\treadonly details: Record<string, unknown> | undefined;\n\n\tconstructor({ message, status = 500, service = \"unknownService\", method = \"unknownMethod\", details = undefined }: AppErrorConfig) {\n\t\tsuper(message);\n\t\tthis.status = status;\n\t\tthis.service = service;\n\t\tthis.method = method;\n\t\tthis.details = details;\n\n\t\tError.captureStackTrace(this, this.constructor);\n\t}\n}\n"
  },
  {
    "path": "server/src/utils/dataUtils.ts",
    "content": "import type { GroupedCheck, NormalizedCheck, NormalizedUptimeCheck, HasResponseTime } from \"@/types/index.js\";\n\nexport const getDateForRange = (dateRange: string): Date | undefined => {\n\tconst now = Date.now();\n\tswitch (dateRange) {\n\t\tcase \"recent\":\n\t\t\treturn new Date(now - 2 * 60 * 60 * 1000); // 2 hours\n\t\tcase \"hour\":\n\t\t\treturn new Date(now - 60 * 60 * 1000); // 1 hour\n\t\tcase \"day\":\n\t\t\treturn new Date(now - 24 * 60 * 60 * 1000); // 1 day\n\t\tcase \"week\":\n\t\t\treturn new Date(now - 7 * 24 * 60 * 60 * 1000); // 7 days\n\t\tcase \"month\":\n\t\t\treturn new Date(now - 30 * 24 * 60 * 60 * 1000); // 30 days\n\t\tcase \"all\":\n\t\t\treturn undefined;\n\t\tdefault:\n\t\t\treturn undefined;\n\t}\n};\n\nconst calculatePercentile = <T extends HasResponseTime>(arr: T[], percentile: number): number => {\n\tconst sorted = arr.slice().sort((a, b) => a.responseTime - b.responseTime);\n\tconst index = (percentile / 100) * (sorted.length - 1);\n\tconst lower = Math.floor(index);\n\tconst upper = lower + 1;\n\tconst weight = index % 1;\n\tif (upper >= sorted.length) return sorted[lower]!.responseTime;\n\treturn sorted[lower]!.responseTime * (1 - weight) + sorted[upper]!.responseTime * weight;\n};\n\nconst calculatePercentileUptimeDetails = (arr: GroupedCheck[], percentile: number): number => {\n\tconst sorted = arr.slice().sort((a, b) => a.avgResponseTime - b.avgResponseTime);\n\tconst index = (percentile / 100) * (sorted.length - 1);\n\tconst lower = Math.floor(index);\n\tconst upper = lower + 1;\n\tconst weight = index % 1;\n\tif (upper >= sorted.length) return sorted[lower]!.avgResponseTime;\n\treturn sorted[lower]!.avgResponseTime * (1 - weight) + sorted[upper]!.avgResponseTime * weight;\n};\n\nexport const NormalizeData = <T extends HasResponseTime>(checks: T[], rangeMin: number, rangeMax: number): NormalizedCheck<T>[] => {\n\tif (checks.length > 1) {\n\t\tconst min = calculatePercentile(checks, 0);\n\t\tconst max = calculatePercentile(checks, 95);\n\t\tconst normalizedChecks = checks.map((check) => {\n\t\t\tconst originalResponseTime = typeof check.responseTime === \"number\" ? check.responseTime : 0;\n\t\t\tlet normalizedResponseTime = rangeMin + ((check.responseTime - min) * (rangeMax - rangeMin)) / (max - min);\n\n\t\t\tnormalizedResponseTime = Math.max(rangeMin, Math.min(rangeMax, normalizedResponseTime));\n\t\t\treturn {\n\t\t\t\t...check,\n\t\t\t\tresponseTime: normalizedResponseTime,\n\t\t\t\toriginalResponseTime: originalResponseTime,\n\t\t\t};\n\t\t});\n\n\t\treturn normalizedChecks;\n\t} else {\n\t\treturn checks.map((check) => {\n\t\t\tconst originalResponseTime = typeof check.responseTime === \"number\" ? check.responseTime : 0;\n\t\t\treturn { ...check, originalResponseTime: originalResponseTime };\n\t\t});\n\t}\n};\n\nexport const NormalizeDataUptimeDetails = <T extends GroupedCheck>(checks: T[], rangeMin: number, rangeMax: number): NormalizedUptimeCheck<T>[] => {\n\tif (checks.length > 1) {\n\t\tconst min = calculatePercentileUptimeDetails(checks, 0);\n\t\tconst max = calculatePercentileUptimeDetails(checks, 95);\n\n\t\tconst normalizedChecks = checks.map((check) => {\n\t\t\tconst originalResponseTime = check.avgResponseTime;\n\t\t\tlet normalizedResponseTime = rangeMin + ((check.avgResponseTime - min) * (rangeMax - rangeMin)) / (max - min);\n\n\t\t\tnormalizedResponseTime = Math.max(rangeMin, Math.min(rangeMax, normalizedResponseTime));\n\t\t\treturn {\n\t\t\t\t...check,\n\t\t\t\tavgResponseTime: normalizedResponseTime,\n\t\t\t\toriginalAvgResponseTime: originalResponseTime,\n\t\t\t};\n\t\t});\n\n\t\treturn normalizedChecks;\n\t} else {\n\t\treturn checks.map((check) => {\n\t\t\treturn { ...check, originalAvgResponseTime: check.avgResponseTime };\n\t\t});\n\t}\n};\n"
  },
  {
    "path": "server/src/utils/demoMonitors.json",
    "content": "[\n\t{\n\t\t\"name\": \"Google\",\n\t\t\"url\": \"https://www.google.com\"\n\t},\n\t{\n\t\t\"name\": \"Facebook\",\n\t\t\"url\": \"https://www.facebook.com\"\n\t},\n\t{\n\t\t\"name\": \"Yahoo\",\n\t\t\"url\": \"https://www.yahoo.com\"\n\t},\n\t{\n\t\t\"name\": \"Amazon\",\n\t\t\"url\": \"https://www.amazon.com\"\n\t},\n\t{\n\t\t\"name\": \"Apple\",\n\t\t\"url\": \"https://www.apple.com\"\n\t}\n]\n"
  },
  {
    "path": "server/src/utils/imageProcessing.ts",
    "content": "import sharp from \"sharp\";\n\nconst GenerateAvatarImage = async (file: Express.Multer.File) => {\n\t// Resize to target 64 * 64\n\tconst resizedImageBuffer = await sharp(file.buffer)\n\t\t.resize({\n\t\t\twidth: 64,\n\t\t\theight: 64,\n\t\t\tfit: \"cover\",\n\t\t})\n\t\t.toBuffer();\n\n\t//Get b64 string\n\tconst base64Image = resizedImageBuffer.toString(\"base64\");\n\treturn base64Image;\n};\n\nexport { GenerateAvatarImage };\n"
  },
  {
    "path": "server/src/utils/logger.ts",
    "content": "import { createLogger, format, transports, Logger as WinstonLogger } from \"winston\";\nimport type { Logform } from \"winston\";\nimport dotenv from \"dotenv\";\nimport { EnvConfig } from \"@/service/system/settingsService.js\";\ndotenv.config();\n\nconst SERVICE_NAME = \"Logger\";\n\ninterface LogConfig {\n\tmessage: string;\n\tservice?: string;\n\tmethod?: string;\n\tdetails?: Record<string, unknown>;\n\tstack?: string;\n}\n\ninterface LogEntry extends LogConfig {\n\tlevel: string;\n\ttimestamp: string;\n}\n\nexport interface ILogger {\n\treadonly serviceName: string;\n\tinfo(config: LogConfig): void;\n\twarn(config: LogConfig): void;\n\terror(config: LogConfig): void;\n\tdebug(config: LogConfig): void;\n\tcacheLog(entry: LogEntry): void;\n\tgetLogs(): LogEntry[];\n\tbuildLogEntry(level: string, config: LogConfig): LogEntry;\n}\n\nclass Logger implements ILogger {\n\tstatic SERVICE_NAME = SERVICE_NAME;\n\n\tprivate logger: WinstonLogger;\n\tprivate envSettings: Partial<EnvConfig>;\n\tprivate logCache: LogEntry[];\n\tprivate maxCacheSize: number;\n\n\tconstructor({ envSettings }: { envSettings: Partial<EnvConfig> }) {\n\t\tthis.envSettings = envSettings;\n\t\tthis.logCache = [];\n\t\tthis.maxCacheSize = 1000;\n\t\tconst consoleFormat = format.printf((info: Logform.TransformableInfo) => {\n\t\t\tconst { level, service, method, details, timestamp, stack } = info;\n\t\t\tconst message = info.message as string;\n\t\t\tlet formattedMessage: string = message;\n\t\t\tlet formattedDetails: string | undefined;\n\n\t\t\tif (typeof message === \"object\" && message !== null) {\n\t\t\t\tformattedMessage = JSON.stringify(message, null, 2);\n\t\t\t}\n\n\t\t\tif (typeof details === \"object\" && details !== null) {\n\t\t\t\tformattedDetails = JSON.stringify(details, null, 2);\n\t\t\t}\n\n\t\t\tlet msg = `${timestamp} ${level}:`;\n\t\t\tif (service) msg += ` [${service}]`;\n\t\t\tif (method) msg += `(${method})`;\n\t\t\tif (formattedMessage) msg += ` ${formattedMessage}`;\n\t\t\tif (formattedDetails) msg += ` (details: ${formattedDetails})`;\n\n\t\t\tif (typeof stack === \"string\") {\n\t\t\t\tconst stackTrace = stack\n\t\t\t\t\t.split(\"\\n\")\n\t\t\t\t\t.slice(1) // Remove first line (error message)\n\t\t\t\t\t.map((line: string) => {\n\t\t\t\t\t\tconst match = line.match(/at\\s+(.+?)\\s+\\((.+?):(\\d+):(\\d+)\\)/);\n\t\t\t\t\t\tif (match) {\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\tfunction: match[1],\n\t\t\t\t\t\t\t\tfile: match[2],\n\t\t\t\t\t\t\t\tline: parseInt(match[3] ?? \"0\", 10),\n\t\t\t\t\t\t\t\tcolumn: parseInt(match[4] ?? \"0\", 10),\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn line.trim();\n\t\t\t\t\t});\n\t\t\t\tmsg += ` (stack: ${JSON.stringify(stackTrace, null, 2)})`;\n\t\t\t}\n\n\t\t\treturn msg;\n\t\t});\n\n\t\tconst logLevel = this.envSettings.logLevel || \"info\";\n\n\t\tthis.logger = createLogger({\n\t\t\tlevel: logLevel,\n\t\t\tformat: format.combine(format.timestamp()),\n\t\t\ttransports: [\n\t\t\t\tnew transports.Console({\n\t\t\t\t\tformat: format.combine(format.colorize(), format.prettyPrint(), format.json(), consoleFormat),\n\t\t\t\t}),\n\t\t\t\tnew transports.File({\n\t\t\t\t\tformat: format.combine(format.json()),\n\t\t\t\t\tfilename: \"app.log\",\n\t\t\t\t}),\n\t\t\t],\n\t\t});\n\t}\n\n\tget serviceName() {\n\t\treturn Logger.SERVICE_NAME;\n\t}\n\n\tinfo(config: LogConfig) {\n\t\tconst logEntry = this.buildLogEntry(\"info\", config);\n\t\tthis.cacheLog(logEntry);\n\t\tthis.logger.info(logEntry);\n\t}\n\n\twarn(config: LogConfig) {\n\t\tconst logEntry = this.buildLogEntry(\"warn\", config);\n\t\tthis.cacheLog(logEntry);\n\t\tthis.logger.warn(logEntry);\n\t}\n\n\terror(config: LogConfig) {\n\t\tconst logEntry = this.buildLogEntry(\"error\", config);\n\t\tthis.cacheLog(logEntry);\n\t\tthis.logger.error(logEntry);\n\t}\n\n\tdebug(config: LogConfig) {\n\t\tconst logEntry = this.buildLogEntry(\"debug\", config);\n\t\tthis.cacheLog(logEntry);\n\t\tthis.logger.debug(logEntry);\n\t}\n\n\tcacheLog(entry: LogEntry) {\n\t\tthis.logCache.push(entry);\n\t\tif (this.logCache.length > this.maxCacheSize) {\n\t\t\tthis.logCache.shift();\n\t\t}\n\t}\n\n\tgetLogs() {\n\t\treturn this.logCache;\n\t}\n\n\tbuildLogEntry(level: string, config: LogConfig): LogEntry {\n\t\treturn {\n\t\t\tlevel,\n\t\t\tmessage: config.message,\n\t\t\tservice: config.service,\n\t\t\tmethod: config.method,\n\t\t\tdetails: config.details,\n\t\t\tstack: config.stack,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t};\n\t}\n}\n\nexport default Logger;\n\n// Legacy logger\nconst logger = new Logger({ envSettings: { logLevel: \"debug\" } });\nexport { logger };\nexport type { LogConfig, LogEntry };\n"
  },
  {
    "path": "server/src/utils/utils.ts",
    "content": "export const ParseBoolean = (value: boolean | string | null | undefined) => {\n\tif (value === true || value === \"true\") {\n\t\treturn true;\n\t} else if (value === false || value === \"false\" || value === null || value === undefined) {\n\t\treturn false;\n\t}\n};\n\nexport const getTokenFromHeaders = (headers: Record<string, string>) => {\n\tconst authorizationHeader = headers.authorization;\n\tif (!authorizationHeader) throw new Error(\"No auth headers\");\n\n\tconst parts = authorizationHeader.split(\" \");\n\tif (parts.length !== 2 || parts[0] !== \"Bearer\") throw new Error(\"Invalid auth headers\");\n\n\treturn parts[1];\n};\n"
  },
  {
    "path": "server/src/validation/authValidation.ts",
    "content": "import { z } from \"zod\";\nimport { passwordPattern, nameValidation, lowercaseEmailValidation } from \"./shared.js\";\n\n//****************************************\n// Auth Validations\n//****************************************\n\nexport const loginValidation = z.object({\n\temail: z.email(\"Must be a valid email address\").transform((val) => val.toLowerCase()),\n\tpassword: z.string().min(1, \"Password is required\"),\n});\n\nexport const registrationBodyValidation = z.object({\n\tfirstName: nameValidation,\n\tlastName: nameValidation,\n\temail: lowercaseEmailValidation,\n\tpassword: z\n\t\t.string()\n\t\t.min(8, \"Password must be at least 8 characters\")\n\t\t.regex(passwordPattern, \"Password must contain at least one lowercase letter, one uppercase letter, one number, and one special character\"),\n\tprofileImage: z.any().optional(),\n\tinviteToken: z.string().optional().default(\"\"),\n});\n\nexport const recoveryValidation = z.object({\n\temail: z.email(\"Must be a valid email address\"),\n});\n\nexport const recoveryTokenBodyValidation = z.object({\n\trecoveryToken: z.string().min(1, \"Recovery token is required\"),\n});\n\nexport const newPasswordValidation = z.object({\n\trecoveryToken: z.string().min(1, \"Recovery token is required\"),\n\tpassword: z\n\t\t.string()\n\t\t.min(8, \"Password must be at least 8 characters\")\n\t\t.regex(passwordPattern, \"Password must contain at least one lowercase letter, one uppercase letter, one number, and one special character\"),\n\tconfirm: z.string().optional(),\n});\n\nexport const inviteBodyValidation = z.object({\n\temail: z.email(\"Must be a valid email address\"),\n\trole: z.array(z.string()).min(1, \"At least one role is required\"),\n\tteamId: z.string().min(1, \"Team ID is required\"),\n});\n\nexport const inviteVerificationBodyValidation = z.object({\n\ttoken: z.string().min(1, \"Token is required\"),\n});\n"
  },
  {
    "path": "server/src/validation/checkValidation.ts",
    "content": "import { z } from \"zod\";\nimport { booleanCoercion } from \"./shared.js\";\nimport { GeoContinents } from \"@/types/geoCheck.js\";\n\n//****************************************\n// Check Validations\n//****************************************\n\nexport const getChecksParamValidation = z.object({\n\tmonitorId: z.string().min(1, \"Monitor ID is required\"),\n});\n\nexport const getChecksQueryValidation = z.object({\n\ttype: z.enum([\"http\", \"ping\", \"pagespeed\", \"hardware\", \"docker\", \"port\", \"game\", \"grpc\", \"websocket\"]).optional(),\n\tsortOrder: z.enum([\"asc\", \"desc\"]),\n\tlimit: z.coerce.number().optional(),\n\tdateRange: z.enum([\"recent\", \"hour\", \"day\", \"week\", \"month\", \"all\"]),\n\tfilter: z.enum([\"all\", \"up\", \"down\", \"resolve\"]).optional(),\n\tack: booleanCoercion.optional(),\n\tpage: z.coerce.number(),\n\trowsPerPage: z.coerce.number(),\n\tstatus: booleanCoercion.optional(),\n\tcontinent: z.union([z.enum(GeoContinents), z.array(z.enum(GeoContinents))]).optional(),\n});\n\nexport const getTeamChecksQueryValidation = z.object({\n\tsortOrder: z.enum([\"asc\", \"desc\"]),\n\tlimit: z.coerce.number().optional(),\n\tdateRange: z.enum([\"recent\", \"hour\", \"day\", \"week\", \"month\", \"all\"]),\n\tfilter: z.enum([\"all\", \"up\", \"down\", \"resolve\"]).optional(),\n\tack: booleanCoercion.optional(),\n\tpage: z.coerce.number(),\n\trowsPerPage: z.coerce.number(),\n});\n\nexport const deleteChecksParamValidation = z.object({\n\tmonitorId: z.string().min(1, \"Monitor ID is required\"),\n});\n\nexport const getChecksSummaryByTeamIdQueryValidation = z.object({\n\tdateRange: z.enum([\"recent\", \"hour\", \"day\", \"week\", \"month\", \"all\"]).optional(),\n});\n"
  },
  {
    "path": "server/src/validation/envValidation.ts",
    "content": "import { z } from \"zod\";\n\nconst envSchema = z.object({\n\t// Server Configuration\n\tPORT: z.string().default(\"52345\"),\n\tNODE_ENV: z.enum([\"development\", \"production\", \"test\"]).default(\"development\"),\n\tLOG_LEVEL: z.enum([\"error\", \"warn\", \"info\", \"debug\"]).default(\"debug\"),\n\n\t// Database\n\tDB_CONNECTION_STRING: z.string().min(1, \"Database connection string is required\"),\n\n\t// JWT Authentication\n\tJWT_SECRET: z.string().min(1, \"JWT_SECRET is required\"),\n\tTOKEN_TTL: z.string().default(\"99d\"),\n\n\t// Client Configuration\n\tCLIENT_HOST: z.string().url(\"CLIENT_HOST must be a valid URL\"),\n\n\t// Optional\n\tORIGIN: z.string().optional(),\n});\n\nexport type ValidatedEnv = z.infer<typeof envSchema>;\n\nexport const validateEnv = (): ValidatedEnv => {\n\tconst result = envSchema.safeParse(process.env);\n\n\tif (!result.success) {\n\t\tconsole.error(\"Environment validation failed:\");\n\t\tconsole.error(\"\");\n\n\t\tconst errors = result.error.format();\n\t\tfor (const [key, value] of Object.entries(errors)) {\n\t\t\tif (key !== \"_errors\" && value && typeof value === \"object\" && \"_errors\" in value) {\n\t\t\t\tconsole.error(`  ${key}: ${value._errors.join(\", \")}`);\n\t\t\t}\n\t\t}\n\n\t\tconsole.error(\"Please check your .env file and ensure all required variables are set.\");\n\t\tprocess.exit(1);\n\t}\n\n\tconsole.log(\"Environment variables validated successfully\");\n\treturn result.data;\n};\n"
  },
  {
    "path": "server/src/validation/incidentValidation.ts",
    "content": "import { z } from \"zod\";\nimport { booleanCoercion } from \"./shared.js\";\n\n//****************************************\n// Incident Validations\n//****************************************\n\nexport const getIncidentsByTeamQueryValidation = z.object({\n\tsortOrder: z.enum([\"asc\", \"desc\"]),\n\tdateRange: z.enum([\"recent\", \"hour\", \"day\", \"week\", \"month\", \"all\"]),\n\tpage: z.coerce.number().int().min(0),\n\trowsPerPage: z.coerce.number().int().min(1),\n\tstatus: booleanCoercion.optional(),\n\tmonitorId: z.string().optional(),\n\tresolutionType: z.enum([\"manual\", \"automatic\"]).optional(),\n});\n\nexport const getIncidentSummaryQueryValidation = z.object({\n\tlimit: z.coerce.number().int().min(1).optional(),\n});\n"
  },
  {
    "path": "server/src/validation/index.ts",
    "content": "/**\n * Central validation exports\n *\n * This file re-exports all validation schemas from their respective modules.\n * Import from here for convenience: import { loginValidation } from \"@/validation\";\n */\n\n// Shared utilities\nexport * from \"./shared.js\";\n\n// Environment validation\nexport * from \"./envValidation.js\";\n\n// Domain-specific validations\nexport * from \"./authValidation.js\";\nexport * from \"./monitorValidation.js\";\nexport * from \"./checkValidation.js\";\nexport * from \"./maintenanceWindowValidation.js\";\nexport * from \"./settingsValidation.js\";\nexport * from \"./statusPageValidation.js\";\nexport * from \"./notificationValidation.js\";\nexport * from \"./userValidation.js\";\nexport * from \"./incidentValidation.js\";\n"
  },
  {
    "path": "server/src/validation/maintenanceWindowValidation.ts",
    "content": "import { z } from \"zod\";\nimport { booleanCoercion } from \"./shared.js\";\n\nconst dateToString = z.coerce.date().transform((d) => d.toISOString());\n\n//****************************************\n// Maintenance Window Validations\n//****************************************\n\nexport const createMaintenanceWindowBodyValidation = z.object({\n\tmonitors: z.array(z.string()).min(1, \"At least one monitor is required\"),\n\tname: z.string().min(1, \"Name is required\"),\n\tactive: z.boolean().optional(),\n\tduration: z.number().min(1, \"Duration is required\"),\n\tdurationUnit: z.enum([\"seconds\", \"minutes\", \"hours\", \"days\"]),\n\tstart: dateToString,\n\tend: dateToString,\n\trepeat: z.number().min(0, \"Repeat must be a non-negative number\"),\n\texpiry: dateToString.optional(),\n});\n\nexport const getMaintenanceWindowByIdParamValidation = z.object({\n\tid: z.string().min(1, \"ID is required\"),\n});\n\nexport const getMaintenanceWindowsByTeamIdQueryValidation = z.object({\n\tactive: booleanCoercion.optional(),\n\tpage: z.coerce.number().optional(),\n\trowsPerPage: z.coerce.number().optional(),\n\tfield: z.string().optional(),\n\torder: z.enum([\"asc\", \"desc\"]).optional(),\n});\n\nexport const getMaintenanceWindowsByMonitorIdParamValidation = z.object({\n\tmonitorId: z.string().min(1, \"Monitor ID is required\"),\n});\n\nexport const deleteMaintenanceWindowByIdParamValidation = z.object({\n\tid: z.string().min(1, \"ID is required\"),\n});\n\nexport const editMaintenanceWindowByIdParamValidation = z.object({\n\tid: z.string().min(1, \"ID is required\"),\n});\n\nexport const editMaintenanceByIdWindowBodyValidation = z.object({\n\tactive: z.boolean().optional(),\n\tname: z.string().optional(),\n\trepeat: z.number().optional(),\n\tstart: dateToString.optional(),\n\tend: dateToString.optional(),\n\texpiry: dateToString.optional(),\n\tmonitors: z.array(z.string()).optional(),\n\tduration: z.number().optional(),\n\tdurationUnit: z.enum([\"seconds\", \"minutes\", \"hours\", \"days\"]).optional(),\n});\n"
  },
  {
    "path": "server/src/validation/monitorValidation.ts",
    "content": "import { z } from \"zod\";\nimport { booleanCoercion } from \"./shared.js\";\nimport { GeoContinents } from \"@/types/geoCheck.js\";\nimport { MonitorMatchMethods, MonitorTypes } from \"@/types/monitor.js\";\n\nexport const getMonitorByIdParamValidation = z.object({\n\tmonitorId: z.string().min(1, \"Monitor ID is required\"),\n});\n\nexport const getMonitorByIdQueryValidation = z.object({\n\tstatus: booleanCoercion.optional(),\n\tsortOrder: z.enum([\"asc\", \"desc\"]).optional(),\n\tlimit: z.coerce.number().optional(),\n\tdateRange: z.enum([\"recent\", \"hour\", \"day\", \"week\", \"month\", \"all\"]).optional(),\n\tnumToDisplay: z.coerce.number().optional(),\n\tnormalize: booleanCoercion.optional(),\n\tcontinent: z.union([z.enum(GeoContinents), z.array(z.enum(GeoContinents))]).optional(),\n});\n\nexport const getMonitorsByTeamIdParamValidation = z.object({});\n\nexport const getMonitorsByTeamIdQueryValidation = z.object({\n\ttype: z\n\t\t.union([\n\t\t\tz.enum([\"http\", \"ping\", \"pagespeed\", \"docker\", \"hardware\", \"port\", \"game\", \"grpc\", \"websocket\"]),\n\t\t\tz.array(z.enum([\"http\", \"ping\", \"pagespeed\", \"docker\", \"hardware\", \"port\", \"game\", \"grpc\", \"websocket\"])),\n\t\t])\n\t\t.optional(),\n\tfilter: z.union([z.string(), z.literal(\"\")]).optional(),\n});\n\nexport const getMonitorsWithChecksQueryValidation = z.object({\n\tlimit: z.coerce.number().int().min(1).max(100).optional(),\n\tpage: z.coerce.number().int().min(0).optional(),\n\trowsPerPage: z.coerce.number().int().min(1).max(100).optional(),\n\tfilter: z.union([z.string(), z.literal(\"\")]).optional(),\n\tfield: z.string().optional(),\n\torder: z.enum([\"asc\", \"desc\"]).optional(),\n\ttype: z\n\t\t.union([\n\t\t\tz.enum([\"http\", \"ping\", \"pagespeed\", \"docker\", \"hardware\", \"port\", \"game\", \"grpc\", \"websocket\"]),\n\t\t\tz.array(z.enum([\"http\", \"ping\", \"pagespeed\", \"docker\", \"hardware\", \"port\", \"game\", \"grpc\", \"websocket\"])),\n\t\t])\n\t\t.optional(),\n\texplain: booleanCoercion.optional(),\n});\n\nexport const getCertificateParamValidation = z.object({\n\tmonitorId: z.string().min(1, \"Monitor ID is required\"),\n});\n\nexport const createMonitorBodyValidation = z.object({\n\t_id: z.string().optional(),\n\tname: z.string().min(1, \"Name is required\"),\n\tdescription: z.union([z.string(), z.literal(\"\")]).optional(),\n\ttype: z.enum(MonitorTypes, \"Invalid monitor type\"),\n\tstatusWindowSize: z.number().min(1).max(20).default(5),\n\tstatusWindowThreshold: z.number().min(1).max(100).default(60),\n\turl: z.string().min(1, \"URL is required\"),\n\tignoreTlsErrors: z.boolean().default(false),\n\tuseAdvancedMatching: z.boolean().default(false),\n\tport: z.number().optional(),\n\tisActive: z.boolean().optional(),\n\tinterval: z.number().optional(),\n\tcpuAlertThreshold: z.number().optional(),\n\tmemoryAlertThreshold: z.number().optional(),\n\tdiskAlertThreshold: z.number().optional(),\n\ttempAlertThreshold: z.number().optional(),\n\tnotifications: z.array(z.string()).optional(),\n\tsecret: z.string().optional(),\n\tjsonPath: z.union([z.string(), z.literal(\"\")]).optional(),\n\texpectedValue: z.union([z.string(), z.literal(\"\")]).optional(),\n\tmatchMethod: z.union([z.enum(MonitorMatchMethods), z.literal(\"\")]).optional(),\n\tgameId: z.union([z.string(), z.literal(\"\")]).optional(),\n\tgrpcServiceName: z.union([z.string(), z.literal(\"\")]).default(\"\"),\n\tselectedDisks: z.array(z.string()).optional(),\n\tgroup: z.union([z.string().max(50).trim(), z.null(), z.literal(\"\")]).optional(),\n\tgeoCheckEnabled: z.boolean().optional(),\n\tgeoCheckLocations: z.array(z.enum(GeoContinents)).optional(),\n\tgeoCheckInterval: z.number().min(300000).optional(),\n});\n\nexport const editMonitorBodyValidation = z.object({\n\tname: z.string().optional(),\n\ttype: z.enum(MonitorTypes).optional(),\n\turl: z.string().optional(),\n\tstatusWindowSize: z.number().min(1).max(20).default(5),\n\tstatusWindowThreshold: z.number().min(1).max(100).default(60),\n\tdescription: z.union([z.string(), z.literal(\"\")]).optional(),\n\tinterval: z.number().optional(),\n\tnotifications: z.array(z.string()).optional(),\n\tsecret: z.string().optional(),\n\tignoreTlsErrors: z.boolean().optional(),\n\tuseAdvancedMatching: z.boolean().optional(),\n\tjsonPath: z.union([z.string(), z.literal(\"\")]).optional(),\n\texpectedValue: z.union([z.string(), z.literal(\"\")]).optional(),\n\tmatchMethod: z.union([z.enum(MonitorMatchMethods), z.literal(\"\")]).optional(),\n\tport: z.number().min(1).max(65535).optional(),\n\tcpuAlertThreshold: z.number().optional(),\n\tmemoryAlertThreshold: z.number().optional(),\n\tdiskAlertThreshold: z.number().optional(),\n\ttempAlertThreshold: z.number().optional(),\n\tgameId: z.union([z.string(), z.literal(\"\")]).optional(),\n\tgrpcServiceName: z.union([z.string(), z.literal(\"\")]).optional(),\n\tselectedDisks: z.array(z.string()).optional(),\n\tgroup: z.union([z.string().max(50).trim(), z.null(), z.literal(\"\")]).optional(),\n\tgeoCheckEnabled: z.boolean().optional(),\n\tgeoCheckLocations: z.array(z.enum(GeoContinents)).optional(),\n\tgeoCheckInterval: z.number().min(300000).optional(),\n});\n\nexport const pauseMonitorParamValidation = z.object({\n\tmonitorId: z.string().min(1, \"Monitor ID is required\"),\n});\n\nexport const getUptimeDetailsByIdParamValidation = z.object({\n\tmonitorId: z.string().min(1, \"Monitor ID is required\"),\n});\n\nexport const getUptimeDetailsByIdQueryValidation = z.object({\n\tdateRange: z.enum([\"recent\", \"hour\", \"day\", \"week\", \"month\", \"all\"]),\n\tnormalize: booleanCoercion.optional(),\n});\n\nconst importedMonitorSchema = z.object({\n\tid: z.string().optional(),\n\tuserId: z.string().optional(),\n\tteamId: z.string().optional(),\n\tname: z.string().min(1, \"Name is required\"),\n\tdescription: z.union([z.string(), z.literal(\"\")]).optional(),\n\tstatus: z.enum([\"up\", \"down\", \"paused\", \"initializing\", \"maintenance\", \"breached\"]).default(\"initializing\"),\n\tstatusWindow: z.array(z.boolean()).default([]),\n\tstatusWindowSize: z.number().min(1).max(20).default(5),\n\tstatusWindowThreshold: z.number().min(1).max(100).default(60),\n\ttype: z.enum(MonitorTypes, \"Invalid monitor type\"),\n\tignoreTlsErrors: z.boolean().default(false),\n\tuseAdvancedMatching: z.boolean().default(false),\n\tjsonPath: z.union([z.string(), z.literal(\"\")]).optional(),\n\texpectedValue: z.union([z.string(), z.literal(\"\")]).optional(),\n\tmatchMethod: z.union([z.enum(MonitorMatchMethods), z.literal(\"\")]).optional(),\n\turl: z.string().min(1, \"URL is required\"),\n\tport: z.number().optional(),\n\tisActive: z.boolean().default(true),\n\tinterval: z.number().default(60000),\n\tuptimePercentage: z.number().optional(),\n\tnotifications: z.array(z.string()).default([]),\n\tsecret: z.string().optional(),\n\tcpuAlertThreshold: z.number().default(100),\n\tcpuAlertCounter: z.number().default(5),\n\tmemoryAlertThreshold: z.number().default(100),\n\tmemoryAlertCounter: z.number().default(5),\n\tdiskAlertThreshold: z.number().default(100),\n\tdiskAlertCounter: z.number().default(5),\n\ttempAlertThreshold: z.number().default(100),\n\ttempAlertCounter: z.number().default(5),\n\tselectedDisks: z.array(z.string()).default([]),\n\tgameId: z.union([z.string(), z.literal(\"\")]).optional(),\n\tgrpcServiceName: z.union([z.string(), z.literal(\"\")]).default(\"\"),\n\tgroup: z.union([z.string().max(50).trim(), z.null()]).default(null),\n\tgeoCheckEnabled: z.boolean().default(false),\n\tgeoCheckLocations: z.array(z.enum(GeoContinents)).default([]),\n\tgeoCheckInterval: z.number().min(300000).default(300000),\n\tcreatedAt: z.string().optional(),\n\tupdatedAt: z.string().optional(),\n});\n\nexport const importMonitorsBodyValidation = z.object({\n\tmonitors: z.array(importedMonitorSchema).min(1, \"At least one monitor is required\"),\n});\n\nexport type ImportedMonitor = z.output<typeof importedMonitorSchema>;\n\nexport const getHardwareDetailsByIdParamValidation = z.object({\n\tmonitorId: z.string().min(1, \"Monitor ID is required\"),\n});\n\nexport const getHardwareDetailsByIdQueryValidation = z.object({\n\tdateRange: z.enum([\"recent\", \"hour\", \"day\", \"week\", \"month\", \"all\"]).optional(),\n});\n"
  },
  {
    "path": "server/src/validation/notificationValidation.ts",
    "content": "import { z } from \"zod\";\n\n//****************************************\n// Notification Validations\n//****************************************\n\nexport const createNotificationBodyValidation = z.discriminatedUnion(\"type\", [\n\t// Email notification\n\tz.object({\n\t\tnotificationName: z.string().min(1, \"Notification name is required\"),\n\t\ttype: z.literal(\"email\"),\n\t\taddress: z.email(\"Please enter a valid e-mail address\"),\n\t\thomeserverUrl: z.union([z.string(), z.literal(\"\")]).optional(),\n\t\troomId: z.union([z.string(), z.literal(\"\")]).optional(),\n\t\taccessToken: z.union([z.string(), z.literal(\"\")]).optional(),\n\t}),\n\t// Webhook notification\n\tz.object({\n\t\tnotificationName: z.string().min(1, \"Notification name is required\"),\n\t\ttype: z.literal(\"webhook\"),\n\t\taddress: z.url({ message: \"Please enter a valid Webhook URL\" }),\n\t\thomeserverUrl: z.union([z.string(), z.literal(\"\")]).optional(),\n\t\troomId: z.union([z.string(), z.literal(\"\")]).optional(),\n\t\taccessToken: z.union([z.string(), z.literal(\"\")]).optional(),\n\t}),\n\t// Slack notification\n\tz.object({\n\t\tnotificationName: z.string().min(1, \"Notification name is required\"),\n\t\ttype: z.literal(\"slack\"),\n\t\taddress: z.url({ message: \"Please enter a valid Webhook URL\" }),\n\t\thomeserverUrl: z.union([z.string(), z.literal(\"\")]).optional(),\n\t\troomId: z.union([z.string(), z.literal(\"\")]).optional(),\n\t\taccessToken: z.union([z.string(), z.literal(\"\")]).optional(),\n\t}),\n\t// Discord notification\n\tz.object({\n\t\tnotificationName: z.string().min(1, \"Notification name is required\"),\n\t\ttype: z.literal(\"discord\"),\n\t\taddress: z.url({ message: \"Please enter a valid Webhook URL\" }),\n\t\thomeserverUrl: z.union([z.string(), z.literal(\"\")]).optional(),\n\t\troomId: z.union([z.string(), z.literal(\"\")]).optional(),\n\t\taccessToken: z.union([z.string(), z.literal(\"\")]).optional(),\n\t}),\n\t// PagerDuty notification\n\tz.object({\n\t\tnotificationName: z.string().min(1, \"Notification name is required\"),\n\t\ttype: z.literal(\"pager_duty\"),\n\t\taddress: z.string().min(1, \"PagerDuty integration key is required\"),\n\t\thomeserverUrl: z.union([z.string(), z.literal(\"\")]).optional(),\n\t\troomId: z.union([z.string(), z.literal(\"\")]).optional(),\n\t\taccessToken: z.union([z.string(), z.literal(\"\")]).optional(),\n\t}),\n\t// Matrix notification\n\tz.object({\n\t\tnotificationName: z.string().min(1, \"Notification name is required\"),\n\t\ttype: z.literal(\"matrix\"),\n\t\taddress: z.union([z.string(), z.literal(\"\")]).optional(),\n\t\thomeserverUrl: z.url({ message: \"Please enter a valid Homeserver URL\" }),\n\t\troomId: z.string().min(1, \"Room ID is required\"),\n\t\taccessToken: z.string().min(1, \"Access Token is required\"),\n\t}),\n\t// Teams notification\n\tz.object({\n\t\tnotificationName: z.string().min(1, \"Notification name is required\"),\n\t\ttype: z.literal(\"teams\"),\n\t\taddress: z.url({ message: \"Please enter a valid Webhook URL\" }),\n\t}),\n]);\n\nexport const testNotificationBodyValidation = createNotificationBodyValidation;\n\nexport const deleteNotificationParamValidation = z.object({\n\tid: z.string().min(1, \"Notification ID is required\"),\n});\nexport const getNotificationByIdParamValidation = z.object({\n\tid: z.string().min(1, \"Notification ID is required\"),\n});\nexport const editNotificationParamValidation = z.object({\n\tid: z.string().min(1, \"Notification ID is required\"),\n});\n\nexport const testAllNotificationsBodyValidation = z.object({\n\tmonitorId: z.string().min(1, \"Monitor ID is required\"),\n});\n\nexport const sendTestEmailBodyValidation = z.object({\n\tto: z.string().min(1, \"To field is required\"),\n\tsystemEmailHost: z.string().optional(),\n\tsystemEmailPort: z.number().optional(),\n\tsystemEmailSecure: z.boolean().optional(),\n\tsystemEmailPool: z.boolean().optional(),\n\tsystemEmailAddress: z.string().optional(),\n\tsystemEmailPassword: z.string().optional(),\n\tsystemEmailUser: z.string().optional(),\n\tsystemEmailConnectionHost: z.union([z.string(), z.literal(\"\")]).optional(),\n\tsystemEmailIgnoreTLS: z.boolean().optional(),\n\tsystemEmailRequireTLS: z.boolean().optional(),\n\tsystemEmailRejectUnauthorized: z.boolean().optional(),\n\tsystemEmailTLSServername: z.union([z.string(), z.literal(\"\")]).optional(),\n});\n"
  },
  {
    "path": "server/src/validation/settingsValidation.ts",
    "content": "import { CHECK_TTL_SENTINEL } from \"@/types/check.js\";\nimport { z } from \"zod\";\n\n//****************************************\n// Settings Validations\n//****************************************\n\nexport const updateAppSettingsBodyValidation = z\n\t.object({\n\t\tcheckTTL: z.number().int().min(1).max(CHECK_TTL_SENTINEL).optional(),\n\t\tsystemEmailPort: z.number().nullable().optional(),\n\t\tpagespeedApiKey: z.string().nullable().optional(),\n\t\tlanguage: z.string().optional(),\n\t\ttimezone: z.string().optional(),\n\t\tsystemEmailHost: z.string().nullable().optional(),\n\t\tsystemEmailAddress: z.string().nullable().optional(),\n\t\tsystemEmailPassword: z.string().nullable().optional(),\n\t\tsystemEmailUser: z.string().nullable().optional(),\n\t\tsystemEmailConnectionHost: z.string().nullable().optional(),\n\t\tsystemEmailTLSServername: z.string().nullable().optional(),\n\n\t\tshowURL: z.boolean().optional(),\n\t\tsystemEmailSecure: z.boolean().optional(),\n\t\tsystemEmailPool: z.boolean().optional(),\n\t\tsystemEmailIgnoreTLS: z.boolean().optional(),\n\t\tsystemEmailRequireTLS: z.boolean().optional(),\n\t\tsystemEmailRejectUnauthorized: z.boolean().optional(),\n\n\t\tglobalThresholds: z\n\t\t\t.object({\n\t\t\t\tcpu: z.number().min(1).max(100).optional(),\n\t\t\t\tmemory: z.number().min(1).max(100).optional(),\n\t\t\t\tdisk: z.number().min(1).max(100).optional(),\n\t\t\t\ttemperature: z.number().min(1).max(150).optional(),\n\t\t\t})\n\t\t\t.optional(),\n\t})\n\t.strip();\n"
  },
  {
    "path": "server/src/validation/shared.ts",
    "content": "import { z } from \"zod\";\nimport { type UserRole } from \"@/types/user.js\";\n\nexport const passwordPattern =\n\t/^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!?@#$%^&*()\\-_=+[\\]{};:'\",.~`|\\\\/])[A-Za-z0-9!?@#$%^&*()\\-_=+[\\]{};:'\",.~`|\\\\/]+$/;\n\nexport const nameValidation = z\n\t.string()\n\t.trim()\n\t.max(50, \"Name must be less than 50 characters\")\n\t.regex(\n\t\t/^(?=.*[\\p{L}\\p{Sc}])[\\p{L}\\p{Sc}\\s'\\-().]+$/u,\n\t\t\"Names must contain at least 1 letter and may only include letters, currency symbols, spaces, apostrophes, hyphens (-), periods (.), and parentheses ().\"\n\t);\n\nexport const lowercaseEmailValidation = z.email().transform((val) => val.toLowerCase());\n\nexport const booleanCoercion = z.preprocess((val) => {\n\tif (val === \"true\" || val === true) return true;\n\tif (val === \"false\" || val === false) return false;\n\treturn val; // Let Zod validation handle invalid values\n}, z.boolean());\n\nexport const roleValidator = (allowedRoles: UserRole[]) => {\n\treturn z.array(z.custom<UserRole>()).refine((userRoles) => allowedRoles.some((role) => userRoles.includes(role)), {\n\t\tmessage: `You do not have the required authorization. Required roles: ${allowedRoles.join(\", \")}`,\n\t});\n};\n"
  },
  {
    "path": "server/src/validation/statusPageValidation.ts",
    "content": "import { z } from \"zod\";\nimport { booleanCoercion } from \"./shared.js\";\nimport { StatusPageTypes } from \"@/types/statusPage.js\";\n\n//****************************************\n// Status Page Validations\n//****************************************\n\nexport const getStatusPageParamValidation = z.object({\n\turl: z.string().min(1, \"URL is required\"),\n});\n\nexport const getStatusPageQueryValidation = z.object({\n\ttype: z.union([z.enum(StatusPageTypes), z.array(z.enum(StatusPageTypes))]).transform((val) => (Array.isArray(val) ? val : [val])),\n\ttimeFrame: z.coerce.number().optional(),\n});\n\nexport const createStatusPageBodyValidation = z\n\t.object({\n\t\ttype: z.union([z.enum(StatusPageTypes), z.array(z.enum(StatusPageTypes))]).transform((val) => (Array.isArray(val) ? val : [val])),\n\t\tcompanyName: z.string().min(1, \"Company name is required\"),\n\t\turl: z.string().regex(/^[a-zA-Z0-9_-]+$/, {\n\t\t\tmessage: \"URL can only contain letters, numbers, underscores, and hyphens\",\n\t\t}),\n\t\ttimezone: z.string().optional(),\n\t\tcolor: z.string().optional(),\n\t\tmonitors: z.array(z.string().regex(/^[0-9a-fA-F]{24}$/, \"Must be a valid monitor ID\")).min(1, \"At least one monitor is required\"),\n\t\tsubMonitors: z.array(z.string().regex(/^[0-9a-fA-F]{24}$/)).optional(),\n\t\tdeleteSubmonitors: z.boolean().optional(),\n\t\tisPublished: booleanCoercion,\n\t\tshowCharts: booleanCoercion.optional(),\n\t\tshowUptimePercentage: booleanCoercion,\n\t\tshowAdminLoginLink: booleanCoercion.optional(),\n\t\tshowInfrastructure: booleanCoercion.optional(),\n\t\tremoveLogo: z.union([z.literal(\"true\"), z.literal(\"false\")]).optional(),\n\t})\n\t.strip();\n\nexport const imageValidation = z\n\t.object({\n\t\tfieldname: z.string().min(1, \"Field name is required\"),\n\t\toriginalname: z.string().min(1, \"Original name is required\"),\n\t\tencoding: z.string().min(1, \"Encoding is required\"),\n\t\tmimetype: z.enum([\"image/jpeg\", \"image/png\", \"image/jpg\"], {\n\t\t\tmessage: \"File must be a valid image (jpeg, jpg, or png)\",\n\t\t}),\n\t\tsize: z.number().max(3145728, \"File size must be less than 3MB\"),\n\t\tbuffer: z.instanceof(Buffer, { message: \"Buffer is required\" }),\n\t\tdestination: z.string().optional(),\n\t\tfilename: z.string().optional(),\n\t\tpath: z.string().optional(),\n\t})\n\t.refine((data) => data.buffer, {\n\t\tmessage: \"Image file is required\",\n\t});\n"
  },
  {
    "path": "server/src/validation/userValidation.ts",
    "content": "import { z } from \"zod\";\nimport { UserRoles } from \"@/types/user.js\";\nimport { nameValidation, lowercaseEmailValidation, passwordPattern } from \"./shared.js\";\n\n//****************************************\n// User Validations\n//****************************************\n\nexport const getUserByIdParamValidation = z.object({\n\tuserId: z.string().min(1, \"User ID is required\"),\n});\n\nexport const editUserByIdParamValidation = z.object({\n\tuserId: z.string().min(1, \"User ID is required\"),\n});\n\nexport const editUserByIdBodyValidation = z.object({\n\tfirstName: nameValidation,\n\tlastName: nameValidation,\n\trole: z.array(z.enum(UserRoles)).min(1, \"At least one role is required\"),\n});\n\nexport const editSuperadminUserByIdBodyValidation = z.object({\n\tfirstName: nameValidation,\n\tlastName: nameValidation,\n\trole: z.array(z.enum(UserRoles)).min(1, \"At least one role is required\"),\n});\n\nexport const editUserPasswordByIdBodyValidation = z.object({\n\tpassword: z\n\t\t.string()\n\t\t.min(8, \"Password must be at least 8 characters\")\n\t\t.regex(passwordPattern, \"Password must contain at least one lowercase letter, one uppercase letter, one number, and one special character\"),\n});\n\nexport const createUserBodyValidation = z.object({\n\tfirstName: nameValidation,\n\tlastName: nameValidation,\n\temail: lowercaseEmailValidation,\n\tpassword: z\n\t\t.string()\n\t\t.min(8, \"Password must be at least 8 characters\")\n\t\t.regex(passwordPattern, \"Password must contain at least one lowercase letter, one uppercase letter, one number, and one special character\"),\n\trole: z.array(z.enum(UserRoles)).min(1, \"At least one role is required\"),\n});\n\nexport const editUserBodyValidation = z.object({\n\tfirstName: nameValidation.optional(),\n\tlastName: nameValidation.optional(),\n\temail: lowercaseEmailValidation.optional(),\n\tprofilePicture: z.string().optional(),\n});\n"
  },
  {
    "path": "server/test/monitorService.test.ts",
    "content": "import { jest } from \"@jest/globals\";\nimport { MonitorService } from \"../src/service/business/monitorService.ts\";\nimport type { IChecksRepository, IMonitorStatsRepository, IMonitorsRepository, IStatusPagesRepository } from \"../src/repositories/index.ts\";\n\nconst createMonitorsRepositoryMock = () =>\n\t({\n\t\tfindMonitorCountByTeamIdAndType: jest.fn(),\n\t\tfindByTeamId: jest.fn(),\n\t\tfindById: jest.fn(),\n\t\tfindMonitorsSummaryByTeamId: jest.fn(),\n\t\tfindGroupsByTeamId: jest.fn(),\n\t\tcreate: jest.fn(),\n\t\tcreateBulkMonitors: jest.fn(),\n\t\tdeleteByTeamId: jest.fn(),\n\t}) as unknown as IMonitorsRepository;\n\nconst createChecksRepositoryMock = () =>\n\t({\n\t\tfindLatestChecksByMonitorIds: jest.fn(),\n\t\tfindDateRangeChecksByMonitor: jest.fn(),\n\t}) as unknown as IChecksRepository;\n\nconst createMonitorStatsRepositoryMock = () =>\n\t({\n\t\tfindByMonitorId: jest.fn(),\n\t\tdeleteByMonitorId: jest.fn(),\n\t}) as unknown as IMonitorStatsRepository;\n\nconst createStatusPagesRepositoryMock = () =>\n\t({\n\t\tremoveMonitorFromStatusPages: jest.fn(),\n\t}) as unknown as IStatusPagesRepository;\n\nconst createService = ({\n\tmonitorsRepository = createMonitorsRepositoryMock(),\n\tchecksRepository = createChecksRepositoryMock(),\n\tmonitorStatsRepository = createMonitorStatsRepositoryMock(),\n\tstatusPagesRepository = createStatusPagesRepositoryMock(),\n}: {\n\tmonitorsRepository?: IMonitorsRepository;\n\tchecksRepository?: IChecksRepository;\n\tmonitorStatsRepository?: IMonitorStatsRepository;\n\tstatusPagesRepository?: IStatusPagesRepository;\n} = {}) => {\n\treturn new MonitorService({\n\t\tdb: {\n\t\t\tcheckModule: { deleteChecks: jest.fn() },\n\t\t\tstatusPageModule: { deleteStatusPagesByMonitorId: jest.fn() },\n\t\t\tpageSpeedCheckModule: { deletePageSpeedChecksByMonitorId: jest.fn() },\n\t\t\tnotificationModule: { deleteNotificationsByMonitorId: jest.fn() },\n\t\t},\n\t\tjobQueue: {\n\t\t\taddJob: jest.fn(),\n\t\t\tupdateJob: jest.fn(),\n\t\t\tresumeJob: jest.fn(),\n\t\t\tpauseJob: jest.fn(),\n\t\t\tdeleteJob: jest.fn(),\n\t\t},\n\t\tstringService: {},\n\t\temailService: { buildEmail: jest.fn(), sendEmail: jest.fn() },\n\t\tpapaparse: { parse: jest.fn(), unparse: jest.fn() },\n\t\tlogger: { info: jest.fn(), error: jest.fn(), warn: jest.fn() },\n\t\terrorService: {\n\t\t\tcreateAuthorizationError: jest.fn(() => new Error(\"unauthorized\")),\n\t\t\tcreateServerError: jest.fn(() => new Error(\"server\")),\n\t\t\tcreateBadRequestError: jest.fn(() => new Error(\"bad request\")),\n\t\t\tcreateNotFoundError: jest.fn(() => new Error(\"not found\")),\n\t\t},\n\t\tgames: [],\n\t\tmonitorsRepository,\n\t\tchecksRepository,\n\t\tmonitorStatsRepository,\n\t\tstatusPagesRepository,\n\t});\n};\n\ndescribe(\"MonitorService\", () => {\n\tdescribe(\"getMonitorsWithChecksByTeamId\", () => {\n\t\tit(\"returns monitors enriched with normalized checks\", async () => {\n\t\t\tconst monitorsRepository = createMonitorsRepositoryMock();\n\t\t\t(monitorsRepository.findMonitorCountByTeamIdAndType as jest.Mock).mockResolvedValue(2);\n\t\t\t(monitorsRepository.findByTeamId as jest.Mock).mockResolvedValue([\n\t\t\t\t{ id: \"m1\", name: \"Monitor 1\", interval: 60000 },\n\t\t\t\t{ id: \"m2\", name: \"Monitor 2\", interval: 60000 },\n\t\t\t]);\n\n\t\t\tconst checksRepository = createChecksRepositoryMock();\n\t\t\t(checksRepository.findLatestChecksByMonitorIds as jest.Mock).mockResolvedValue({\n\t\t\t\tm1: [\n\t\t\t\t\t{ responseTime: 10, status: true, message: \"OK\" },\n\t\t\t\t\t{ responseTime: 20, status: true, message: \"OK\" },\n\t\t\t\t],\n\t\t\t\tm2: [{ responseTime: 50, status: true, message: \"OK\" }],\n\t\t\t});\n\n\t\t\tconst service = createService({ monitorsRepository, checksRepository });\n\t\t\tconst result = await service.getMonitorsWithChecksByTeamId({ teamId: \"team\" });\n\n\t\t\texpect(result).toMatchObject({ count: 2 });\n\t\t\texpect(result.monitors).toHaveLength(2);\n\t\t\texpect(result.monitors[0]).toHaveProperty(\"checks\");\n\t\t\texpect(result.monitors[0].checks.length).toBeGreaterThan(0);\n\t\t\texpect(result.monitors[0].checks[0]).toEqual(\n\t\t\t\texpect.objectContaining({\n\t\t\t\t\tresponseTime: expect.any(Number),\n\t\t\t\t\tstatus: expect.any(Boolean),\n\t\t\t\t\tmessage: expect.any(String),\n\t\t\t\t})\n\t\t\t);\n\t\t});\n\t});\n\n\tdescribe(\"getMonitorsByTeamId\", () => {\n\t\tit(\"returns monitors array from repository\", async () => {\n\t\t\tconst monitorsRepository = createMonitorsRepositoryMock();\n\t\t\t(monitorsRepository.findByTeamId as jest.Mock).mockResolvedValue([\n\t\t\t\t{ id: \"m1\", name: \"Monitor 1\" },\n\t\t\t\t{ id: \"m2\", name: \"Monitor 2\" },\n\t\t\t]);\n\t\t\tconst service = createService({ monitorsRepository });\n\t\t\tconst result = await service.getMonitorsByTeamId({ teamId: \"team\" } as any);\n\t\t\texpect(result).toHaveLength(2);\n\t\t\texpect(result[0]).toHaveProperty(\"id\", \"m1\");\n\t\t});\n\t});\n\n\tdescribe(\"getMonitorsWithChecksByTeamId summary\", () => {\n\t\tit(\"includes summary and monitors with checks\", async () => {\n\t\t\tconst monitorsRepository = createMonitorsRepositoryMock();\n\t\t\t(monitorsRepository.findMonitorCountByTeamIdAndType as jest.Mock).mockResolvedValue(1);\n\t\t\t(monitorsRepository.findByTeamId as jest.Mock).mockResolvedValue([{ id: \"m1\", type: \"http\" }]);\n\t\t\t(monitorsRepository.findMonitorsSummaryByTeamId as jest.Mock).mockResolvedValue({\n\t\t\t\ttotalMonitors: 1,\n\t\t\t\tupMonitors: 1,\n\t\t\t\tdownMonitors: 0,\n\t\t\t\tpausedMonitors: 0,\n\t\t\t});\n\n\t\t\tconst checksRepository = createChecksRepositoryMock();\n\t\t\t(checksRepository.findLatestChecksByMonitorIds as jest.Mock).mockResolvedValue({ m1: [] });\n\n\t\t\tconst service = createService({ monitorsRepository, checksRepository });\n\t\t\tconst result = await service.getMonitorsWithChecksByTeamId({ teamId: \"team\" });\n\t\t\texpect(result).toEqual({\n\t\t\t\tsummary: { totalMonitors: 1, upMonitors: 1, downMonitors: 0, pausedMonitors: 0 },\n\t\t\t\tcount: 1,\n\t\t\t\tmonitors: [{ id: \"m1\", type: \"http\", checks: [] }],\n\t\t\t});\n\t\t});\n\t});\n\n\tdescribe(\"getUptimeDetailsById\", () => {\n\t\tit(\"returns monitorData and monitorStats with expected shape\", async () => {\n\t\t\tconst TEAM_ID = \"team\";\n\t\t\tconst monitor = {\n\t\t\t\tid: \"monitor-1\",\n\t\t\t\tteamId: TEAM_ID,\n\t\t\t\tname: \"Hardware monitor\",\n\t\t\t\tinterval: 60000,\n\t\t\t\tstatusWindow: [],\n\t\t\t\tstatusWindowSize: 5,\n\t\t\t\tstatusWindowThreshold: 60,\n\t\t\t\ttype: \"http\",\n\t\t\t\tignoreTlsErrors: false,\n\t\t\t\turl: \"https://example.com\",\n\t\t\t\tisActive: true,\n\t\t\t\talertThreshold: 5,\n\t\t\t\tcpuAlertThreshold: 5,\n\t\t\t\tmemoryAlertThreshold: 5,\n\t\t\t\tdiskAlertThreshold: 5,\n\t\t\t\ttempAlertThreshold: 5,\n\t\t\t\tselectedDisks: [],\n\t\t\t\tnotifications: [],\n\t\t\t\tgroup: null,\n\t\t\t\tcreatedAt: new Date().toISOString(),\n\t\t\t\tupdatedAt: new Date().toISOString(),\n\t\t\t};\n\n\t\t\tconst monitorsRepository = createMonitorsRepositoryMock();\n\t\t\t(monitorsRepository.findById as jest.Mock).mockResolvedValue(monitor);\n\t\t\tconst checksRepository = createChecksRepositoryMock();\n\t\t\t(checksRepository.findDateRangeChecksByMonitor as jest.Mock).mockResolvedValue({\n\t\t\t\tmonitorType: \"http\",\n\t\t\t\tgroupedChecks: [{ _id: \"2024-01-01\", avgResponseTime: 100, totalChecks: 2 }],\n\t\t\t\tgroupedUpChecks: [{ _id: \"2024-01-01\", totalChecks: 2, avgResponseTime: 90 }],\n\t\t\t\tgroupedDownChecks: [{ _id: \"2024-01-01\", totalChecks: 0, avgResponseTime: 0 }],\n\t\t\t\tuptimePercentage: 0.99,\n\t\t\t\tavgResponseTime: 95,\n\t\t\t});\n\n\t\t\tconst monitorStatsRepository = createMonitorStatsRepositoryMock();\n\t\t\t(monitorStatsRepository.findByMonitorId as jest.Mock).mockResolvedValue({\n\t\t\t\tid: \"stats-1\",\n\t\t\t\tmonitorId: monitor.id,\n\t\t\t\tavgResponseTime: 90,\n\t\t\t\ttotalChecks: 10,\n\t\t\t\ttotalUpChecks: 9,\n\t\t\t\ttotalDownChecks: 1,\n\t\t\t\tuptimePercentage: 0.9,\n\t\t\t\tlastCheckTimestamp: 123456789,\n\t\t\t\tlastResponseTime: 80,\n\t\t\t\ttimeOfLastFailure: 123456700,\n\t\t\t\tcreatedAt: new Date().toISOString(),\n\t\t\t\tupdatedAt: new Date().toISOString(),\n\t\t\t});\n\n\t\t\tconst service = createService({ monitorsRepository, checksRepository, monitorStatsRepository });\n\t\t\tconst result = await service.getUptimeDetailsById({ teamId: TEAM_ID, monitorId: \"monitor-1\", dateRange: \"recent\" });\n\n\t\t\texpect(result).toHaveProperty(\"monitorData\");\n\t\t\texpect(result.monitorData.monitor).toMatchObject({ id: monitor.id, name: monitor.name });\n\t\t\texpect(result.monitorData.groupedChecks[0]).toEqual(\n\t\t\t\texpect.objectContaining({\n\t\t\t\t\t_id: expect.any(String),\n\t\t\t\t\tavgResponseTime: expect.any(Number),\n\t\t\t\t\ttotalChecks: expect.any(Number),\n\t\t\t\t})\n\t\t\t);\n\t\t\texpect(result.monitorStats).toEqual(\n\t\t\t\texpect.objectContaining({\n\t\t\t\t\tmonitorId: monitor.id,\n\t\t\t\t\tavgResponseTime: 90,\n\t\t\t\t\ttotalChecks: 10,\n\t\t\t\t\ttotalUpChecks: 9,\n\t\t\t\t\ttotalDownChecks: 1,\n\t\t\t\t})\n\t\t\t);\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "server/test/superSimpleQueueHelper.test.ts",
    "content": "import { describe, expect, it, jest } from \"@jest/globals\";\nimport SuperSimpleQueueHelper from \"../src/service/infrastructure/SuperSimpleQueue/SuperSimpleQueueHelper.ts\";\nimport type { Monitor } from \"../src/types/monitor.ts\";\n\nconst createLogger = () => ({ info: jest.fn(), error: jest.fn(), warn: jest.fn(), debug: jest.fn() });\n\nconst createHelper = (overrides?: Partial<ConstructorParameters<typeof SuperSimpleQueueHelper>[0]>) => {\n\tconst maintenanceWindowsRepository = {\n\t\tfindByMonitorId: jest.fn().mockResolvedValue([]),\n\t};\n\tconst statusServiceMock = {\n\t\tupdateMonitorStatus: jest.fn().mockResolvedValue({ monitor: { id: \"m1\" }, statusChanged: true, prevStatus: false }),\n\t};\n\tconst helper = new SuperSimpleQueueHelper({\n\t\tlogger: createLogger(),\n\t\tnetworkService: { requestStatus: jest.fn() },\n\t\tstatusService: statusServiceMock,\n\t\tnotificationsService: { handleNotifications: jest.fn().mockResolvedValue(undefined) },\n\t\tcheckService: { buildCheck: jest.fn().mockResolvedValue({}) },\n\t\tbuffer: { addToBuffer: jest.fn() },\n\t\tincidentService: { handleIncident: jest.fn().mockResolvedValue(undefined) },\n\t\tmaintenanceWindowsRepository,\n\t\t...overrides,\n\t});\n\treturn { helper, maintenanceWindowsRepository };\n};\n\ndescribe(\"SuperSimpleQueueHelper\", () => {\n\tdescribe(\"getMonitorJob\", () => {\n\t\tit(\"skips execution when monitor is in maintenance window\", async () => {\n\t\t\tconst { helper } = createHelper();\n\t\t\tconst spy = jest.spyOn(helper, \"isInMaintenanceWindow\").mockResolvedValue(true);\n\t\t\tconst job = helper.getMonitorJob();\n\t\t\tawait job({ id: \"m1\", teamId: \"team\", interval: 60000 } as Monitor);\n\t\t\texpect(helper[\"networkService\"].requestStatus).not.toHaveBeenCalled();\n\t\t\texpect(helper[\"logger\"].debug).toHaveBeenCalledWith(\n\t\t\t\texpect.objectContaining({ message: expect.stringContaining(\"Monitor m1 is in maintenance window\") })\n\t\t\t);\n\t\t\tspy.mockRestore();\n\t\t});\n\n\t\tit(\"processes monitor status and notifications when active\", async () => {\n\t\t\tconst networkResponse = { monitor: { id: \"m1\" }, status: true };\n\t\t\tconst updatedMonitor = { id: \"m1\", status: true };\n\t\t\tconst { helper } = createHelper({\n\t\t\t\tnetworkService: { requestStatus: jest.fn().mockResolvedValue(networkResponse) },\n\t\t\t\tstatusService: {\n\t\t\t\t\tupdateMonitorStatus: jest.fn().mockResolvedValue({ monitor: updatedMonitor, statusChanged: true, prevStatus: false, code: 200 }),\n\t\t\t\t},\n\t\t\t\tnotificationsService: { handleNotifications: jest.fn().mockResolvedValue(undefined) },\n\t\t\t});\n\t\t\tjest.spyOn(helper, \"isInMaintenanceWindow\").mockResolvedValue(false);\n\t\t\tconst job = helper.getMonitorJob();\n\t\t\tconst monitor = { id: \"m1\", teamId: \"team\" } as Monitor;\n\t\t\tawait job(monitor);\n\t\t\texpect(helper[\"networkService\"].requestStatus).toHaveBeenCalledWith(monitor);\n\t\t});\n\n\t\tit(\"throws when monitor id is missing\", async () => {\n\t\t\tconst { helper } = createHelper();\n\t\t\tconst job = helper.getMonitorJob();\n\t\t\tawait expect(job({} as Monitor)).rejects.toThrow(\"No monitor id\");\n\t\t\texpect(helper[\"logger\"].warn).toHaveBeenCalled();\n\t\t});\n\t});\n\n\tdescribe(\"isInMaintenanceWindow\", () => {\n\t\tit(\"returns true when an active window spans now\", async () => {\n\t\t\tconst now = new Date();\n\t\t\tconst { helper, maintenanceWindowsRepository } = createHelper();\n\t\t\tmaintenanceWindowsRepository.findByMonitorId.mockResolvedValue([\n\t\t\t\t{\n\t\t\t\t\tactive: true,\n\t\t\t\t\tstart: new Date(now.getTime() - 1000).toISOString(),\n\t\t\t\t\tend: new Date(now.getTime() + 1000).toISOString(),\n\t\t\t\t\trepeat: 0,\n\t\t\t\t},\n\t\t\t]);\n\t\t\tawait expect(helper.isInMaintenanceWindow(\"m1\", \"team\")).resolves.toBe(true);\n\t\t});\n\n\t\tit(\"returns true when repeat interval advances window into current time\", async () => {\n\t\t\tconst now = Date.now();\n\t\t\tconst { helper, maintenanceWindowsRepository } = createHelper();\n\t\t\tmaintenanceWindowsRepository.findByMonitorId.mockResolvedValue([\n\t\t\t\t{\n\t\t\t\t\tactive: true,\n\t\t\t\t\tstart: new Date(now - 7200000).toISOString(),\n\t\t\t\t\tend: new Date(now - 6600000).toISOString(),\n\t\t\t\t\trepeat: 3600000,\n\t\t\t\t},\n\t\t\t]);\n\t\t\tawait expect(helper.isInMaintenanceWindow(\"m1\", \"team\")).resolves.toBe(true);\n\t\t});\n\n\t\tit(\"returns false when no active windows exist\", async () => {\n\t\t\tconst { helper } = createHelper();\n\t\t\tawait expect(helper.isInMaintenanceWindow(\"m1\", \"team\")).resolves.toBe(false);\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "server/test/teamsProvider.test.ts",
    "content": "import { describe, expect, it, jest, beforeEach } from \"@jest/globals\";\nimport { TeamsProvider } from \"../src/service/infrastructure/notificationProviders/teams.ts\";\nimport type { Notification } from \"../src/types/notification.ts\";\nimport type { NotificationMessage } from \"../src/types/notificationMessage.ts\";\n\n// Mock got\njest.unstable_mockModule(\"got\", () => ({\n\tdefault: { post: jest.fn() },\n}));\n\nconst createLogger = () => ({\n\tinfo: jest.fn(),\n\twarn: jest.fn(),\n\terror: jest.fn(),\n\tdebug: jest.fn(),\n});\n\nconst createNotification = (overrides?: Partial<Notification>): Notification => ({\n\tid: \"notif-1\",\n\tuserId: \"user-1\",\n\tteamId: \"team-1\",\n\ttype: \"teams\",\n\tnotificationName: \"Teams Alert\",\n\taddress: \"https://xxxxx.webhook.office.com/webhookb2/test\",\n\tcreatedAt: new Date().toISOString(),\n\tupdatedAt: new Date().toISOString(),\n\t...overrides,\n});\n\nconst createMessage = (overrides?: Partial<NotificationMessage>): NotificationMessage => ({\n\ttype: \"monitor_down\",\n\tseverity: \"critical\",\n\tmonitor: {\n\t\tid: \"mon-1\",\n\t\tname: \"API Server\",\n\t\turl: \"https://api.example.com\",\n\t\ttype: \"http\",\n\t\tstatus: \"down\",\n\t},\n\tcontent: {\n\t\ttitle: \"🔴 Monitor Down\",\n\t\tsummary: \"API Server is not responding\",\n\t\tdetails: [\"Response timeout after 30s\"],\n\t\tthresholds: [],\n\t\tincident: {\n\t\t\tid: \"inc-1\",\n\t\t\turl: \"https://app.example.com/incidents/inc-1\",\n\t\t\tcreatedAt: new Date(),\n\t\t},\n\t\ttimestamp: new Date(\"2026-01-15T12:00:00Z\"),\n\t},\n\tclientHost: \"https://app.example.com\",\n\tmetadata: {\n\t\tteamId: \"team-1\",\n\t\tnotificationReason: \"monitor_down\",\n\t},\n\t...overrides,\n});\n\ndescribe(\"TeamsProvider\", () => {\n\tlet provider: TeamsProvider;\n\tlet logger: ReturnType<typeof createLogger>;\n\tlet gotPost: jest.Mock;\n\n\tbeforeEach(async () => {\n\t\tlogger = createLogger();\n\t\tprovider = new TeamsProvider(logger);\n\t\tconst got = await import(\"got\");\n\t\tgotPost = got.default.post as jest.Mock;\n\t\tgotPost.mockReset();\n\t\tgotPost.mockResolvedValue({});\n\t});\n\n\tdescribe(\"sendTestAlert\", () => {\n\t\tit(\"returns false when address is missing\", async () => {\n\t\t\tconst notification = createNotification({ address: undefined });\n\t\t\tconst result = await provider.sendTestAlert(notification);\n\t\t\texpect(result).toBe(false);\n\t\t\texpect(gotPost).not.toHaveBeenCalled();\n\t\t});\n\n\t\tit(\"sends an Adaptive Card test message and returns true on success\", async () => {\n\t\t\tconst notification = createNotification();\n\t\t\tconst result = await provider.sendTestAlert(notification);\n\t\t\texpect(result).toBe(true);\n\t\t\texpect(gotPost).toHaveBeenCalledTimes(1);\n\n\t\t\tconst [url, options] = gotPost.mock.calls[0] as [string, { json: any; headers: any }];\n\t\t\texpect(url).toBe(notification.address);\n\t\t\texpect(options.headers[\"Content-Type\"]).toBe(\"application/json\");\n\n\t\t\t// Verify Teams webhook envelope\n\t\t\tconst payload = options.json;\n\t\t\texpect(payload.type).toBe(\"message\");\n\t\t\texpect(payload.attachments).toHaveLength(1);\n\t\t\texpect(payload.attachments[0].contentType).toBe(\"application/vnd.microsoft.card.adaptive\");\n\n\t\t\t// Verify Adaptive Card structure\n\t\t\tconst card = payload.attachments[0].content;\n\t\t\texpect(card.type).toBe(\"AdaptiveCard\");\n\t\t\texpect(card.version).toBe(\"1.4\");\n\t\t\texpect(card.body[0].type).toBe(\"TextBlock\");\n\t\t\texpect(card.body[0].text).toContain(\"test notification\");\n\t\t});\n\n\t\tit(\"returns false and logs warning on HTTP error\", async () => {\n\t\t\tgotPost.mockRejectedValue(new Error(\"Network error\"));\n\t\t\tconst notification = createNotification();\n\t\t\tconst result = await provider.sendTestAlert(notification);\n\t\t\texpect(result).toBe(false);\n\t\t\texpect(logger.warn).toHaveBeenCalledWith(\n\t\t\t\texpect.objectContaining({\n\t\t\t\t\tmessage: \"Teams test alert failed\",\n\t\t\t\t\tservice: \"TeamsProvider\",\n\t\t\t\t})\n\t\t\t);\n\t\t});\n\t});\n\n\tdescribe(\"sendMessage\", () => {\n\t\tit(\"returns false when address is missing\", async () => {\n\t\t\tconst notification = createNotification({ address: undefined });\n\t\t\tconst result = await provider.sendMessage(notification, createMessage());\n\t\t\texpect(result).toBe(false);\n\t\t\texpect(gotPost).not.toHaveBeenCalled();\n\t\t});\n\n\t\tit(\"sends a well-formed Adaptive Card and returns true\", async () => {\n\t\t\tconst notification = createNotification();\n\t\t\tconst message = createMessage();\n\t\t\tconst result = await provider.sendMessage(notification, message);\n\n\t\t\texpect(result).toBe(true);\n\t\t\texpect(gotPost).toHaveBeenCalledTimes(1);\n\n\t\t\tconst [url, options] = gotPost.mock.calls[0] as [string, { json: any }];\n\t\t\texpect(url).toBe(notification.address);\n\n\t\t\tconst payload = options.json;\n\t\t\texpect(payload.type).toBe(\"message\");\n\n\t\t\tconst card = payload.attachments[0].content;\n\t\t\texpect(card.type).toBe(\"AdaptiveCard\");\n\t\t\texpect(card.version).toBe(\"1.4\");\n\n\t\t\t// Verify body contains expected elements\n\t\t\tconst textBlocks = card.body.filter((b: any) => b.type === \"TextBlock\");\n\t\t\tconst factSets = card.body.filter((b: any) => b.type === \"FactSet\");\n\n\t\t\t// Title block\n\t\t\texpect(textBlocks[0].text).toBe(message.content.title);\n\t\t\texpect(textBlocks[0].color).toBe(\"attention\"); // critical -> attention\n\n\t\t\t// Summary block\n\t\t\texpect(textBlocks[1].text).toBe(message.content.summary);\n\n\t\t\t// FactSet with monitor details\n\t\t\texpect(factSets).toHaveLength(1);\n\t\t\tconst facts = factSets[0].facts;\n\t\t\texpect(facts).toEqual(\n\t\t\t\texpect.arrayContaining([\n\t\t\t\t\texpect.objectContaining({ title: \"Name\", value: \"API Server\" }),\n\t\t\t\t\texpect.objectContaining({ title: \"URL\", value: \"https://api.example.com\" }),\n\t\t\t\t\texpect.objectContaining({ title: \"Status\", value: \"down\" }),\n\t\t\t\t])\n\t\t\t);\n\n\t\t\t// Incident action button\n\t\t\texpect(card.actions).toHaveLength(1);\n\t\t\texpect(card.actions[0].type).toBe(\"Action.OpenUrl\");\n\t\t\texpect(card.actions[0].title).toBe(\"View Incident\");\n\t\t\texpect(card.actions[0].url).toContain(\"/infrastructure/mon-1\");\n\t\t});\n\n\t\tit(\"omits actions when no incident is present\", async () => {\n\t\t\tconst notification = createNotification();\n\t\t\tconst message = createMessage({\n\t\t\t\tcontent: {\n\t\t\t\t\ttitle: \"Test\",\n\t\t\t\t\tsummary: \"Summary\",\n\t\t\t\t\ttimestamp: new Date(),\n\t\t\t\t},\n\t\t\t});\n\t\t\tconst result = await provider.sendMessage(notification, message);\n\t\t\texpect(result).toBe(true);\n\n\t\t\tconst [, options] = gotPost.mock.calls[0] as [string, { json: any }];\n\t\t\tconst card = options.json.attachments[0].content;\n\t\t\texpect(card.actions).toBeUndefined();\n\t\t});\n\n\t\tit(\"includes threshold breaches when present\", async () => {\n\t\t\tconst notification = createNotification();\n\t\t\tconst message = createMessage({\n\t\t\t\ttype: \"threshold_breach\",\n\t\t\t\tseverity: \"warning\",\n\t\t\t\tcontent: {\n\t\t\t\t\ttitle: \"Threshold Breach\",\n\t\t\t\t\tsummary: \"CPU usage exceeded\",\n\t\t\t\t\tthresholds: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tmetric: \"cpu\",\n\t\t\t\t\t\t\tcurrentValue: 95,\n\t\t\t\t\t\t\tthreshold: 80,\n\t\t\t\t\t\t\tunit: \"%\",\n\t\t\t\t\t\t\tformattedValue: \"95%\",\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\ttimestamp: new Date(),\n\t\t\t\t},\n\t\t\t});\n\n\t\t\tawait provider.sendMessage(notification, message);\n\n\t\t\tconst [, options] = gotPost.mock.calls[0] as [string, { json: any }];\n\t\t\tconst card = options.json.attachments[0].content;\n\n\t\t\t// Title should use \"warning\" color\n\t\t\texpect(card.body[0].color).toBe(\"warning\");\n\n\t\t\t// Find threshold text blocks\n\t\t\tconst thresholdHeader = card.body.find((b: any) => b.type === \"TextBlock\" && b.text === \"**Threshold Breaches**\");\n\t\t\texpect(thresholdHeader).toBeDefined();\n\n\t\t\tconst cpuBlock = card.body.find((b: any) => b.type === \"TextBlock\" && b.text?.includes(\"CPU\"));\n\t\t\texpect(cpuBlock).toBeDefined();\n\t\t\texpect(cpuBlock.text).toContain(\"95%\");\n\t\t\texpect(cpuBlock.text).toContain(\"threshold: 80%\");\n\t\t});\n\n\t\tit(\"maps severity to correct Adaptive Card colors\", async () => {\n\t\t\tconst notification = createNotification();\n\n\t\t\tconst severityMap = [\n\t\t\t\t{ severity: \"critical\", expected: \"attention\" },\n\t\t\t\t{ severity: \"warning\", expected: \"warning\" },\n\t\t\t\t{ severity: \"success\", expected: \"good\" },\n\t\t\t\t{ severity: \"info\", expected: \"accent\" },\n\t\t\t] as const;\n\n\t\t\tfor (const { severity, expected } of severityMap) {\n\t\t\t\tgotPost.mockReset();\n\t\t\t\tgotPost.mockResolvedValue({});\n\n\t\t\t\tconst message = createMessage({ severity });\n\t\t\t\tawait provider.sendMessage(notification, message);\n\n\t\t\t\tconst [, options] = gotPost.mock.calls[0] as [string, { json: any }];\n\t\t\t\tconst card = options.json.attachments[0].content;\n\t\t\t\texpect(card.body[0].color).toBe(expected);\n\t\t\t}\n\t\t});\n\n\t\tit(\"returns false and logs warning on HTTP error\", async () => {\n\t\t\tgotPost.mockRejectedValue(new Error(\"502 Bad Gateway\"));\n\t\t\tconst notification = createNotification();\n\t\t\tconst result = await provider.sendMessage(notification, createMessage());\n\t\t\texpect(result).toBe(false);\n\t\t\texpect(logger.warn).toHaveBeenCalledWith(\n\t\t\t\texpect.objectContaining({\n\t\t\t\t\tmessage: \"Teams alert failed via sendMessage\",\n\t\t\t\t\tservice: \"TeamsProvider\",\n\t\t\t\t})\n\t\t\t);\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "server/tsconfig.jest.json",
    "content": "{\n\t\"extends\": \"./tsconfig.json\",\n\t\"compilerOptions\": {\n\t\t\"rootDir\": \".\",\n\t\t\"types\": [\"jest\"],\n\t\t\"noEmit\": true,\n\t\t\"resolveJsonModule\": true\n\t},\n\t\"include\": [\"src\", \"test\"]\n}\n"
  },
  {
    "path": "server/tsconfig.json",
    "content": "{\n\t\"compilerOptions\": {\n\t\t\"rootDir\": \"./src\",\n\t\t\"allowJs\": true,\n\t\t\"checkJs\": false,\n\t\t\"paths\": {\n\t\t\t\"@/*\": [\"./src/*\"]\n\t\t},\n\t\t\"outDir\": \"./dist\",\n\t\t\"strict\": true,\n\t\t\"noImplicitAny\": true,\n\t\t\"esModuleInterop\": true,\n\t\t\"module\": \"nodenext\",\n\t\t\"moduleResolution\": \"nodenext\",\n\t\t\"skipLibCheck\": true,\n\t\t\"noUncheckedIndexedAccess\": true,\n\t\t\"isolatedModules\": true,\n\t\t\"resolveJsonModule\": true\n\t},\n\t\"include\": [\"src\"],\n\t\"exclude\": [\"tests\", \"dist\", \"node_modules\"]\n}\n"
  }
]