@@ -12,63 +12,45 @@ import { skipToken } from '@reduxjs/toolkit/query';
1212import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus' ;
1313import { toast } from 'features/toast/toast' ;
1414import type { ChangeEvent } from 'react' ;
15- import { useCallback , useMemo , useState } from 'react' ;
15+ import { memo , useCallback , useMemo , useState } from 'react' ;
1616import { useTranslation } from 'react-i18next' ;
17- import { useGetHFTokenStatusQuery , useSetHFTokenMutation } from 'services/api/endpoints/models' ;
18- import { UNAUTHORIZED_TOAST_ID } from 'services/events/onModelInstallError' ;
17+ import {
18+ useGetHFTokenStatusQuery ,
19+ useResetHFTokenMutation ,
20+ useSetHFTokenMutation ,
21+ } from 'services/api/endpoints/models' ;
22+ import type { Equals } from 'tsafe' ;
23+ import { assert } from 'tsafe' ;
1924
2025export const HFToken = ( ) => {
2126 const { t } = useTranslation ( ) ;
2227 const isHFTokenEnabled = useFeatureStatus ( 'hfToken' ) ;
23- const [ token , setToken ] = useState ( '' ) ;
2428 const { currentData } = useGetHFTokenStatusQuery ( isHFTokenEnabled ? undefined : skipToken ) ;
25- const [ trigger , { isLoading, isUninitialized } ] = useSetHFTokenMutation ( ) ;
26- const onChange = useCallback ( ( e : ChangeEvent < HTMLInputElement > ) => {
27- setToken ( e . target . value ) ;
28- } , [ ] ) ;
29- const onClick = useCallback ( ( ) => {
30- trigger ( { token } )
31- . unwrap ( )
32- . then ( ( res ) => {
33- if ( res === 'valid' ) {
34- setToken ( '' ) ;
35- toast ( {
36- id : UNAUTHORIZED_TOAST_ID ,
37- title : t ( 'modelManager.hfTokenSaved' ) ,
38- status : 'success' ,
39- duration : 3000 ,
40- } ) ;
41- }
42- } ) ;
43- } , [ t , token , trigger ] ) ;
4429
4530 const error = useMemo ( ( ) => {
46- if ( ! currentData || isUninitialized || isLoading ) {
47- return null ;
48- }
49- if ( currentData === 'invalid' ) {
50- return t ( 'modelManager.hfTokenInvalidErrorMessage' ) ;
51- }
52- if ( currentData === 'unknown' ) {
53- return t ( 'modelManager.hfTokenUnableToVerifyErrorMessage' ) ;
31+ switch ( currentData ) {
32+ case 'invalid' :
33+ return t ( 'modelManager.hfTokenInvalidErrorMessage' ) ;
34+ case 'unknown' :
35+ return t ( 'modelManager.hfTokenUnableToVerifyErrorMessage' ) ;
36+ case 'valid' :
37+ case undefined :
38+ return null ;
39+ default :
40+ assert < Equals < never , typeof currentData > > ( false , 'Unexpected HF token status' ) ;
5441 }
55- return null ;
56- } , [ currentData , isLoading , isUninitialized , t ] ) ;
42+ } , [ currentData , t ] ) ;
5743
58- if ( ! currentData || currentData === 'valid' ) {
44+ if ( ! currentData ) {
5945 return null ;
6046 }
6147
6248 return (
6349 < Flex borderRadius = "base" w = "full" >
64- < FormControl isInvalid = { ! isUninitialized && Boolean ( error ) } orientation = "vertical" >
50+ < FormControl isInvalid = { Boolean ( error ) } orientation = "vertical" >
6551 < FormLabel > { t ( 'modelManager.hfTokenLabel' ) } </ FormLabel >
66- < Flex gap = { 3 } alignItems = "center" w = "full" >
67- < Input type = "password" value = { token } onChange = { onChange } />
68- < Button onClick = { onClick } size = "sm" isDisabled = { token . trim ( ) . length === 0 } isLoading = { isLoading } >
69- { t ( 'common.save' ) }
70- </ Button >
71- </ Flex >
52+ { error && < SetHFTokenInput /> }
53+ { ! error && < ResetHFTokenButton /> }
7254 < FormHelperText >
7355 < ExternalLink label = { t ( 'modelManager.hfTokenHelperText' ) } href = "https://huggingface.co/settings/tokens" />
7456 </ FormHelperText >
@@ -77,3 +59,73 @@ export const HFToken = () => {
7759 </ Flex >
7860 ) ;
7961} ;
62+
63+ const PLACEHOLDER_TOKEN = Array . from ( { length : 37 } , ( ) => 'a' ) . join ( '' ) ;
64+
65+ const ResetHFTokenButton = memo ( ( ) => {
66+ const { t } = useTranslation ( ) ;
67+ const [ resetHFToken , { isLoading } ] = useResetHFTokenMutation ( ) ;
68+
69+ const onClick = useCallback ( ( ) => {
70+ resetHFToken ( )
71+ . unwrap ( )
72+ . then ( ( ) => {
73+ toast ( {
74+ title : t ( 'modelManager.hfTokenReset' ) ,
75+ status : 'info' ,
76+ } ) ;
77+ } ) ;
78+ } , [ resetHFToken , t ] ) ;
79+
80+ return (
81+ < Flex gap = { 3 } alignItems = "center" w = "full" >
82+ < Input type = "password" value = { PLACEHOLDER_TOKEN } isDisabled />
83+ < Button onClick = { onClick } size = "sm" isLoading = { isLoading } >
84+ { t ( 'common.reset' ) }
85+ </ Button >
86+ </ Flex >
87+ ) ;
88+ } ) ;
89+ ResetHFTokenButton . displayName = 'ResetHFTokenButton' ;
90+
91+ const SetHFTokenInput = memo ( ( ) => {
92+ const { t } = useTranslation ( ) ;
93+ const [ token , setToken ] = useState ( '' ) ;
94+ const [ trigger , { isLoading } ] = useSetHFTokenMutation ( ) ;
95+ const onChange = useCallback ( ( e : ChangeEvent < HTMLInputElement > ) => {
96+ setToken ( e . target . value ) ;
97+ } , [ ] ) ;
98+ const onClick = useCallback ( ( ) => {
99+ trigger ( { token } )
100+ . unwrap ( )
101+ . then ( ( res ) => {
102+ switch ( res ) {
103+ case 'valid' :
104+ setToken ( '' ) ;
105+ toast ( {
106+ title : t ( 'modelManager.hfTokenSaved' ) ,
107+ status : 'success' ,
108+ } ) ;
109+ break ;
110+ case 'invalid' :
111+ case 'unknown' :
112+ default :
113+ toast ( {
114+ title : t ( 'modelManager.hfTokenUnableToVerify' ) ,
115+ status : 'error' ,
116+ } ) ;
117+ break ;
118+ }
119+ } ) ;
120+ } , [ t , token , trigger ] ) ;
121+
122+ return (
123+ < Flex gap = { 3 } alignItems = "center" w = "full" >
124+ < Input type = "password" value = { token } onChange = { onChange } />
125+ < Button onClick = { onClick } size = "sm" isDisabled = { token . trim ( ) . length === 0 } isLoading = { isLoading } >
126+ { t ( 'common.save' ) }
127+ </ Button >
128+ </ Flex >
129+ ) ;
130+ } ) ;
131+ SetHFTokenInput . displayName = 'SetHFTokenInput' ;
0 commit comments