diff --git a/.github/workflows/docker_deploy.yml b/.github/workflows/docker_deploy.yml index 0152aaefd..361c502e1 100644 --- a/.github/workflows/docker_deploy.yml +++ b/.github/workflows/docker_deploy.yml @@ -10,8 +10,8 @@ name: Docker Build on: - schedule: - - cron: '0 0 * * *' # Midnight +# schedule: +# - cron: '0 0 * * *' # Midnight workflow_dispatch: pull_request: paths: diff --git a/src/components/ExternalIds/ExternalIds.tsx b/src/components/ExternalIds/ExternalIds.tsx index 5a3b72c82..f6498cc0f 100644 --- a/src/components/ExternalIds/ExternalIds.tsx +++ b/src/components/ExternalIds/ExternalIds.tsx @@ -16,13 +16,60 @@ interface Props { } } +/** + * Expands external IDs for display, with special handling for 'package-url'. + * If package-url value is a JSON array string, it expands into multiple entries. + */ +const expandExternalIds = (externalIds: { + [k: string]: string +}): Array< + [ + string, + string, + ] +> => { + const result: Array< + [ + string, + string, + ] + > = [] + + Object.entries(externalIds).forEach(([key, value]) => { + if (key === 'package-url' && value.trimStart().startsWith('[')) { + try { + const urls = JSON.parse(value) as string[] + if (Array.isArray(urls)) { + urls.forEach((url) => { + result.push([ + 'package-url', + url, + ]) + }) + return + } + } catch { + // Not valid JSON, fall through to default handling + } + } + result.push([ + key, + value, + ]) + }) + + return result +} + const ExternalIds = ({ externalIds }: Props): JSX.Element => { + const expandedIds = expandExternalIds(externalIds) + return ( <> {' '} - {Object.entries(externalIds).map(([key, value]) => { + {expandedIds.map(([key, value], index) => { return ( -
  • +
  • {key}: {value}
  • diff --git a/src/components/sw360/AddKeyValue/AddKeyValue.tsx b/src/components/sw360/AddKeyValue/AddKeyValue.tsx index 236c8db2f..db5df1430 100644 --- a/src/components/sw360/AddKeyValue/AddKeyValue.tsx +++ b/src/components/sw360/AddKeyValue/AddKeyValue.tsx @@ -10,7 +10,7 @@ 'use client' import { useTranslations } from 'next-intl' -import React, { type JSX, useEffect, useState } from 'react' +import React, { type JSX, useCallback, useEffect, useState } from 'react' import { OverlayTrigger, Tooltip } from 'react-bootstrap' import { BsFillTrashFill } from 'react-icons/bs' import DeleteItemWarning from '@/components/sw360/DeleteItemWarning/DeleteItemWarning' @@ -44,6 +44,33 @@ function AddKeyValue(props: Props): JSX.Element { props.data, ]) + /** + * Converts an input list to a map, with special handling for 'package-url' key. + * Multiple 'package-url' entries are combined into a single JSON array string. + */ + const convertListToMap = useCallback((list: Input[]): Map => { + const map = new Map() + const packageUrls: string[] = [] + + list.forEach((item) => { + if (item.key === 'package-url') { + // Collect all package-url values + if (item.value.trim() !== '') { + packageUrls.push(item.value) + } + } else { + map.set(item.key, item.value) + } + }) + + // Combine package-url values into a JSON array string + if (packageUrls.length > 0) { + map.set('package-url', JSON.stringify(packageUrls)) + } + + return map + }, []) + const handleInputChange = (e: React.ChangeEvent, index: number) => { const { name, value } = e.target const list: Input[] = [ @@ -52,11 +79,7 @@ function AddKeyValue(props: Props): JSX.Element { list[index][name as keyof Input] = value props.setData(list) if (props.setObject) { - const map = new Map() - list.forEach((item) => { - map.set(item.key, item.value) - }) - props.setObject(map) + props.setObject(convertListToMap(list)) } } @@ -67,11 +90,7 @@ function AddKeyValue(props: Props): JSX.Element { list[index].key = value props.setData(list) if (props.setObject) { - const map = new Map() - list.forEach((item) => { - map.set(item.key, item.value) - }) - props.setObject(map) + props.setObject(convertListToMap(list)) } } diff --git a/src/utils/common.utils.ts b/src/utils/common.utils.ts index 4068d1097..b44a8a912 100644 --- a/src/utils/common.utils.ts +++ b/src/utils/common.utils.ts @@ -114,6 +114,8 @@ const getEmailsModerators = (users: User[]): string[] => { /** * Converts an object to a map of key-value pairs. + * Special handling for 'package-url' key: if the value is a JSON array string, + * it will be expanded into multiple entries with the same key. * @param data - The object to convert. * @returns An array of key-value pairs. */ @@ -121,6 +123,23 @@ const convertObjectToMap = (data: { [k: string]: string }): InputKeyValue[] => { const map = new Map(Object.entries(data)) const inputs: InputKeyValue[] = [] map.forEach((value, key) => { + // Special handling for package-url: expand JSON array into multiple entries + if (key === 'package-url' && value.trimStart().startsWith('[')) { + try { + const urls = JSON.parse(value) as string[] + if (Array.isArray(urls)) { + urls.forEach((url) => { + inputs.push({ + key: key, + value: url, + }) + }) + return + } + } catch { + // If parsing fails, treat as regular value + } + } const input: InputKeyValue = { key: key, value: value,