Merge remote-tracking branch 'upstream/develop' into feat/handleTestNotification

This commit is contained in:
Skorpios committed 2025-03-11 16:37:37 -07:00
commit 845b7692bc
21 files changed
+636 -37

No files matched your search

+89
View File
@@ -0,0 +1,89 @@
import axios from 'axios';
import fs from 'fs-extra';
import path from 'path';
import { URLSearchParams } from 'url';
// POEditor API information
const API_TOKEN = process.env.POEDITOR_API;
const PROJECT_ID = process.env.POEDITOR_PROJECT_ID;
const LANGUAGES = (process.env.LANGUAGES || 'tr,en').split(',');
const EXPORT_FORMAT = process.env.EXPORT_FORMAT || 'key_value_json';
// POEditor API endpoint
const API_URL = 'https://api.poeditor.com/v2';
// Function to download translations
async function downloadTranslations() {
try {
console.log('Downloading translations from POEditor...');
console.log(`Using export format: ${EXPORT_FORMAT}`);
for (const language of LANGUAGES) {
console.log(`Downloading translations for ${language} language...`);
// Get export URL from POEditor
const exportResponse = await axios.post(`${API_URL}/projects/export`,
new URLSearchParams({
api_token: API_TOKEN,
id: PROJECT_ID,
language: language,
type: EXPORT_FORMAT
})
);
if (exportResponse.data.response.status !== 'success') {
throw new Error(`Failed to get export URL for ${language} language: ${JSON.stringify(exportResponse.data)}`);
}
const fileUrl = exportResponse.data.result.url;
console.log(`Export URL obtained for ${language}`);
// Download translation file
const downloadResponse = await axios.get(fileUrl, { responseType: 'json' });
const translations = downloadResponse.data;
console.log(`Downloaded translations for ${language}`);
// Check the format of data returned from POEditor and convert if necessary
let formattedTranslations = translations;
// If data is in array format, convert it to key-value format
if (Array.isArray(translations)) {
console.log(`Converting array format to key-value format for ${language}`);
formattedTranslations = {};
translations.forEach(item => {
if (item.term && item.definition) {
formattedTranslations[item.term] = item.definition;
}
});
}
// Save file
const outputPath = path.join(process.cwd(), 'temp', `${language}.json`);
await fs.writeJson(outputPath, formattedTranslations, { spaces: 2 });
console.log(`Translations for ${language} language successfully downloaded and saved: ${outputPath}`);
}
console.log('All translations successfully downloaded!');
} catch (error) {
console.error('An error occurred while downloading translations:', error);
process.exit(1);
}
}
// Main function
async function main() {
try {
// Clean temp folder
await fs.emptyDir(path.join(process.cwd(), 'temp'));
// Download translations
await downloadTranslations();
} catch (error) {
console.error('An error occurred during the process:', error);
process.exit(1);
}
}
// Run script
main();
+64
View File
@@ -0,0 +1,64 @@
import axios from "axios";
import FormData from "form-data";
import fs from "fs-extra";
// POEditor API information
const API_TOKEN = process.env.POEDITOR_API;
const PROJECT_ID = process.env.POEDITOR_PROJECT_ID;
const FILE_PATH = process.env.FILE_PATH;
const LANGUAGE = process.env.LANGUAGE;
// POEditor API endpoint
const API_URL = 'https://api.poeditor.com/v2';
// Function to upload translations
async function uploadTranslations() {
try {
console.log(`Uploading translations for ${LANGUAGE} language from ${FILE_PATH}... test1`);
// Check if file exists
if (!await fs.pathExists(FILE_PATH)) {
throw new Error(`File not found: ${FILE_PATH}`);
}
// Read file content
const fileContent = await fs.readFile(FILE_PATH, 'utf8');
// Validate JSON format
try {
JSON.parse(fileContent);
} catch (error) {
throw new Error(`Invalid JSON format in ${FILE_PATH}: ${error.message}`);
}
// Create form data for upload
const formData = new FormData();
formData.append('api_token', API_TOKEN);
formData.append('id', PROJECT_ID);
formData.append('language', LANGUAGE);
formData.append('updating', 'terms_translations');
formData.append('file', fs.createReadStream(FILE_PATH));
formData.append('overwrite', '1');
formData.append('sync_terms', '1');
// Upload to POEditor
const response = await axios.post(`${API_URL}/projects/upload`, formData, {
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
}
});
if (response.data.response.status !== 'success') {
throw new Error(`Failed to upload translations: ${JSON.stringify(response.data)}`);
}
console.log(`Successfully uploaded translations for ${LANGUAGE} language.`);
console.log(`Statistics: ${JSON.stringify(response.data.result)}`);
} catch (error) {
console.error('An error occurred while uploading translations:', error);
process.exit(1);
}
}
// Run script
uploadTranslations();
+69
View File
@@ -0,0 +1,69 @@
# POEditor Translation Synchronization
This GitHub Actions workflow automatically downloads translation files from POEditor and integrates them into the project.
## How It Works
The workflow can be triggered in two ways:
1. **Manual Trigger**: You can manually run the "POEditor Translation Synchronization" workflow from the "Actions" tab in the GitHub interface.
2. **Automatic Trigger**: The workflow runs automatically every day at midnight (UTC).
## Required Settings
For this workflow to function, you need to define the following secrets in your GitHub repository:
1. `POEDITOR_API_TOKEN`: Your POEditor API token
2. `POEDITOR_PROJECT_ID`: Your POEditor project ID
You can add these secrets in the "Settings > Secrets and variables > Actions" section of your GitHub repository.
## Manual Execution
When running the workflow manually, you can specify which languages to download. Languages should be entered as comma-separated values (e.g., `tr,gb,es`).
If you don't specify any languages, the default languages `tr` and `en` will be downloaded.
## Output
When the workflow completes successfully:
1. Translation files for the specified languages are downloaded from POEditor
2. These files are copied to the `src/locales/` directory
3. Changes are automatically committed and pushed to the main branch
## Troubleshooting
If the workflow fails:
1. Check the GitHub Actions logs
2. Make sure your POEditor API token and project ID are correct
3. Ensure that the languages you specified exist in your POEditor project
# POEditor Upload Workflow
## Summary of Implemented Translation Workflow
We 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:
### Created Files
1. .github/scripts/upload-translations.js
- A Node.js script that handles the upload of translation files to POEditor
- Uses the POEditor API to upload JSON translation files
- Validates file existence and JSON format before uploading
- Provides detailed logging of the upload process
2. .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
### Workflow Process
1. When a PR is merged to the develop branch, the workflow checks if any files in src/locales were modified.
1. If translation files were changed, the workflow:
- Sets up the necessary Node.js environment
- Installs required dependencies
- Identifies which specific translation files were changed
- For each changed file, extracts the language code and uploads to POEditor
- Provides status notifications about the upload process
This 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.
+92
View File
@@ -0,0 +1,92 @@
name: POEditor Translation Synchronization
on:
# For manual triggering
workflow_dispatch:
inputs:
languages:
description: "Languages to synchronize (comma separated, e.g.: tr,en,es)"
required: false
default: "tr,en"
format:
description: "Export format (key_value_json or json)"
required: false
default: "key_value_json"
# For automatic execution at a specific time (every day at midnight)
schedule:
- cron: "0 0 * * *"
jobs:
sync-translations:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: "18"
- name: Create package.json for scripts
run: |
mkdir -p .github/scripts
cat > .github/scripts/package.json << EOF
{
"name": "poeditor-scripts",
"version": "1.0.0",
"private": true,
"type": "module",
"dependencies": {
"axios": "^1.6.0",
"fs-extra": "^11.1.1"
}
}
EOF
- name: Install dependencies
run: |
cd .github/scripts
npm install
- name: Download translations from POEditor
env:
POEDITOR_API: ${{ secrets.POEDITOR_API }}
POEDITOR_PROJECT_ID: ${{ secrets.POEDITOR_PROJECT_ID }}
LANGUAGES: ${{ github.event.inputs.languages || 'tr,en' }}
EXPORT_FORMAT: ${{ github.event.inputs.format || 'key_value_json' }}
run: |
mkdir -p temp
node .github/scripts/download-translations.js
- name: Verify translation files
run: |
echo "Verifying translation files..."
for file in temp/*.json; do
echo "Checking $file"
if [ ! -s "$file" ]; then
echo "Error: $file is empty or does not exist"
exit 1
fi
# Validate JSON format
cat "$file" | jq . > /dev/null || { echo "Error: $file is not valid JSON"; exit 1; }
done
echo "All translation files are valid"
- name: Copy translations to project
run: |
mkdir -p src/locales
cp -r temp/* src/locales/
echo "Translation files copied to src/locales/"
- name: Commit changes
run: |
git config --local user.email "github-actions[bot]@users.noreply.github.com"
git config --local user.name "github-actions[bot]"
git add src/locales/*.json
git diff --staged --quiet || git commit -m "Translations updated from POEditor"
git push
+101
View File
@@ -0,0 +1,101 @@
name: Upload Translations to POEditor on PR Merge
on:
pull_request:
types: [closed]
branches:
- develop
paths:
- "src/locales/**"
jobs:
upload-translations:
# Only run if the PR was merged (not just closed) or manually triggered
if: github.event.pull_request.merged == true
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
with:
fetch-depth: 0 # Fetch all history to get changed files
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: "18"
- name: Create package.json for scripts
run: |
mkdir -p .github/scripts
cat > .github/scripts/package.json << EOF
{
"name": "poeditor-scripts",
"version": "1.0.0",
"private": true,
"type": "module",
"dependencies": {
"axios": "^1.6.0",
"fs-extra": "^11.1.1",
"form-data": "^4.0.0"
}
}
EOF
- name: Install dependencies
run: |
cd .github/scripts
npm install
- name: Get changed locale files
id: changed-files
if: github.event_name == 'pull_request'
run: |
# Get list of changed files in src/locales directory
CHANGED_FILES=$(git diff --name-only ${{ github.event.pull_request.base.sha }} ${{ github.event.pull_request.head.sha }} -- src/locales/*.json)
echo "Changed files: $CHANGED_FILES"
# Create a JSON array of changed files with language codes
echo "CHANGED_FILES<<EOF" >> $GITHUB_ENV
echo "$CHANGED_FILES" >> $GITHUB_ENV
echo "EOF" >> $GITHUB_ENV
- name: Upload changed translations to POEditor
if: env.CHANGED_FILES != ''
env:
POEDITOR_API: ${{ secrets.POEDITOR_API }}
POEDITOR_PROJECT_ID: ${{ secrets.POEDITOR_PROJECT_ID }}
run: |
# Process each changed file
for FILE in $CHANGED_FILES; do
if [[ -f "$FILE" ]]; then
# Extract language code from filename (e.g., src/locales/en.json -> en)
FILENAME=$(basename "$FILE")
# Special case: map gb.json to en language code
if [ "$FILENAME" == "gb.json" ]; then
LANG="en"
echo "Found gb.json, mapping to language code 'en'"
else
LANG=$(basename "$FILE" .json)
fi
echo "Processing $FILE for language $LANG"
# Upload to POEditor
LANGUAGE=$LANG FILE_PATH=$FILE node .github/scripts/upload-translations.js
fi
done
- name: Notify on success
if: success() && env.CHANGED_FILES != ''
run: |
echo "Successfully uploaded translation files to POEditor."
if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
echo "Manual trigger comment: ${{ github.event.inputs.comment }}"
fi
- name: Notify on no changes
if: env.CHANGED_FILES == ''
run: |
echo "No translation files were found to upload."
+3 -3
View File
@@ -128,7 +128,7 @@ const Search = ({
<Typography
component="span"
className="input-error"
color={theme.palette.error.contrastText}
color={theme.palette.error.main}
mt={theme.spacing(2)}
sx={{
opacity: 0.8,
@@ -188,8 +188,8 @@ const Search = ({
color: "red",
},
"& li.MuiAutocomplete-option:hover:not([aria-selected='true'])": {
color: theme.palette.primary.main,
backgroundColor: theme.palette.primary.contrastTextSecondary,
color: theme.palette.secondary.contrastText,
backgroundColor: theme.palette.secondary.main,
},
"& .MuiAutocomplete-noOptions": {
px: theme.spacing(6),
+8 -1
View File
@@ -14,7 +14,14 @@ const Link = ({ level, label, url }) => {
const theme = useTheme();
const levelConfig = {
primary: {},
primary: {
color: theme.palette.primary.contrastTextTertiary,
sx: {
":hover": {
color: theme.palette.primary.contrastTextSecondary,
},
},
},
secondary: {
color: theme.palette.primary.contrastTextSecondary,
sx: {
+3
View File
@@ -17,6 +17,7 @@ import {
} from "@mui/material";
import ThemeSwitch from "../ThemeSwitch";
import Avatar from "../Avatar";
import StarPrompt from "../StarPrompt";
import LockSvg from "../../assets/icons/lock.svg?react";
import UserSvg from "../../assets/icons/user.svg?react";
import TeamSvg from "../../assets/icons/user-two.svg?react";
@@ -608,6 +609,8 @@ function Sidebar() {
</List>
</Box>
{!collapsed && <StarPrompt />}
<List
component="nav"
disablePadding
+101
View File
@@ -0,0 +1,101 @@
import React from 'react';
import { Typography, IconButton, Stack, Box } from '@mui/material';
import CloseIcon from '@mui/icons-material/Close';
import { useTheme } from '@emotion/react';
import { useSelector, useDispatch } from 'react-redux';
import { useTranslation } from 'react-i18next';
import { setStarPromptOpen } from '../../Features/UI/uiSlice';
const StarPrompt = ({
repoUrl = 'https://github.com/bluewave-labs/checkmate'
}) => {
const theme = useTheme();
const dispatch = useDispatch();
const { t } = useTranslation();
const isOpen = useSelector((state) => state.ui?.starPromptOpen ?? true);
const mode = useSelector((state) => state.ui.mode);
const handleClose = () => {
dispatch(setStarPromptOpen(false));
};
const handleStarClick = () => {
window.open(repoUrl, '_blank');
};
if (!isOpen) return null;
return (
<Stack
direction="column"
sx={{
width: '100%',
padding: `${theme.spacing(6)} ${theme.spacing(6)}`,
borderTop: `1px solid ${theme.palette.primary.lowContrast}`,
borderBottom: `1px solid ${theme.palette.primary.lowContrast}`,
borderRadius: 0,
gap: theme.spacing(1.5),
backgroundColor: theme.palette.primary.main,
}}
>
<Stack direction="row" justifyContent="space-between" alignItems="center" width="100%" pl={theme.spacing(4)}>
<Typography
variant="subtitle2"
sx={{
color: mode === 'dark' ? theme.palette.primary.contrastText : theme.palette.text.primary,
mt: theme.spacing(3)
}}
>
{t('starPromptTitle')}
</Typography>
<IconButton
onClick={handleClose}
size="small"
sx={{
color: theme.palette.text.primary,
padding: 0,
marginTop: theme.spacing(-5),
'&:hover': {
backgroundColor: 'transparent',
opacity: 0.8
},
}}
>
<CloseIcon sx={{ fontSize: '1.25rem' }} />
</IconButton>
</Stack>
<Typography
variant="body1"
sx={{
color: theme.palette.text.secondary,
fontSize: '0.938rem',
lineHeight: 1.5,
mb: 1,
px: theme.spacing(4)
}}
>
{t('starPromptDescription')}
</Typography>
<Box
component="img"
src={`https://img.shields.io/github/stars/bluewave-labs/checkmate?label=checkmate&style=social${mode === 'dark' ? '&color=white' : ''}`}
alt="GitHub stars"
onClick={handleStarClick}
sx={{
cursor: 'pointer',
transform: 'scale(0.65)',
transformOrigin: 'left center',
'&:hover': {
opacity: 0.8
},
pl: theme.spacing(4),
filter: mode === 'dark' ? 'invert(1)' : 'none'
}}
/>
</Stack>
);
};
export default StarPrompt;
+51
View File
@@ -0,0 +1,51 @@
.wallet-adapter-dropdown {
width: 100%;
display: flex;
flex-wrap: wrap;
justify-content: center;
align-items: center;
gap: var(--env-var-spacing-1);
}
.wallet-adapter-button {
display: flex;
align-items: center;
justify-content: center;
width: auto;
height: var(--env-var-height-2) !important;
font-size: var(--env-var-font-size-medium-plus) !important;
font-weight: 500 !important;
margin: 0;
padding: calc((var(--env-var-height-2) - var(--env-var-font-size-medium-plus) * 1.2) / 2) var(--env-var-spacing-1);
white-space: nowrap;
}
.wallet-adapter-modal-title {
font-size: var(--font-size-h5) !important;
}
/* Separator styling */
.wallet-adapter-modal-divider {
background-color: var(--border-color) !important;
margin: var(--spacing-md) 0 !important;
}
/* Responsive fixes */
@media (max-width: 1200px) {
.wallet-adapter-button {
font-size: var(--env-var-font-size-medium) !important;
padding: calc((var(--env-var-height-2) - var(--env-var-font-size-medium) * 1.2) / 2)
var(--env-var-spacing-1-minus) !important;
}
}
@media (max-width: 900px) {
.wallet-adapter-modal-wrapper {
flex-direction: column !important;
}
.wallet-adapter-modal-divider {
margin: var(--spacing-sm) 0 !important;
}
}
+1
View File
@@ -9,6 +9,7 @@ import {
import { WalletModalProvider } from "@solana/wallet-adapter-react-ui";
import { clusterApiUrl } from "@solana/web3.js";
import PropTypes from "prop-types";
import "./index.css";
// Default styles that can be overridden by your app
import "@solana/wallet-adapter-react-ui/styles.css";
+5
View File
@@ -24,6 +24,7 @@ const initialState = {
timezone: "America/Toronto",
distributedUptimeEnabled: false,
language: "gb",
starPromptOpen: true,
};
const uiSlice = createSlice({
@@ -55,6 +56,9 @@ const uiSlice = createSlice({
setLanguage(state, action) {
state.language = action.payload;
},
setStarPromptOpen: (state, action) => {
state.starPromptOpen = action.payload;
},
},
});
@@ -67,4 +71,5 @@ export const {
setTimezone,
setDistributedUptimeEnabled,
setLanguage,
setStarPromptOpen,
} = uiSlice.actions;
@@ -30,7 +30,6 @@ const StatusHeader = ({ monitor, connectionStatus, elementToCapture }) => {
};
let bgColor = COLOR_MAP[connectionStatus];
return (
<ColContainer backgroundColor={bgColor}>
<Stack
@@ -61,7 +60,8 @@ const StatusHeader = ({ monitor, connectionStatus, elementToCapture }) => {
backgroundColor={theme.palette.successSecondary.lowContrast}
color={theme.palette.success.lowContrast}
>
{t("distributedUptimeDetailsStatusHeaderUptime")} {(monitor.totalUptime * 100).toFixed(2)}%
{t("distributedUptimeDetailsStatusHeaderUptime")}{" "}
{(monitor.uptimePercentage * 100).toFixed(2)}%
</Typography>
</Stack>
<Typography
+2 -1
View File
@@ -298,7 +298,7 @@ const Settings = () => {
{t("settingsWalletDescription")}
</Typography>
</Box>
<Box>
<Box sx={{ display: 'flex', flexWrap: 'wrap', justifyContent: 'flex-start', gap: 2 }}>
<Stack
direction="row"
spacing={2}
@@ -401,6 +401,7 @@ const Settings = () => {
</ConfigBox>
)}
<ConfigBox>
<Box>
<Typography component="h1">{t("settingsAbout")}</Typography>
-2
View File
@@ -24,7 +24,6 @@ const PublicStatus = () => {
const [isDeleteOpen, setIsDeleteOpen] = useState(false);
// Utils
const theme = useTheme();
const isAdmin = useIsAdmin();
const location = useLocation();
const navigate = useNavigate();
@@ -33,7 +32,6 @@ const PublicStatus = () => {
const [deleteStatusPage, isDeleting] = useStatusPageDelete(fetchStatusPage, url);
// Setup
const currentPath = location.pathname;
let sx = { paddingLeft: theme.spacing(20), paddingRight: theme.spacing(20) };
let link = undefined;
const isPublic = location.pathname.startsWith("/status/uptime/public");
@@ -25,7 +25,7 @@ const StatusPagesTable = ({ data }) => {
row.type === "distributed"
? `/status/distributed/public/${row.url}`
: `/status/uptime/public/${row.url}`;
navigate(url);
window.open(url, "_blank", "noopener,noreferrer")
}
},
render: (row) => {
@@ -2,18 +2,30 @@ import { useState } from "react";
import { useEffect } from "react";
import { networkService } from "../../../../main";
import { createToast } from "../../../../Utils/toastUtils";
export const useChecksFetch = ({ monitorId, dateRange, page, rowsPerPage }) => {
export const useChecksFetch = ({
monitorId,
monitorType,
dateRange,
page,
rowsPerPage,
}) => {
const [checks, setChecks] = useState(undefined);
const [checksCount, setChecksCount] = useState(undefined);
const [isLoading, setIsLoading] = useState(false);
const [networkError, setNetworkError] = useState(false);
useEffect(() => {
if (!monitorType) {
console.warn("Monitor Type is not provided. Fetching checks will not proceed.");
return;
}
const fetchChecks = async () => {
try {
setIsLoading(true);
const res = await networkService.getChecksByMonitor({
monitorId: monitorId,
type: monitorType,
sortOrder: "desc",
limit: null,
dateRange: dateRange,
@@ -31,7 +43,7 @@ export const useChecksFetch = ({ monitorId, dateRange, page, rowsPerPage }) => {
}
};
fetchChecks();
}, [monitorId, dateRange, page, rowsPerPage]);
}, [monitorId, monitorType, dateRange, page, rowsPerPage]);
return [checks, checksCount, isLoading, networkError];
};
+3
View File
@@ -59,8 +59,11 @@ const UptimeDetails = () => {
uiTimezone,
});
const monitorType = monitor?.type;
const [checks, checksCount, checksAreLoading, checksNetworkError] = useChecksFetch({
monitorId,
monitorType,
dateRange,
page,
rowsPerPage,
+1 -1
View File
@@ -332,13 +332,13 @@ const baseTheme = (palette) => ({
color: palette.error.main,
opacity: 0.8,
fontSize: "var(--env-var-font-size-medium)",
marginLeft: 0,
},
"& .MuiFormHelperText-root.Mui-error": {
opacity: 0.8,
fontSize: "var(--env-var-font-size-medium)",
color: palette.error.main,
whiteSpace: 'nowrap',
},
}),
},
+21 -21
View File
@@ -100,7 +100,7 @@
"distributedUptimeDetailsMonitorHeader": "Distributed Uptime Monitoring powered by DePIN",
"distributedUptimeDetailsStatusHeaderUptime": "Uptime:",
"distributedUptimeDetailsStatusHeaderLastUpdate": "Last updated",
"settingsGeneralSettings": "General settings",
"settingsDisplayTimezone": "Display timezone",
"settingsDisplayTimezoneDescription": "The timezone of the dashboard you publicly display.",
@@ -142,37 +142,37 @@
"settingsFailedToAddDemoMonitors": "Failed to add demo monitors",
"settingsMonitorsDeleted": "Successfully deleted all monitors",
"settingsFailedToDeleteMonitors": "Failed to delete all monitors",
"starPromptTitle": "Star Checkmate",
"starPromptDescription": "See the latest releases and help grow the community on GitHub",
"notifications": {
"enableNotifications": "Enable {{platform}} notifications",
"testNotification": "Test notification",
"addOrEditNotifications": "Add or edit notifications",
"slack": {
"label": "Slack",
"description": "To enable Slack notifications, create a Slack app and enable incoming webhooks. After that, simply provide the webhook URL here.",
"webhookLabel": "Webhook URL",
"webhookPlaceholder": "https://hooks.slack.com/services/..."
"label": "Slack",
"description": "To enable Slack notifications, create a Slack app and enable incoming webhooks. After that, simply provide the webhook URL here.",
"webhookLabel": "Webhook URL",
"webhookPlaceholder": "https://hooks.slack.com/services/..."
},
"discord": {
"label": "Discord",
"description": "To send data to a Discord channel from Checkmate via Discord notifications using webhooks, you can use Discord's incoming Webhooks feature.",
"webhookLabel": "Discord Webhook URL",
"webhookPlaceholder": "https://discord.com/api/webhooks/..."
"label": "Discord",
"description": "To send data to a Discord channel from Checkmate via Discord notifications using webhooks, you can use Discord's incoming Webhooks feature.",
"webhookLabel": "Discord Webhook URL",
"webhookPlaceholder": "https://discord.com/api/webhooks/..."
},
"telegram": {
"label": "Telegram",
"description": "To enable Telegram notifications, create a Telegram bot using BotFather, an official bot for creating and managing Telegram bots. Then, get the API token and chat ID and write them down here.",
"tokenLabel": "Your bot token",
"tokenPlaceholder": "123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11",
"chatIdLabel": "Your Chat ID",
"chatIdPlaceholder": "-1001234567890"
"label": "Telegram",
"description": "To enable Telegram notifications, create a Telegram bot using BotFather, an official bot for creating and managing Telegram bots. Then, get the API token and chat ID and write them down here.",
"tokenLabel": "Your bot token",
"tokenPlaceholder": "123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11",
"chatIdLabel": "Your Chat ID",
"chatIdPlaceholder": "-1001234567890"
},
"webhook": {
"label": "Webhooks",
"description": "You can set up a custom webhook to receive notifications when incidents occur.",
"urlLabel": "Webhook URL",
"urlPlaceholder": "https://your-server.com/webhook"
"label": "Webhooks",
"description": "You can set up a custom webhook to receive notifications when incidents occur.",
"urlLabel": "Webhook URL",
"urlPlaceholder": "https://your-server.com/webhook"
}
}
}
+5 -3
View File
@@ -60,7 +60,6 @@
"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",
"distributedRightCatagoryTitle": "Monitör",
"distributedRightCatagoryDescription": "Mainnet Beta Kümesi",
"settingsGeneralSettings": "Genel ayarlar",
"settingsDisplayTimezone": "Görüntüleme saat dilimi",
"settingsDisplayTimezoneDescription": "Herkese açık olarak görüntülediğiniz kontrol panelinin saat dilimi.",
@@ -101,5 +100,8 @@
"settingsDemoMonitorsAdded": "Demo monitörler başarıyla eklendi",
"settingsFailedToAddDemoMonitors": "Demo monitörler eklenemedi",
"settingsMonitorsDeleted": "Tüm monitörler başarıyla silindi",
"settingsFailedToDeleteMonitors": "Monitörler silinemedi"
}
"settingsFailedToDeleteMonitors": "Monitörler silinemedi",
"starPromptTitle": "Checkmate yıldızla değerlendirin",
"starPromptDescription": "En son sürümleri görün ve GitHub'daki topluluğun büyümesine yardımcı olun",
"testLocale": "TEST1311 UPLOAD"
}