Add tab system to right sidebar with Indicators and Strategies

- Add two-tab navigation (Indicators, Strategies) in right sidebar
- Move all strategy-related content to Strategies tab
- Implement sidebar collapse/expand functionality
- Add indicator visibility toggle (eye button)
- Fix bug where wrong interval data was deleted on TF switch
- Add localStorage persistence for sidebar state and active tab
- Ensure indicators recalculate when TF changes
This commit is contained in:
DiTus
2026-02-26 14:56:03 +01:00
parent 6e21be6523
commit 5f84215acd
6 changed files with 319 additions and 143 deletions

View File

@ -193,21 +193,19 @@ export function renderIndicatorPanel() {
}
function renderIndicatorItem(indicator, isFavorite) {
const colorDots = '';
return `
<div class="indicator-item ${isFavorite ? 'favorite' : ''}" data-type="${indicator.type}">
<div class="indicator-item-main">
<span class="indicator-name">${indicator.name}</span>
<span class="indicator-desc">${indicator.description || ''}</span>
</div>
<div class="indicator-actions">
<button class="indicator-btn add" data-type="${indicator.type}" title="Add to chart">+</button>
${isFavorite ? '' : `
<button class="indicator-btn favorite" data-type="${indicator.type}" title="Add to favorites">
${userPresets.favorites?.includes(indicator.type) ? '★' : '☆'}
</button>
`}
<div class="indicator-actions">
<button class="indicator-btn add" data-type="${indicator.type}" title="Add to chart">+</button>
${isFavorite ? '' : `
<button class="indicator-btn favorite" data-type="${indicator.type}" title="Add to favorites">
${userPresets.favorites?.includes(indicator.type) ? '★' : '☆'}
</button>
`}
</div>
</div>
</div>
`;
@ -238,7 +236,7 @@ function renderActiveIndicator(indicator) {
<button class="indicator-btn favorite" onclick="event.stopPropagation(); window.toggleFavorite && window.toggleFavorite('${indicator.type}')" title="Add to favorites">
${isFavorite ? '★' : '☆'}
</button>
<button class="indicator-btn expand ${isExpanded ? 'rotated' : ''}" data-id="${indicator.id}" title="Show settings">
<button class="indicator-btn expand ${isExpanded ? 'rotated' : ''}" data-id="${indicator.id}" onclick="event.stopPropagation(); window.toggleIndicatorExpand && window.toggleIndicatorExpand('${indicator.id}')" title="Show settings">
${isExpanded ? '▼' : '▶'}
</button>
</div>
@ -640,7 +638,21 @@ function saveUserPresets() {
}
function renderIndicatorOnPane(indicator, meta, instance, candles, paneIndex, lineStyleMap) {
console.log(`renderIndicatorOnPane for ${indicator.id}, candles.length=${candles.length}, paneIndex=${paneIndex}`);
// Recalculate with current TF candles
const results = instance.calculate(candles);
console.log(`Calculated results for ${indicator.id}:`, results?.length || 0, 'values');
// Clear previous series for this indicator
if (indicator.series && indicator.series.length > 0) {
indicator.series.forEach(s => {
try {
window.dashboard.chart.removeSeries(s);
console.log(`Removed series for ${indicator.id}`);
} catch(e) { console.error('Error removing series:', e); }
});
}
indicator.series = [];
const lineStyle = lineStyleMap[indicator.params._lineType] || LightweightCharts.LineStyle.Solid;
@ -649,10 +661,14 @@ function renderIndicatorOnPane(indicator, meta, instance, candles, paneIndex, li
const firstNonNull = results?.find(r => r !== null && r !== undefined);
const isObjectResult = firstNonNull && typeof firstNonNull === 'object';
let plotsCreated = 0;
meta.plots.forEach((plot, plotIdx) => {
if (isObjectResult) {
const hasData = results.some(r => r && r[plot.id] !== undefined && r[plot.id] !== null);
if (!hasData) return;
if (!hasData) {
console.log(`No data for plot ${plot.id} in ${indicator.id}`);
return;
}
}
const plotColor = indicator.params[`_color_${plotIdx}`] || plot.color || '#2962ff';
@ -674,6 +690,7 @@ function renderIndicatorOnPane(indicator, meta, instance, candles, paneIndex, li
}
}
console.log(`Plot ${plot.id} has ${data.length} data points`);
if (data.length === 0) return;
let series;
@ -716,6 +733,8 @@ function renderIndicatorOnPane(indicator, meta, instance, candles, paneIndex, li
series.setData(data);
indicator.series.push(series);
plotsCreated++;
console.log(`Created series for ${indicator.id}, plot=${plot.id}, total series now=${indicator.series.length}`);
// Create horizontal band lines for RSI
if (meta.name === 'RSI' && indicator.series.length > 0) {
@ -756,17 +775,28 @@ function renderIndicatorOnPane(indicator, meta, instance, candles, paneIndex, li
// Chart drawing
export function drawIndicatorsOnChart() {
if (!window.dashboard || !window.dashboard.chart) return;
if (!window.dashboard || !window.dashboard.chart) {
return;
}
const currentInterval = window.dashboard.currentInterval;
const candles = window.dashboard.allData.get(currentInterval);
if (!candles || candles.length === 0) {
return;
}
// Log: Ensure we're using the correct interval candles
console.log(`drawIndicatorsOnChart for interval=${currentInterval}, candles=${candles.length}`);
// First, remove all existing series
activeIndicators.forEach(ind => {
ind.series?.forEach(s => {
try { window.dashboard.chart.removeSeries(s); } catch(e) {}
});
ind.series = [];
});
const candles = window.dashboard.allData.get(window.dashboard.currentInterval);
if (!candles || candles.length === 0) return;
const lineStyleMap = {
'solid': LightweightCharts.LineStyle.Solid,
'dotted': LightweightCharts.LineStyle.Dotted,
@ -779,7 +809,12 @@ export function drawIndicatorsOnChart() {
const overlayIndicators = [];
const paneIndicators = [];
// Process all indicators, filtering by visibility
activeIndicators.forEach(ind => {
if (ind.visible === false) {
return;
}
const IndicatorClass = IR?.[ind.type];
if (!IndicatorClass) return;
@ -793,37 +828,37 @@ export function drawIndicatorsOnChart() {
}
});
console.log('Rendering indicators:', { overlayCount: overlayIndicators.length, paneCount: paneIndicators.length });
// Calculate heights based on VISIBLE indicators only
const totalPanes = 1 + paneIndicators.length;
const mainPaneHeight = paneIndicators.length > 0 ? 60 : 100;
const paneHeight = paneIndicators.length > 0 ? Math.floor(40 / paneIndicators.length) : 0;
window.dashboard.chart.panes()[0]?.setHeight(mainPaneHeight);
let totalSeriesCreated = 0;
overlayIndicators.forEach(({ indicator, meta, instance }) => {
if (indicator.visible === false) {
indicator.series = [];
return;
}
const oldLen = indicator.series.length;
renderIndicatorOnPane(indicator, meta, instance, candles, 0, lineStyleMap);
totalSeriesCreated += indicator.series.length - oldLen;
});
paneIndicators.forEach(({ indicator, meta, instance }, idx) => {
if (indicator.visible === false) {
indicator.series = [];
return;
}
const paneIndex = nextPaneIndex++;
indicatorPanes.set(indicator.id, paneIndex);
const oldLen = indicator.series.length;
renderIndicatorOnPane(indicator, meta, instance, candles, paneIndex, lineStyleMap);
totalSeriesCreated += indicator.series.length - oldLen;
const pane = window.dashboard.chart.panes()[paneIndex];
if (pane) {
pane.setHeight(paneHeight);
}
});
console.log(`drawIndicatorsOnChart complete - created ${totalSeriesCreated} series for ${overlayIndicators.length + paneIndicators.length} visible indicators`);
}
function resetIndicator(id) {
@ -849,14 +884,31 @@ function removeIndicator(id) {
removeIndicatorById(id);
}
function toggleIndicatorVisibility(id) {
const indicator = activeIndicators.find(a => a.id === id);
if (!indicator) {
return;
}
indicator.visible = indicator.visible === false;
// Full redraw to ensure all indicators render correctly
if (typeof drawIndicatorsOnChart === 'function') {
drawIndicatorsOnChart();
}
renderIndicatorPanel();
}
// Export functions for module access
export { addIndicator, removeIndicatorById };
export { addIndicator, removeIndicatorById, toggleIndicatorVisibility };
// Legacy compatibility functions
window.renderIndicatorList = renderIndicatorPanel;
window.resetIndicator = resetIndicator;
window.removeIndicator = removeIndicator;
window.toggleIndicator = addIndicator;
window.toggleIndicatorVisibility = toggleIndicatorVisibility;
window.showIndicatorConfig = function(id) {
const ind = activeIndicators.find(a => a.id === id);
if (ind) configuringId = id;