- Theme: momentry (custom theme with REST API routes) - Plugins: code-snippets (contains all API proxies) - Languages: zh_TW translations - Excludes: cache, backups, uploads, logs
249 lines
10 KiB
JavaScript
249 lines
10 KiB
JavaScript
(function($) {
|
|
'use strict';
|
|
|
|
const MomentryPortal = {
|
|
apiRoot: momentryApi.root,
|
|
nonce: momentryApi.nonce,
|
|
|
|
init: function() {
|
|
this.bindEvents();
|
|
this.loadIdentities();
|
|
},
|
|
|
|
bindEvents: function() {
|
|
$(document).on('click', '.identity-card', this.showIdentityDetail.bind(this));
|
|
$(document).on('click', '.angle-coverage-btn', this.showAngleCoverage.bind(this));
|
|
$(document).on('click', '.body-actions-btn', this.showBodyActions.bind(this));
|
|
},
|
|
|
|
request: function(endpoint, method, data) {
|
|
return $.ajax({
|
|
url: this.apiRoot + endpoint,
|
|
method: method,
|
|
data: data,
|
|
beforeSend: function(xhr) {
|
|
xhr.setRequestHeader('X-WP-Nonce', momentryApi.nonce);
|
|
},
|
|
});
|
|
},
|
|
|
|
loadIdentities: function(page = 1) {
|
|
const self = this;
|
|
|
|
this.request('momentry/v1/identities', 'GET', {page: page, per_page: 20})
|
|
.done(function(response) {
|
|
if (response.success) {
|
|
self.renderIdentityList(response.data);
|
|
self.renderPagination(response.pagination);
|
|
}
|
|
})
|
|
.fail(function(error) {
|
|
console.error('Failed to load identities:', error);
|
|
$('.identity-list').html('<p class="error">Failed to load identities. Please try again.</p>');
|
|
});
|
|
},
|
|
|
|
renderIdentityList: function(identities) {
|
|
const html = identities.map(function(identity) {
|
|
return `
|
|
<div class="identity-card" data-uuid="${identity.uuid}">
|
|
<h3 class="identity-name">${identity.name}</h3>
|
|
<div class="identity-meta">
|
|
<span class="source badge">${identity.source}</span>
|
|
<span class="references">${identity.total_references} vectors</span>
|
|
</div>
|
|
<div class="quality-score">
|
|
<div class="score-bar" style="width: ${(identity.quality_avg || 0) * 100}%"></div>
|
|
<span class="score-value">${((identity.quality_avg || 0) * 100).toFixed(1)}%</span>
|
|
</div>
|
|
${identity.trace_duration ? `
|
|
<div class="trace-stats">
|
|
<span class="duration">${identity.trace_duration}s</span>
|
|
<span class="confidence">${(identity.trace_confidence * 100).toFixed(1)}% confidence</span>
|
|
</div>
|
|
` : ''}
|
|
<div class="identity-actions">
|
|
<button class="btn angle-coverage-btn" data-uuid="${identity.uuid}">
|
|
Angle Coverage
|
|
</button>
|
|
<button class="btn body-actions-btn" data-uuid="${identity.uuid}">
|
|
Body Actions
|
|
</button>
|
|
</div>
|
|
</div>
|
|
`;
|
|
}).join('');
|
|
|
|
$('.identity-list').html(html);
|
|
},
|
|
|
|
renderPagination: function(pagination) {
|
|
const html = `
|
|
<div class="pagination">
|
|
<button class="btn prev" ${pagination.page === 1 ? 'disabled' : ''}>
|
|
Previous
|
|
</button>
|
|
<span class="page-info">
|
|
Page ${pagination.page} of ${pagination.total_pages}
|
|
</span>
|
|
<button class="btn next" ${pagination.page >= pagination.total_pages ? 'disabled' : ''}>
|
|
Next
|
|
</button>
|
|
</div>
|
|
`;
|
|
|
|
$('.pagination-container').html(html);
|
|
},
|
|
|
|
showIdentityDetail: function(e) {
|
|
const uuid = $(e.currentTarget).data('uuid');
|
|
const self = this;
|
|
|
|
this.request(`momentry/v1/identities/${uuid}`, 'GET')
|
|
.done(function(response) {
|
|
if (response.success) {
|
|
self.renderIdentityDetail(response.data);
|
|
}
|
|
})
|
|
.fail(function(error) {
|
|
console.error('Failed to load identity detail:', error);
|
|
});
|
|
},
|
|
|
|
renderIdentityDetail: function(identity) {
|
|
const html = `
|
|
<div class="identity-detail-modal">
|
|
<h2>${identity.name}</h2>
|
|
<div class="detail-section">
|
|
<h3>Reference Vectors</h3>
|
|
<p>Total: ${identity.reference_vectors.total}</p>
|
|
<p>Angles: ${identity.reference_vectors.angles.join(', ') || 'None'}</p>
|
|
<p>Quality Avg: ${((identity.reference_vectors.quality_avg || 0) * 100).toFixed(1)}%</p>
|
|
</div>
|
|
${identity.trace_stats ? `
|
|
<div class="detail-section">
|
|
<h3>Trace Statistics</h3>
|
|
<p>Duration: ${identity.trace_stats.duration_seconds}s</p>
|
|
<p>Confidence: ${(identity.trace_stats.avg_confidence * 100).toFixed(1)}%</p>
|
|
<p>Appearances: ${identity.trace_stats.total_appearances} frames</p>
|
|
</div>
|
|
` : ''}
|
|
<button class="btn close-modal">Close</button>
|
|
</div>
|
|
`;
|
|
|
|
$('.modal-container').html(html).show();
|
|
},
|
|
|
|
showAngleCoverage: function(e) {
|
|
e.stopPropagation();
|
|
const uuid = $(e.currentTarget).data('uuid');
|
|
const self = this;
|
|
|
|
this.request(`momentry/v1/identities/${uuid}/angle-coverage`, 'GET')
|
|
.done(function(response) {
|
|
if (response.success) {
|
|
self.renderAngleCoverage(response.data);
|
|
}
|
|
})
|
|
.fail(function(error) {
|
|
console.error('Failed to load angle coverage:', error);
|
|
});
|
|
},
|
|
|
|
renderAngleCoverage: function(data) {
|
|
const angles = Object.entries(data.angles).map(function([angle, stats]) {
|
|
const statusIcon = stats.status === 'dominant' ? '✅' :
|
|
stats.status === 'present' ? '✅' : '⚠️';
|
|
const count = stats.count > 0 ? `${stats.count} frames` : '0 frames';
|
|
const quality = stats.quality_avg ? `(${(stats.quality_avg * 100).toFixed(1)}%)` : '';
|
|
|
|
return `
|
|
<div class="angle-item ${stats.status}">
|
|
<span class="status-icon">${statusIcon}</span>
|
|
<span class="angle-name">${angle.replace('_', ' ')}</span>
|
|
<span class="count">${count} ${quality}</span>
|
|
</div>
|
|
`;
|
|
}).join('');
|
|
|
|
const html = `
|
|
<div class="angle-coverage-modal">
|
|
<h2>Angle Coverage</h2>
|
|
<div class="coverage-score">
|
|
Coverage Score: ${data.score}%
|
|
</div>
|
|
<div class="angles-list">
|
|
${angles}
|
|
</div>
|
|
<p class="recommendation">${data.recommendation}</p>
|
|
<button class="btn close-modal">Close</button>
|
|
</div>
|
|
`;
|
|
|
|
$('.modal-container').html(html).show();
|
|
},
|
|
|
|
showBodyActions: function(e) {
|
|
e.stopPropagation();
|
|
const uuid = $(e.currentTarget).data('uuid');
|
|
const self = this;
|
|
|
|
this.request(`momentry/v1/identities/${uuid}/body-actions`, 'GET')
|
|
.done(function(response) {
|
|
if (response.success) {
|
|
self.renderBodyActions(response.data);
|
|
}
|
|
})
|
|
.fail(function(error) {
|
|
console.error('Failed to load body actions:', error);
|
|
});
|
|
},
|
|
|
|
renderBodyActions: function(data) {
|
|
const actions = Object.entries(data.actions || {}).map(function([category, items]) {
|
|
const itemsHtml = items.map(function(item) {
|
|
return `<span class="action-badge">${item.action}: ${item.count}</span>`;
|
|
}).join('');
|
|
|
|
return `
|
|
<div class="action-category">
|
|
<h4>${category}</h4>
|
|
<div class="action-list">${itemsHtml}</div>
|
|
</div>
|
|
`;
|
|
}).join('');
|
|
|
|
const html = `
|
|
<div class="body-actions-modal">
|
|
<h2>Body Actions: ${data.name}</h2>
|
|
<div class="actions-container">
|
|
${actions || '<p>No body actions detected</p>'}
|
|
</div>
|
|
<button class="btn close-modal">Close</button>
|
|
</div>
|
|
`;
|
|
|
|
$('.modal-container').html(html).show();
|
|
},
|
|
};
|
|
|
|
$(document).ready(function() {
|
|
MomentryPortal.init();
|
|
|
|
$(document).on('click', '.close-modal', function() {
|
|
$('.modal-container').hide();
|
|
});
|
|
|
|
$(document).on('click', '.pagination .prev:not([disabled])', function() {
|
|
const page = parseInt($('.page-info').text().match(/Page (\d+)/)[1]);
|
|
MomentryPortal.loadIdentities(page - 1);
|
|
});
|
|
|
|
$(document).on('click', '.pagination .next:not([disabled])', function() {
|
|
const page = parseInt($('.page-info').text().match(/Page (\d+)/)[1]);
|
|
MomentryPortal.loadIdentities(page + 1);
|
|
});
|
|
});
|
|
|
|
})(jQuery); |