Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 29 additions & 8 deletions IntelliTrader.Web/Views/Home/Dashboard.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -27,25 +27,27 @@
</div>
</div>

<!-- Дополнительные настройки звука -->
<!-- Дополнительные настройки звука и фильтров -->
<div class="row align-items-center mt-2 pt-2" style="border-top: 1px solid var(--card-border); font-size: 13px;">
<div class="col-md-5 d-flex align-items-center mb-2 mb-md-0">
<div class="col-md-4 d-flex align-items-center mb-2 mb-md-0">
<i class="fas fa-sliders-h mr-2" style="color: #7aa2f7;"></i>
<span class="mr-2" style="white-space: nowrap;">Громкость:</span>
<input type="range" id="soundVolumeSlider" min="0" max="1" step="0.05" value="0.5" style="flex-grow: 1; height: 4px; background: var(--bg-color); outline: none; transition: background 450ms ease-in-out; -webkit-appearance: none; cursor: pointer;" />
<span id="soundVolumeValue" class="ml-2" style="font-weight: bold; color: #7aa2f7; min-width: 40px; text-align: right;">50%</span>
</div>
<div class="col-md-5 d-flex align-items-center mb-2 mb-md-0">
<div class="col-md-4 d-flex align-items-center mb-2 mb-md-0">
<i class="fas fa-music mr-2" style="color: #bb9af3;"></i>
<span class="mr-2" style="white-space: nowrap;">Профиль звука:</span>
<span class="mr-2" style="white-space: nowrap;">Профиль:</span>
<select id="soundProfileSelect" class="form-control form-control-sm" style="background-color: var(--input-bg); color: var(--text-color); border: 1px solid var(--input-border); border-radius: 4px; height: 28px; padding: 2px 8px; font-size: 12px; width: auto;">
<option value="chime">Приятный звон (Chime)</option>
<option value="beep">Высокий писк (Beep)</option>
<option value="arcade">Ретро аркада (Arcade)</option>
</select>
</div>
<div class="col-md-2 text-md-right text-muted" style="font-size: 11px;">
Настройки звука
<div class="col-md-4 d-flex align-items-center mb-2 mb-md-0">
<i class="fas fa-filter mr-2" style="color: #e0af68;"></i>
<span class="mr-2" style="white-space: nowrap;">Мин. объем ($):</span>
<input type="number" id="minTradeSizeInput" min="0" step="1" value="0" placeholder="0" class="form-control form-control-sm" style="background-color: var(--input-bg); color: var(--text-color); border: 1px solid var(--input-border); border-radius: 4px; height: 28px; width: 90px; padding: 2px 8px; font-size: 12px;" />
</div>
</div>
</div>
Expand All @@ -59,6 +61,7 @@
const soundVolumeSlider = document.getElementById("soundVolumeSlider");
const soundVolumeValue = document.getElementById("soundVolumeValue");
const soundProfileSelect = document.getElementById("soundProfileSelect");
const minTradeSizeInput = document.getElementById("minTradeSizeInput");
const notificationContainer = document.getElementById("notificationContainer");

let isSoundEnabled = localStorage.getItem("realtime_sound_enabled") !== "false";
Expand All @@ -74,10 +77,15 @@
// Load sound profile with fallback to 'chime'
let soundProfile = localStorage.getItem("realtime_sound_profile") || "chime";

// Load minimum trade size threshold in USDT (default 0)
let minTradeSize = parseFloat(localStorage.getItem("realtime_min_trade_size") || "0");
if (isNaN(minTradeSize) || minTradeSize < 0) minTradeSize = 0;

// Sync UI controls with values
soundVolumeSlider.value = soundVolume;
soundVolumeValue.textContent = Math.round(soundVolume * 100) + "%";
soundProfileSelect.value = soundProfile;
if (minTradeSizeInput) minTradeSizeInput.value = minTradeSize;

updateSoundButtonUI();

Expand Down Expand Up @@ -206,6 +214,16 @@
playNotificationSound();
});

