@@ -48,6 +48,7 @@ import { UpdateBanner } from './components/UpdateBanner'
4848import { BatchGenerationPanel } from './components/BatchGenerationPanel'
4949import { SkillComposer } from './components/SkillComposer'
5050import { SkillRegistry } from './components/SkillRegistry'
51+ import { OntologyPanel } from './components/OntologyPanel'
5152import { SkillBuilder } from './components/SkillBuilder'
5253import type { ModelInfo , CitationEntry , Skill } from './types'
5354import type { SearXNGResult } from './lib/searxngApi'
@@ -65,7 +66,7 @@ import type { Locale } from './lib/i18n'
6566import './App.css'
6667import { useLocale } from './hooks/useLocale'
6768
68- type View = 'chat' | 'models' | 'changelog' | 'cache' | 'arena' | 'benchmark' | 'custom-models' | 'persona-marketplace' | 'knowledge' | 'plugins' | 'mcp-servers' | 'webdav' | 'memory' | 'agent' | 'usage-analytics' | 'comparison' | 'skill-registry' | 'skill-builder'
69+ type View = 'chat' | 'models' | 'changelog' | 'cache' | 'arena' | 'benchmark' | 'custom-models' | 'persona-marketplace' | 'knowledge' | 'plugins' | 'mcp-servers' | 'webdav' | 'memory' | 'agent' | 'usage-analytics' | 'comparison' | 'skill-registry' | 'skill-builder' | 'ontology'
6970
7071const BASE = '/monday'
7172
@@ -88,6 +89,7 @@ const VIEW_PATH: Record<View, string> = {
8889 comparison : BASE + '/comparison' ,
8990 'skill-registry' : BASE + '/skill-registry' ,
9091 'skill-builder' : BASE + '/skill-builder' ,
92+ ontology : BASE + '/ontology' ,
9193}
9294
9395function viewFromPath ( pathname : string ) : View {
@@ -176,6 +178,7 @@ export default function App() {
176178
177179 // v1.2: load persistent memories and skills when memory view is open
178180 const [ installedSkills , setInstalledSkills ] = useState < Skill [ ] > ( [ ] )
181+ const [ ontologyEntities , setOntologyEntities ] = useState < import ( './types' ) . OntologyEntity [ ] > ( [ ] )
179182 useEffect ( ( ) => {
180183 if ( view === 'memory' ) {
181184 Promise . all ( [
@@ -188,6 +191,12 @@ export default function App() {
188191 }
189192 } , [ view ] )
190193
194+ useEffect ( ( ) => {
195+ if ( view === 'ontology' ) {
196+ import ( './lib/storage' ) . then ( ( m ) => m . loadOntologyEntities ( ) ) . then ( ( ents ) => setOntologyEntities ( ents ) )
197+ }
198+ } , [ view ] )
199+
191200 // Apply base filter to vector store when active base changes
192201 useEffect ( ( ) => {
193202 vectorStore . setBaseFilter ( activeBaseDocIds ?? null )
@@ -533,6 +542,10 @@ export default function App() {
533542 setView ( 'comparison' )
534543 closeSidebarOnMobile ( )
535544 } }
545+ onOpenOntology = { ( ) => {
546+ setView ( 'ontology' )
547+ closeSidebarOnMobile ( )
548+ } }
536549 onOpenShortcuts = { ( ) => {
537550 setShowShortcuts ( true )
538551 closeSidebarOnMobile ( )
@@ -842,6 +855,40 @@ export default function App() {
842855 onClose = { ( ) => setView ( 'chat' ) }
843856 />
844857 </ div >
858+ ) : view === 'ontology' ? (
859+ < div className = "main-content main-content--ontology" >
860+ < OntologyPanel
861+ entities = { ontologyEntities }
862+ onAdd = { async ( type , name , props ) => {
863+ const m = await import ( './lib/storage' )
864+ const ent = await m . createOntologyEntity ( type , name , props )
865+ setOntologyEntities ( ( prev ) => [ ent , ...prev ] )
866+ } }
867+ onEdit = { async ( id , name , props ) => {
868+ await import ( './lib/storage' ) . then ( ( m ) => m . updateOntologyEntity ( id , name , props ) )
869+ setOntologyEntities ( ( prev ) => prev . map ( ( e ) => e . id === id ? { ...e , name, properties : props , updatedAt : Date . now ( ) } : e ) )
870+ } }
871+ onDelete = { async ( id ) => {
872+ await import ( './lib/storage' ) . then ( ( m ) => m . deleteOntologyEntity ( id ) )
873+ setOntologyEntities ( ( prev ) => prev . filter ( ( e ) => e . id !== id ) )
874+ } }
875+ onAddRelationship = { async ( fromId , toId , label ) => {
876+ await import ( './lib/storage' ) . then ( ( m ) => m . addEntityRelationship ( fromId , toId , label ) )
877+ setOntologyEntities ( ( prev ) => prev . map ( ( e ) => e . id === fromId ? { ...e , relationships : [ ...e . relationships , toId ] , updatedAt : Date . now ( ) } : e ) )
878+ } }
879+ onRemoveRelationship = { async ( fromId , toId ) => {
880+ await import ( './lib/storage' ) . then ( ( m ) => m . removeEntityRelationship ( fromId , toId ) )
881+ setOntologyEntities ( ( prev ) => prev . map ( ( e ) => e . id === fromId ? { ...e , relationships : e . relationships . filter ( ( r ) => r !== toId ) , updatedAt : Date . now ( ) } : e ) )
882+ } }
883+ onInjectAsContext = { ( ) => {
884+ import ( './lib/storage' ) . then ( ( m ) => {
885+ const ctx = ontologyEntities . map ( ( e ) => `[${ e . type } ] ${ e . name } ${ Object . keys ( e . properties ) . length > 0 ? ' {' + Object . entries ( e . properties ) . map ( ( [ k , v ] ) => ` ${ k } : ${ v } ` ) . join ( ', ' ) + ' }' : '' } ` ) . join ( '; ' )
886+ navigator . clipboard . writeText ( ctx )
887+ } )
888+ } }
889+ onClose = { ( ) => setView ( 'chat' ) }
890+ />
891+ </ div >
845892 ) : view === 'usage-analytics' ? (
846893 < div className = "main-content main-content--usage-analytics" >
847894 < UsageAnalytics />
0 commit comments