diff --git a/react/src/components/ModelCardModal.tsx b/react/src/components/ModelCardModal.tsx index 9e22386ab..2204697f7 100644 --- a/react/src/components/ModelCardModal.tsx +++ b/react/src/components/ModelCardModal.tsx @@ -215,14 +215,6 @@ const ModelCardModal: React.FC = ({ size="small" disabled={!model_card?.vfolder?.cloneable} onClick={() => { - // const event = new CustomEvent('backend-ai-vfolder-cloning', { - // detail: { - // // TODO: change this to vfolder name - // name: mode_card?.name, - // }, - // }); - // onRequestClose(); - // document.dispatchEvent(event); setVisibleCloneModal(true); }} > diff --git a/react/src/components/ModelCloneModal.tsx b/react/src/components/ModelCloneModal.tsx index 7c9d6a4e8..5b9b6094d 100644 --- a/react/src/components/ModelCloneModal.tsx +++ b/react/src/components/ModelCloneModal.tsx @@ -94,11 +94,11 @@ const ModelCloneModal: React.FC = ({ formRef.current ?.validateFields() .then((values) => { - if (vfolder?.name && vfolder.host) { + if (vfolder?.id && vfolder.host) { mutationToClone.mutate( { input: values, - name: vfolder.name, + name: vfolder.id, }, { onSuccess(data) { diff --git a/src/components/backend-ai-data-view.ts b/src/components/backend-ai-data-view.ts index 8c247922f..74f97a502 100644 --- a/src/components/backend-ai-data-view.ts +++ b/src/components/backend-ai-data-view.ts @@ -92,7 +92,7 @@ export default class BackendAIData extends BackendAIPage { @property({ type: Object }) _helpDescriptionStorageProxyInfo = Object(); @property({ type: Object }) options; @property({ type: Number }) capacity; - @property({ type: String }) cloneFolderName = ''; + @property({ type: String }) cloneFolderID = ''; @property({ type: Object }) storageProxyInfo = Object(); @property({ type: String }) folderType = 'user'; @property({ type: Number }) currentGroupIdx = 0; @@ -550,7 +550,7 @@ export default class BackendAIData extends BackendAIPage { { if (e.detail) { const selectedItems = e.detail; - this.cloneFolderName = selectedItems.name; + this.cloneFolderID = globalThis.backendaiclient.supports( + 'vfolder-id-based', + ) + ? selectedItems.id + : selectedItems.name; this._cloneFolderDialog(); } }); @@ -976,7 +980,7 @@ export default class BackendAIData extends BackendAIPage { this.allowedGroups = group_info.groups; } this.cloneFolderNameInput.value = await this._checkFolderNameAlreadyExists( - this.cloneFolderName, + this.cloneFolderID, ); this.openDialog('clone-folder-dialog'); } @@ -1267,7 +1271,7 @@ export default class BackendAIData extends BackendAIPage { }; const job = globalThis.backendaiclient.vfolder.clone( input, - this.cloneFolderName, + this.cloneFolderID, ); job .then(() => { diff --git a/src/components/backend-ai-folder-explorer.ts b/src/components/backend-ai-folder-explorer.ts index 691408d6d..177de23de 100644 --- a/src/components/backend-ai-folder-explorer.ts +++ b/src/components/backend-ai-folder-explorer.ts @@ -53,6 +53,7 @@ export default class BackendAIFolderExplorer extends BackendAIPage { // [target vfolder information] @property({ type: String }) vfolderID = ''; @property({ type: String }) vfolderName = ''; + @property({ type: String }) vfolder = ''; @property({ type: Array }) vfolderFiles = []; @property({ type: String }) vhost = ''; @property({ type: Boolean }) isWritable = false; @@ -496,7 +497,7 @@ export default class BackendAIFolderExplorer extends BackendAIPage { const path = this.breadcrumb.concat(fn).join('/'); const job = globalThis.backendaiclient.vfolder.request_download_token( path, - this.vfolderName, + this.vfolder, archive, ); job @@ -777,6 +778,9 @@ export default class BackendAIFolderExplorer extends BackendAIPage { return vfolder.id === this.vfolderID; }); this.vfolderName = vfolder.name; + this.vfolder = globalThis.backendaiclient.supports('vfolder-id-based') + ? vfolder.id + : vfolder.name; this.vhost = vfolder.host; this.isWritable = vfolder.permission.includes('w'); @@ -791,7 +795,7 @@ export default class BackendAIFolderExplorer extends BackendAIPage { this.fileListGrid.selectedItems = []; const filesInfo = await globalThis.backendaiclient.vfolder.list_files( this.breadcrumb.join('/'), - this.vfolderName, + this.vfolder, ); const details = filesInfo.items; @@ -968,7 +972,7 @@ export default class BackendAIFolderExplorer extends BackendAIPage { const job = globalThis.backendaiclient.vfolder.rename_file( path, newName, - this.vfolderName, + this.vfolder, this.is_dir, ); job @@ -1034,7 +1038,7 @@ export default class BackendAIFolderExplorer extends BackendAIPage { const job = globalThis.backendaiclient.vfolder.delete_files( filenames, true, - this.vfolderName, + this.vfolder, ); job.then((res) => { this.notification.text = @@ -1054,7 +1058,7 @@ export default class BackendAIFolderExplorer extends BackendAIPage { const job = globalThis.backendaiclient.vfolder.delete_files( [path], true, - this.vfolderName, + this.vfolder, ); job .then((res) => { @@ -1121,7 +1125,7 @@ export default class BackendAIFolderExplorer extends BackendAIPage { this.mkdirNameInput.reportValidity(); if (this.mkdirNameInput.checkValidity()) { const job = globalThis.backendaiclient.vfolder - .mkdir([...this.breadcrumb, newfolder].join('/'), this.vfolderName) + .mkdir([...this.breadcrumb, newfolder].join('/'), this.vfolder) .catch((err) => { if (err & err.message) { this.notification.text = PainKiller.relieve(err.title); @@ -1290,7 +1294,7 @@ export default class BackendAIFolderExplorer extends BackendAIPage { const job = globalThis.backendaiclient.vfolder.create_upload_session( path, fileObj, - this.vfolderName, + this.vfolder, ); job.then((url) => { const start_date = new Date().getTime(); diff --git a/src/components/backend-ai-storage-list.ts b/src/components/backend-ai-storage-list.ts index 04d334b56..2708569b6 100644 --- a/src/components/backend-ai-storage-list.ts +++ b/src/components/backend-ai-storage-list.ts @@ -105,6 +105,7 @@ export default class BackendAiStorageList extends BackendAIPage { @property({ type: Boolean }) enableVfolderTrashBin = false; @property({ type: Boolean }) authenticated = false; @property({ type: String }) renameFolderName = ''; + @property({ type: String }) renameFolderID = ''; @property({ type: String }) deleteFolderName = ''; @property({ type: String }) deleteFolderID = ''; @property({ type: String }) leaveFolderName = ''; @@ -1932,8 +1933,10 @@ export default class BackendAiStorageList extends BackendAIPage { * @param {Event} e - click the info icon button * */ _infoFolder(e) { - const folderName = this._getControlName(e); - const job = globalThis.backendaiclient.vfolder.info(folderName); + const folder = globalThis.backendaiclient.supports('vfolder-id-based') + ? this._getControlID(e) + : this._getControlName(e); + const job = globalThis.backendaiclient.vfolder.info(folder); job .then((value) => { this.folderInfo = value; @@ -1955,10 +1958,10 @@ export default class BackendAiStorageList extends BackendAIPage { * @param {Event} e - click the settings icon button * */ _modifyFolderOptionDialog(e) { - globalThis.backendaiclient.vfolder.name = this._getControlName(e); - const job = globalThis.backendaiclient.vfolder.info( - globalThis.backendaiclient.vfolder.name, - ); + const folder = globalThis.backendaiclient.supports('vfolder-id-based') + ? this._getControlID(e) + : this._getControlName(e); + const job = globalThis.backendaiclient.vfolder.info(folder); job .then((value) => { this.folderInfo = value; @@ -2020,10 +2023,7 @@ export default class BackendAiStorageList extends BackendAIPage { const modifyFolderJobQueue: Promise[] = []; if (Object.keys(input).length > 0) { const updateFolderConfig = - globalThis.backendaiclient.vfolder.update_folder( - input, - globalThis.backendaiclient.vfolder.name, - ); + globalThis.backendaiclient.vfolder.update_folder(input, folder); modifyFolderJobQueue.push(updateFolderConfig); } if ( @@ -2074,13 +2074,15 @@ export default class BackendAiStorageList extends BackendAIPage { * */ async _updateFolderName() { - globalThis.backendaiclient.vfolder.name = this.renameFolderName; + const folder = globalThis.backendaiclient.supports('vfolder-id-based') + ? this.renameFolderID + : this.renameFolderName; const newName = this.newFolderNameInput.value; this.newFolderNameInput.reportValidity(); if (newName) { if (this.newFolderNameInput.checkValidity()) { try { - await globalThis.backendaiclient.vfolder.rename(newName); + await globalThis.backendaiclient.vfolder.rename(newName, folder); this.notification.text = _text('data.folders.FolderRenamed'); this.notification.show(); this._refreshFolderList(true, 'updateFolder'); @@ -2101,6 +2103,11 @@ export default class BackendAiStorageList extends BackendAIPage { * @param {Event} e - click the */ _renameFolderDialog(e) { + this.renameFolderID = globalThis.backendaiclient.supports( + 'vfolder-id-based', + ) + ? this._getControlID(e) + : this._getControlName(e); this.renameFolderName = this._getControlName(e); this.newFolderNameInput.value = ''; this.openDialog('modify-folder-name-dialog'); @@ -2427,7 +2434,11 @@ export default class BackendAiStorageList extends BackendAIPage { * @param {Event} e - click the share button * */ _shareFolderDialog(e) { - this.selectedFolder = this._getControlName(e); + this.selectedFolder = globalThis.backendaiclient.supports( + 'vfolder-id-based', + ) + ? this._getControlID(e) + : this._getControlName(e); this.selectedFolderType = this._getControlType(e); this._initializeSharingFolderDialogLayout(); this.openDialog('share-folder-dialog'); diff --git a/src/components/backend-ai-summary-view.ts b/src/components/backend-ai-summary-view.ts index 01ff36706..206969c63 100644 --- a/src/components/backend-ai-summary-view.ts +++ b/src/components/backend-ai-summary-view.ts @@ -430,7 +430,7 @@ export default class BackendAISummary extends BackendAIPage { try { await globalThis.backendaiclient.vfolder.accept_invitation(invitation.id); const vfolderInfo = await globalThis.backendaiclient.vfolder.info( - invitation.vfolder_name, + invitation.vfolder_id, ); const tabName = BackendAISummary.getVFolderTabByVFolderInfo(vfolderInfo); this.notification.url = `/data?tab=${tabName}&folder=${invitation.vfolder_id.replace('-', '')}`; diff --git a/src/lib/backend.ai-client-esm.ts b/src/lib/backend.ai-client-esm.ts index cc862b4de..17f99cc73 100644 --- a/src/lib/backend.ai-client-esm.ts +++ b/src/lib/backend.ai-client-esm.ts @@ -734,6 +734,9 @@ class Client { this._features['max_network_count'] = true; this._features['replicas'] = true; } + if (this.isManagerVersionCompatibleWith(['25.1.0', '24.09.6', '24.03.12'])) { + this._features['vfolder-id-based'] = true; + } } /** @@ -2079,6 +2082,7 @@ class ResourcePreset { class VFolder { public client: any; public name: any; + public id: any; public urlPrefix: any; /** @@ -2087,9 +2091,10 @@ class VFolder { * @param {Client} client - the Client API wrapper object to bind * @param {string} name - Virtual folder name. */ - constructor(client, name = null) { + constructor(client, name = null, id = null) { this.client = client; this.name = name; + this.id = id; this.urlPrefix = '/folders'; } @@ -2256,12 +2261,16 @@ class VFolder { * Rename a Virtual folder. * * @param {string} new_name - New virtual folder name. + * @param {string} vfolder - Virtual folder id or name to rename. */ - async rename(new_name = null): Promise { + async rename(new_name = null, vfolder = null): Promise { + if (vfolder == null) { + vfolder = this.client.supports('vfolder-id-based') ? this.id : this.name; + } const body = { new_name }; let rqst = this.client.newSignedRequest( 'POST', - `${this.urlPrefix}/${this.name}/rename`, + `${this.urlPrefix}/${vfolder}/rename`, body, ); return this.client._wrapWithPromise(rqst); diff --git a/src/lib/pep440.test.ts b/src/lib/pep440.test.ts index cbf9774d1..f64b5971a 100644 --- a/src/lib/pep440.test.ts +++ b/src/lib/pep440.test.ts @@ -80,5 +80,10 @@ describe('isCompatibleMultipleConditions', ()=>{ expect(isCompatibleMultipleConditions('23.03.3', ['24.3.1', '23.03.4'])).toBe(false) expect(isCompatibleMultipleConditions('25.03.3', ['24.3.1', '23.03.4'])).toBe(true) expect(isCompatibleMultipleConditions('22.03.3', ['24.3.1', '23.03.4'])).toBe(false) + expect(isCompatibleMultipleConditions('24.12.1', ['25.1.0', '24.09.6', '24.03.12'])).toBe(false) + expect(isCompatibleMultipleConditions('25.1.1', ['25.1.0', '24.09.6', '24.03.12'])).toBe(true) + expect(isCompatibleMultipleConditions('25.0.0', ['25.1.0', '24.09.6', '24.03.12'])).toBe(false) + expect(isCompatibleMultipleConditions('24.09.5', ['25.1.0', '24.09.6', '24.03.12'])).toBe(false) + expect(isCompatibleMultipleConditions('24.09.7', ['25.1.0', '24.09.6', '24.03.12'])).toBe(true) }); }) \ No newline at end of file