diff --git a/messages/de.json b/messages/de.json index e16da0b1..27457c72 100644 --- a/messages/de.json +++ b/messages/de.json @@ -1069,6 +1069,7 @@ "UPLOAD SBOM HEADER": "Bitte laden Sie das SBOM-Dokument {fileFormats hoch.", "URL": "URL", "Unknown": "Unbekannt", + "Unsubscribe": "Abbestellen", "Update": "Aktualisierung", "Update Component": "Update Component", "Update External Link Failed!": "", diff --git a/messages/en.json b/messages/en.json index eb586d26..a4e291c6 100644 --- a/messages/en.json +++ b/messages/en.json @@ -1069,6 +1069,7 @@ "UPLOAD SBOM HEADER": "Please upload the {fileFormats} SBOM document.", "URL": "URL", "Unknown": "Unknown", + "Unsubscribe": "Unsubscribe", "Update": "Update", "Update Component": "Update Component", "Update External Link Failed!": "Update External Link Failed!", diff --git a/messages/es.json b/messages/es.json index 85f88dec..e270da75 100644 --- a/messages/es.json +++ b/messages/es.json @@ -1069,6 +1069,7 @@ "UPLOAD SBOM HEADER": "Cargue el documento SBOM {fileFormats}.", "URL": "URL", "Unknown": "Desconocido", + "Unsubscribe": "Darse de baja", "Update": "Actualización", "Update Component": "Componente de actualización", "Update External Link Failed!": "", diff --git a/messages/fr.json b/messages/fr.json index 974c2eb1..746600b5 100644 --- a/messages/fr.json +++ b/messages/fr.json @@ -1069,6 +1069,7 @@ "UPLOAD SBOM HEADER": "Veuillez télécharger le document SBOM {fileFormats>.", "URL": "URL", "Unknown": "Inconnu", + "Unsubscribe": "Se désabonner", "Update": "Mise à jour", "Update Component": "Composante mise à jour", "Update External Link Failed!": "", diff --git a/messages/ja.json b/messages/ja.json index b9807e50..f32ebc87 100644 --- a/messages/ja.json +++ b/messages/ja.json @@ -1069,6 +1069,7 @@ "UPLOAD SBOM HEADER": "{fileFormats} SBOM ドキュメントをアップロードしてください。", "URL": "URL", "Unknown": "未知", + "Unsubscribe": "購読を解除する", "Update": "アップデート", "Update Component": "コンポーネントの更新", "Update External Link Failed!": "", diff --git a/messages/ko.json b/messages/ko.json index d1c8dcd4..330b1342 100644 --- a/messages/ko.json +++ b/messages/ko.json @@ -1069,6 +1069,7 @@ "UPLOAD SBOM HEADER": "{fileFormats} SBOM 문서를 업로드하세요.", "URL": "사이트 맵", "Unknown": "이름 *", + "Unsubscribe": "구독 취소", "Update": "(주)", "Update Component": "업데이트 구성", "Update External Link Failed!": "", diff --git a/messages/pt-BR.json b/messages/pt-BR.json index 392f0c86..03c82dc5 100644 --- a/messages/pt-BR.json +++ b/messages/pt-BR.json @@ -1069,6 +1069,7 @@ "UPLOAD SBOM HEADER": "Faça upload do documento SBOM {fileFormats}.", "URL": "URL", "Unknown": "Desconhecido", + "Unsubscribe": "Cancelar inscrição", "Update": "Atualização", "Update Component": "Atualizar componente", "Update External Link Failed!": "", diff --git a/messages/vi.json b/messages/vi.json index e6b38415..f6d786ac 100644 --- a/messages/vi.json +++ b/messages/vi.json @@ -1069,6 +1069,7 @@ "UPLOAD SBOM HEADER": "Vui lòng tải lên tài liệu SBOM {fileFormats.", "URL": "URL", "Unknown": "không xác định", + "Unsubscribe": "Hủy đăng ký", "Update": "Cập nhật", "Update Component": "Cập nhật thành phần", "Update External Link Failed!": "", diff --git a/messages/zh-CN.json b/messages/zh-CN.json index b0458c11..947f521c 100644 --- a/messages/zh-CN.json +++ b/messages/zh-CN.json @@ -1069,6 +1069,7 @@ "UPLOAD SBOM HEADER": "请上传{fileFormats} SBOM 文档。", "URL": "网址", "Unknown": "未知", + "Unsubscribe": "退订", "Update": "更新", "Update Component": "更新组件", "Update External Link Failed!": "", diff --git a/messages/zh-TW.json b/messages/zh-TW.json index 73b3aed6..987655bf 100644 --- a/messages/zh-TW.json +++ b/messages/zh-TW.json @@ -1069,6 +1069,7 @@ "UPLOAD SBOM HEADER": "請上傳{fileFormats} SBOM 文件。", "URL": "網址", "Unknown": "未知", + "Unsubscribe": "退訂", "Update": "更新", "Update Component": "更新元件", "Update External Link Failed!": "", diff --git a/src/app/[locale]/components/detail/[id]/components/DetailOverview.tsx b/src/app/[locale]/components/detail/[id]/components/DetailOverview.tsx index 5abf537d..d94a4e77 100644 --- a/src/app/[locale]/components/detail/[id]/components/DetailOverview.tsx +++ b/src/app/[locale]/components/detail/[id]/components/DetailOverview.tsx @@ -28,11 +28,13 @@ import { Embedded, HttpStatus, LinkedVulnerability, + User, } from '@/object-types' import DownloadService from '@/services/download.service' import { ApiUtils, CommonUtils } from '@/utils' import ReleaseOverview from './ReleaseOverview' import Summary from './Summary' +import MessageService from '@/services/message.service' type EmbeddedChangelogs = Embedded type EmbeddedVulnerabilities = Embedded @@ -73,6 +75,8 @@ const DetailOverview = ({ componentId }: Props) : ReactNode => { const [changeLogList, setChangeLogList] = useState>([]) const [vulnerData, setVulnerData] = useState>([]) const [attachmentNumber, setAttachmentNumber] = useState(0) + const [subscribers, setSubscribers] = useState>([]) + const [userEmail, setUserEmail] = useState(undefined) const fetchData = useCallback( async (url: string) => { @@ -103,11 +107,20 @@ const DetailOverview = ({ componentId }: Props) : ReactNode => { ) } + const extractUserEmailFromSession = async () => { + const session = await getSession() + if (CommonUtils.isNullOrUndefined(session)) + return + setUserEmail(session.user.email) + } + useEffect(() => { + void extractUserEmailFromSession() fetchData(`components/${componentId}`) .then((component: Component | undefined) => { if (component === undefined) return setComponent(component) + setSubscribers(getSubcribersEmail(component)) if ( !CommonUtils.isNullOrUndefined(component['_embedded']) && !CommonUtils.isNullOrUndefined(component['_embedded']['sw360:attachments']) @@ -139,11 +152,42 @@ const DetailOverview = ({ componentId }: Props) : ReactNode => { .catch((err) => console.error(err)) }, [componentId, fetchData]) + const getSubcribersEmail = (component: Component) => { + return (component._embedded !== undefined && component._embedded['sw360:subscribers'] !== undefined) + ? Object.values(component._embedded['sw360:subscribers'].map((user: User) => user.email)) + : [] + } + + const isUserSubscribed = () => { + if (userEmail === undefined) return false + return subscribers.includes(userEmail) + } + + const handleSubcriptions = async () => { + const session = await getSession() + if (CommonUtils.isNullOrUndefined(session)) { + MessageService.error(t('Session has expired')) + return + } + await ApiUtils.POST(`components/${componentId}/subscriptions`, {}, session.user.access_token) + fetchData(`components/${componentId}`) + .then((component: Component | undefined) => { + if (component === undefined) return + setComponent(component) + setSubscribers(getSubcribersEmail(component)) + }).catch((e) => console.error(e)) + } + const headerButtons = { Edit: { link: `/components/edit/${componentId}`, type: 'primary', name: t('Edit component') }, Merge: { link: '', type: 'secondary', name: t('Merge') }, Split: { link: '', type: 'secondary', name: t('Split') }, - Subscribe: { link: '', type: 'outline-success', name: t('Subscribe') }, + Subscribe: { + link: '', + type: isUserSubscribed() ? 'outline-danger' : 'outline-success', + name: isUserSubscribed() ? t('Unsubscribe') : t('Subscribe'), + onClick: handleSubcriptions + } } return ( diff --git a/src/app/[locale]/components/releases/detail/[id]/components/DetailOverview.tsx b/src/app/[locale]/components/releases/detail/[id]/components/DetailOverview.tsx index 883912b3..1ee54ed7 100644 --- a/src/app/[locale]/components/releases/detail/[id]/components/DetailOverview.tsx +++ b/src/app/[locale]/components/releases/detail/[id]/components/DetailOverview.tsx @@ -34,6 +34,7 @@ import { ReleaseDetail, ReleaseLink, ReleaseTabIds, + User, } from '@/object-types' import DownloadService from '@/services/download.service' import { ApiUtils, CommonUtils } from '@/utils' @@ -46,6 +47,7 @@ import LinkedReleases from './LinkedReleases' import ReleaseDetailTabs from './ReleaseDetailTabs' import Summary from './Summary' import SPDXDocumentTab from './spdx/SPDXDocumentTab' +import MessageService from '@/services/message.service' type EmbeddedChangelogs = Embedded type EmbeddedVulnerabilities = Embedded @@ -66,8 +68,10 @@ const DetailOverview = ({ releaseId }: Props) : ReactNode => { const [changeLogIndex, setChangeLogIndex] = useState(-1) const [changeLogList, setChangeLogList] = useState>([]) const [linkProjectModalShow, setLinkProjectModalShow] = useState(false) + const [subscribers, setSubscribers] = useState>([]) const [tabList, setTabList] = useState(ReleaseDetailTabs.WITHOUT_COMMERCIAL_DETAILS_AND_SPDX) + const [userEmail, setUserEmail] = useState(undefined) const fetchData = useCallback( async (url: string) => { @@ -87,7 +91,21 @@ const DetailOverview = ({ releaseId }: Props) : ReactNode => { [] ) + const getSubcribersEmail = (release: ReleaseDetail) => { + return (release._embedded['sw360:subscribers']) + ? Object.values(release._embedded['sw360:subscribers'].map((user: User) => user.email)) + : [] + } + + const extractUserEmail = async () => { + const session = await getSession() + if (CommonUtils.isNullOrUndefined(session)) + return + setUserEmail(session.user.email) + } + useEffect(() => { + void extractUserEmail() fetchData(`releases/${releaseId}`) .then((release: ReleaseDetail | undefined) => { if (CommonUtils.isNullOrUndefined(release)){ @@ -96,6 +114,8 @@ const DetailOverview = ({ releaseId }: Props) : ReactNode => { setRelease(release) + setSubscribers(getSubcribersEmail(release)) + if ( !CommonUtils.isNullOrUndefined(release._embedded) && !CommonUtils.isNullOrUndefined(release._embedded['sw360:attachments']) @@ -164,6 +184,26 @@ const DetailOverview = ({ releaseId }: Props) : ReactNode => { ) } + const handleSubcriptions = async () => { + const session = await getSession() + if (CommonUtils.isNullOrUndefined(session)) { + MessageService.error(t('Session has expired')) + return + } + await ApiUtils.POST(`releases/${releaseId}/subscriptions`, {}, session.user.access_token) + fetchData(`releases/${releaseId}`) + .then((release: ReleaseDetail | undefined) => { + if (release === undefined) return + setRelease(release) + setSubscribers(getSubcribersEmail(release)) + }).catch((e) => console.error(e)) + } + + const isUserSubscribed = () => { + if (userEmail === undefined) return false + return subscribers.includes(userEmail) + } + const headerButtons = { 'Edit release': { link: `/components/editRelease/${releaseId}`, type: 'primary', name: t('Edit release') }, 'Link To Project': { @@ -175,7 +215,12 @@ const DetailOverview = ({ releaseId }: Props) : ReactNode => { name: t('Link To Project'), }, Merge: { link: '', type: 'secondary', name: t('Merge') }, - Subscribe: { link: '', type: 'outline-success', name: t('Subscribe') }, + Subscribe: { + link: '', + type: isUserSubscribed() ? 'outline-danger' : 'outline-success', + name: isUserSubscribed() ? t('Unsubscribe') : t('Subscribe'), + onClick: handleSubcriptions + }, } return ( @@ -193,80 +238,79 @@ const DetailOverview = ({ releaseId }: Props) : ReactNode => {
- -
- - - - {`${t('Version')} ${release.version}`} - - - { - Object.entries(releasesSameComponent).map( - ([index, item]: [string, ReleaseLink]) => ( - - - - {`${t('Version')} ${item.version}`} - - - ) +
+ + + + {`${t('Version')} ${release.version}`} + + + { + Object.entries(releasesSameComponent).map( + ([index, item]: [string, ReleaseLink]) => ( + + + + {`${t('Version')} ${item.version}`} + + ) - } - - -
- {selectedTab === CommonTabIds.ATTACHMENTS && embeddedAttachments.length > 0 && ( -
-
- + )} + + +
+
+ + {selectedTab === CommonTabIds.ATTACHMENTS && embeddedAttachments.length > 0 && ( +
+
+ +
-
- )} - {selectedTab === CommonTabIds.CHANGE_LOG && ( - + )} + +