secubox-openwrt/luci-app-secubox/htdocs/luci-static/resources/view/secubox/dev-status.js
2025-12-29 09:03:49 +01:00

583 lines
14 KiB
JavaScript

'use strict';
'require view';
'require ui';
'require poll';
'require rpc';
'require secubox/api as API';
'require secubox/nav as SecuNav';
/**
* SecuBox Development Status View (LuCI)
* Real-time development progress tracker for LuCI interface
*/
return view.extend({
statusData: {},
// Development milestones data
milestones: {
'modules-core': {
name: _('Core Modules'),
progress: 100,
total: 13,
completed: 13,
icon: '📦',
color: '#10b981',
items: [
{ name: 'Bandwidth Manager', status: 'completed' },
{ name: 'Auth Guardian', status: 'completed' },
{ name: 'Media Flow', status: 'completed' },
{ name: 'VHost Manager', status: 'completed' },
{ name: 'CrowdSec Dashboard', status: 'completed' },
{ name: 'WireGuard Dashboard', status: 'completed' },
{ name: 'Netdata Dashboard', status: 'completed' },
{ name: 'Netifyd Dashboard', status: 'completed' },
{ name: 'Client Guardian', status: 'completed' },
{ name: 'Network Modes', status: 'completed' },
{ name: 'Traffic Shaper', status: 'completed' },
{ name: 'CDN Cache', status: 'completed' },
{ name: 'SecuBox Hub', status: 'completed' }
]
},
'hardware-support': {
name: _('Hardware Support'),
progress: 95,
total: 4,
completed: 3,
icon: '🔧',
color: '#f59e0b',
items: [
{ name: 'ESPRESSObin Ultra', status: 'completed' },
{ name: 'Sheeva64 (WiFi 6)', status: 'completed' },
{ name: 'MOCHAbin (10GbE)', status: 'completed' },
{ name: 'Performance Optimization', status: 'in-progress' }
]
},
'integration': {
name: _('Integration & Testing'),
progress: 85,
total: 6,
completed: 5,
icon: '🧪',
color: '#3b82f6',
items: [
{ name: 'LuCI Integration', status: 'completed' },
{ name: 'RPCD Backends', status: 'completed' },
{ name: 'ubus APIs', status: 'completed' },
{ name: 'Multi-platform Build', status: 'completed' },
{ name: 'Documentation', status: 'completed' },
{ name: 'Beta Testing Program', status: 'in-progress' }
]
},
'campaign-prep': {
name: _('Campaign Preparation'),
progress: 70,
total: 5,
completed: 3,
icon: '🚀',
color: '#8b5cf6',
items: [
{ name: 'Website Multi-language', status: 'completed' },
{ name: 'Demo Pages', status: 'completed' },
{ name: 'Video Tutorials', status: 'in-progress' },
{ name: 'Marketing Materials', status: 'in-progress' },
{ name: 'Crowdfunding Setup', status: 'planned' }
]
}
},
// Timeline data
timeline: [
{
phase: _('Phase 1'),
name: _('Core Development'),
period: 'Q4 2024 - Q1 2025',
status: 'completed',
progress: 100
},
{
phase: _('Phase 2'),
name: _('Advanced Modules'),
period: 'Q1 - Q2 2025',
status: 'completed',
progress: 100
},
{
phase: _('Phase 3'),
name: _('Hardware Integration'),
period: 'Q2 - Q4 2025',
status: 'in-progress',
progress: 95
},
{
phase: _('Phase 4'),
name: _('Beta Testing'),
period: 'Q1 2026',
status: 'in-progress',
progress: 40
},
{
phase: _('Phase 5'),
name: _('Crowdfunding Campaign'),
period: 'Q2 2026',
status: 'planned',
progress: 20
},
{
phase: _('Phase 6'),
name: _('Production & Delivery'),
period: 'Q3 - Q4 2026',
status: 'planned',
progress: 0
}
],
// Project statistics
stats: {
modulesCount: 13,
languagesSupported: 11,
architectures: 4,
linesOfCode: 15000,
contributors: 3,
commits: 450,
openIssues: 12,
closedIssues: 87
},
/**
* Calculate overall progress
*/
getOverallProgress: function() {
var milestones = Object.values(this.milestones);
var totalProgress = 0;
for (var i = 0; i < milestones.length; i++) {
totalProgress += milestones[i].progress;
}
return Math.round(totalProgress / milestones.length);
},
/**
* Get status icon
*/
getStatusIcon: function(status) {
var icons = {
'completed': '✅',
'in-progress': '🔄',
'planned': '📋'
};
return icons[status] || '⚪';
},
/**
* Render milestone card
*/
renderMilestone: function(key, milestone) {
var items = milestone.items.map(function(item) {
var statusClass = 'dsw-item-' + item.status;
return E('div', { 'class': 'dsw-item ' + statusClass }, [
E('span', { 'class': 'dsw-item-icon' }, this.getStatusIcon(item.status)),
E('span', { 'class': 'dsw-item-name' }, item.name)
]);
}.bind(this));
return E('div', { 'class': 'cbi-section', 'data-key': key }, [
E('div', { 'class': 'dsw-milestone-header' }, [
E('div', { 'class': 'dsw-milestone-info' }, [
E('span', { 'class': 'dsw-milestone-icon' }, milestone.icon),
E('span', { 'class': 'dsw-milestone-name' }, milestone.name)
]),
E('div', { 'class': 'dsw-milestone-stats' }, [
E('span', { 'class': 'dsw-milestone-count' },
milestone.completed + '/' + milestone.total),
E('span', { 'class': 'dsw-milestone-percent' },
{ 'style': 'color: ' + milestone.color },
milestone.progress + '%')
])
]),
E('div', { 'class': 'cbi-progressbar', 'title': milestone.progress + '%' }, [
E('div', {
'style': 'width: ' + milestone.progress + '%; background: ' + milestone.color
})
]),
E('div', { 'class': 'dsw-milestone-items' }, items)
]);
},
/**
* Render timeline item
*/
renderTimelineItem: function(phase, index, total) {
var statusClass = 'dsw-timeline-' + phase.status;
var showLine = index < total - 1;
return E('div', { 'class': 'dsw-timeline-item ' + statusClass }, [
E('div', { 'class': 'dsw-timeline-marker' }, [
E('div', { 'class': 'dsw-timeline-dot' }),
showLine ? E('div', { 'class': 'dsw-timeline-line' }) : null
]),
E('div', { 'class': 'dsw-timeline-content' }, [
E('div', { 'class': 'dsw-timeline-header' }, [
E('span', { 'class': 'dsw-timeline-phase' }, phase.phase),
E('span', { 'class': 'dsw-timeline-period' }, phase.period)
]),
E('div', { 'class': 'dsw-timeline-name' }, phase.name),
E('div', { 'class': 'cbi-progressbar', 'title': phase.progress + '%' }, [
E('div', { 'style': 'width: ' + phase.progress + '%' })
])
])
]);
},
/**
* Render statistics grid
*/
renderStats: function() {
return E('div', { 'class': 'dsw-stats-grid' }, [
E('div', { 'class': 'dsw-stat' }, [
E('div', { 'class': 'dsw-stat-value' }, String(this.stats.modulesCount)),
E('div', { 'class': 'dsw-stat-label' }, _('Modules'))
]),
E('div', { 'class': 'dsw-stat' }, [
E('div', { 'class': 'dsw-stat-value' }, String(this.stats.languagesSupported)),
E('div', { 'class': 'dsw-stat-label' }, _('Languages'))
]),
E('div', { 'class': 'dsw-stat' }, [
E('div', { 'class': 'dsw-stat-value' }, String(this.stats.architectures)),
E('div', { 'class': 'dsw-stat-label' }, _('Architectures'))
]),
E('div', { 'class': 'dsw-stat' }, [
E('div', { 'class': 'dsw-stat-value' }, (this.stats.linesOfCode / 1000).toFixed(1) + 'k'),
E('div', { 'class': 'dsw-stat-label' }, _('Lines of Code'))
]),
E('div', { 'class': 'dsw-stat' }, [
E('div', { 'class': 'dsw-stat-value' }, String(this.stats.contributors)),
E('div', { 'class': 'dsw-stat-label' }, _('Contributors'))
]),
E('div', { 'class': 'dsw-stat' }, [
E('div', { 'class': 'dsw-stat-value' }, String(this.stats.commits)),
E('div', { 'class': 'dsw-stat-label' }, _('Commits'))
]),
E('div', { 'class': 'dsw-stat' }, [
E('div', { 'class': 'dsw-stat-value' }, String(this.stats.openIssues)),
E('div', { 'class': 'dsw-stat-label' }, _('Open Issues'))
]),
E('div', { 'class': 'dsw-stat' }, [
E('div', { 'class': 'dsw-stat-value' }, String(this.stats.closedIssues)),
E('div', { 'class': 'dsw-stat-label' }, _('Closed Issues'))
])
]);
},
/**
* Load view
*/
load: function() {
var self = this;
return API.getStatus().then(function(status) {
self.statusData = status || {};
return status;
});
},
/**
* Render view
*/
render: function() {
var overallProgress = this.getOverallProgress();
// Render milestones
var milestones = [];
for (var key in this.milestones) {
milestones.push(this.renderMilestone(key, this.milestones[key]));
}
// Render timeline
var timelineItems = [];
for (var i = 0; i < this.timeline.length; i++) {
timelineItems.push(
this.renderTimelineItem(this.timeline[i], i, this.timeline.length)
);
}
var main = E('div', { 'class': 'secubox-dev-body' }, [
E('h2', { 'class': 'section-title' }, _('Development Status')),
E('div', { 'class': 'cbi-map-descr' },
_('Real-time project progress tracker showing SecuBox development milestones and achievements.')),
E('div', { 'class': 'cbi-section' }, [
E('div', { 'class': 'dsw-header' }, [
E('div', { 'class': 'dsw-overall-badge' }, [
E('div', { 'class': 'dsw-progress-value' }, overallProgress + '%'),
E('div', { 'class': 'dsw-progress-label' }, _('Overall Progress'))
])
])
]),
E('fieldset', { 'class': 'cbi-section' }, [
E('legend', {}, _('Development Milestones')),
E('div', { 'class': 'dsw-milestones-grid' }, milestones)
]),
E('fieldset', { 'class': 'cbi-section' }, [
E('legend', {}, _('Project Timeline')),
E('div', { 'class': 'dsw-timeline-container' }, timelineItems)
]),
E('fieldset', { 'class': 'cbi-section' }, [
E('legend', {}, _('Project Statistics')),
this.renderStats()
]),
E('style', {}, `
.dsw-header {
text-align: center;
padding: 20px;
margin-bottom: 20px;
}
.dsw-overall-badge {
display: inline-block;
background: linear-gradient(135deg, #10b981, #06b6d4);
padding: 24px 48px;
border-radius: 12px;
color: white;
}
.dsw-progress-value {
font-size: 48px;
font-weight: 800;
line-height: 1;
}
.dsw-progress-label {
font-size: 14px;
opacity: 0.9;
margin-top: 8px;
}
.dsw-milestone-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
}
.dsw-milestone-info {
display: flex;
align-items: center;
gap: 10px;
}
.dsw-milestone-icon {
font-size: 24px;
}
.dsw-milestone-name {
font-size: 16px;
font-weight: 700;
}
.dsw-milestone-stats {
display: flex;
align-items: center;
gap: 12px;
font-size: 14px;
}
.dsw-milestone-count {
opacity: 0.7;
}
.dsw-milestone-percent {
font-weight: 700;
}
.dsw-milestone-items {
display: flex;
flex-direction: column;
gap: 8px;
margin-top: 12px;
}
.dsw-item {
display: flex;
align-items: center;
gap: 8px;
font-size: 13px;
padding: 6px 0;
}
.dsw-item-icon {
font-size: 14px;
}
.dsw-item-completed {
opacity: 0.7;
}
.dsw-item-in-progress {
color: #f59e0b;
}
.dsw-item-planned {
opacity: 0.5;
}
.dsw-milestones-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 16px;
}
.dsw-timeline-container {
display: flex;
flex-direction: column;
gap: 0;
}
.dsw-timeline-item {
display: flex;
gap: 20px;
}
.dsw-timeline-marker {
display: flex;
flex-direction: column;
align-items: center;
padding-top: 8px;
}
.dsw-timeline-dot {
width: 16px;
height: 16px;
border-radius: 50%;
background: #ccc;
z-index: 1;
}
.dsw-timeline-completed .dsw-timeline-dot {
background: #10b981;
}
.dsw-timeline-in-progress .dsw-timeline-dot {
background: #f59e0b;
animation: pulse 2s infinite;
}
.dsw-timeline-line {
width: 2px;
flex: 1;
background: #ccc;
margin-top: 4px;
}
.dsw-timeline-completed .dsw-timeline-line {
background: #10b981;
}
.dsw-timeline-content {
flex: 1;
padding-bottom: 24px;
}
.dsw-timeline-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 8px;
}
.dsw-timeline-phase {
font-size: 12px;
font-weight: 700;
color: #06b6d4;
text-transform: uppercase;
}
.dsw-timeline-period {
font-size: 12px;
opacity: 0.7;
}
.dsw-timeline-name {
font-size: 16px;
font-weight: 600;
margin-bottom: 8px;
}
.dsw-stats-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
gap: 16px;
}
.dsw-stat {
text-align: center;
padding: 20px;
background: rgba(16, 185, 129, 0.1);
border-radius: 8px;
}
.dsw-stat-value {
font-size: 32px;
font-weight: 800;
color: #10b981;
margin-bottom: 4px;
}
.dsw-stat-label {
font-size: 12px;
opacity: 0.7;
}
@keyframes pulse {
0%, 100% { box-shadow: 0 0 0 0 rgba(249, 115, 22, 0.7); }
50% { box-shadow: 0 0 0 10px rgba(249, 115, 22, 0); }
}
`)
]);
return E('div', { 'class': 'secubox-dev-status-page' }, [
E('link', { 'rel': 'stylesheet', 'href': L.resource('secubox/common.css') }),
SecuNav.renderTabs('dev-status'),
this.renderHeader(),
main
]);
},
renderHeader: function() {
var widget = this.getWidget();
var currentPhase = widget.getCurrentPhase() || {};
var status = this.statusData || {};
return E('div', { 'class': 'sh-page-header sh-page-header-lite' }, [
E('div', {}, [
E('h2', { 'class': 'sh-page-title' }, [
E('span', { 'class': 'sh-page-title-icon' }, '🚀'),
_('Development Status')
]),
E('p', { 'class': 'sh-page-subtitle' },
_('SecuBox roadmap, milestones, and release planning.'))
]),
E('div', { 'class': 'sh-header-meta' }, [
this.renderHeaderChip('🏷️', _('Version'), status.version || _('Unknown')),
this.renderHeaderChip('📈', _('Overall'), this.getOverallProgress() + '%'),
this.renderHeaderChip('📅', _('Current phase'),
currentPhase.phase ? currentPhase.phase + ' · ' + currentPhase.name : _('Not set'))
])
]);
},
renderHeaderChip: function(icon, label, value) {
return E('div', { 'class': 'sh-header-chip' }, [
E('span', { 'class': 'sh-chip-icon' }, icon),
E('div', { 'class': 'sh-chip-text' }, [
E('span', { 'class': 'sh-chip-label' }, label),
E('strong', {}, value.toString())
])
]);
},
handleSaveApply: null,
handleSave: null,
handleReset: null
});