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
2 changes: 1 addition & 1 deletion dashboard/backend/tests/test_admin_analytics_frontend.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ def test_app_lifecycle_and_cache_versions_are_wired():
# Lockstep owner for the console's bumped tags and the /admin page's pins:
# every bump edits this test in the same change (Global Constraints).
assert 'styles.css?v=159' in APP_HTML
assert 'app.js?v=160' in APP_HTML
assert 'app.js?v=161' in APP_HTML
assert 'js/admin-tabs.js?v=12' in APP_HTML
for tag in (
'href="admin.css?v=13"',
Expand Down
2 changes: 1 addition & 1 deletion dashboard/backend/tests/test_analytics_frontend.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def _function_body(source: str, signature: str) -> str:


def test_analytics_script_loads_between_app_and_page_scripts():
app_at = APP_HTML.index('<script src="app.js?v=160" defer></script>')
app_at = APP_HTML.index('<script src="app.js?v=161" defer></script>')
analytics_at = APP_HTML.index(
'<script src="js/analytics.js?v=1" defer></script>'
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ def test_exact_raw_ties_mark_every_tied_series_best():

def test_comparison_script_and_semantic_table_ship_before_app():
helper = '<script src="js/backtest-comparison.js?v=1" defer></script>'
app = '<script src="app.js?v=160" defer></script>'
app = '<script src="app.js?v=161" defer></script>'
assert 'href="styles.css?v=159"' in APP_HTML
assert APP_HTML.index(helper) < APP_HTML.index(app)
for element_id in (
Expand Down
2 changes: 1 addition & 1 deletion dashboard/backend/tests/test_frontend_fast_boot.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ def test_cache_busters_bumped():
# the next bump, so the exact one looks like the broken guard and gets
# "fixed" by loosening it. That collision has already cost this repo one
# round of follow-ups (#347/#348).
assert "app.js?v=160" in APP_HTML
assert "app.js?v=161" in APP_HTML
assert "js/agent-editor.js?v=32" in APP_HTML
assert "styles.css?v=159" in APP_HTML
assert "js/leaderboard.js?v=38" in APP_HTML
Expand Down
28 changes: 14 additions & 14 deletions dashboard/backend/tests/test_research_guest_shelf.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
RENDER = APP[APP.index('let researchShelfRenderVersion = 0;'):APP.index('/** The Community research card', APP.index('async function renderResearchShelf()'))]


@pytest.mark.parametrize('mode', ['guest', 'owner', 'failure'])
@pytest.mark.parametrize('mode', ['guest', 'empty_owner', 'owner', 'failure'])
def test_research_shelf_access_states(mode):
if not shutil.which('node'):
pytest.skip('Node required')
Expand All @@ -23,27 +23,27 @@ def test_research_shelf_access_states(mode):
const empty = {}, count = {};
const document = {getElementById:id=>({agentsGridResearch:grid,agentsEmptyResearch:empty,agentsCountResearch:count}[id])};
const agent = {template_id:'research',name:'Research demo',research:{},added:true};
const fetchResearchAgents = async()=> {if(mode==='owner') return [agent,{...agent,name:'Unadded',added:false}]; throw {status:mode==='guest'?401:503};};
const fetchResearchAgents = async()=> {if(mode==='empty_owner')return []; if(mode==='owner') return [agent,{...agent,name:'Unadded',added:false}]; throw {status:mode==='guest'?401:503};};
let catalogCalls=0;
const API = {get:async()=>{catalogCalls++;return {templates:[agent,{name:'Trading',template_id:'trading'}]};}};
const API_BASE='';
const templateMarketplaceShelf = a=>a.research?'research':'open';
const escapeHtml=s=>String(s??'');
const openAuthModal=()=>login=true;
const openResearchWorkbench=()=>workbench=true;
const communityShelfButtonHtml=()=>'';
const communityShelfButtonHtml=()=>'<button>Community</button>';
RENDER
(async()=>{await renderResearchShelf();if(handler)handler();console.log(JSON.stringify({html:grid.innerHTML,display:section.style.display,login,workbench,catalogCalls,error:empty.textContent}));})().catch(e=>{console.error(e);process.exit(1)});
(async()=>{await renderResearchShelf();if(handler)handler();console.log(JSON.stringify({html:grid.innerHTML,display:section.style.display,login,workbench,catalogCalls,error:empty.textContent,emptyHtml:empty.innerHTML,countHidden:count.hidden}));})().catch(e=>{console.error(e);process.exit(1)});
'''.replace('MODE', json.dumps(mode)).replace('RENDER', RENDER)
result = json.loads(subprocess.check_output(['node', '-e', script], text=True))
assert result['display'] == ''
if mode == 'guest':
assert 'Research demo' in result['html']
assert 'Sign in to use' in result['html']
assert 'research-remove-btn' not in result['html']
assert 'Trading' not in result['html']
assert result['login'] and not result['workbench']
assert result['catalogCalls'] == 1
if mode in ('guest', 'empty_owner'):
assert result['html'] == ''
assert 'No research agents yet.' in result['emptyHtml']
assert '<button>Community</button>' in result['emptyHtml']
assert result['countHidden']
assert not result['login'] and not result['workbench']
assert result['catalogCalls'] == 0
elif mode == 'owner':
assert 'Open workbench' in result['html']
assert 'Unadded' not in result['html']
Expand All @@ -67,7 +67,7 @@ def test_pending_guest_response_cannot_overwrite_signed_in_shelf(reject_old):
const catalogStarted = new Promise(resolve=>started=resolve);
const catalog = new Promise((resolve,reject)=>{resolveCatalog=resolve;rejectCatalog=reject;});
const agent = {template_id:'research',name:'Owned research',research:{},added:true};
const fetchResearchAgents = async()=>{if(signedIn)return [agent];throw {status:401};};
const fetchResearchAgents = async()=>{if(signedIn)return [agent];started();return catalog;};
const API = {get:()=>{started();return catalog;}};
const API_BASE='';
const templateMarketplaceShelf=()=> 'research';
Expand All @@ -80,8 +80,8 @@ def test_pending_guest_response_cannot_overwrite_signed_in_shelf(reject_old):
signedIn=true;
await renderResearchShelf();
const expected=grid.innerHTML;
if(REJECT)rejectCatalog(new Error('Late failure'));
else resolveCatalog({templates:[{...agent,name:'Guest research'}]});
if(REJECT)rejectCatalog({status:401});
else resolveCatalog([]);
await oldRender;
console.log(JSON.stringify({unchanged:expected===grid.innerHTML,html:grid.innerHTML,error:empty.textContent}));
})().catch(e=>{console.error(e);process.exit(1)});
Expand Down
2 changes: 1 addition & 1 deletion dashboard/frontend/app.html
Original file line number Diff line number Diff line change
Expand Up @@ -2512,7 +2512,7 @@ <h2 id="creditsRefundTitle">Refund Credits purchase</h2>
<script src="market-events/MarketEventFeed.js" defer></script>
<script src="js/portfolio.js?v=18" defer></script>
<script src="js/backtest-comparison.js?v=1" defer></script>
<script src="app.js?v=160" defer></script>
<script src="app.js?v=161" defer></script>
<script src="js/analytics.js?v=1" defer></script>
<script src="js/agent-editor.js?v=32" defer></script>
<script src="js/credit-format.js?v=1" defer></script>
Expand Down
15 changes: 6 additions & 9 deletions dashboard/frontend/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -13381,16 +13381,14 @@ async function renderResearchShelf() {
const section = grid.closest('.agents-category');
if (section) section.style.display = '';
let agents = [];
let guest = false;
try {
try {
agents = await fetchResearchAgents();
} catch (error) {
if (renderVersion !== researchShelfRenderVersion) return;
if (error?.status !== 401) throw error;
guest = true;
const catalog = await API.get(`${API_BASE}/api/v1/agents/marketplace`);
agents = (catalog.templates || []).filter(agent => templateMarketplaceShelf(agent) === 'research');
// Guests share the unadded shelf state; discovery lives in Community.
agents = [];
}
} catch (error) {
if (renderVersion !== researchShelfRenderVersion) return;
Expand All @@ -13403,7 +13401,7 @@ async function renderResearchShelf() {
return;
}
if (renderVersion !== researchShelfRenderVersion) return;
const added = guest ? agents : agents.filter((agent) => agent.added);
const added = agents.filter((agent) => agent.added);
if (countEl) {
countEl.textContent = String(added.length);
countEl.hidden = added.length === 0;
Expand All @@ -13412,7 +13410,7 @@ async function renderResearchShelf() {
grid.innerHTML = '';
if (emptyEl) {
emptyEl.hidden = false;
emptyEl.innerHTML = 'No research agents yet. Add one from '
emptyEl.innerHTML = 'No research agents yet. Add a research agent from '
+ communityShelfButtonHtml('all') + '.';
}
return;
Expand All @@ -13432,14 +13430,13 @@ async function renderResearchShelf() {
<svg class="ui-icon research-fact-icon" aria-hidden="true"><use href="#icon-file-text"></use></svg> ${escapeHtml(((agent.research || {}).output_formats || []).join(' / '))}
</p>
<div class="research-agent-card-actions">
<button type="button" class="auth-btn auth-btn-primary research-open-btn">${guest ? 'Sign in to use' : 'Open workbench'}</button>
${guest ? '' : `<button type="button" class="research-remove-btn" data-remove-template-id="${escapeHtml(agent.template_id)}" data-agent-name="${escapeHtml(agent.name)}">Remove</button>`}
<button type="button" class="auth-btn auth-btn-primary research-open-btn">Open workbench</button>
<button type="button" class="research-remove-btn" data-remove-template-id="${escapeHtml(agent.template_id)}" data-agent-name="${escapeHtml(agent.name)}">Remove</button>
</div>
</article>`;
}).join('');
grid.querySelectorAll('.research-agent-card').forEach((card) => {
card.querySelector('.research-open-btn')?.addEventListener('click', () => {
if (guest) { openAuthModal('login'); return; }
openResearchWorkbench(card.dataset.templateId);
});
card.querySelector('.research-remove-btn')?.addEventListener('click', async (event) => {
Expand Down
Loading