Skip to content

Commit babfc2f

Browse files
committed
feat(FR-1636): Add a control to the reservoir page for entering a HuggingFace token.
1 parent c752c1e commit babfc2f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+532
-24
lines changed

.cspell.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
"Frgmts",
3838
"Gaudi",
3939
"hoverable",
40+
"huggingface",
4041
"Hyperaccel",
4142
"keypair",
4243
"Keypairs",

packages/backend.ai-ui/src/components/fragments/BAIArtifactTable.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,12 +258,13 @@ const BAIArtifactTable = ({
258258

259259
return (
260260
<BAITable<Artifact>
261+
size="small"
261262
rowKey={(record) => record.id}
262263
columns={filterOutEmpty(columns)}
263264
dataSource={filterOutNullAndUndefined(artifact)}
264265
scroll={{ x: 'max-content' }}
265266
{...tableProps}
266-
></BAITable>
267+
/>
267268
);
268269
};
269270

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
import { BAIHuggingFaceRegistrySettingModalFragment$key } from '../../__generated__/BAIHuggingFaceRegistrySettingModalFragment.graphql';
2+
import { toLocalId } from '../../helper';
3+
import BAIFlex from '../BAIFlex';
4+
import BAIModal, { BAIModalProps } from '../BAIModal';
5+
import BAIUnmountAfterClose from '../BAIUnmountAfterClose';
6+
import { EditOutlined } from '@ant-design/icons';
7+
import { App, Button, Form, FormInstance, Input } from 'antd';
8+
import { useState, useRef } from 'react';
9+
import { useTranslation } from 'react-i18next';
10+
import { graphql, useFragment, useMutation } from 'react-relay';
11+
12+
export type BAIHuggingFaceRegistrySettingModalFragmentKey =
13+
BAIHuggingFaceRegistrySettingModalFragment$key;
14+
15+
export interface BAIHuggingFaceRegistrySettingModalProps extends BAIModalProps {
16+
huggingFaceRegistryFragment?: BAIHuggingFaceRegistrySettingModalFragmentKey;
17+
onRequestClose?: (success?: boolean) => void;
18+
}
19+
20+
const BAIHuggingFaceRegistrySettingModal = ({
21+
huggingFaceRegistryFragment,
22+
onRequestClose,
23+
...baiModalProps
24+
}: BAIHuggingFaceRegistrySettingModalProps) => {
25+
'use memo';
26+
const { t } = useTranslation();
27+
const { message, modal } = App.useApp();
28+
const formRef = useRef<FormInstance>(null);
29+
30+
const huggingFaceRegistry = useFragment(
31+
graphql`
32+
fragment BAIHuggingFaceRegistrySettingModalFragment on HuggingFaceRegistry {
33+
id
34+
token
35+
}
36+
`,
37+
huggingFaceRegistryFragment,
38+
);
39+
40+
const [updateHuggingFaceRegistry, isInflightUpdateHuggingFaceRegistry] =
41+
useMutation(graphql`
42+
mutation BAIHuggingFaceRegistrySettingModalMutation(
43+
$input: UpdateHuggingFaceRegistryInput!
44+
) {
45+
updateHuggingfaceRegistry(input: $input) {
46+
huggingfaceRegistry {
47+
id
48+
token
49+
}
50+
}
51+
}
52+
`);
53+
54+
const initialToken = huggingFaceRegistry?.token;
55+
const [isEditing, setIsEditing] = useState(false);
56+
57+
const hasToken = initialToken && initialToken.length > 0;
58+
59+
const executeUpdate = (values: any) => {
60+
updateHuggingFaceRegistry({
61+
variables: {
62+
input: {
63+
id: toLocalId(huggingFaceRegistry!.id),
64+
token: values.token,
65+
},
66+
},
67+
onCompleted: (_res, errors) => {
68+
if (errors && errors.length > 0) {
69+
errors.forEach((err) =>
70+
message.error(
71+
err.message ??
72+
t('comp:HuggingFaceRegistrySettingModal.FailedToUpdateToken'),
73+
),
74+
);
75+
return;
76+
}
77+
message.success(
78+
t('comp:HuggingFaceRegistrySettingModal.TokenUpdatedSuccessfully'),
79+
);
80+
onRequestClose?.(true);
81+
},
82+
onError: (err) => {
83+
message.error(
84+
err.message ??
85+
t('comp:HuggingFaceRegistrySettingModal.FailedToUpdateToken'),
86+
);
87+
},
88+
});
89+
};
90+
91+
const handleOk = () => {
92+
if (!huggingFaceRegistry?.id) {
93+
message.error(
94+
t('comp:HuggingFaceRegistrySettingModal.HuggingFaceRegistryNotFound'),
95+
);
96+
return;
97+
}
98+
99+
formRef.current
100+
?.validateFields()
101+
.then((values) => {
102+
// Check if current token exists and is empty string, but new token is not empty
103+
104+
if (hasToken && !values.token) {
105+
modal.confirm({
106+
title: t('comp:HuggingFaceRegistrySettingModal.ResetTokenConfirm'),
107+
content: t(
108+
'comp:HuggingFaceRegistrySettingModal.ResetTokenConfirmMessage',
109+
),
110+
onOk() {
111+
executeUpdate(values);
112+
},
113+
onCancel() {
114+
// Don't proceed with update
115+
},
116+
okButtonProps: { danger: true },
117+
okText: t('button.Reset'),
118+
});
119+
} else {
120+
executeUpdate(values);
121+
}
122+
})
123+
.catch(() => {});
124+
};
125+
126+
return (
127+
<BAIUnmountAfterClose>
128+
<BAIModal
129+
destroyOnHidden
130+
afterClose={() => setIsEditing(false)}
131+
title={t('comp:HuggingFaceRegistrySettingModal.HuggingFaceSettings')}
132+
centered
133+
okText={t('button.Save')}
134+
onOk={handleOk}
135+
onCancel={() => onRequestClose?.(false)}
136+
okButtonProps={{
137+
loading: isInflightUpdateHuggingFaceRegistry,
138+
}}
139+
{...baiModalProps}
140+
>
141+
<Form ref={formRef} layout="vertical">
142+
<Form.Item
143+
label={t('comp:HuggingFaceRegistrySettingModal.Token')}
144+
name="token"
145+
>
146+
{hasToken && !isEditing ? (
147+
<BAIFlex gap={'xs'}>
148+
{/* For security, we display a masked token instead of initial value. */}
149+
<Input type="password" disabled value="••••••••••••••••" />
150+
<Button
151+
icon={<EditOutlined />}
152+
onClick={() => {
153+
setIsEditing(true);
154+
}}
155+
type="text"
156+
/>
157+
</BAIFlex>
158+
) : (
159+
<Input.Password
160+
placeholder={t(
161+
'comp:HuggingFaceRegistrySettingModal.EnterToken',
162+
)}
163+
autoFocus={isEditing}
164+
/>
165+
)}
166+
</Form.Item>
167+
</Form>
168+
</BAIModal>
169+
</BAIUnmountAfterClose>
170+
);
171+
};
172+
173+
export default BAIHuggingFaceRegistrySettingModal;

packages/backend.ai-ui/src/components/fragments/index.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,8 @@ export type {
4545
BAIActivateArtifactsModalArtifactsFragmentKey,
4646
} from './BAIActivateArtifactsModal';
4747
export { default as BAIVFolderDeleteButton } from './BAIVFolderDeleteButton';
48+
export { default as BAIHuggingFaceRegistrySettingModal } from './BAIHuggingFaceRegistrySettingModal';
49+
export type {
50+
BAIHuggingFaceRegistrySettingModalProps,
51+
BAIHuggingFaceRegistrySettingModalFragmentKey,
52+
} from './BAIHuggingFaceRegistrySettingModal';

packages/backend.ai-ui/src/locale/de.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
{
22
"$schema": "../../i18n.schema.json",
3+
"button": {
4+
"Reset": "Zurücksetzen",
5+
"Save": "Speichern"
6+
},
37
"comp:BAIActivateArtifactsModal": {
48
"Activate": "Aktivieren",
59
"ActivateArtifacts": "Artefakte aktivieren",
@@ -135,6 +139,15 @@
135139
"FileNameRequired": "Bitte geben Sie einen Datei- oder Ordnernamen ein."
136140
}
137141
},
142+
"comp:HuggingFaceRegistrySettingModal": {
143+
"FailedToUpdateToken": "Das Token konnte nicht aktualisiert werden.",
144+
"HuggingFaceRegistryNotFound": "Hugging Face-Registrierung nicht gefunden.",
145+
"HuggingFaceSettings": "Einstellungen für Hugging Face.",
146+
"ResetTokenConfirm": "Token zurücksetzen",
147+
"ResetTokenConfirmMessage": "Der Token scheint leer zu sein. \nMöchten Sie es mit einem neuen Wert initialisieren?",
148+
"Token": "Token",
149+
"TokenUpdatedSuccessfully": "Token erfolgreich aktualisiert."
150+
},
138151
"comp:PaginationInfoText": {
139152
"Total": "{{start}} - {{end}} von {{total}} Elementen"
140153
},

packages/backend.ai-ui/src/locale/el.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
{
22
"$schema": "../../i18n.schema.json",
3+
"button": {
4+
"Reset": "Επαναφορά",
5+
"Save": "Εκτός"
6+
},
37
"comp:BAIActivateArtifactsModal": {
48
"Activate": "Δραστηριοποιώ",
59
"ActivateArtifacts": "Ενεργοποιήστε αντικείμενα",
@@ -135,6 +139,15 @@
135139
"FileNameRequired": "Εισαγάγετε ένα αρχείο ή ένα όνομα φακέλου."
136140
}
137141
},
142+
"comp:HuggingFaceRegistrySettingModal": {
143+
"FailedToUpdateToken": "Η ενημέρωση του διακριτικού απέτυχε.",
144+
"HuggingFaceRegistryNotFound": "Το μητρώο Hugging Face δεν βρέθηκε.",
145+
"HuggingFaceSettings": "Ρυθμίσεις Hugging Face",
146+
"ResetTokenConfirm": "Επαναφορά διακριτικού",
147+
"ResetTokenConfirmMessage": "Το διακριτικό φαίνεται να είναι κενό. \nΘέλετε να το αρχικοποιήσετε με μια νέα τιμή;",
148+
"Token": "Ενδειξη",
149+
"TokenUpdatedSuccessfully": "Το διακριτικό ενημερώθηκε με επιτυχία."
150+
},
138151
"comp:PaginationInfoText": {
139152
"Total": "{{start}} - {{end}} των στοιχείων {{total}}"
140153
},

packages/backend.ai-ui/src/locale/en.json

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
{
22
"$schema": "../../i18n.schema.json",
3+
"button": {
4+
"Reset": "Reset",
5+
"Save": "Save"
6+
},
37
"comp:BAIActivateArtifactsModal": {
48
"Activate": "Activate",
59
"ActivateArtifacts": "Activate Artifacts",
@@ -138,6 +142,16 @@
138142
"FileNameRequired": "Please enter a file or folder name."
139143
}
140144
},
145+
"comp:HuggingFaceRegistrySettingModal": {
146+
"EnterToken": "Enter your HuggingFace token",
147+
"FailedToUpdateToken": "Failed to update token.",
148+
"HuggingFaceRegistryNotFound": "Hugging Face Registry not found.",
149+
"HuggingFaceSettings": "Hugging Face Settings",
150+
"ResetTokenConfirm": "Reset Token",
151+
"ResetTokenConfirmMessage": "The token appears to be empty. Would you like to initialize it with a new value?",
152+
"Token": "Token",
153+
"TokenUpdatedSuccessfully": "Token updated successfully."
154+
},
141155
"comp:PaginationInfoText": {
142156
"Total": "{{start}} - {{end}} of {{total}} items"
143157
},

packages/backend.ai-ui/src/locale/es.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
{
22
"$schema": "../../i18n.schema.json",
3+
"button": {
4+
"Reset": "Reiniciar",
5+
"Save": "Ahorrar"
6+
},
37
"comp:BAIActivateArtifactsModal": {
48
"Activate": "Activar",
59
"ActivateArtifacts": "Activar artefactos",
@@ -135,6 +139,15 @@
135139
"FileNameRequired": "Ingrese un nombre de archivo o carpeta."
136140
}
137141
},
142+
"comp:HuggingFaceRegistrySettingModal": {
143+
"FailedToUpdateToken": "No se pudo actualizar el token.",
144+
"HuggingFaceRegistryNotFound": "Hugging Face Registro no encontrado.",
145+
"HuggingFaceSettings": "Configuración de Hugging Face",
146+
"ResetTokenConfirm": "Restablecer token",
147+
"ResetTokenConfirmMessage": "El token parece estar vacío. \n¿Le gustaría inicializarlo con un nuevo valor?",
148+
"Token": "Simbólico",
149+
"TokenUpdatedSuccessfully": "Token actualizado exitosamente."
150+
},
138151
"comp:PaginationInfoText": {
139152
"Total": "{{start}} - {{end}} de {{total}} elementos"
140153
},

packages/backend.ai-ui/src/locale/fi.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
{
22
"$schema": "../../i18n.schema.json",
3+
"button": {
4+
"Reset": "Nollaa",
5+
"Save": "Tallentaa"
6+
},
37
"comp:BAIActivateArtifactsModal": {
48
"Activate": "Aktivoida",
59
"ActivateArtifacts": "Aktivoida esineitä",
@@ -135,6 +139,15 @@
135139
"FileNameRequired": "Anna tiedoston tai kansionimi."
136140
}
137141
},
142+
"comp:HuggingFaceRegistrySettingModal": {
143+
"FailedToUpdateToken": "Tunnusteen päivittäminen epäonnistui.",
144+
"HuggingFaceRegistryNotFound": "Hugging Face-rekisteriä ei löydy.",
145+
"HuggingFaceSettings": "Halaavat kasvot -asetukset",
146+
"ResetTokenConfirm": "Reset Token",
147+
"ResetTokenConfirmMessage": "Tunnus näyttää olevan tyhjä. \nHaluatko alustaa sen uudella arvolla?",
148+
"Token": "Token",
149+
"TokenUpdatedSuccessfully": "Tunnus päivitetty onnistuneesti."
150+
},
138151
"comp:PaginationInfoText": {
139152
"Total": "{{start}}–{{end}} yhteensä {{total}} kohteesta"
140153
},

packages/backend.ai-ui/src/locale/fr.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
{
22
"$schema": "../../i18n.schema.json",
3+
"button": {
4+
"Reset": "Réinitialiser",
5+
"Save": "Sauvegarder"
6+
},
37
"comp:BAIActivateArtifactsModal": {
48
"Activate": "Activer",
59
"ActivateArtifacts": "Activer les artefacts",
@@ -135,6 +139,15 @@
135139
"FileNameRequired": "Veuillez saisir un fichier ou un nom de dossier."
136140
}
137141
},
142+
"comp:HuggingFaceRegistrySettingModal": {
143+
"FailedToUpdateToken": "Échec de la mise à jour du jeton.",
144+
"HuggingFaceRegistryNotFound": "Registre Hugging Face introuvable.",
145+
"HuggingFaceSettings": "Paramètres Hugging Face",
146+
"ResetTokenConfirm": "Réinitialiser le jeton",
147+
"ResetTokenConfirmMessage": "Le jeton semble vide. \nSouhaitez-vous l'initialiser avec une nouvelle valeur ?",
148+
"Token": "Jeton",
149+
"TokenUpdatedSuccessfully": "Jeton mis à jour avec succès."
150+
},
138151
"comp:PaginationInfoText": {
139152
"Total": "{{start}} - {{end}} des éléments {{total}}"
140153
},

0 commit comments

Comments
 (0)