@@ -827,6 +827,7 @@ function Details({ details, daily, partitions = [], accounts = [], users = [] })
827827function Rates ( { onRatesUpdated } ) {
828828 const [ config , setConfig ] = useState ( null ) ;
829829 const [ overrides , setOverrides ] = useState ( [ ] ) ;
830+ const [ accounts , setAccounts ] = useState ( [ ] ) ;
830831 const [ error , setError ] = useState ( null ) ;
831832 const [ saving , setSaving ] = useState ( false ) ;
832833 const [ status , setStatus ] = useState ( null ) ;
@@ -851,7 +852,7 @@ function Rates({ onRatesUpdated }) {
851852 ? Object . entries ( json . overrides ) . map ( ( [ account , cfg ] ) => ( {
852853 account,
853854 rate : cfg . rate ?? '' ,
854- discount : cfg . discount ?? ''
855+ discount : cfg . discount != null ? cfg . discount * 100 : ''
855856 } ) )
856857 : [ ] ;
857858 setOverrides ( ovrs ) ;
@@ -866,6 +867,41 @@ function Rates({ onRatesUpdated }) {
866867 } ;
867868 } , [ ] ) ;
868869
870+ useEffect ( ( ) => {
871+ let cancelled = false ;
872+ async function loadAccounts ( ) {
873+ try {
874+ let json ;
875+ if ( window . cockpit && window . cockpit . spawn ) {
876+ const { start, end } = getBillingPeriod ( ) ;
877+ const args = [
878+ 'python3' ,
879+ `${ PLUGIN_BASE } /slurmdb.py` ,
880+ '--start' ,
881+ start ,
882+ '--end' ,
883+ end ,
884+ '--output' ,
885+ '-' ,
886+ ] ;
887+ const output = await window . cockpit . spawn ( args , { err : 'message' } ) ;
888+ json = JSON . parse ( output ) ;
889+ } else {
890+ const resp = await fetch ( 'billing.json' ) ;
891+ if ( ! resp . ok ) throw new Error ( 'Failed to fetch billing data' ) ;
892+ json = await resp . json ( ) ;
893+ }
894+ if ( ! cancelled ) setAccounts ( json . accounts || [ ] ) ;
895+ } catch ( e ) {
896+ console . error ( e ) ;
897+ }
898+ }
899+ loadAccounts ( ) ;
900+ return ( ) => {
901+ cancelled = true ;
902+ } ;
903+ } , [ ] ) ;
904+
869905 function updateOverride ( index , field , value ) {
870906 setOverrides ( prev =>
871907 prev . map ( ( o , i ) => ( i === index ? { ...o , [ field ] : value } : o ) )
@@ -911,7 +947,7 @@ function Rates({ onRatesUpdated }) {
911947 if ( o . discount !== '' ) {
912948 const discount = parseFloat ( o . discount ) ;
913949 if ( Number . isFinite ( discount ) ) {
914- entry . discount = discount ;
950+ entry . discount = discount / 100 ;
915951 } else {
916952 console . warn (
917953 `Ignoring invalid discount for account ${ o . account } :` ,
@@ -981,7 +1017,7 @@ function Rates({ onRatesUpdated }) {
9811017 null ,
9821018 React . createElement ( 'th' , null , 'Account' ) ,
9831019 React . createElement ( 'th' , null , 'Rate' ) ,
984- React . createElement ( 'th' , null , 'Discount' ) ,
1020+ React . createElement ( 'th' , null , 'Discount (%) ' ) ,
9851021 React . createElement ( 'th' , null )
9861022 )
9871023 ) ,
@@ -992,12 +1028,22 @@ function Rates({ onRatesUpdated }) {
9921028 React . createElement (
9931029 'tr' ,
9941030 { key : idx } ,
995- React . createElement ( 'td' , null ,
996- React . createElement ( 'input' , {
997- value : o . account ,
998- onChange : e =>
999- updateOverride ( idx , 'account' , e . target . value )
1000- } )
1031+ React . createElement (
1032+ 'td' ,
1033+ null ,
1034+ React . createElement (
1035+ 'select' ,
1036+ {
1037+ value : o . account ,
1038+ onChange : e => updateOverride ( idx , 'account' , e . target . value )
1039+ } ,
1040+ [
1041+ React . createElement ( 'option' , { key : '' , value : '' } , '' ) ,
1042+ ...accounts . map ( acct =>
1043+ React . createElement ( 'option' , { key : acct , value : acct } , acct )
1044+ )
1045+ ]
1046+ )
10011047 ) ,
10021048 React . createElement ( 'td' , null ,
10031049 React . createElement ( 'input' , {
@@ -1011,7 +1057,7 @@ function Rates({ onRatesUpdated }) {
10111057 React . createElement ( 'td' , null ,
10121058 React . createElement ( 'input' , {
10131059 type : 'number' ,
1014- step : '0.01 ' ,
1060+ step : '0.1 ' ,
10151061 value : o . discount ,
10161062 onChange : e =>
10171063 updateOverride ( idx , 'discount' , e . target . value )
0 commit comments