Skip to content

Commit 3e76a71

Browse files
committed
WIP: date format issue and restructure of menu
1 parent f992b57 commit 3e76a71

File tree

9 files changed

+333
-19
lines changed

9 files changed

+333
-19
lines changed

embabel-database-server/src/main/kotlin/com/embabel/database/server/controller/DirectAgentController.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,14 @@ class DirectAgentController {
4242
//return
4343
return ResponseEntity.ok(agentProcess.id)
4444
}
45+
46+
@GetMapping("/{agentName}/processes")
47+
fun getProcessesForAgent(@PathVariable agentName: String): ResponseEntity<List<String>> {
48+
val processIds = agentExecutionService.getProcessIds(agentName)
49+
return if (processIds.isEmpty()) {
50+
ResponseEntity.notFound().build()
51+
} else {
52+
ResponseEntity.ok(processIds)
53+
}
54+
}
4555
}

embabel-database-server/src/main/kotlin/com/embabel/database/server/service/AgentExecutionService.kt

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,17 @@ import com.embabel.agent.core.ProcessOptions;
2323
import org.springframework.scheduling.annotation.Async
2424
import org.springframework.stereotype.Service
2525

26+
import java.util.concurrent.ConcurrentHashMap
27+
28+
object AgentProcessRegistry {
29+
val processMap: MutableMap<String, String> = ConcurrentHashMap()
30+
31+
fun getProcessIdsByAgentName(agentName: String): List<String> {
32+
return processMap.filterValues { it == agentName }.keys.toList()
33+
}
34+
}
35+
36+
2637
@Service
2738
class AgentExecutionService(
2839
private val agentFactory: AgentPlatform
@@ -32,6 +43,9 @@ class AgentExecutionService(
3243
val agent = agentFactory.agents().find { it.name == agentName } ?: throw IllegalArgumentException("Agent with name $agentName not found")
3344
val processOptions = ProcessOptions.DEFAULT
3445
val agentProcess = agentFactory.createAgentProcess(agent, processOptions, emptyMap<String, Any>())
46+
//update the registry
47+
AgentProcessRegistry.processMap[agentProcess.id] = agentName
48+
//return
3549
return agentProcess
3650
}
3751

@@ -42,4 +56,13 @@ class AgentExecutionService(
4256
agentProcess.run()
4357
}
4458

59+
fun getProcessIds(agentName: String) : List<String> {
60+
val processIds = AgentProcessRegistry.getProcessIdsByAgentName(agentName)
61+
return if (processIds.isEmpty()) {
62+
emptyList()
63+
} else {
64+
processIds
65+
} //end if
66+
}
67+
4568
}
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
import { defineMock } from 'vite-plugin-mock-dev-server'
2+
3+
export default defineMock({
4+
url: '/api/v1/platform-info/agents',
5+
method: 'GET',
6+
body: () => [
7+
{
8+
"name": "AiModelRepositoryAgent",
9+
"provider": "com.embabel.database.agent",
10+
"version": "0.1.0-SNAPSHOT",
11+
"description": "Discovers and loads AI models from various sources",
12+
"goals": [
13+
{
14+
"name": "com.embabel.database.agent.AiModelRepositoryAgent.maintainCatalog",
15+
"description": "Retrieves latest models and updates the repository",
16+
"pre": [
17+
"hasRun_com.embabel.database.agent.AiModelRepositoryAgent.maintainCatalog",
18+
"it:com.embabel.database.agent.ListModelMetadata",
19+
"it:java.time.LocalDateTime"
20+
],
21+
"inputs": [
22+
"it:java.time.LocalDateTime"
23+
],
24+
"outputClass": "java.time.LocalDateTime",
25+
"value": 0.0,
26+
"tags": [],
27+
"examples": [],
28+
"export": {
29+
"name": null,
30+
"remote": false,
31+
"local": true,
32+
"startingInputTypes": []
33+
}
34+
}
35+
],
36+
"actions": [
37+
{
38+
"name": "com.embabel.database.agent.AiModelRepositoryAgent.maintainCatalog",
39+
"description": "maintainCatalog",
40+
"inputs": [
41+
"it:com.embabel.database.agent.ListModelMetadata"
42+
],
43+
"outputs": [
44+
"it:java.time.LocalDateTime"
45+
],
46+
"preconditions": {
47+
"it:com.embabel.database.agent.ListModelMetadata": "TRUE",
48+
"it:java.time.LocalDateTime": "FALSE",
49+
"hasRun_com.embabel.database.agent.AiModelRepositoryAgent.maintainCatalog": "FALSE"
50+
},
51+
"effects": {
52+
"it:java.time.LocalDateTime": "TRUE",
53+
"hasRun_com.embabel.database.agent.AiModelRepositoryAgent.maintainCatalog": "TRUE"
54+
},
55+
"cost": 0.0,
56+
"value": 0.0,
57+
"canRerun": false,
58+
"qos": {
59+
"maxAttempts": 5,
60+
"backoffMillis": 10000,
61+
"backoffMultiplier": 5.0,
62+
"backoffMaxInterval": 60000,
63+
"idempotent": false,
64+
"retryPolicy": {
65+
"maxAttempts": -1
66+
}
67+
}
68+
},
69+
{
70+
"name": "com.embabel.database.agent.AiModelRepositoryAgent.discoverModels",
71+
"description": "discoverModels",
72+
"inputs": [],
73+
"outputs": [
74+
"it:com.embabel.database.agent.ListModelMetadata"
75+
],
76+
"preconditions": {
77+
"repository_needs_refresh": "TRUE",
78+
"it:com.embabel.database.agent.ListModelMetadata": "FALSE",
79+
"hasRun_com.embabel.database.agent.AiModelRepositoryAgent.discoverModels": "FALSE"
80+
},
81+
"effects": {
82+
"it:com.embabel.database.agent.ListModelMetadata": "TRUE",
83+
"hasRun_com.embabel.database.agent.AiModelRepositoryAgent.discoverModels": "TRUE"
84+
},
85+
"cost": 0.0,
86+
"value": 0.0,
87+
"canRerun": false,
88+
"qos": {
89+
"maxAttempts": 5,
90+
"backoffMillis": 10000,
91+
"backoffMultiplier": 5.0,
92+
"backoffMaxInterval": 60000,
93+
"idempotent": false,
94+
"retryPolicy": {
95+
"maxAttempts": -1
96+
}
97+
}
98+
},
99+
{
100+
"name": "com.embabel.database.agent.AiModelRepositoryAgent.validateModels",
101+
"description": "validateModels",
102+
"inputs": [
103+
"it:com.embabel.database.agent.ListModelMetadata"
104+
],
105+
"outputs": [
106+
"it:com.embabel.database.agent.ListModelMetadata"
107+
],
108+
"preconditions": {
109+
"have_models": "TRUE",
110+
"it:com.embabel.database.agent.ListModelMetadata": "TRUE",
111+
"hasRun_com.embabel.database.agent.AiModelRepositoryAgent.validateModels": "FALSE"
112+
},
113+
"effects": {
114+
"it:com.embabel.database.agent.ListModelMetadata": "TRUE",
115+
"hasRun_com.embabel.database.agent.AiModelRepositoryAgent.validateModels": "TRUE"
116+
},
117+
"cost": 0.0,
118+
"value": 0.0,
119+
"canRerun": false,
120+
"qos": {
121+
"maxAttempts": 5,
122+
"backoffMillis": 10000,
123+
"backoffMultiplier": 5.0,
124+
"backoffMaxInterval": 60000,
125+
"idempotent": false,
126+
"retryPolicy": {
127+
"maxAttempts": -1
128+
}
129+
}
130+
}
131+
],
132+
"conditions": [
133+
"repository_needs_refresh",
134+
"have_models"
135+
]
136+
}
137+
]
138+
},{
139+
url: '/api/v1/agents/AiModelRepositoryAgent/processes',
140+
method: 'GET',
141+
body: () => [
142+
"zealous_roentgen"
143+
]
144+
},{
145+
url: '/api/v1/process/zealous_roentgen',
146+
method: 'GET',
147+
body: () => ({
148+
"id": "zealous_roentgen",
149+
"status": "COMPLETED",
150+
"timestamp": "2025-08-30T15:30:28.691605Z",
151+
"runningTime": "PT15.588515S",
152+
"result": "2025-08-30T18:30:31.996141",
153+
"statusUrl": "/api/v1/process/zealous_roentgen",
154+
"sseUrl": "/events/process/zealous_roentgen/status"
155+
})
156+
})
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { defineMock } from 'vite-plugin-mock-dev-server'
2+
import { randomUUID } from 'crypto'
3+
4+
export default defineMock({
5+
url: '/api/v1/agents/AiModelRepositoryAgent',
6+
method: 'POST',
7+
body: ({ params }) => {
8+
const { agentId } = 'zealous_roentgen';
9+
return agentId;
10+
}
11+
})

