diff --git a/react/src/components/ComputeSessionNodeItems/SessionActionButtons.tsx b/react/src/components/ComputeSessionNodeItems/SessionActionButtons.tsx index b163606bbb..021c505d8d 100644 --- a/react/src/components/ComputeSessionNodeItems/SessionActionButtons.tsx +++ b/react/src/components/ComputeSessionNodeItems/SessionActionButtons.tsx @@ -256,7 +256,9 @@ const SessionActionButtons: React.FC = ({ - - + {vfolderNode && !vfolderNode?.unmanaged_path ? ( + }> + + + + + + + ) : null} diff --git a/react/src/components/FolderExplorerModal.tsx b/react/src/components/FolderExplorerModal.tsx index 0fbcddfe2e..07963c0c18 100644 --- a/react/src/components/FolderExplorerModal.tsx +++ b/react/src/components/FolderExplorerModal.tsx @@ -160,7 +160,6 @@ const FolderExplorerModal: React.FC = ({ zIndex: token.zIndexPopupBase + 2, }} vfolderNodeFrgmt={vfolder_node} - folderExplorerRef={folderExplorerRef} /> ) : null } diff --git a/react/src/components/SFTPServerButton.tsx b/react/src/components/SFTPServerButton.tsx new file mode 100644 index 0000000000..46ee64a79d --- /dev/null +++ b/react/src/components/SFTPServerButton.tsx @@ -0,0 +1,196 @@ +import { App, Image, Tooltip } from 'antd'; +import { + BAIButton, + BAIButtonProps, + useErrorMessageResolver, +} from 'backend.ai-ui'; +import _ from 'lodash'; +import { useTranslation } from 'react-i18next'; +import { graphql, useFragment } from 'react-relay'; +import { SFTPServerButtonFragment$key } from 'src/__generated__/SFTPServerButtonFragment.graphql'; +import { useCurrentDomainValue, useSuspendedBackendaiClient } from 'src/hooks'; +import { useSetBAINotification } from 'src/hooks/useBAINotification'; +import { + useCurrentProjectValue, + useResourceGroupsForCurrentProject, +} from 'src/hooks/useCurrentProject'; +import { useDefaultSystemSSHImageWithFallback } from 'src/hooks/useDefaultImagesWithFallback'; +import { useMergedAllowedStorageHostPermission } from 'src/hooks/useMergedAllowedStorageHostPermission'; +import { + startSessionErrorCodes, + StartSessionWithDefaultValue, + useStartSession, +} from 'src/hooks/useStartSession'; + +interface SFTPServerButtonProps extends BAIButtonProps { + showTitle?: boolean; + vfolderFrgmt: SFTPServerButtonFragment$key; +} + +const SFTPServerButton: React.FC = ({ + showTitle = true, + vfolderFrgmt, + ...buttonProps +}) => { + 'use memo'; + + const { t } = useTranslation(); + const { message, modal } = App.useApp(); + + const baiClient = useSuspendedBackendaiClient(); + const currentDomain = useCurrentDomainValue(); + const currentProject = useCurrentProjectValue(); + const currentUserAccessKey = baiClient?._config?.accessKey; + const { unitedAllowedPermissionByVolume } = + useMergedAllowedStorageHostPermission( + currentDomain, + currentProject.id, + currentUserAccessKey, + ); + const { vhostInfo: vhostInfoByCurrentProject } = + useResourceGroupsForCurrentProject(); + + const { getErrorMessage } = useErrorMessageResolver(); + const { startSessionWithDefault, upsertSessionNotification } = + useStartSession(); + const { upsertNotification } = useSetBAINotification(); + + const { systemSSHImage, systemSSHImageInfo } = + useDefaultSystemSSHImageWithFallback(); + + console.log('systemSSHImage', systemSSHImageInfo); + + const vfolder = useFragment( + graphql` + fragment SFTPServerButtonFragment on VirtualFolderNode { + id + row_id + host + } + `, + vfolderFrgmt, + ); + + // Verify that the current user has access to the volume of the vfolder. + // Check the project has SFTP scaling groups for the host of the vfolder. + const sftpScalingGroupByCurrentProject = + vhostInfoByCurrentProject?.volume_info[vfolder?.host || ''] + ?.sftp_scaling_groups; + // Verify that the current project has access to the volumes in the folder. + // Check the user has 'mount-in-session' permission united by domain, project, and keypair resource policy. + const hasAccessPermission = _.includes( + unitedAllowedPermissionByVolume[vfolder?.host ?? ''], + 'mount-in-session', + ); + + const getTooltipTitle = () => { + if (!hasAccessPermission) { + return t('data.explorer.NoPermissionToMountFolder'); + } else if (_.isEmpty(sftpScalingGroupByCurrentProject)) { + return t('data.explorer.NoSFTPSupportingScalingGroup'); + } else if (!systemSSHImage) { + return t('data.explorer.NoImagesSupportingSystemSession'); + } else if (!showTitle && systemSSHImage) { + return t('data.explorer.RunSSH/SFTPserver'); + } else return ''; + }; + + return ( + + + } + action={async () => { + const resource: StartSessionWithDefaultValue['resource'] = { + cpu: + _.toNumber( + _.find(systemSSHImageInfo?.resource_limits, { key: 'cpu' }) + ?.min, + ) || 2, + mem: + _.find(systemSSHImageInfo?.resource_limits, { key: 'mem' }) + ?.min || '0.5g', + }; + + const sftpSessionConf: StartSessionWithDefaultValue = { + sessionName: `sftp-${vfolder?.row_id}`, + sessionType: 'system', + // use default system SSH image if configured and allowed + ...(baiClient._config?.systemSSHImage && + baiClient._config?.allow_manual_image_name_for_session + ? { + environments: { + manual: baiClient._config.systemSSHImage, + }, + } + : // otherwise use the first image found + { + environments: { + version: systemSSHImage || '', + }, + }), + cluster_mode: 'single-node', + cluster_size: 1, + mount_ids: [vfolder?.row_id?.replaceAll('-', '') || ''], + resourceGroup: sftpScalingGroupByCurrentProject?.[0], + resource: { + cpu: resource.cpu < 2 ? 2 : resource.cpu, + mem: resource.mem, + }, + }; + + await startSessionWithDefault(sftpSessionConf) + .then((results) => { + if (results?.fulfilled && results.fulfilled.length > 0) { + // set notification key for handling duplicate session creation + upsertSessionNotification(results.fulfilled, [ + { + key: `sftp-${vfolder?.row_id}`, + }, + ]); + } + if (results?.rejected && results.rejected.length > 0) { + const error = results.rejected[0].reason; + if ( + _.includes( + error.message, + startSessionErrorCodes.DUPLICATED_SESSION, + ) + ) { + upsertNotification({ + key: `sftp-${vfolder?.row_id}`, + open: true, + }); + } else { + modal.error({ + title: error?.title, + content: getErrorMessage(error), + }); + } + } + }) + .catch((error) => { + console.error('Unexpected error during session creation:', error); + message.error(t('error.UnexpectedError')); + }); + }} + {...buttonProps} + > + {showTitle && t('data.explorer.RunSSH/SFTPserver')} + + + ); +}; + +export default SFTPServerButton; diff --git a/react/src/hooks/useDefaultFileBrowserImageWithFallback.ts b/react/src/hooks/useDefaultFileBrowserImageWithFallback.ts deleted file mode 100644 index 5ac315fd44..0000000000 --- a/react/src/hooks/useDefaultFileBrowserImageWithFallback.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { backendaiClientPromise } from '.'; -import { useAtom } from 'jotai'; -import { atomWithDefault } from 'jotai/utils'; -import _ from 'lodash'; -import { useEffect } from 'react'; -import { fetchQuery, graphql, useRelayEnvironment } from 'react-relay'; -import { useDefaultFileBrowserImageWithFallbackQuery } from 'src/__generated__/useDefaultFileBrowserImageWithFallbackQuery.graphql'; -import { getImageFullName } from 'src/helper'; - -const defaultFileBrowserAtom = atomWithDefault< - string | null | undefined | Promise ->(async () => { - // backendaiClientPromise is a promise instance; - const baiClient = await backendaiClientPromise; - return _.isEmpty(baiClient._config?.defaultFileBrowserImage) - ? undefined //if '', treat as undefined - : baiClient._config?.defaultFileBrowserImage; -}); - -export const useDefaultFileBrowserImageWithFallback = () => { - 'use memo'; - const [defaultFileBrowserImage, setDefaultFileBrowserImage] = useAtom( - defaultFileBrowserAtom, - ); - const relayEnv = useRelayEnvironment(); - - // If no default image is configured, fetch the first available image with filebrowser label - useEffect(() => { - if (defaultFileBrowserImage === undefined) { - // TODO: Currently, file browser filtering by server-side is not supported. - // Once supported, modify the query to fetch only relevant images. - fetchQuery( - relayEnv, - graphql` - query useDefaultFileBrowserImageWithFallbackQuery( - $installed: Boolean - ) { - images(is_installed: $installed) { - id - tag - registry - architecture - name @deprecatedSince(version: "24.12.0") - namespace @since(version: "24.12.0") - labels { - key - value - } - tags @since(version: "24.12.0") { - key - value - } - } - } - `, - { - installed: true, - }, - { - fetchPolicy: 'store-or-network', - }, - ) - .toPromise() - .then((response) => - response?.images?.filter((image) => - image?.labels?.find( - (label) => - label?.key === 'ai.backend.service-ports' && - label?.value?.toLowerCase().includes('filebrowser'), - ), - ), - ) - .then(async (filebrowserImages) => { - const firstImage = _.first(filebrowserImages); - setDefaultFileBrowserImage( - firstImage ? getImageFullName(firstImage) : null, - ); - }) - .catch(() => { - // in case of error, set null to disable file browser button - setDefaultFileBrowserImage(null); - }); - } - }, [relayEnv, defaultFileBrowserImage, setDefaultFileBrowserImage]); - - return defaultFileBrowserImage; -}; diff --git a/react/src/hooks/useDefaultImagesWithFallback.ts b/react/src/hooks/useDefaultImagesWithFallback.ts new file mode 100644 index 0000000000..1cfc6238ad --- /dev/null +++ b/react/src/hooks/useDefaultImagesWithFallback.ts @@ -0,0 +1,160 @@ +import { backendaiClientPromise } from '.'; +import { atom, useAtom } from 'jotai'; +import { atomWithDefault } from 'jotai/utils'; +import _ from 'lodash'; +import { useEffect, useEffectEvent } from 'react'; +import { fetchQuery, graphql, useRelayEnvironment } from 'react-relay'; +import { + useDefaultImagesWithFallbackQuery, + useDefaultImagesWithFallbackQuery$data, +} from 'src/__generated__/useDefaultImagesWithFallbackQuery.graphql'; +import { getImageFullName } from 'src/helper'; + +const IMAGES_QUERY = graphql` + query useDefaultImagesWithFallbackQuery($installed: Boolean) { + images(is_installed: $installed) { + id + tag + registry + architecture + name @deprecatedSince(version: "24.12.0") + namespace @since(version: "24.12.0") + labels { + key + value + } + tags @since(version: "24.12.0") { + key + value + } + resource_limits { + key + min + max + } + } + } +`; + +const defaultFileBrowserImageAtom = atomWithDefault< + string | null | undefined | Promise +>(async () => { + const baiClient = await backendaiClientPromise; + return _.isEmpty(baiClient._config?.defaultFileBrowserImage) + ? undefined + : baiClient._config?.defaultFileBrowserImage; +}); + +const systemSSHImageAtom = atomWithDefault< + string | null | undefined | Promise +>(async () => { + const baiClient = await backendaiClientPromise; + return _.isEmpty(baiClient._config?.systemSSHImage) + ? undefined + : baiClient._config?.systemSSHImage; +}); +const systemSSHImageInfoAtom = + atom[number]>(); + +export const useDefaultFileBrowserImageWithFallback = () => { + 'use memo'; + const [defaultFileBrowserImage, setDefaultFileBrowserImage] = useAtom( + defaultFileBrowserImageAtom, + ); + const relayEnv = useRelayEnvironment(); + + const getImage = useEffectEvent(() => { + if (defaultFileBrowserImage === undefined) { + // TODO: Currently, file browser filtering by server-side is not supported. + // Once supported, modify the query to fetch only relevant images. + fetchQuery( + relayEnv, + IMAGES_QUERY, + { + installed: true, + }, + { + fetchPolicy: 'store-or-network', + }, + ) + .toPromise() + .then((response) => + response?.images?.filter((image) => + image?.labels?.find( + (label) => + label?.key === 'ai.backend.service-ports' && + label?.value?.toLowerCase().includes('filebrowser'), + ), + ), + ) + .then(async (filebrowserImages) => { + const firstImage = _.first(filebrowserImages); + setDefaultFileBrowserImage( + firstImage ? getImageFullName(firstImage) : null, + ); + }) + .catch(() => { + // in case of error, set null to disable file browser button + setDefaultFileBrowserImage(null); + }); + } + }); + + useEffect(() => { + getImage(); + }, []); + + return defaultFileBrowserImage; +}; + +export const useDefaultSystemSSHImageWithFallback = () => { + 'use memo'; + const [systemSSHImage, setSystemSSHImage] = useAtom(systemSSHImageAtom); + const [systemSSHImageInfo, setSystemSSHImageInfo] = useAtom( + systemSSHImageInfoAtom, + ); + const relayEnv = useRelayEnvironment(); + + const getImage = useEffectEvent(() => { + if (systemSSHImage === undefined) { + // TODO: Currently, SSH/SFTP filtering by server-side is not supported. + // Once supported, modify the query to fetch only relevant images. + fetchQuery( + relayEnv, + IMAGES_QUERY, + { + installed: true, + }, + { + fetchPolicy: 'store-or-network', + }, + ) + .toPromise() + .then((response) => + response?.images?.filter((image) => + image?.labels?.find( + (label) => + label?.key === 'ai.backend.role' && + label?.value?.toLowerCase().includes('system'), + ), + ), + ) + .then(async (sshImages) => { + const firstImage = _.first(sshImages); + console.log(firstImage); + setSystemSSHImage(firstImage ? getImageFullName(firstImage) : null); + setSystemSSHImageInfo(firstImage || undefined); + }) + .catch(() => { + // in case of error, set null to disable SFTP button + setSystemSSHImage(null); + }); + } + }); + + useEffect(() => { + getImage(); + }, []); + + return { systemSSHImage, systemSSHImageInfo }; +}; diff --git a/react/src/hooks/useStartSession.tsx b/react/src/hooks/useStartSession.tsx index 0df823bae8..f8dcf4277c 100644 --- a/react/src/hooks/useStartSession.tsx +++ b/react/src/hooks/useStartSession.tsx @@ -31,6 +31,10 @@ interface CreateSessionInfo { resources: SessionResources; } +export const startSessionErrorCodes = { + DUPLICATED_SESSION: 'DUPLICATED_SESSION', +}; + export const SESSION_LAUNCHER_NOTI_PREFIX = 'session-launcher:'; // Field names that have default values in SessionLauncherFormValue @@ -275,20 +279,20 @@ export const useStartSession = () => { undefined, sessionInfo.architecture, ) - .then((res: { created: boolean; status: string }) => { - // // When session is already created with the same name, the status code - // // is 200, but the response body has 'created' field as false. For better - // // user experience, we show the notification message. - if (!res?.created) { - // message.warning(t('session.launcher.SessionAlreadyExists')); - throw new Error(t('session.launcher.SessionAlreadyExists')); - } - if (res?.status === 'CANCELLED') { - // Case about failed to start new session kind of "docker image not found" or etc. - throw new Error(t('session.launcher.FailedToStartNewSession')); - } - return res; - }) + .then( + (res: { created: boolean; status: string; sessionId: string }) => { + // When session is already created with the same name, the status code + // is 200, but the response body has 'created' field as false. + // For such cases, we throw an error to be handled by using component. + if (!res?.created) { + const error = new Error( + startSessionErrorCodes.DUPLICATED_SESSION, + ); + throw error; + } + return res; + }, + ) .catch((err: any) => { if (err?.message?.includes('The session already exists')) { throw new Error(t('session.launcher.SessionAlreadyExists')); diff --git a/react/src/pages/SessionLauncherPage.tsx b/react/src/pages/SessionLauncherPage.tsx index 89f297cffb..9fa5e79c94 100644 --- a/react/src/pages/SessionLauncherPage.tsx +++ b/react/src/pages/SessionLauncherPage.tsx @@ -133,7 +133,7 @@ export interface SessionResources { } interface SessionLauncherValue { - sessionType: 'interactive' | 'batch' | 'inference'; + sessionType: 'interactive' | 'batch' | 'inference' | 'system'; batch: { enabled: boolean; scheduleDate?: string; diff --git a/resources/i18n/de.json b/resources/i18n/de.json index e3991a7276..d2b8e92869 100644 --- a/resources/i18n/de.json +++ b/resources/i18n/de.json @@ -320,8 +320,11 @@ "Name": "Name", "NewFileName": "Neuer Dateiname", "NewFolder": "Neuer Ordner", + "NoAccessPermissionToVolume": "Das aktuelle Projekt hat keinen Zugriff auf das SFTP-Volume.", "NoImagesSupportingFileBrowser": "Es gibt noch keine Bilder, die den Dateibrowser unterstützen. Zum Hochladen von Ordnern ist mindestens ein Bild erforderlich, das den Dateibrowser unterstützt.", "NoImagesSupportingSystemSession": "Es gibt noch kein Image, das SSH / SFTP unterstützt. Mindestens ein oder mehrere Images, die Systemrollen-Images unterstützen, um SSH / SFTP zu verwenden.", + "NoPermissionToMountFolder": "Das aktuelle Projekt hat keine Berechtigung, den mit diesem Ordner verknüpften Speicher-Host einzubinden.", + "NoSFTPSupportingScalingGroup": "Der Storage-Host dieses Ordners hat keine SFTP-Ressourcengruppe.", "NoSharedFolders": "Keine freigegebenen Ordner", "NoSharedUsers": "Niemand wurde eingeladen", "NotEnoughResourceForFileBrowserSession": "Nicht genügend Ressourcen (CPU: 1 Core, Speicher: 0,5 GB), um die Sitzung für den Dateibrowser zu erstellen. Bitte überprüfen Sie die verfügbaren Ressourcen.", diff --git a/resources/i18n/el.json b/resources/i18n/el.json index a2cf29827c..48b35bee8e 100644 --- a/resources/i18n/el.json +++ b/resources/i18n/el.json @@ -319,8 +319,11 @@ "Name": "Ονομα", "NewFileName": "Νέο όνομα αρχείου", "NewFolder": "Νέος φάκελος", + "NoAccessPermissionToVolume": "Το τρέχον έργο δεν έχει πρόσβαση στον τόμο SFTP.", "NoImagesSupportingFileBrowser": "Δεν υπάρχουν εικόνες που να υποστηρίζουν το πρόγραμμα περιήγησης. Για τη μεταφόρτωση φακέλων απαιτείται τουλάχιστον μία ή περισσότερες εικόνες που υποστηρίζουν το πρόγραμμα περιήγησης αρχείων.", "NoImagesSupportingSystemSession": "Δεν υπάρχει ακόμα εικόνα που να υποστηρίζει SSH / SFTP. Τουλάχιστον μία ή περισσότερες εικόνες που υποστηρίζουν εικόνες ρόλων συστήματος για τη χρήση SSH / SFTP.", + "NoPermissionToMountFolder": "Το τρέχον έργο δεν έχει δικαιώματα προσάρτησης στον διακομιστή αποθήκευσης που σχετίζεται με αυτόν τον φάκελο.", + "NoSFTPSupportingScalingGroup": "Ο διακομιστής αποθήκευσης αυτού του φακέλου δεν έχει ομάδα πόρων SFTP.", "NoSharedFolders": "Δεν υπάρχουν κοινόχρηστοι φάκελοι", "NotEnoughResourceForFileBrowserSession": "Δεν υπάρχουν αρκετοί πόροι (cpu: 1 Core, mem: 0,5 GB) για τη δημιουργία της περιόδου λειτουργίας για το πρόγραμμα περιήγησης αρχείων παρακαλούμε ελέγξτε τους διαθέσιμους πόρους.", "NumberOfSFTPSessionsExceededBody": "Εκτελείτε όλες τις διαθέσιμες συνεδρίες μεταφόρτωσης που επιτρέπεται να δημιουργήσετε. Παρακαλούμε τερματίστε τις αχρησιμοποίητες συνεδρίες μεταφόρτωσης πριν ξεκινήσετε μια νέα συνεδρία.", diff --git a/resources/i18n/en.json b/resources/i18n/en.json index f28c37cd89..602a5ce736 100644 --- a/resources/i18n/en.json +++ b/resources/i18n/en.json @@ -323,8 +323,11 @@ "Name": "Name", "NewFileName": "New file name", "NewFolder": "New Folder", + "NoAccessPermissionToVolume": "Current Project does not have access to SFTP volume.", "NoImagesSupportingFileBrowser": "There is no image supporting filebrowser yet. At least one or more image that supports filebrowser is required to upload folder(s).", "NoImagesSupportingSystemSession": "There is no image supporting SSH / SFTP yet. At least one or more image that supports system role images to use SSH / SFTP.", + "NoPermissionToMountFolder": "The current project does not have mount permissions for the storage host associated with this folder.", + "NoSFTPSupportingScalingGroup": "This folder’s storage host has no SFTP resource group.", "NoSharedFolders": "No shared folders", "NoSharedUsers": "No one has been invited", "NotEnoughResourceForFileBrowserSession": "No enough resources(cpu: 1 Core, mem: 0.5GB) to create the session for filebrowser. please check the available resources.", diff --git a/resources/i18n/es.json b/resources/i18n/es.json index 628c3e8502..eb8c5f136d 100644 --- a/resources/i18n/es.json +++ b/resources/i18n/es.json @@ -320,8 +320,11 @@ "Name": "Nombre", "NewFileName": "Nuevo nombre de archivo", "NewFolder": "Nueva carpeta", + "NoAccessPermissionToVolume": "El proyecto actual no tiene acceso al volumen SFTP.", "NoImagesSupportingFileBrowser": "Todavía no hay ninguna imagen que soporte filebrowser. Se requiere al menos una o más imágenes compatibles con filebrowser para cargar carpetas.", "NoImagesSupportingSystemSession": "Todavía no hay ninguna imagen que soporte SSH / SFTP. Al menos una o más imágenes que soporten imágenes de rol de sistema para usar SSH / SFTP.", + "NoPermissionToMountFolder": "El proyecto actual no tiene permisos para montar en el host de almacenamiento asociado a esta carpeta.", + "NoSFTPSupportingScalingGroup": "El host de almacenamiento de esta carpeta no tiene un grupo de recursos SFTP.", "NoSharedFolders": "Sin carpetas compartidas", "NoSharedUsers": "No se ha invitado a nadie.", "NotEnoughResourceForFileBrowserSession": "No hay recursos suficientes (cpu: 1 Core, mem: 0.5GB) para crear la sesión para filebrowser. por favor compruebe los recursos disponibles.", diff --git a/resources/i18n/fi.json b/resources/i18n/fi.json index fdb7fe9793..1608a73a20 100644 --- a/resources/i18n/fi.json +++ b/resources/i18n/fi.json @@ -320,8 +320,11 @@ "Name": "Nimi", "NewFileName": "Uusi tiedostonimi", "NewFolder": "Uusi kansio", + "NoAccessPermissionToVolume": "Tällä projektilla ei ole pääsyä SFTP-tilavuuteen.", "NoImagesSupportingFileBrowser": "Kuvia tukevaa tiedostoselainta ei ole vielä olemassa. Kansion tai kansioiden lataamiseen tarvitaan vähintään yksi tai useampi kuva, joka tukee tiedostoselainta.", "NoImagesSupportingSystemSession": "SSH:ta / SFTP:tä tukevaa kuvaa ei vielä ole. Ainakin yksi tai useampi kuva, joka tukee SSH:n / SFTP:n käyttöä tukevia järjestelmäroolikuvia.", + "NoPermissionToMountFolder": "Nykyisellä projektilla ei ole oikeuksia liittää tähän kansioon liitettyä tallennusisäntää.", + "NoSFTPSupportingScalingGroup": "Tämän kansion tallennuspalvelimella ei ole SFTP-resurssiryhmää.", "NoSharedFolders": "Ei jaettuja kansioita", "NoSharedUsers": "Ketään ei ole kutsuttu.", "NotEnoughResourceForFileBrowserSession": "Resurssit eivät riitä (cpu: 1 Core, mem: 0.5GB) filebrowser-istunnon luomiseen. tarkista käytettävissä olevat resurssit.", diff --git a/resources/i18n/fr.json b/resources/i18n/fr.json index 4adde471b3..ac30ff8a02 100644 --- a/resources/i18n/fr.json +++ b/resources/i18n/fr.json @@ -320,8 +320,11 @@ "Name": "Nom", "NewFileName": "Nouveau nom de fichier", "NewFolder": "Nouveau dossier", + "NoAccessPermissionToVolume": "Le projet actuel n'a pas accès au volume SFTP.", "NoImagesSupportingFileBrowser": "Il n'y a pas encore d'images prenant en charge le navigateur de fichiers. Au moins une ou plusieurs images prenant en charge le navigateur de fichiers sont requises pour télécharger le(s) dossier(s).", "NoImagesSupportingSystemSession": "Il n'y a pas encore d'image supportant SSH / SFTP. Au moins une ou plusieurs images prenant en charge les images de rôle du système doivent utiliser SSH / SFTP.", + "NoPermissionToMountFolder": "Le projet actuel n’a pas les autorisations de montage pour l’hôte de stockage associé à ce dossier.", + "NoSFTPSupportingScalingGroup": "L'hôte de stockage de ce dossier ne possède aucun groupe de ressources SFTP.", "NoSharedFolders": "Aucun dossier partagé", "NoSharedUsers": "Personne n'a été invité.", "NotEnoughResourceForFileBrowserSession": "Pas assez de ressources (cpu : 1 Core, mem : 0,5 Go) pour créer la session pour le navigateur de fichiers. veuillez vérifier les ressources disponibles.", diff --git a/resources/i18n/id.json b/resources/i18n/id.json index 474dbc9968..a0c41a21a2 100644 --- a/resources/i18n/id.json +++ b/resources/i18n/id.json @@ -319,8 +319,11 @@ "Name": "Nama", "NewFileName": "Nama file baru", "NewFolder": "Folder Baru", + "NoAccessPermissionToVolume": "Proyek saat ini tidak memiliki akses ke volume SFTP.", "NoImagesSupportingFileBrowser": "Belum ada image yang mendukung file browser. Setidaknya satu atau lebih image yang mendukung file browser diperlukan untuk mengunggah folder.", "NoImagesSupportingSystemSession": "Belum ada image yang mendukung SSH / SFTP. Setidaknya satu atau lebih image yang mendukung image peran sistem untuk menggunakan SSH / SFTP.", + "NoPermissionToMountFolder": "Proyek saat ini tidak memiliki izin mount untuk host penyimpanan yang terkait dengan folder ini.", + "NoSFTPSupportingScalingGroup": "Host penyimpanan folder ini tidak memiliki grup sumber daya SFTP.", "NoSharedFolders": "Tidak ada folder bersama", "NoSharedUsers": "Tidak ada yang diundang", "NotEnoughResourceForFileBrowserSession": "Tidak ada sumber daya yang cukup (cpu: 1 Core, mem: 0.5GB) untuk membuat sesi untuk filebrowser. Mohon periksa sumber daya yang tersedia.", diff --git a/resources/i18n/it.json b/resources/i18n/it.json index a0e634b844..d3514400a7 100644 --- a/resources/i18n/it.json +++ b/resources/i18n/it.json @@ -319,8 +319,11 @@ "Name": "Nome", "NewFileName": "Nuovo nome file", "NewFolder": "Nuova cartella", + "NoAccessPermissionToVolume": "Il progetto corrente non ha accesso al volume SFTP.", "NoImagesSupportingFileBrowser": "Non ci sono ancora immagini che supportano filebrowser. Per caricare le cartelle è necessaria almeno una o più immagini che supportino il browser di file.", "NoImagesSupportingSystemSession": "Non esiste ancora un'immagine che supporti SSH / SFTP. Almeno una o più immagini che supportano il ruolo del sistema devono utilizzare SSH / SFTP.", + "NoPermissionToMountFolder": "Il progetto corrente non dispone delle autorizzazioni di montaggio per l'host di storage associato a questa cartella.", + "NoSFTPSupportingScalingGroup": "L'host di archiviazione per questa cartella non dispone di un gruppo di risorse SFTP.", "NoSharedFolders": "Nessuna cartella condivisa", "NoSharedUsers": "Nessuno è stato invitato", "NotEnoughResourceForFileBrowserSession": "Risorse insufficienti (cpu: 1 Core, mem: 0,5 GB) per creare la sessione per filebrowser. si prega di controllare le risorse disponibili.", diff --git a/resources/i18n/ja.json b/resources/i18n/ja.json index 4c5167a002..67e1ee3482 100644 --- a/resources/i18n/ja.json +++ b/resources/i18n/ja.json @@ -319,8 +319,11 @@ "Name": "名前", "NewFileName": "新しいファイル名", "NewFolder": "新しいフォルダ", + "NoAccessPermissionToVolume": "現在のプロジェクトはSFTPボリュームへのアクセス権がありません。", "NoImagesSupportingFileBrowser": "Filebrowserを利用するには、対応するイメージが必要です。現在はまだ登録されていません。フォルダーをアップロードするには、少なくとも1つ以上の対応イメージを追加してください。", "NoImagesSupportingSystemSession": "SSH / SFTPをサポートするイメージがありません。 SSH / SFTPを利用するには、システムイメージが必要です。", + "NoPermissionToMountFolder": "現在のプロジェクトには、このフォルダーに紐づくストレージホストをマウントする権限がありません。", + "NoSFTPSupportingScalingGroup": "このフォルダのストレージホストにSFTPのリソースグループがありません。", "NoSharedFolders": "共有フォルダーはありません", "NoSharedUsers": "誰も招待されていません", "NotEnoughResourceForFileBrowserSession": "ファイルブラウザのセッションを作成するのに十分なリソース(CPU:1コア、メモリ:0.5GB)がありません。利用可能なリソースを確認してください。", diff --git a/resources/i18n/ko.json b/resources/i18n/ko.json index 623796ccdc..a13753557f 100644 --- a/resources/i18n/ko.json +++ b/resources/i18n/ko.json @@ -322,8 +322,11 @@ "Name": "이름", "NewFileName": "새로운 파일 이름", "NewFolder": "새 폴더", + "NoAccessPermissionToVolume": "현재 프로젝트에 SFTP 볼륨에 대한 액세스 권한이 없습니다.", "NoImagesSupportingFileBrowser": "파일브라우저를 지원하는 이미지가 없습니다. 폴더를 업로드하려면 파일브라우저 지원 이미지가 필요합니다.", "NoImagesSupportingSystemSession": "SSH / SFTP를 지원하는 이미지가 없습니다. SSH / SFTP를 이용하려면 시스템 이미지가 필요합니다.", + "NoPermissionToMountFolder": "현재 프로젝트는 이 폴더에 연결된 스토리지 호스트에 대한 마운트 권한이 없습니다.", + "NoSFTPSupportingScalingGroup": "해당 폴더의 스토리지 호스트에 SFTP용 리소스 그룹이 없습니다.", "NoSharedFolders": "공유 폴더가 없습니다.", "NoSharedUsers": "공유된 사용자가 없습니다.", "NotEnoughResourceForFileBrowserSession": "파일브라우저용 세션 생성을 위한 충분한 자원(cpu: 1 Core, mem: 0.5GB)이 없습니다. 자원 확인 후 다시 시도하세요.", diff --git a/resources/i18n/mn.json b/resources/i18n/mn.json index 25a8c279d7..65c64af76a 100644 --- a/resources/i18n/mn.json +++ b/resources/i18n/mn.json @@ -319,8 +319,11 @@ "Name": "Нэр", "NewFileName": "Шинэ файлын нэр", "NewFolder": "Шинэ хавтас", + "NoAccessPermissionToVolume": "Одоогийн төсөл SFTP хэмжээ рүү хандах эрхгүй байна.", "NoImagesSupportingFileBrowser": "Файл хөтөчийг дэмжих зураг хараахан алга байна. Фолдер хөтөчийг дэмждэг дор хаяж нэг буюу түүнээс дээш дүрс оруулах шаардлагатай.", "NoImagesSupportingSystemSession": "Одоогоор SSH / SFTP-г дэмждэг зураг байхгүй байна. \nSSH / SFTP ашиглахын тулд системийн дүр төрхийг дэмждэг дор хаяж нэг буюу хэд хэдэн зураг.", + "NoPermissionToMountFolder": "Одоогийн төсөлд энэ хавтастай холбоотой хадгалах хост дээр маунтлах зөвшөөрөл байхгүй.", + "NoSFTPSupportingScalingGroup": "Энэ хавтасны хадгалах хост дээр SFTP ресурсын бүлэг байхгүй байна.", "NoSharedFolders": "Хуваалцсан фолдер байхгүй", "NoSharedUsers": "Хэн ч уригдсангүй", "NotEnoughResourceForFileBrowserSession": "Filebrowser-д зориулж Session үүсгэх хангалттай нөөц байхгүй (cpu: 1 Core, mem: 0.5GB). боломжтой нөөцийг шалгана уу.", diff --git a/resources/i18n/ms.json b/resources/i18n/ms.json index 03b4b22217..109f1c909b 100644 --- a/resources/i18n/ms.json +++ b/resources/i18n/ms.json @@ -319,8 +319,11 @@ "Name": "Nama", "NewFileName": "Nama fail baru", "NewFolder": "Fail baharu", + "NoAccessPermissionToVolume": "Projek semasa tidak mempunyai akses ke volum SFTP.", "NoImagesSupportingFileBrowser": "Masih belum ada gambar yang menyokong penyaring gambar. Sekurang-kurangnya satu atau lebih gambar yang menyokong penyemak imbas diperlukan untuk memuat naik folder.", "NoImagesSupportingSystemSession": "Belum ada imej yang menyokong SSH / SFTP. \nSekurang-kurangnya satu atau lebih imej yang menyokong imej peranan sistem untuk menggunakan SSH / SFTP.", + "NoPermissionToMountFolder": "Projek semasa tidak mempunyai kebenaran untuk memasang hos storan yang berkaitan dengan folder ini.", + "NoSFTPSupportingScalingGroup": "Hos storan folder ini tidak mempunyai kumpulan sumber SFTP.", "NoSharedFolders": "Tiada folder kongsi", "NoSharedUsers": "Tidak ada yang dijemput", "NotEnoughResourceForFileBrowserSession": "Tidak ada sumber yang mencukupi (cpu: 1 Core, mem: 0.5GB) untuk membuat sesi untuk penyemak imbas fail. sila periksa sumber yang ada.", diff --git a/resources/i18n/pl.json b/resources/i18n/pl.json index 497b5880c8..5e64c9522f 100644 --- a/resources/i18n/pl.json +++ b/resources/i18n/pl.json @@ -320,8 +320,11 @@ "Name": "Nazwa", "NewFileName": "Nowa nazwa pliku", "NewFolder": "Nowy folder", + "NoAccessPermissionToVolume": "Bieżący projekt nie ma dostępu do woluminu SFTP.", "NoImagesSupportingFileBrowser": "Nie ma jeszcze obrazów obsługujących przeglądarkę plików. Do przesłania folderów wymagany jest co najmniej jeden obraz obsługujący przeglądarkę plików.", "NoImagesSupportingSystemSession": "Nie ma jeszcze obrazu obsługującego SSH / SFTP. Co najmniej jeden obraz, który obsługuje obrazy ról systemowych do korzystania z SSH / SFTP.", + "NoPermissionToMountFolder": "Bieżący projekt nie ma uprawnień do montowania hosta pamięci masowej powiązanego z tym folderem.", + "NoSFTPSupportingScalingGroup": "Host przechowywania tego folderu nie ma grupy zasobów SFTP.", "NoSharedFolders": "Brak folderów udostępnionych", "NoSharedUsers": "Nikt nie został zaproszony", "NotEnoughResourceForFileBrowserSession": "Brak wystarczających zasobów (cpu: 1 rdzeń, mem: 0,5 GB), aby utworzyć sesję dla przeglądarki plików. sprawdź dostępne zasoby.", diff --git a/resources/i18n/pt-BR.json b/resources/i18n/pt-BR.json index 6dede51ba6..ed0f23b70e 100644 --- a/resources/i18n/pt-BR.json +++ b/resources/i18n/pt-BR.json @@ -320,8 +320,11 @@ "Name": "Nome", "NewFileName": "Novo nome de arquivo", "NewFolder": "Nova pasta", + "NoAccessPermissionToVolume": "O projeto atual não tem acesso ao volume SFTP.", "NoImagesSupportingFileBrowser": "Ainda não há imagens que suportem o navegador de arquivos. Pelo menos uma ou mais imagens que suportam o navegador de arquivos são necessárias para carregar a (s) pasta (s).", "NoImagesSupportingSystemSession": "Ainda não existe nenhuma imagem que suporte SSH / SFTP. Pelo menos uma ou mais imagens que suportam imagens de funções de sistema para usar SSH / SFTP.", + "NoPermissionToMountFolder": "O projeto atual não possui permissões de montagem no host de armazenamento associado a esta pasta.", + "NoSFTPSupportingScalingGroup": "O host de armazenamento desta pasta não possui um grupo de recursos SFTP.", "NoSharedFolders": "Nenhuma pasta compartilhada", "NoSharedUsers": "Ninguém foi convidado", "NotEnoughResourceForFileBrowserSession": "Sem recursos suficientes (cpu: 1 Core, mem: 0,5 GB) para criar a sessão para o navegador de arquivos. verifique os recursos disponíveis.", diff --git a/resources/i18n/pt.json b/resources/i18n/pt.json index 7429611d0c..6c9ea32df6 100644 --- a/resources/i18n/pt.json +++ b/resources/i18n/pt.json @@ -320,8 +320,11 @@ "Name": "Nome", "NewFileName": "Novo nome de arquivo", "NewFolder": "Nova pasta", + "NoAccessPermissionToVolume": "O projeto atual não tem acesso ao volume SFTP.", "NoImagesSupportingFileBrowser": "Ainda não há imagens que suportem o navegador de arquivos. Pelo menos uma ou mais imagens que suportam o navegador de arquivos são necessárias para carregar a (s) pasta (s).", "NoImagesSupportingSystemSession": "Ainda não existe nenhuma imagem que suporte SSH / SFTP. Pelo menos uma ou mais imagens que suportam imagens de funções de sistema para usar SSH / SFTP.", + "NoPermissionToMountFolder": "O projeto atual não tem permissões para montar o host de armazenamento associado a esta pasta.", + "NoSFTPSupportingScalingGroup": "O host de armazenamento desta pasta não possui um grupo de recursos SFTP.", "NoSharedFolders": "Nenhuma pasta compartilhada", "NoSharedUsers": "Ninguém foi convidado", "NotEnoughResourceForFileBrowserSession": "Sem recursos suficientes (cpu: 1 Core, mem: 0,5 GB) para criar a sessão para o navegador de arquivos. verifique os recursos disponíveis.", diff --git a/resources/i18n/ru.json b/resources/i18n/ru.json index b4800891d5..c9d146a420 100644 --- a/resources/i18n/ru.json +++ b/resources/i18n/ru.json @@ -320,8 +320,11 @@ "Name": "Имя", "NewFileName": "Новое имя файла", "NewFolder": "Новая папка", + "NoAccessPermissionToVolume": "У текущего проекта нет доступа к SFTP-тому.", "NoImagesSupportingFileBrowser": "Пока нет изображений, поддерживающих просмотрщик файлов. Для загрузки папок требуется по крайней мере одно или несколько изображений, поддерживающих просмотрщик файлов.", "NoImagesSupportingSystemSession": "Образов, поддерживающих SSH / SFTP, пока не существует. Необходимо наличие хотя бы одного или нескольких образов, поддерживающих образы системных ролей для использования SSH / SFTP.", + "NoPermissionToMountFolder": "У текущего проекта нет прав на монтирование хоста хранилища, связанного с этой папкой.", + "NoSFTPSupportingScalingGroup": "У хоста хранилища этой папки нет группы ресурсов SFTP.", "NoSharedFolders": "Нет общих папок", "NoSharedUsers": "Никто не был приглашен", "NotEnoughResourceForFileBrowserSession": "Недостаточно ресурсов (cpu: 1 Core, mem: 0,5GB) для создания сеанса для просмотра файлов. пожалуйста, проверьте доступные ресурсы.", diff --git a/resources/i18n/th.json b/resources/i18n/th.json index 29c4ba4682..b8bcc06eba 100644 --- a/resources/i18n/th.json +++ b/resources/i18n/th.json @@ -320,8 +320,11 @@ "Name": "ชื่อ", "NewFileName": "ชื่อไฟล์ใหม่", "NewFolder": "โฟลเดอร์ใหม่", + "NoAccessPermissionToVolume": "โปรเจกต์ปัจจุบันไม่มีสิทธิ์เข้าถึงวอลุ่ม SFTP", "NoImagesSupportingFileBrowser": "ยังไม่มีอิมเมจที่รองรับเบราว์เซอร์ไฟล์ ต้องมีอย่างน้อยหนึ่งอิมเมจที่รองรับเบราว์เซอร์ไฟล์เพื่ออัปโหลดโฟลเดอร์", "NoImagesSupportingSystemSession": "ยังไม่มีอิมเมจที่รองรับ SSH / SFTP ต้องมีอย่างน้อยหนึ่งอิมเมจที่รองรับบทบาทระบบเพื่อใช้ SSH / SFTP", + "NoPermissionToMountFolder": "โปรเจกต์ปัจจุบันไม่มีสิทธิ์ในการเมานต์โฮสต์เก็บข้อมูลที่เชื่อมกับโฟลเดอร์นี้", + "NoSFTPSupportingScalingGroup": "โฮสต์ที่เก็บข้อมูลของโฟลเดอร์นี้ไม่มีกลุ่มทรัพยากร SFTP", "NoSharedFolders": "ไม่มีโฟลเดอร์ที่ใช้ร่วมกัน", "NoSharedUsers": "ไม่มีใครได้รับเชิญ", "NotEnoughResourceForFileBrowserSession": "ทรัพยากรไม่เพียงพอ (cpu: 1 คอร์, หน่วยความจำ: 0.5GB) ในการสร้างเซสชันสำหรับเบราว์เซอร์ไฟล์ กรุณาตรวจสอบทรัพยากรที่มีอยู่", diff --git a/resources/i18n/tr.json b/resources/i18n/tr.json index fa7b4120d5..5c2c7bf30c 100644 --- a/resources/i18n/tr.json +++ b/resources/i18n/tr.json @@ -320,8 +320,11 @@ "Name": "isim", "NewFileName": "Yeni dosya adı", "NewFolder": "Yeni dosya", + "NoAccessPermissionToVolume": "Mevcut projenin SFTP hacmine erişimi yok.", "NoImagesSupportingFileBrowser": "Henüz filebrowser'ı destekleyen bir resim yok. Klasörleri yüklemek için dosya tarayıcıyı destekleyen en az bir veya daha fazla resim gereklidir.", "NoImagesSupportingSystemSession": "Henüz SSH / SFTP'yi destekleyen bir görüntü yok. SSH / SFTP kullanmak için sistem rolü görüntülerini destekleyen en az bir veya daha fazla görüntü.", + "NoPermissionToMountFolder": "Mevcut projenin bu klasörle ilişkili depolama sunucusunu bağlama izni yok.", + "NoSFTPSupportingScalingGroup": "Bu klasörün depolama sunucusunda SFTP kaynak grubu bulunmuyor.", "NoSharedFolders": "Paylaşılan klasör yok", "NoSharedUsers": "Kimse davet edilmedi", "NotEnoughResourceForFileBrowserSession": "Dosya tarayıcısı için oturum oluşturmak için yeterli kaynak (işlemci: 1 Çekirdek, mem: 0,5 GB) yok. lütfen mevcut kaynakları kontrol edin.", diff --git a/resources/i18n/vi.json b/resources/i18n/vi.json index ec04d2b01b..629e488cd9 100644 --- a/resources/i18n/vi.json +++ b/resources/i18n/vi.json @@ -320,8 +320,11 @@ "Name": "Tên", "NewFileName": "Tên tệp mới", "NewFolder": "Thư mục mới", + "NoAccessPermissionToVolume": "Dự án hiện tại không có quyền truy cập vào ổ lưu trữ SFTP.", "NoImagesSupportingFileBrowser": "Không có hình ảnh nào hỗ trợ trình duyệt tệp. Cần có ít nhất một hoặc nhiều hình ảnh hỗ trợ trình duyệt tệp để tải lên (các) thư mục.", "NoImagesSupportingSystemSession": "Chưa có hình ảnh nào hỗ trợ SSH/SFTP. \nÍt nhất một hoặc nhiều image hỗ trợ image vai trò hệ thống để sử dụng SSH/SFTP.", + "NoPermissionToMountFolder": "Dự án hiện tại không có quyền gắn vào máy chủ lưu trữ liên kết với thư mục này.", + "NoSFTPSupportingScalingGroup": "Máy chủ lưu trữ của thư mục này không có nhóm tài nguyên SFTP.", "NoSharedFolders": "Không có thư mục chia sẻ", "NoSharedUsers": "Không ai được mời", "NotEnoughResourceForFileBrowserSession": "Không có đủ tài nguyên (cpu: 1 Core, mem: 0,5GB) để tạo phiên cho trình duyệt tệp. xin vui lòng kiểm tra các tài nguyên có sẵn.", diff --git a/resources/i18n/zh-CN.json b/resources/i18n/zh-CN.json index 1652eb0057..c5ed796c0c 100644 --- a/resources/i18n/zh-CN.json +++ b/resources/i18n/zh-CN.json @@ -320,8 +320,11 @@ "Name": "名称", "NewFileName": "新文件名", "NewFolder": "新建文件夹", + "NoAccessPermissionToVolume": "当前项目没有对 SFTP 卷的访问权限。", "NoImagesSupportingFileBrowser": "尚无支持文件浏览器的图像。上传文件夹至少需要一张或多张支持文件浏览器的图片。", "NoImagesSupportingSystemSession": "目前还没有支持 SSH / SFTP 的映像。至少有一个或多个支持系统角色映像的映像可使用 SSH / SFTP。", + "NoPermissionToMountFolder": "当前项目没有对与此文件夹关联的存储主机的挂载权限。", + "NoSFTPSupportingScalingGroup": "此文件夹的存储主机未配置 SFTP 资源组。", "NoSharedFolders": "没有共享文件夹", "NoSharedUsers": "没有人被邀请", "NotEnoughResourceForFileBrowserSession": "没有足够的资源(cpu: 1 Core, mem: 0.5GB)来为文件浏览器创建会话。请检查可用资源。", diff --git a/resources/i18n/zh-TW.json b/resources/i18n/zh-TW.json index 3259ae3d50..dcb0ed4614 100644 --- a/resources/i18n/zh-TW.json +++ b/resources/i18n/zh-TW.json @@ -320,8 +320,11 @@ "Name": "名稱", "NewFileName": "新文件名", "NewFolder": "新建文件夾", + "NoAccessPermissionToVolume": "目前專案無法存取 SFTP 儲存卷。", "NoImagesSupportingFileBrowser": "尚無支持文件瀏覽器的圖像。上傳文件夾至少需要一張或多張支持文件瀏覽器的圖片。", "NoImagesSupportingSystemSession": "目前还没有支持 SSH / SFTP 的映像。至少有一个或多个支持系统角色映像的映像可使用 SSH / SFTP。", + "NoPermissionToMountFolder": "此專案目前沒有對與此資料夾關聯的儲存主機的掛載權限。", + "NoSFTPSupportingScalingGroup": "此資料夾的儲存主機沒有 SFTP 資源群組。", "NoSharedFolders": "沒有共享資料夾", "NoSharedUsers": "沒有人被邀請", "NotEnoughResourceForFileBrowserSession": "沒有足夠的資源(cpu: 1 Core, mem: 0.5GB)來為文件瀏覽器創建會話。請檢查可用資源。",