From 76d12f2ecb971bc7a0c1699c1f603fd9887e7ed7 Mon Sep 17 00:00:00 2001 From: agatha197 Date: Tue, 5 Nov 2024 23:26:58 +0900 Subject: [PATCH] refactor: parsing image data in session launcher for before 24.12 --- react/src/hooks/index.test.tsx | 90 +++++++++++++++++++++++++++++++ react/src/hooks/index.tsx | 96 +++++++++++++++++----------------- 2 files changed, 139 insertions(+), 47 deletions(-) create mode 100644 react/src/hooks/index.test.tsx diff --git a/react/src/hooks/index.test.tsx b/react/src/hooks/index.test.tsx new file mode 100644 index 000000000..6da732b2d --- /dev/null +++ b/react/src/hooks/index.test.tsx @@ -0,0 +1,90 @@ +import { imageParser } from '.'; +import _ from 'lodash'; + +describe('Image util functions tests', () => { + // TODO: Use test hooks to test the functions + + const { getBaseImage, getBaseVersion, getTags } = imageParser; + + describe('Test with underbar image tag', () => { + const IMAGE_NAME = 'abc-def.ghi.systems/llm/jkl/mno_pqr:0.0.0_stu'; + describe('getBaseVersion', () => { + it('should correctly parse the base version from an image name', () => { + const baseVersion = getBaseVersion(IMAGE_NAME); + expect(baseVersion).toBe('0.0.0'); + }); + }); + + describe('getBaseImage', () => { + it('should correctly parse the base image from an image name', () => { + const baseImage = getBaseImage(IMAGE_NAME); + expect(baseImage).toBe('mno_pqr'); + }); + }); + + describe('getTags', () => { + it('should correctly parse and process tags from a given tag string', () => { + const tag = '0.0.0_stu'; + const labels = [{ key: 'abc', value: 'def' }]; + const tags = getTags(tag, labels); + expect(tags).toEqual([{ key: 'stu', value: '' }]); + }); + }); + }); + describe('Test with dash image tag', () => { + const IMAGE_NAME = 'abc-def.ghi.systems/llm/jkl/mno_pqr:0.0.0-stu'; + describe('getBaseVersion', () => { + it('should correctly parse the base version from an image name', () => { + const baseVersion = getBaseVersion(IMAGE_NAME); + expect(baseVersion).toBe('0.0.0'); + }); + }); + + describe('getBaseImage', () => { + it('should correctly parse the base image from an image name', () => { + const baseImage = getBaseImage(IMAGE_NAME); + expect(baseImage).toBe('mno_pqr'); + }); + }); + + describe('getTags', () => { + it('should correctly parse and process tags from a given tag string', () => { + const tag = '0.0.0_stu'; + const labels = [{ key: 'abc', value: 'def' }]; + const tags = getTags(tag, labels); + expect(tags).toEqual([{ key: 'stu', value: '' }]); + }); + }); + }); + describe('Test with customized image tag', () => { + const IMAGE_NAME = + 'abc-def.ghi.systems/llm/jkl/mno_pqr:0.0.0-stu_customized_asdflkjnweri'; + describe('getBaseVersion', () => { + it('should correctly parse the base version from an image name', () => { + const baseVersion = getBaseVersion(IMAGE_NAME); + expect(baseVersion).toBe('0.0.0'); + }); + }); + + describe('getBaseImage', () => { + it('should correctly parse the base image from an image name', () => { + const baseImage = getBaseImage(IMAGE_NAME); + expect(baseImage).toBe('mno_pqr'); + }); + }); + + describe('getTags', () => { + it('should handle customized_ tags correctly', () => { + const tag = '0.0.0-stu_customized_asdflkjnweri'; + const labels = [ + { key: 'ai.backend.customized-image.name', value: 'CustomImage' }, + ]; + const tags = getTags(tag, labels); + expect(tags).toEqual([ + { key: 'stu', value: '' }, + { key: 'Customized', value: 'CustomImage' }, + ]); + }); + }); + }); +}); diff --git a/react/src/hooks/index.tsx b/react/src/hooks/index.tsx index f1a539be1..38d2340f2 100644 --- a/react/src/hooks/index.tsx +++ b/react/src/hooks/index.tsx @@ -149,6 +149,54 @@ interface ImageMetadata { }[]; } +export const imageParser = { + getBaseVersion: (imageName: string) => { + return ( + _.first(_.split(_.last(_.split(imageName, ':')), /[^a-zA-Z\d.]+/)) || '' + ); + }, + getBaseImage: (imageName: string) => { + const splitByColon = _.split(imageName, ':'); + const beforeLastColon = _.join(_.initial(splitByColon), ':'); + const lastItemAfterSplitBySlash = _.last(_.split(beforeLastColon, '/')); + return lastItemAfterSplitBySlash || ''; + }, + getTags: (tag: string, labels: Array<{ key: string; value: string }>) => { + // Remove the 'customized_' prefix and its following string from the tag + const cleanedTag = _.replace(tag, /customized_[a-zA-Z\d.]+/, ''); + // Split the remaining tag into segments based on alphanumeric and '.' characters, ignoring the first segment + const tags = _.tail(_.split(cleanedTag, /[^a-zA-Z\d.]+/)); + const result: Array<{ key: string; value: string }> = []; + + // Process not 'customized_' tags + _.forEach(tags, (currentTag) => { + // Separate the alphabetic prefix from the numeric and '.' suffix for each tag + const match = /^([a-zA-Z]+)(.*)$/.exec(currentTag); + if (match) { + const [, key, value] = match; + // Ensure the value is an empty string if it's undefined + result.push({ key, value: value || '' }); + } + }); + + // Handle the 'customized_' tag separately by finding the custom image name in labels + const customizedNameLabel = _.get( + _.find(labels, { key: 'ai.backend.customized-image.name' }), + 'value', + '', + ); + // If a custom image name exists, add it to the result with the key 'Customized' + if (customizedNameLabel) { + result.push({ key: 'Customized', value: customizedNameLabel }); + } + + // Remove duplicates and entries with an empty 'key' + return _.uniqWith( + _.filter(result, ({ key }) => !_.isEmpty(key)), + _.isEqual, + ); + }, +}; export const useBackendAIImageMetaData = () => { const { data: metadata } = useSuspenseTanQuery<{ imageInfo: { @@ -261,18 +309,6 @@ export const useBackendAIImageMetaData = () => { })?.value; return customizedNameLabel; }, - getBaseVersion: (imageName: string) => { - return ( - _.first(_.split(_.last(_.split(imageName, ':')), /[^a-zA-Z\d.]+/)) || - '' - ); - }, - getBaseImage: (imageName: string) => { - const splitByColon = _.split(imageName, ':'); - const beforeLastColon = _.join(_.initial(splitByColon), ':'); - const lastItemAfterSplitBySlash = _.last(_.split(beforeLastColon, '/')); - return lastItemAfterSplitBySlash || ''; - }, getBaseImages: (tag: string, name: string) => { const tags = tag.split('-'); let baseImage; @@ -297,41 +333,6 @@ export const useBackendAIImageMetaData = () => { return baseImageArr; }, getImageMeta, - getTags: (tag: string, labels: Array<{ key: string; value: string }>) => { - // Remove the 'customized_' prefix and its following string from the tag - const cleanedTag = _.replace(tag, /customized_[a-zA-Z\d.]+/, ''); - // Split the remaining tag into segments based on alphanumeric and '.' characters, ignoring the first segment - const tags = _.tail(_.split(cleanedTag, /[^a-zA-Z\d.]+/)); - const result: Array<{ key: string; value: string }> = []; - - // Process not 'customized_' tags - _.forEach(tags, (currentTag) => { - // Separate the alphabetic prefix from the numeric and '.' suffix for each tag - const match = /^([a-zA-Z]+)(.*)$/.exec(currentTag); - if (match) { - const [, key, value] = match; - // Ensure the value is an empty string if it's undefined - result.push({ key, value: value || '' }); - } - }); - - // Handle the 'customized_' tag separately by finding the custom image name in labels - const customizedNameLabel = _.get( - _.find(labels, { key: 'ai.backend.customized-image.name' }), - 'value', - '', - ); - // If a custom image name exists, add it to the result with the key 'Customized' - if (customizedNameLabel) { - result.push({ key: 'Customized', value: customizedNameLabel }); - } - - // Remove duplicates and entries with an empty 'key' - return _.uniqWith( - _.filter(result, ({ key }) => !_.isEmpty(key)), - _.isEqual, - ); - }, getConstraints: ( tag: string, labels: { key: string; value: string }[], @@ -371,6 +372,7 @@ export const useBackendAIImageMetaData = () => { preserveDotStartCase(tag) ); }, + ...imageParser, }, ] as const; };