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,