@@ -45,9 +45,11 @@ function PermissionSummary({ user, onClick }) {
4545 const perms = user . permissions || { }
4646 const apiFeatures = [ 'chat' , 'images' , 'audio_speech' , 'audio_transcription' , 'vad' , 'detection' , 'video' , 'embeddings' , 'sound' ]
4747 const agentFeatures = [ 'agents' , 'skills' , 'collections' , 'mcp_jobs' ]
48+ const generalFeatures = [ 'fine_tuning' ]
4849
4950 const apiOn = apiFeatures . filter ( f => perms [ f ] !== false && ( perms [ f ] === true || perms [ f ] === undefined ) ) . length
5051 const agentOn = agentFeatures . filter ( f => perms [ f ] ) . length
52+ const generalOn = generalFeatures . filter ( f => perms [ f ] ) . length
5153
5254 const modelRestricted = user . allowed_models ?. enabled
5355
@@ -58,7 +60,7 @@ function PermissionSummary({ user, onClick }) {
5860 title = "Edit permissions"
5961 >
6062 < i className = "fas fa-shield-halved" />
61- { apiOn } /{ apiFeatures . length } API, { agentOn } /{ agentFeatures . length } Agent
63+ { apiOn } /{ apiFeatures . length } API, { agentOn } /{ agentFeatures . length } Agent, { generalOn } / { generalFeatures . length } Features
6264 { modelRestricted && ' | Models restricted' }
6365 </ button >
6466 )
@@ -71,6 +73,7 @@ function PermissionsModal({ user, featureMeta, availableModels, onClose, onSave,
7173
7274 const apiFeatures = featureMeta ?. api_features || [ ]
7375 const agentFeatures = featureMeta ?. agent_features || [ ]
76+ const generalFeatures = featureMeta ?. general_features || [ ]
7477
7578 useEffect ( ( ) => {
7679 const handleKeyDown = ( e ) => {
@@ -189,6 +192,33 @@ function PermissionsModal({ user, featureMeta, availableModels, onClose, onSave,
189192 </ div >
190193 </ div >
191194
195+ { /* General Features */ }
196+ { generalFeatures . length > 0 && (
197+ < div className = "perm-section" >
198+ < div className = "perm-section-header" >
199+ < strong className = "perm-section-title" >
200+ < i className = "fas fa-sliders" />
201+ Features
202+ </ strong >
203+ < div className = "action-group" >
204+ < button className = "btn btn-sm btn-secondary perm-btn-all-none" onClick = { ( ) => setAllFeatures ( generalFeatures , true ) } > All</ button >
205+ < button className = "btn btn-sm btn-secondary perm-btn-all-none" onClick = { ( ) => setAllFeatures ( generalFeatures , false ) } > None</ button >
206+ </ div >
207+ </ div >
208+ < div className = "perm-grid" >
209+ { generalFeatures . map ( f => (
210+ < button
211+ key = { f . key }
212+ className = { `btn btn-sm ${ permissions [ f . key ] ? 'btn-primary' : 'btn-secondary' } perm-btn-feature` }
213+ onClick = { ( ) => toggleFeature ( f . key ) }
214+ >
215+ { f . label }
216+ </ button >
217+ ) ) }
218+ </ div >
219+ </ div >
220+ ) }
221+
192222 { /* Model Access */ }
193223 < div className = "perm-section" >
194224 < div className = "perm-section-header" >
@@ -510,6 +540,9 @@ export default function Users() {
510540 { key : 'collections' , label : 'Collections' , default : false } ,
511541 { key : 'mcp_jobs' , label : 'MCP CI Jobs' , default : false } ,
512542 ] ,
543+ general_features : [
544+ { key : 'fine_tuning' , label : 'Fine-Tuning' , default : false } ,
545+ ] ,
513546 } )
514547 }
515548 } , [ ] )
0 commit comments