// Min trade size threshold input handling
if (minTradeSizeInput) {
minTradeSizeInput.addEventListener("input", function () {
let val = parseFloat(minTradeSizeInput.value);
if (isNaN(val) || val < 0) val = 0;
minTradeSize = val;
localStorage.setItem("realtime_min_trade_size", minTradeSize);
});
}

// Sound profile select handling
soundProfileSelect.addEventListener("change", function () {
soundProfile = soundProfileSelect.value;
Expand Down Expand Up @@ -332,8 +350,11 @@
knownTrades.add(tradeId);

if (!isFirstLoad) {
hasNewTrade = true;
showToastNotification(trade);
const tradeValue = (parseFloat(trade.Amount) || 0) * (parseFloat(trade.SellPrice) || parseFloat(trade.AveragePrice) || 0);
if (minTradeSize === 0 || tradeValue >= minTradeSize) {
hasNewTrade = true;
showToastNotification(trade);
}
}
}
});
Expand Down
95 changes: 95 additions & 0 deletions IntelliTrader.Web/Views/Home/Settings.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,39 @@
</div>
</div>

<!-- Настройки уведомлений и звуковых оповещений -->
<div class="configs mt-4" style="background-color: var(--card-bg) !important; border: 1px solid var(--border-color) !important; color: var(--text-color) !important; padding: 20px; border-radius: 4px; margin-top: 20px;">
<h2>Уведомления и оповещения</h2>
<div style="margin-bottom: 15px; display: flex; align-items: center; flex-wrap: wrap;">
<label style="margin-right: 15px; margin-bottom: 0; font-weight: bold;">Звук уведомлений:</label>
<div class="custom-control custom-switch">
<input type="checkbox" class="custom-control-input" id="settingsSoundToggle">
<label class="custom-control-label" for="settingsSoundToggle" id="settingsSoundToggleLabel">Включен</label>
</div>
</div>

<div style="margin-bottom: 15px; display: flex; align-items: center; flex-wrap: wrap;">
<label style="margin-right: 15px; margin-bottom: 0; font-weight: bold; width: 180px;">Громкость звука:</label>
<input type="range" id="settingsSoundVolumeSlider" min="0" max="1" step="0.05" value="0.5" style="width: 150px; height: 4px; background: var(--bg-color); outline: none; -webkit-appearance: none; cursor: pointer;" />
<span id="settingsSoundVolumeValue" style="margin-left: 10px; font-weight: bold; color: #7aa2f7; min-width: 45px;">50%</span>
</div>

<div style="margin-bottom: 15px; display: flex; align-items: center; flex-wrap: wrap;">
<label style="margin-right: 15px; margin-bottom: 0; font-weight: bold; width: 180px;">Звуковой профиль:</label>
<select id="settingsSoundProfileSelect" class="form-control form-control-sm" style="width: auto; background-color: var(--input-bg); color: var(--text-color); border: 1px solid var(--input-border); border-radius: 4px;">
<option value="chime">Приятный звон (Chime)</option>
<option value="beep">Высокий писк (Beep)</option>
<option value="arcade">Ретро аркада (Arcade)</option>
</select>
</div>

<div style="margin-bottom: 15px; display: flex; align-items: center; flex-wrap: wrap;">
<label style="margin-right: 15px; margin-bottom: 0; font-weight: bold; width: 180px;">Мин. размер сделки (USDT):</label>
<input type="number" id="settingsMinTradeSizeInput" min="0" step="1" value="0" placeholder="0" class="form-control form-control-sm" style="width: 120px; background-color: var(--input-bg); color: var(--text-color); border: 1px solid var(--input-border); border-radius: 4px;" />
<small class="text-muted style-help" style="display: block; margin-left: 10px;">(0 = показывать все сделки)</small>
</div>
</div>

<script>
document.addEventListener("DOMContentLoaded", function() {
const select = document.getElementById("settingsThemeSelect");
Expand Down Expand Up @@ -87,6 +120,68 @@
}
});
}

