diff --git a/react/src/components/BAIGeneralNotificationItem.tsx b/react/src/components/BAIGeneralNotificationItem.tsx index 813149991a..9713ffbe34 100644 --- a/react/src/components/BAIGeneralNotificationItem.tsx +++ b/react/src/components/BAIGeneralNotificationItem.tsx @@ -108,7 +108,15 @@ const BAIGeneralNotificationItem: React.FC<{ ) : null} {notification.extraDescription && showExtraDescription ? ( - + {notification.extraDescription} diff --git a/react/src/components/BAISessionNotificationItem.tsx b/react/src/components/BAISessionNotificationItem.tsx index 98515b12eb..c33c62fa9e 100644 --- a/react/src/components/BAISessionNotificationItem.tsx +++ b/react/src/components/BAISessionNotificationItem.tsx @@ -147,7 +147,15 @@ const BAISessionNotificationItem: React.FC<{ ) : null} {notification.extraDescription && showExtraDescription ? ( - + {notification.extraDescription} diff --git a/react/src/components/FileUploadManager.tsx b/react/src/components/FileUploadManager.tsx index e1fc34d5f2..49d43c43f9 100644 --- a/react/src/components/FileUploadManager.tsx +++ b/react/src/components/FileUploadManager.tsx @@ -17,6 +17,7 @@ import { useTranslation } from 'react-i18next'; import { graphql, useLazyLoadQuery } from 'react-relay'; import { FileUploadManagerQuery } from 'src/__generated__/FileUploadManagerQuery.graphql'; import { useSuspendedBackendaiClient } from 'src/hooks'; +import { useBAISettingUserState } from 'src/hooks/useBAISetting'; import * as tus from 'tus-js-client'; type uploadStartFunction = (callbacks?: { @@ -76,7 +77,10 @@ const FileUploadManager: React.FC = () => { const { generateFolderPath } = useFolderExplorerOpener(); const [uploadRequests, setUploadRequests] = useAtom(uploadRequestAtom); const [uploadStatus, setUploadStatus] = useAtom(uploadStatusAtom); - const queue = new PQueue({ concurrency: 4 }); + const [maxConcurrentUploads] = useBAISettingUserState( + 'max_concurrent_uploads', + ); + const queue = new PQueue({ concurrency: maxConcurrentUploads || 2 }); const pendingDeltaBytesRef = useRef>({}); const throttledUploadRequests = _.throttle( @@ -119,7 +123,7 @@ const FileUploadManager: React.FC = () => { maxWidth: '300px', }} > - ({t('explorer.Filename')}: {fileName}) + {fileName} ), @@ -205,56 +209,61 @@ const FileUploadManager: React.FC = () => { }; }); - uploadFileInfo.forEach(({ startFunction }) => { + uploadFileInfo.forEach(({ file, startFunction }) => { queue.add(async () => { + // Capture fileName before any async operations + const fileName = file.webkitRelativePath || file.name; let previousBytesUploaded = 0; - await startFunction({ - onProgress: (bytesUploaded, _bytesTotal, fileName) => { - // Since bytesUploaded is cumulative, calculate delta from previous value - const deltaBytes = bytesUploaded - previousBytesUploaded; - previousBytesUploaded = bytesUploaded; - pendingDeltaBytesRef.current[vFolderId] = - (pendingDeltaBytesRef.current[vFolderId] || 0) + deltaBytes; - - throttledUploadRequests(vFolderId, fileName); - }, - }) - // handle uploaded file name only, size is already handled in progress - .then(({ name: fileName }) => { - throttledUploadRequests.flush(); - delete pendingDeltaBytesRef.current[vFolderId]; - - setUploadStatus((prev) => ({ - ...prev, - [vFolderId]: { - ...prev[vFolderId], - pendingFiles: prev[vFolderId].pendingFiles.filter( - (f: string) => f !== fileName, - ), - completedFiles: [ - ...(prev[vFolderId]?.completedFiles || []), - fileName, - ], - }, - })); - }) - .catch(({ name: fileName }) => { - delete pendingDeltaBytesRef.current[vFolderId]; - - setUploadStatus((prev) => ({ - ...prev, - [vFolderId]: { - ...prev[vFolderId], - pendingFiles: prev[vFolderId].pendingFiles.filter( - (f: string) => f !== fileName, - ), - failedFiles: [ - ...(prev[vFolderId]?.failedFiles || []), - fileName, - ], - }, - })); + + try { + await startFunction({ + onProgress: (bytesUploaded, _bytesTotal, fileName) => { + // Since bytesUploaded is cumulative, calculate delta from previous value + const deltaBytes = bytesUploaded - previousBytesUploaded; + previousBytesUploaded = bytesUploaded; + pendingDeltaBytesRef.current[vFolderId] = + (pendingDeltaBytesRef.current[vFolderId] || 0) + deltaBytes; + + throttledUploadRequests(vFolderId, fileName); + }, }); + + // Success case + throttledUploadRequests.flush(); + delete pendingDeltaBytesRef.current[vFolderId]; + + setUploadStatus((prev) => ({ + ...prev, + [vFolderId]: { + ...prev[vFolderId], + pendingFiles: prev[vFolderId].pendingFiles.filter( + (f: string) => f !== fileName, + ), + completedFiles: [ + ...(prev[vFolderId]?.completedFiles || []), + fileName, + ], + }, + })); + } catch (error) { + // Error case - use the captured fileName regardless of error structure + throttledUploadRequests.flush(); + delete pendingDeltaBytesRef.current[vFolderId]; + + setUploadStatus((prev) => ({ + ...prev, + [vFolderId]: { + ...prev[vFolderId], + pendingFiles: prev[vFolderId].pendingFiles.filter( + (f: string) => f !== fileName, + ), + failedFiles: [ + ...(prev[vFolderId]?.failedFiles || []), + fileName, + ], + }, + })); + } }); }); }); @@ -403,46 +412,63 @@ export const useFileUploadManager = (vFolderId: string) => { fileName: string, ) => void; }) => { - const uploadPath = [currentPath, file.webkitRelativePath || file.name] - .filter(Boolean) - .join('/'); - const uploadUrl: string = await baiClient.vfolder.create_upload_session( - uploadPath, - file, - vfolderId, - ); - - return new Promise<{ name: string; bytes: number }>( - (resolve, reject) => { - const upload = new tus.Upload(file, { - endpoint: uploadUrl, - uploadUrl: uploadUrl, - retryDelays: [0, 3000, 5000, 10000, 20000], - chunkSize: getOptimalChunkSize(file.size), - storeFingerprintForResuming: false, // Disable localStorage storage - metadata: { - filename: file.name, - filetype: file.type, - }, - onProgress: (bytesUploaded, bytesTotal) => { - callbacks?.onProgress?.(bytesUploaded, bytesTotal, file.name); - }, - onSuccess: () => { - resolve({ - name: file.webkitRelativePath || file.name, - bytes: file.size, - }); - }, - onError: () => { - reject({ - name: file.webkitRelativePath || file.name, - bytes: file.size, + const fileName = file.webkitRelativePath || file.name; + + try { + const uploadPath = [currentPath, fileName].filter(Boolean).join('/'); + + const uploadUrl: string = + await baiClient.vfolder.create_upload_session( + uploadPath, + file, + vfolderId, + ); + + return await new Promise<{ name: string; bytes: number }>( + (resolve, reject) => { + try { + const upload = new tus.Upload(file, { + endpoint: uploadUrl, + uploadUrl: uploadUrl, + retryDelays: [0, 3000, 5000, 10000, 20000], + chunkSize: getOptimalChunkSize(file.size), + storeFingerprintForResuming: false, // Disable localStorage storage + metadata: { + filename: file.name, + filetype: file.type, + }, + onProgress: (bytesUploaded, bytesTotal) => { + callbacks?.onProgress?.( + bytesUploaded, + bytesTotal, + fileName, + ); + }, + onSuccess: () => { + resolve({ + name: fileName, + bytes: file.size, + }); + }, + onError: (_error) => { + // Always reject with consistent structure + reject(new Error(`Upload failed for ${fileName}`)); + }, }); - }, - }); - upload.start(); - }, - ); + upload.start(); + } catch (error) { + // Handle synchronous errors from tus.Upload constructor or start() + reject( + new Error(`Failed to initialize upload for ${fileName}`), + ); + } + }, + ); + } catch (error) { + // Handle API errors or any other errors + // Always throw with a consistent error message + throw new Error(`Failed to prepare upload for ${fileName}`); + } }; }); diff --git a/react/src/components/FolderExplorerOpener.tsx b/react/src/components/FolderExplorerOpener.tsx index b6d8d04997..7a8a4bedfb 100644 --- a/react/src/components/FolderExplorerOpener.tsx +++ b/react/src/components/FolderExplorerOpener.tsx @@ -1,4 +1,3 @@ -import { BAIUnmountAfterClose } from 'backend.ai-ui'; import React from 'react'; import { useLocation } from 'react-router-dom'; import { StringParam, useQueryParam } from 'use-query-params'; @@ -11,17 +10,15 @@ const FolderExplorerOpener = () => { const normalizedFolderId = folderId?.replaceAll('-', ''); return ( - - { - setFolderId(null, 'replaceIn'); - setCurrentPath(null, 'replaceIn'); - }} - destroyOnHidden - /> - + { + setFolderId(null, 'replaceIn'); + setCurrentPath(null, 'replaceIn'); + }} + destroyOnHidden + /> ); }; diff --git a/react/src/hooks/useBAISetting.tsx b/react/src/hooks/useBAISetting.tsx index 1075167fef..e6af4b69ba 100644 --- a/react/src/hooks/useBAISetting.tsx +++ b/react/src/hooks/useBAISetting.tsx @@ -34,6 +34,7 @@ interface UserSettings { [key: `table_column_overrides.${string}`]: BAITableColumnOverrideRecord; classic_session_list?: boolean; // `experimental_neo_session_list` has been replaced with `classic_session_list` + max_concurrent_uploads?: number; } export type SessionHistory = { diff --git a/react/src/pages/UserSettingsPage.tsx b/react/src/pages/UserSettingsPage.tsx index 39207315ce..392b7a9da0 100644 --- a/react/src/pages/UserSettingsPage.tsx +++ b/react/src/pages/UserSettingsPage.tsx @@ -57,6 +57,9 @@ const UserPreferencesPage = () => { const [shellInfo, setShellInfo] = useState('bootstrap'); const [isOpenShellScriptEditModal, { toggle: toggleShellScriptEditModal }] = useToggle(false); + const [maxConcurrentUpload, setMaxConcurrentUpload] = useBAISettingUserState( + 'max_concurrent_uploads', + ); const languageOptions = [ { label: t('language.English'), value: 'en' }, @@ -249,6 +252,38 @@ const UserPreferencesPage = () => { ), }, + { + 'data-testid': 'items-max-concurrent-uploads', + type: 'select', + title: t('userSettings.MaxConcurrentUploads'), + description: t('userSettings.DescMaxConcurrentUploads'), + selectProps: { + options: _.map([2, 3, 4, 5], (num) => + num === 2 + ? { + label: ( + <> + {num}  + + ({t('userSettings.Default')}) + + + ), + value: num, + } + : { + label: num.toString(), + value: num, + }, + ), + }, + defaultValue: 2, + value: maxConcurrentUpload || 2, + setValue: setMaxConcurrentUpload, + onChange: (value: any) => { + setMaxConcurrentUpload(value); + }, + }, ]), }, { diff --git a/resources/i18n/de.json b/resources/i18n/de.json index 5436fedab7..23f254c27b 100644 --- a/resources/i18n/de.json +++ b/resources/i18n/de.json @@ -1943,6 +1943,7 @@ "DescKeepLoginSessionInformation": "Lassen Sie die Webui-App beim nächsten Mal die aktuellen Anmeldesitzungsinformationen beibehalten.
Wenn die Option deaktiviert ist, werden die Anmeldeinformationen bei jeder Abmeldung gelöscht.", "DescLanguage": "Setzen Sie die Schnittstelle. Andere Sprachen als Englisch und Koreanisch werden per maschineller Übersetzung bereitgestellt.", "DescLetUserUpdateScriptWithNonEmptyValue": "Bitte aktualisieren Sie das Skript mit einem nicht leeren Wert.", + "DescMaxConcurrentUploads": "Begrenzt die Anzahl der Dateien, die gleichzeitig über den Datei-Explorer hochgeladen werden können.", "DescMyKeypairInfo": "Siehe meine Schlüsselpaarinformationen", "DescNewUserConfigFileCreated": "Eine neue Benutzerkonfigurationsdatei kann mit nicht leeren Daten erstellt werden.", "DescNoBetaFeatures": "Derzeit keine Beta-Funktion verfügbar. :)", @@ -1969,6 +1970,7 @@ "Language": "Sprache", "LightMode": "Lichtmodus", "Logs": "Protokolle", + "MaxConcurrentUploads": "Maximales Limit für gleichzeitiges Hochladen von Dateien", "MyKeypairInfo": "Meine Schlüsselpaarinformationen", "NEODataPage": "NEO -Datenseite", "NEOSessionList": "NEO Sitzungsliste", diff --git a/resources/i18n/el.json b/resources/i18n/el.json index e3ee9cb715..a08b130183 100644 --- a/resources/i18n/el.json +++ b/resources/i18n/el.json @@ -1942,6 +1942,7 @@ "DescKeepLoginSessionInformation": "Αφήστε την εφαρμογή webui να διατηρήσει τις τρέχουσες πληροφορίες σύνδεσης κατά την επόμενη φορά.
Εάν η επιλογή είναι απενεργοποιημένη, οι πληροφορίες σύνδεσης θα εκκαθαρίζονται σε κάθε αποσύνδεση.", "DescLanguage": "Ρυθμίστε τη γλώσσα διεπαφής. Οι γλώσσες εκτός από τα αγγλικά και τα κορεατικά θα παρέχονται μέσω μηχανικής μετάφρασης.", "DescLetUserUpdateScriptWithNonEmptyValue": "Ενημερώστε το σενάριο χωρίς κενή τιμή.", + "DescMaxConcurrentUploads": "Περιορίζει τον αριθμό των αρχείων που μπορούν να μεταφορτωθούν ταυτόχρονα μέσω της Εξερεύνησης αρχείων.", "DescMyKeypairInfo": "Δείτε τις πληροφορίες του ζεύγους κλειδιών μου", "DescNewUserConfigFileCreated": "Νέο αρχείο ρυθμίσεων χρήστη μπορεί να δημιουργηθεί με μη κενά δεδομένα.", "DescNoBetaFeatures": "Δεν υπάρχει διαθέσιμη δυνατότητα beta τώρα. :)", @@ -1968,6 +1969,7 @@ "Language": "Γλώσσα", "LightMode": "Λειτουργία φωτός", "Logs": "Κούτσουρα", + "MaxConcurrentUploads": "Μέγιστο όριο ταυτόχρονης μεταφόρτωσης αρχείων", "MyKeypairInfo": "Πληροφορίες για το ζεύγος κλειδιών μου", "NEOSessionList": "NEO Κατάλογος συνόδων", "NoExistingSSHKeypair": "Δεν πρέπει να αντιγραφεί το πληκτρολόγιο SSH. Για να λάβετε SSH Keypair, πατήστε το κουμπί Δημιουργία.", diff --git a/resources/i18n/en.json b/resources/i18n/en.json index 6a1eea4c27..3be731a777 100644 --- a/resources/i18n/en.json +++ b/resources/i18n/en.json @@ -1953,6 +1953,7 @@ "DescKeepLoginSessionInformation": "Let webui app keep current login session information next time.
If the option is turned off, login information will be cleared each logout.", "DescLanguage": "Set interface language. Languages other than English and Korean will be provided via machine translation.", "DescLetUserUpdateScriptWithNonEmptyValue": "Please update script with non empty value.", + "DescMaxConcurrentUploads": "Limits the number of files that can be uploaded simultaneously through the File Explorer.", "DescMyKeypairInfo": "See my keypair information", "DescNewUserConfigFileCreated": "New User config file can be created with non-empty data.", "DescNoBetaFeatures": "No beta feature available now. :)", @@ -1979,6 +1980,7 @@ "Language": "Language", "LightMode": "Light mode", "Logs": "Logs", + "MaxConcurrentUploads": "Max Concurrent File Upload Limit", "MyKeypairInfo": "My Keypair Information", "NEODataPage": "NEO Data page", "NEOSessionList": "NEO Session list", diff --git a/resources/i18n/es.json b/resources/i18n/es.json index ddfa48e66e..3ced53dc8f 100644 --- a/resources/i18n/es.json +++ b/resources/i18n/es.json @@ -1945,6 +1945,7 @@ "DescKeepLoginSessionInformation": "Permite que la aplicación webui conserve la información de la sesión de inicio de sesión actual la próxima vez.
Si la opción está desactivada, la información de inicio de sesión se borrará cada vez que se cierre la sesión.", "DescLanguage": "Establecer el lenguaje de la interfaz. Los idiomas que no sean inglés y coreano se proporcionarán a través de la traducción automática.", "DescLetUserUpdateScriptWithNonEmptyValue": "Por favor, actualice el script con un valor no vacío.", + "DescMaxConcurrentUploads": "Limita la cantidad de archivos que se pueden cargar simultáneamente a través del Explorador de archivos.", "DescMyKeypairInfo": "Ver la información de mi par de claves", "DescNewUserConfigFileCreated": "Se puede crear un nuevo archivo de configuración de usuario con datos no vacíos.", "DescNoBetaFeatures": "Ahora no hay ninguna función beta disponible. :)", @@ -1971,6 +1972,7 @@ "Language": "Idioma", "LightMode": "Modo de luz", "Logs": "Registros", + "MaxConcurrentUploads": "Límite máximo de carga de archivos simultáneos", "MyKeypairInfo": "Información de mi par de claves", "NEODataPage": "Página de datos neo", "NEOSessionList": "Lista de sesiones NEO", diff --git a/resources/i18n/fi.json b/resources/i18n/fi.json index 32d173500b..dcccb71054 100644 --- a/resources/i18n/fi.json +++ b/resources/i18n/fi.json @@ -1944,6 +1944,7 @@ "DescKeepLoginSessionInformation": "Anna webui-sovelluksen säilyttää nykyisen kirjautumisistunnon tiedot seuraavalla kerralla.
Jos vaihtoehto on pois päältä, kirjautumistiedot tyhjennetään jokaisen uloskirjautumisen yhteydessä.", "DescLanguage": "Aseta käyttöliittymäkieli. Muut kielet kuin englanti ja korea tarjotaan koneen käännöksen kautta.", "DescLetUserUpdateScriptWithNonEmptyValue": "Päivitä skripti ei-tyhjällä arvolla.", + "DescMaxConcurrentUploads": "Rajoittaa tiedostojen määrää, jotka voidaan ladata samanaikaisesti File Explorerin kautta.", "DescMyKeypairInfo": "Katso avainparini tiedot", "DescNewUserConfigFileCreated": "Uusi User config-tiedosto voidaan luoda ei-tyhjillä tiedoilla.", "DescNoBetaFeatures": "Beta-ominaisuutta ei ole nyt saatavilla :)", @@ -1970,6 +1971,7 @@ "Language": "Kieli", "LightMode": "Valotila", "Logs": "Lokit", + "MaxConcurrentUploads": "Samanaikaisen tiedostolatauksen enimmäisraja", "MyKeypairInfo": "Avainparini tiedot", "NEODataPage": "NEO -tietosivu", "NEOSessionList": "NEO-istuntoluettelo", diff --git a/resources/i18n/fr.json b/resources/i18n/fr.json index 79a12df31f..33d6cdacd6 100644 --- a/resources/i18n/fr.json +++ b/resources/i18n/fr.json @@ -1945,6 +1945,7 @@ "DescKeepLoginSessionInformation": "Laissez l'application webui conserver les informations de session de connexion actuelles la prochaine fois.
Si l'option est désactivée, les informations de connexion seront effacées à chaque déconnexion.", "DescLanguage": "Définir la langue d'interface. Des langues autres que l'anglais et le coréen seront fournies par traduction automatique.", "DescLetUserUpdateScriptWithNonEmptyValue": "Veuillez mettre à jour le script avec une valeur non vide.", + "DescMaxConcurrentUploads": "Limite le nombre de fichiers pouvant être téléchargés simultanément via l'explorateur de fichiers.", "DescMyKeypairInfo": "Voir les informations de ma paire de clés", "DescNewUserConfigFileCreated": "Un nouveau fichier de configuration utilisateur peut être créé avec des données non vides.", "DescNoBetaFeatures": "Aucune fonctionnalité bêta disponible actuellement. :)", @@ -1971,6 +1972,7 @@ "Language": "Langue", "LightMode": "Mode lumière", "Logs": "Journaux", + "MaxConcurrentUploads": "Limite maximale de téléchargement de fichiers simultanés", "MyKeypairInfo": "Informations sur ma paire de clés", "NEODataPage": "Page de données néo", "NEOSessionList": "Liste des sessions NEO", diff --git a/resources/i18n/id.json b/resources/i18n/id.json index 788d4b83d5..b0b4faa2ff 100644 --- a/resources/i18n/id.json +++ b/resources/i18n/id.json @@ -1944,6 +1944,7 @@ "DescKeepLoginSessionInformation": "Biarkan aplikasi UI web menyimpan informasi sesi login saat ini di lain waktu.
Jika opsi dimatikan, informasi login akan dihapus setiap keluar.", "DescLanguage": "Atur bahasa antarmuka. Bahasa selain bahasa Inggris dan Korea akan disediakan melalui terjemahan mesin.", "DescLetUserUpdateScriptWithNonEmptyValue": "Harap perbarui skrip dengan nilai yang tidak kosong.", + "DescMaxConcurrentUploads": "Membatasi jumlah file yang dapat diunggah secara bersamaan melalui File Explorer.", "DescMyKeypairInfo": "Lihat informasi keypair saya", "DescNewUserConfigFileCreated": "File konfigurasi pengguna baru dapat dibuat dengan data yang tidak kosong.", "DescNoBetaFeatures": "Tidak ada fitur beta yang tersedia sekarang. :)", @@ -1970,6 +1971,7 @@ "Language": "Bahasa", "LightMode": "Modus Cahaya", "Logs": "Log", + "MaxConcurrentUploads": "Batas Pengunggahan File Bersamaan Maks", "MyKeypairInfo": "Informasi Pasangan Kunci Saya", "NEODataPage": "Halaman data neo", "NEOSessionList": "Daftar Sesi NEO", diff --git a/resources/i18n/it.json b/resources/i18n/it.json index e227aef3cd..57a09e8078 100644 --- a/resources/i18n/it.json +++ b/resources/i18n/it.json @@ -1942,6 +1942,7 @@ "DescKeepLoginSessionInformation": "Consenti all'app webui di conservare le informazioni sulla sessione di accesso corrente la prossima volta.
Se l'opzione è disattivata, le informazioni di accesso verranno cancellate ad ogni logout.", "DescLanguage": "Imposta il linguaggio dell'interfaccia. Le lingue diverse dall'inglese e dal coreano saranno fornite tramite traduzione di macchine.", "DescLetUserUpdateScriptWithNonEmptyValue": "Aggiorna lo script con un valore non vuoto.", + "DescMaxConcurrentUploads": "Limita il numero di file che possono essere caricati contemporaneamente tramite Esplora file.", "DescMyKeypairInfo": "Vedi le informazioni sulla mia coppia di chiavi", "DescNewUserConfigFileCreated": "Il nuovo file di configurazione utente può essere creato con dati non vuoti.", "DescNoBetaFeatures": "Nessuna funzione beta disponibile ora. :)", @@ -1968,6 +1969,7 @@ "Language": "linguaggio", "LightMode": "Modalità luce", "Logs": "Registri", + "MaxConcurrentUploads": "Limite massimo di caricamento file simultanei", "MyKeypairInfo": "Informazioni sulla mia coppia di chiavi", "NEODataPage": "Pagina dati NEO", "NEOSessionList": "Elenco delle sessioni NEO", diff --git a/resources/i18n/ja.json b/resources/i18n/ja.json index 0857320ab2..9ee7aace68 100644 --- a/resources/i18n/ja.json +++ b/resources/i18n/ja.json @@ -1944,6 +1944,7 @@ "DescKeepLoginSessionInformation": "次回、webuiアプリに現在のログインセッション情報を保持させます。
オプションがオフの場合、ログイン情報はログアウトごとにクリアされます。", "DescLanguage": "インターフェイス言語を設定します。英語と韓国以外の言語は、機械翻訳によって提供されます。", "DescLetUserUpdateScriptWithNonEmptyValue": "空でない値でスクリプトを更新してください。", + "DescMaxConcurrentUploads": "ファイル エクスプローラーを通じて同時にアップロードできるファイルの数を制限します。", "DescMyKeypairInfo": "私のキーペア情報を参照してください", "DescNewUserConfigFileCreated": "空でないデータを使用して、新しいユーザー構成ファイルを作成できます。", "DescNoBetaFeatures": "現在、ベータ機能は利用できません。 :)", @@ -1970,6 +1971,7 @@ "Language": "言語", "LightMode": "ライトモード", "Logs": "ログ", + "MaxConcurrentUploads": "最大同時ファイルアップロード制限", "MyKeypairInfo": "私のキーペア情報", "NEODataPage": "NEOデータページ", "NEOSessionList": "NEOセッションリスト", diff --git a/resources/i18n/ko.json b/resources/i18n/ko.json index 5e8c49585a..529c7ca287 100644 --- a/resources/i18n/ko.json +++ b/resources/i18n/ko.json @@ -1950,6 +1950,7 @@ "DescKeepLoginSessionInformation": "웹 UI 앱이 다음 앱 사용시까지 로그인 세션 정보를 저장합니다.
이 옵션이 꺼져있을 경우, 매 종료시마다 로그인 정보가 자동으로 삭제됩니다.", "DescLanguage": "인터페이스 언어를 설정하세요. 영어와 한국어를 제외한 언어는 기계 번역으로 제공됩니다.", "DescLetUserUpdateScriptWithNonEmptyValue": "스크립트 수정을 위한 내용을 입력하세요.", + "DescMaxConcurrentUploads": "파일 익스플로어를 통해 동시에 업로드할 수 있는 파일의 개수를 제한합니다. ", "DescMyKeypairInfo": "내 키페어 정보 보기", "DescNewUserConfigFileCreated": "새 사용자 스크립트 생성을 위한 내용이 필요합니다.", "DescNoBetaFeatures": "사용 가능한 베타 기능이 없습니다. :)", @@ -1976,6 +1977,7 @@ "Language": "언어", "LightMode": "라이트 모드", "Logs": "로그", + "MaxConcurrentUploads": "병렬 파일 업로드 제한", "MyKeypairInfo": "내 키페어 정보", "NEODataPage": "NEO 데이터 페이지", "NEOSessionList": "NEO 세션 목록", diff --git a/resources/i18n/mn.json b/resources/i18n/mn.json index d3c044c833..9719d84819 100644 --- a/resources/i18n/mn.json +++ b/resources/i18n/mn.json @@ -1942,6 +1942,7 @@ "DescKeepLoginSessionInformation": "Webui програмыг нэвтрэх Sessionийн мэдээллийг дараагийн удаа хадгалахыг зөвшөөрнө үү.
Хэрэв тохиргоог унтраасан бол нэвтрэх тухай мэдээллийг нэвтрэх бүрээс хасах болно.", "DescLanguage": "Интерфейсийн хэлийг тохируулах. Англи хэлнээс бусад хэл, солонгос хэлээр машин орчуулга өгөх болно.", "DescLetUserUpdateScriptWithNonEmptyValue": "Хоосон утгатай скриптийг шинэчилнэ үү.", + "DescMaxConcurrentUploads": "Файл судлаачаар дамжуулан байршуулж болох файлуудын тоог хязгаарладаг.", "DescMyKeypairInfo": "Миний товчлуурын мэдээллийг харна уу", "DescNewUserConfigFileCreated": "Хэрэглэгчийн тохиргооны шинэ файлыг хоосон бус өгөгдлөөр үүсгэх боломжтой.", "DescNoBetaFeatures": "Бета хувилбар байхгүй. :)", @@ -1968,6 +1969,7 @@ "Language": "Хэл", "LightMode": "Гэрэл горим", "Logs": "Бүртгэл", + "MaxConcurrentUploads": "Макс тохиролцсон файлын байршуулалт", "MyKeypairInfo": "Миний товчлуурын мэдээлэл", "NEODataPage": "Неож өгөгдүүлэгч", "NEOSessionList": "Neo-ийн хуралдааны жагсаалт", diff --git a/resources/i18n/ms.json b/resources/i18n/ms.json index 9e2a9a5e6c..2e686377d4 100644 --- a/resources/i18n/ms.json +++ b/resources/i18n/ms.json @@ -1943,6 +1943,7 @@ "DescKeepLoginSessionInformation": "Biarkan aplikasi webui menyimpan maklumat sesi log masuk semasa lain kali.
Sekiranya pilihan dimatikan, maklumat log masuk akan dihapus setiap log keluar.", "DescLanguage": "Tetapkan bahasa antara muka. Bahasa selain bahasa Inggeris dan Korea akan disediakan melalui terjemahan mesin.", "DescLetUserUpdateScriptWithNonEmptyValue": "Sila kemas kini skrip dengan nilai yang tidak kosong.", + "DescMaxConcurrentUploads": "Hadkan bilangan fail yang boleh dimuat naik secara serentak melalui Fail Explorer.", "DescMyKeypairInfo": "Lihat maklumat pasangan kunci saya", "DescNewUserConfigFileCreated": "Fail konfigurasi Pengguna baru boleh dibuat dengan data yang tidak kosong.", "DescNoBetaFeatures": "Tidak ada ciri beta yang tersedia sekarang. :)", @@ -1969,6 +1970,7 @@ "Language": "Bahasa", "LightMode": "Mod Cahaya", "Logs": "Log", + "MaxConcurrentUploads": "Had muat naik fail serentak maksimum", "MyKeypairInfo": "Maklumat Pasangan Kunci Saya", "NEODataPage": "Halaman data NEO", "NEOSessionList": "Senarai Sesi NEO", diff --git a/resources/i18n/pl.json b/resources/i18n/pl.json index 765ec7848a..2c4ea512b9 100644 --- a/resources/i18n/pl.json +++ b/resources/i18n/pl.json @@ -1944,6 +1944,7 @@ "DescKeepLoginSessionInformation": "Pozwól aplikacji webui zachować bieżące informacje o sesji logowania następnym razem.
Jeśli opcja jest wyłączona, dane logowania będą usuwane przy każdym wylogowaniu.", "DescLanguage": "Ustaw język interfejsu. Języki inne niż angielski i koreański będą dostarczane przez tłumaczenie maszynowe.", "DescLetUserUpdateScriptWithNonEmptyValue": "Proszę zaktualizować skrypt o niepustą wartość.", + "DescMaxConcurrentUploads": "Ogranicza liczbę plików, które można przesłać jednocześnie za pomocą Eksploratora plików.", "DescMyKeypairInfo": "Zobacz informacje o mojej parze kluczy", "DescNewUserConfigFileCreated": "Nowy plik konfiguracji użytkownika można utworzyć z niepustymi danymi.", "DescNoBetaFeatures": "Obecnie nie ma dostępnej funkcji beta. :)", @@ -1970,6 +1971,7 @@ "Language": "Język", "LightMode": "Tryb światła", "Logs": "Dzienniki", + "MaxConcurrentUploads": "Maksymalny limit jednoczesnego przesyłania plików", "MyKeypairInfo": "Informacje o mojej parze kluczy", "NEODataPage": "Strona danych NEO", "NEOSessionList": "Lista sesji NEO", diff --git a/resources/i18n/pt-BR.json b/resources/i18n/pt-BR.json index 4dc70fd93b..f7a75beeb7 100644 --- a/resources/i18n/pt-BR.json +++ b/resources/i18n/pt-BR.json @@ -1945,6 +1945,7 @@ "DescKeepLoginSessionInformation": "Deixe o aplicativo webui manter as informações atuais da sessão de login na próxima vez.
Se a opção for desligada, as informações de login serão apagadas a cada logout.", "DescLanguage": "Definir linguagem de interface. Outros idiomas que não o inglês e o coreano serão fornecidos via tradução da máquina.", "DescLetUserUpdateScriptWithNonEmptyValue": "Atualize o script com um valor não vazio.", + "DescMaxConcurrentUploads": "Limita o número de arquivos que podem ser carregados simultaneamente por meio do Explorador de Arquivos.", "DescMyKeypairInfo": "Ver as informações do meu par de chaves", "DescNewUserConfigFileCreated": "O novo arquivo de configuração do usuário pode ser criado com dados não vazios.", "DescNoBetaFeatures": "Nenhum recurso beta disponível agora. :)", @@ -1971,6 +1972,7 @@ "Language": "Língua", "LightMode": "Modo claro", "Logs": "Histórico", + "MaxConcurrentUploads": "Limite máximo de upload simultâneo de arquivos", "MyKeypairInfo": "Minhas informações de par de chaves", "NEODataPage": "Página de dados neo", "NEOSessionList": "Lista de sessões NEO", diff --git a/resources/i18n/pt.json b/resources/i18n/pt.json index 6526f4a177..1a7881e757 100644 --- a/resources/i18n/pt.json +++ b/resources/i18n/pt.json @@ -1944,6 +1944,7 @@ "DescKeepLoginSessionInformation": "Deixe o aplicativo webui manter as informações atuais da sessão de login na próxima vez.
Se a opção for desligada, as informações de login serão apagadas a cada logout.", "DescLanguage": "Definir linguagem de interface. Outros idiomas que não o inglês e o coreano serão fornecidos via tradução da máquina.", "DescLetUserUpdateScriptWithNonEmptyValue": "Atualize o script com um valor não vazio.", + "DescMaxConcurrentUploads": "Limita o número de arquivos que podem ser carregados simultaneamente por meio do Explorador de Arquivos.", "DescMyKeypairInfo": "Ver as informações do meu par de chaves", "DescNewUserConfigFileCreated": "O novo arquivo de configuração do usuário pode ser criado com dados não vazios.", "DescNoBetaFeatures": "Nenhum recurso beta disponível agora. :)", @@ -1970,6 +1971,7 @@ "Language": "Língua", "LightMode": "Modo claro", "Logs": "Histórico", + "MaxConcurrentUploads": "Limite máximo de upload simultâneo de arquivos", "MyKeypairInfo": "Minhas informações de par de chaves", "NEODataPage": "Página de dados neo", "NEOSessionList": "Lista de sessões NEO", diff --git a/resources/i18n/ru.json b/resources/i18n/ru.json index 25d9529e94..cbea444a2b 100644 --- a/resources/i18n/ru.json +++ b/resources/i18n/ru.json @@ -1944,6 +1944,7 @@ "DescKeepLoginSessionInformation": "Разрешите приложению webui в следующий раз сохранить текущую информацию о сеансе входа.
Если опция выключена, информация для входа в систему будет очищаться при каждом выходе из системы.", "DescLanguage": "Установить язык интерфейса. Языки, отличные от английского и корейского, будут предоставлены с помощью машинного перевода.", "DescLetUserUpdateScriptWithNonEmptyValue": "Пожалуйста, обновите скрипт с непустым значением.", + "DescMaxConcurrentUploads": "Ограничивает количество файлов, которые можно загрузить одновременно через проводник.", "DescMyKeypairInfo": "Посмотреть информацию о моей паре ключей", "DescNewUserConfigFileCreated": "Файл конфигурации нового пользователя может быть создан с непустыми данными.", "DescNoBetaFeatures": "В настоящее время бета-функция недоступна. :)", @@ -1970,6 +1971,7 @@ "Language": "Язык", "LightMode": "Светлый режим", "Logs": "Журналы", + "MaxConcurrentUploads": "Максимальный лимит одновременной загрузки файлов", "MyKeypairInfo": "Информация о моей паре ключей", "NEODataPage": "НЕО СТРАНИЦА ДАННЫХ", "NEOSessionList": "Список сессий NEO", diff --git a/resources/i18n/th.json b/resources/i18n/th.json index 2733117c24..e164b5a3e1 100644 --- a/resources/i18n/th.json +++ b/resources/i18n/th.json @@ -1928,6 +1928,7 @@ "DescKeepLoginSessionInformation": "ให้แอป webui เก็บข้อมูลเซสชันเข้าสู่ระบบปัจจุบันไว้สำหรับครั้งต่อไป
หากปิดตัวเลือกนี้ ข้อมูลการเข้าสู่ระบบจะถูกล้างทุกครั้งที่ออกจากระบบ", "DescLanguage": "ตั้งค่าภาษาอินเตอร์เฟส ภาษาอื่นที่ไม่ใช่ภาษาอังกฤษและเกาหลีจะได้รับผ่านการแปลด้วยเครื่อง", "DescLetUserUpdateScriptWithNonEmptyValue": "กรุณาอัปเดตสคริปต์ด้วยค่าที่ไม่ว่างเปล่า", + "DescMaxConcurrentUploads": "จำกัดจำนวนไฟล์ที่สามารถอัพโหลดพร้อมกันผ่าน File Explorer", "DescMyKeypairInfo": "ดูข้อมูลคู่คีย์ของฉัน", "DescNewUserConfigFileCreated": "สามารถสร้างไฟล์การกำหนดค่าผู้ใช้ใหม่ได้ด้วยข้อมูลที่ไม่ว่างเปล่า", "DescNoBetaFeatures": "ไม่มีคุณสมบัติเบต้าที่พร้อมใช้งานในขณะนี้ :)", @@ -1954,6 +1955,7 @@ "Language": "ภาษา", "LightMode": "โหมดสว่าง", "Logs": "บันทึก", + "MaxConcurrentUploads": "ขีดจำกัดการอัพโหลดไฟล์สูงสุดพร้อมกัน", "MyKeypairInfo": "ข้อมูลคู่คีย์ของฉัน", "NEODataPage": "หน้าข้อมูลนีโอ", "NEOSessionList": "รายการเซสชัน NEO", diff --git a/resources/i18n/tr.json b/resources/i18n/tr.json index e930f3e314..45dd5d3384 100644 --- a/resources/i18n/tr.json +++ b/resources/i18n/tr.json @@ -1945,6 +1945,7 @@ "DescKeepLoginSessionInformation": "Webui uygulamasının bir dahaki sefere mevcut oturum açma bilgilerini tutmasına izin verin.
Seçenek kapatılırsa, oturum açma bilgileri her oturum kapatıldığında temizlenir.", "DescLanguage": "Arayüz dilini ayarlayın. İngilizce ve Korece dışındaki diller makine çevirisi ile sağlanacaktır.", "DescLetUserUpdateScriptWithNonEmptyValue": "Lütfen komut dosyasını boş olmayan bir değerle güncelleyin.", + "DescMaxConcurrentUploads": "Dosya Gezgini aracılığıyla aynı anda yüklenebilecek dosya sayısını sınırlar.", "DescMyKeypairInfo": "Anahtar çifti bilgilerimi görün", "DescNewUserConfigFileCreated": "Boş olmayan verilerle yeni Kullanıcı yapılandırma dosyası oluşturulabilir.", "DescNoBetaFeatures": "Şu anda mevcut beta özelliği yok. :)", @@ -1971,6 +1972,7 @@ "Language": "Dil", "LightMode": "Işık Modu", "Logs": "Kütükler", + "MaxConcurrentUploads": "Maksimum Eşzamanlı Dosya Yükleme Sınırı", "MyKeypairInfo": "Anahtar Çifti Bilgilerim", "NEODataPage": "NEO veri sayfası", "NEOSessionList": "NEO Oturum listesi", diff --git a/resources/i18n/vi.json b/resources/i18n/vi.json index 1cfcbe2e30..229720747b 100644 --- a/resources/i18n/vi.json +++ b/resources/i18n/vi.json @@ -1945,6 +1945,7 @@ "DescKeepLoginSessionInformation": "Hãy để ứng dụng webui giữ thông tin phiên đăng nhập hiện tại vào lần sau.
Nếu tùy chọn bị tắt, thông tin đăng nhập sẽ bị xóa mỗi lần đăng xuất.", "DescLanguage": "Đặt ngôn ngữ giao diện. Các ngôn ngữ khác ngoài tiếng Anh và tiếng Hàn sẽ được cung cấp thông qua dịch máy.", "DescLetUserUpdateScriptWithNonEmptyValue": "Vui lòng cập nhật tập lệnh với giá trị không trống.", + "DescMaxConcurrentUploads": "Giới hạn số lượng tệp có thể được tải lên đồng thời thông qua File Explorer.", "DescMyKeypairInfo": "Xem thông tin cặp khóa của tôi", "DescNewUserConfigFileCreated": "Tệp cấu hình Người dùng mới có thể được tạo bằng dữ liệu không trống.", "DescNoBetaFeatures": "Hiện không có tính năng beta nào. :)", @@ -1971,6 +1972,7 @@ "Language": "Ngôn ngữ", "LightMode": "Chế độ sáng", "Logs": "Nhật ký", + "MaxConcurrentUploads": "Giới hạn tải lên tệp đồng thời tối đa", "MyKeypairInfo": "Thông tin về cặp khóa của tôi", "NEODataPage": "Trang dữ liệu NEO", "NEOSessionList": "Danh sách phiên Neo", diff --git a/resources/i18n/zh-CN.json b/resources/i18n/zh-CN.json index 881950872c..0191cc3b29 100644 --- a/resources/i18n/zh-CN.json +++ b/resources/i18n/zh-CN.json @@ -1945,6 +1945,7 @@ "DescKeepLoginSessionInformation": "下次让 webui 应用程序保留当前登录会话信息。
如果关闭该选项,则每次注销时都会清除登录信息。", "DescLanguage": "设置接口语言。英语和韩文以外的语言将通过机器翻译提供。", "DescLetUserUpdateScriptWithNonEmptyValue": "请使用非空值更新脚本。", + "DescMaxConcurrentUploads": "限制可以通过文件资源管理器同时上传的文件数量。", "DescMyKeypairInfo": "查看我的密钥对信息", "DescNewUserConfigFileCreated": "可以使用非空数据创建新用户配置文件。", "DescNoBetaFeatures": "现在没有可用的测试版功能。 :)", @@ -1971,6 +1972,7 @@ "Language": "语", "LightMode": "灯光模式", "Logs": "日志", + "MaxConcurrentUploads": "最大并发文件上传限制", "MyKeypairInfo": "我的密钥对信息", "NEODataPage": "NEO数据页", "NEOSessionList": "近地天体会议列表", diff --git a/resources/i18n/zh-TW.json b/resources/i18n/zh-TW.json index cbba0430d2..ba067b9827 100644 --- a/resources/i18n/zh-TW.json +++ b/resources/i18n/zh-TW.json @@ -1943,6 +1943,7 @@ "DescKeepLoginSessionInformation": "下次讓 webui 應用程序保留當前登錄會話信息。
如果關閉該選項,則每次註銷時都會清除登錄信息。", "DescLanguage": "設置接口語言。英語和韓文以外的語言將通過機器翻譯提供。", "DescLetUserUpdateScriptWithNonEmptyValue": "請使用非空值更新腳本。", + "DescMaxConcurrentUploads": "限制可以通過文件資源管理器同時上傳的文件數量。", "DescMyKeypairInfo": "查看我的密鑰對訊息", "DescNewUserConfigFileCreated": "可以使用非空數據創建新用戶配置文件。", "DescNoBetaFeatures": "現在沒有可用的測試版功能。 :)", @@ -1969,6 +1970,7 @@ "Language": "語", "LightMode": "燈光模式", "Logs": "日誌", + "MaxConcurrentUploads": "最大並發文件上傳限制", "MyKeypairInfo": "我的密鑰對訊息", "NEODataPage": "NEO數據頁", "NEOSessionList": "近地天体会议列表",