embabel-database-ui/src/App.jsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@ import Home from './components/pages/Home';
77
import Search from './components/pages/Search';
88
import Tags from './components/pages/Tags';
99
import Providers from './components/pages/Providers';
10+
import Maintenance from './components/pages/Maintenance';
1011
//components
11-
import Menu from './components/layout/Menu';
12+
import MenuBlock from './components/layout/MenuBlock';
1213

1314
function App() {
1415

@@ -17,14 +18,15 @@ function App() {
1718
<Router>
1819
<div id="main-page">
1920
<div id="left-column">
20-
<Menu/>
21+
<MenuBlock/>
2122
</div>
2223
<div id="content">
2324
<Routes>
2425
<Route exact path="/" element={<Home/>}/>
2526
<Route path="/search" element={<Search/>}/>
2627
<Route path="/tags" element={<Tags/>}/>
2728
<Route path="/providers" element={<Providers/>}/>
29+
<Route path="/agent/maintenance" element={<Maintenance/>}/>
2830
</Routes>
2931
</div>
3032
</div>

embabel-database-ui/src/components/layout/AppData.jsx

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { version } from '../../../package.json';
33

44
import { formatDate } from "../../utils/formatDate";
55

6-
function AppData() {
6+
function AppData({ showVersion }) {
77
const [lastUpdated, setLastUpdated] = useState("");
88
const [recordCount, setRecordCount] = useState("");
99

@@ -27,13 +27,20 @@ function AppData() {
2727
return (
2828
<>
2929
<div style={{ textAlign: "start "}}>
30-
<p><strong>Record Count:</strong> </p>
30+
<h4>Record Count</h4>
3131
<p>{recordCount} </p>
32-
<p><strong>Database Last Updated:</strong> </p>
33-
<p>{formatDate(lastUpdated)}</p>
34-
<p><strong>Version:</strong></p>
35-
<p> v{version}</p>
36-
<p><a href="https://github.com/embabel" target="_blank"><img src="/github-mark-white.svg" style={{height: "20px"}}/></a></p>
32+
<h4>Database Last Updated</h4>
33+
<p>{formatDate(lastUpdated)}</p>
34+
{(showVersion) ? (
35+
<>
36+
<h4>Version</h4>
37+
<p style={{ display: "flex", alignItems: "center", gap: "10px" }}> v{version}
38+
<a href="https://github.com/embabel" target="_blank" rel="noreferrer">
39+
<img src="/github-mark-white.svg" style={{height: "20px"}}/>
40+
</a>
41+
</p>
42+
</>
43+
) : (<></>)}
3744
</div>
3845
</>
3946
);

embabel-database-ui/src/components/layout/Menu.jsx renamed to embabel-database-ui/src/components/layout/MenuBlock.jsx

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import { useEffect, useState } from 'react';
22
import { useNavigate } from 'react-router-dom';
3-
import { Button, ButtonGroup, EntityTitle, Section, SectionCard } from "@blueprintjs/core";
3+
import { EntityTitle, Section, SectionCard, Menu, MenuItem, MenuDivider } from "@blueprintjs/core";
44
import { Database } from "@blueprintjs/icons";
55
import { version } from '../../../package.json';
66

77
import AppData from './AppData';
88

9-
function Menu() {
9+
function MenuBlock() {
1010

1111
const [lastUpdated, setLastUpdated] = useState("");
1212
const [recordCount, setRecordCount] = useState("");
@@ -28,6 +28,10 @@ function Menu() {
2828
const handleGoProviders = () => {
2929
navigate('/providers');
3030
}
31+
32+
const handleGoAgentMaintenance = () => {
33+
navigate('/agent/maintenance');
34+
}
3135

3236
useEffect(() => {
3337
async function loadUpdatedDate() {
@@ -64,19 +68,25 @@ function Menu() {
6468
</SectionCard>
6569
<div style={{ flex: 1, display: 'flex', flexDirection: 'column' }}>
6670
<SectionCard>
67-
<ButtonGroup vertical={true} fill={true}>
68-
<Button onClick={handleGoHome}>Home</Button>
69-
<Button onClick={handleGoSearch}>Search</Button>
70-
<Button onClick={handleGoTags}>Tags</Button>
71-
<Button onClick={handleGoProviders}>Providers</Button>
72-
</ButtonGroup>
71+
<Menu>
72+
<MenuItem text="Home" onClick={handleGoHome}/>
73+
<MenuItem text="Search">
74+
<MenuItem text="By Name" onClick={handleGoSearch}/>
75+
<MenuItem text="By Tags" onClick={handleGoTags}/>
76+
<MenuItem text="By Provider" onClick={handleGoProviders}/>
77+
</MenuItem>
78+
<MenuItem text="Agents">
79+
<MenuItem text="Maintenance" onClick={handleGoAgentMaintenance}/>
80+
</MenuItem>
81+
</Menu>
82+
7383
</SectionCard>
7484
</div>
7585
<SectionCard style={{ position: 'sticky', bottom: 0, zIndex: 1, background: 'inherit' }}>
76-
<AppData/>
86+
<AppData showVersion={true} />
7787
</SectionCard>
7888
</Section>
7989
);
8090
}
8191

82-
export default Menu
92+
export default MenuBlock

0 commit comments

Comments
 (0)