// Notification settings sync logic
const settingsSoundToggle = document.getElementById("settingsSoundToggle");
const settingsSoundToggleLabel = document.getElementById("settingsSoundToggleLabel");
const settingsSoundVolumeSlider = document.getElementById("settingsSoundVolumeSlider");
const settingsSoundVolumeValue = document.getElementById("settingsSoundVolumeValue");
const settingsSoundProfileSelect = document.getElementById("settingsSoundProfileSelect");
const settingsMinTradeSizeInput = document.getElementById("settingsMinTradeSizeInput");

if (settingsSoundToggle) {
let isSoundEnabled = localStorage.getItem("realtime_sound_enabled") !== "false";
settingsSoundToggle.checked = isSoundEnabled;
if (settingsSoundToggleLabel) {
settingsSoundToggleLabel.textContent = isSoundEnabled ? "Включен" : "Выключен";
}

settingsSoundToggle.addEventListener("change", function() {
let enabled = settingsSoundToggle.checked;
localStorage.setItem("realtime_sound_enabled", enabled);
if (settingsSoundToggleLabel) {
settingsSoundToggleLabel.textContent = enabled ? "Включен" : "Выключен";
}
});
}

if (settingsSoundVolumeSlider) {
let vol = localStorage.getItem("realtime_sound_volume");
let soundVolume = vol === null ? 0.5 : parseFloat(vol);
settingsSoundVolumeSlider.value = soundVolume;
if (settingsSoundVolumeValue) {
settingsSoundVolumeValue.textContent = Math.round(soundVolume * 100) + "%";
}

settingsSoundVolumeSlider.addEventListener("input", function() {
let val = parseFloat(settingsSoundVolumeSlider.value);
if (settingsSoundVolumeValue) {
settingsSoundVolumeValue.textContent = Math.round(val * 100) + "%";
}
localStorage.setItem("realtime_sound_volume", val);
});
}

if (settingsSoundProfileSelect) {
let profile = localStorage.getItem("realtime_sound_profile") || "chime";
settingsSoundProfileSelect.value = profile;

settingsSoundProfileSelect.addEventListener("change", function() {
localStorage.setItem("realtime_sound_profile", settingsSoundProfileSelect.value);
});
}

if (settingsMinTradeSizeInput) {
let minSize = parseFloat(localStorage.getItem("realtime_min_trade_size") || "0");
if (isNaN(minSize) || minSize < 0) minSize = 0;
settingsMinTradeSizeInput.value = minSize;

settingsMinTradeSizeInput.addEventListener("input", function() {
let val = parseFloat(settingsMinTradeSizeInput.value);
if (isNaN(val) || val < 0) val = 0;
localStorage.setItem("realtime_min_trade_size", val);
});
}
});
</script>

Expand Down
34 changes: 33 additions & 1 deletion magda_agent_system/agent_tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -446,7 +446,7 @@
},
{
"id": "web-dashboard-custom-alerts",
"status": "todo",
"status": "done",
"area": "web",
"risk": "low",
"title": "Add custom notification threshold settings on Dashboard",
Expand All @@ -473,6 +473,38 @@
"acceptance": [
"Order caching mechanism is integrated and avoids frequent disk reads for historical trade logs."
]
},
{
"id": "web-dashboard-log-filter-search",
"status": "todo",
"area": "web",
"risk": "low",
"title": "Add real-time log search and level filtering on Dashboard",
"description": "Implement client-side search input and log level dropdown filters (All, Info, Warning, Error) for the live log monitor terminal in Dashboard.",
"allowed_paths": [
"IntelliTrader.Web/Views/**",
"IntelliTrader.Web/Static/**",
"magda_agent_system/agent_tasks.json"
],
"acceptance": [
"The live log monitor terminal supports searching log text and filtering by severity level."
]
},
{
"id": "web-dashboard-pair-favorite-pinning",
"status": "todo",
"area": "web",
"risk": "low",
"title": "Add favorite pair pinning and persistence on Dashboard",
"description": "Allow users to pin favorite trading pairs to the top of the trading pairs table with persistence in localStorage.",
"allowed_paths": [
"IntelliTrader.Web/Views/**",
"IntelliTrader.Web/Static/**",
"magda_agent_system/agent_tasks.json"
],
"acceptance": [
"Users can click a star icon on any trading pair to pin it to the top of the table."
]
}
]
}