diff --git a/frontend/assets/ansible-brand.svg b/frontend/assets/ansible-brand.svg
new file mode 100644
index 0000000000..4b0b17ddea
--- /dev/null
+++ b/frontend/assets/ansible-brand.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/frontend/assets/awx-logo.svg b/frontend/assets/awx-logo.svg
index 85af5785be..19dcd55505 100644
--- a/frontend/assets/awx-logo.svg
+++ b/frontend/assets/awx-logo.svg
@@ -1,149 +1,91 @@
-
\ No newline at end of file
+
diff --git a/frontend/assets/galaxy-logo-ansibull.png b/frontend/assets/galaxy-logo-ansibull.png
new file mode 100644
index 0000000000..0beac2d214
Binary files /dev/null and b/frontend/assets/galaxy-logo-ansibull.png differ
diff --git a/frontend/assets/galaxy-logo-icon.png b/frontend/assets/galaxy-logo-icon.png
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/frontend/awx/main/AwxMasthead.tsx b/frontend/awx/main/AwxMasthead.tsx
index b89d267d68..ff4e0bb00f 100644
--- a/frontend/awx/main/AwxMasthead.tsx
+++ b/frontend/awx/main/AwxMasthead.tsx
@@ -20,9 +20,11 @@ import { useAwxWebSocketSubscription } from '../common/useAwxWebSocket';
import { getDocsBaseUrl } from '../common/util/getDocsBaseUrl';
import { WorkflowApproval } from '../interfaces/WorkflowApproval';
import { AwxRoute } from './AwxRoutes';
+import { useAwxProductVersionInfo } from './useAwxProductVersionInfo';
export function AwxMasthead() {
const { t } = useTranslation();
+ const versionInfo = useAwxProductVersionInfo();
const openAnsibleAboutModal = useAnsibleAboutModal();
const config = useAwxConfig();
const pageNavigate = usePageNavigate();
@@ -58,7 +60,13 @@ export function AwxMasthead() {
openAnsibleAboutModal({ brandImageSrc: '/assets/awx-logo.svg' })}
+ onClick={() =>
+ openAnsibleAboutModal({
+ brandImageSrc: '/assets/awx-logo.svg',
+ versionInfo,
+ userInfo: activeAwxUser?.username,
+ })
+ }
data-cy="masthead-about"
>
{t('About')}
diff --git a/frontend/awx/main/useAwxProductVersionInfo.tsx b/frontend/awx/main/useAwxProductVersionInfo.tsx
new file mode 100644
index 0000000000..71649c0a2a
--- /dev/null
+++ b/frontend/awx/main/useAwxProductVersionInfo.tsx
@@ -0,0 +1,18 @@
+import { useEffect, useState } from 'react';
+import { awxAPI } from '../common/api/awx-utils';
+
+type ProductVersionInfo = Record>;
+
+export function useAwxProductVersionInfo() {
+ const [, setError] = useState();
+ const [productVersionInfo, setProductVersionInfo] = useState();
+ useEffect(() => {
+ fetch(awxAPI`/ping/`)
+ .then((response) => response.json())
+ .then((data) => setProductVersionInfo(data as ProductVersionInfo))
+ .catch((err) => {
+ setError(err as Error);
+ });
+ }, []);
+ return productVersionInfo;
+}
diff --git a/frontend/common/AboutModal.tsx b/frontend/common/AboutModal.tsx
index 94177d2f69..252bd23013 100644
--- a/frontend/common/AboutModal.tsx
+++ b/frontend/common/AboutModal.tsx
@@ -1,16 +1,33 @@
-import { AboutModal, TextContent, TextList, TextListItem } from '@patternfly/react-core';
-import { useEffect, useState } from 'react';
+import {
+ AboutModal,
+ DescriptionList,
+ DescriptionListDescription,
+ DescriptionListGroup,
+ DescriptionListTerm,
+} from '@patternfly/react-core';
+import { TFunction } from 'i18next';
+import React, { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
+import styled from 'styled-components';
import { usePageDialog } from '../../framework';
export interface AnsibleAboutModalProps {
brandImageSrc: string;
+ versionInfo?: ProductVersionInfo;
+ userInfo?: string;
onClose?: () => void;
}
-function AnsibleAboutModal(props: AnsibleAboutModalProps) {
- const [_dialog, setDialog] = usePageDialog();
+type ProductVersionInfo = Record>;
+
+const StyledDescriptionListDescription = styled(DescriptionListDescription)`
+ font-weight: normal;
+`;
+
+export function AnsibleAboutModal(props: AnsibleAboutModalProps) {
const { t } = useTranslation();
+ const [_dialog, setDialog] = usePageDialog();
+
return (
-
-
- {t('Version')}
- {process.env.VERSION}
-
-
+
+ {Object.entries(props.versionInfo ?? {})
+ .filter(
+ ([product]) =>
+ product !== 'galaxy_ng_commit' &&
+ product !== 'ha' &&
+ product !== 'instances' &&
+ product !== 'instance_groups' &&
+ product !== 'time_zone' &&
+ product !== 'deployment_type'
+ )
+ .map(([product, info]) => (
+
+ {translateVersion(product, t)}
+ {typeof info === 'string' ? (
+ {info}
+ ) : (
+ Object.entries(info).map(([key, value]) => (
+
+ {
+
+ {t(value)}
+
+ }
+
+ ))
+ )}
+
+ ))}
+
+ {t('Username')}
+ {props.userInfo}
+
+
);
}
@@ -49,3 +94,38 @@ export function useAnsibleAboutModal() {
}, [props, setDialog]);
return setProps;
}
+
+export function translateVersion(name: string | undefined, t: TFunction) {
+ const VERSION_NAMES: Record = {
+ server_version: t`Server Version`,
+ galaxy_ng_version: t`Galaxy NG version`,
+ galaxy_importer_version: t`Galaxy Importer Version`,
+ pulp_core_version: t`Pulp Core version`,
+ pulp_ansible_version: t`Pulp Ansible Version`,
+ pulp_container_version: t`Pulp Container Version`,
+ version: t`Version`,
+ active_node: t`Active Node`,
+ install_uuid: t`Install UUID`,
+ instances: t`Instances`,
+ instance_groups: t`Instance Groups`,
+ available_versions: t`Available Versions`,
+ node: t`Node`,
+ node_type: t`Node type`,
+ uuid: t`UUID`,
+ heartbeat: t`Heartbeat`,
+ capacity: t`Capacity`,
+ name: t`Name`,
+ };
+
+ return VERSION_NAMES[name as string] || name;
+}
+
+export function upstreamServices(name: string | undefined, t: TFunction) {
+ const SERVICE_NAMES: Record = {
+ 'Automation Hub': t`Ansible Galaxy`,
+ AWX: t`AWX`,
+ 'Event Driven Automation': t`EDA Server`,
+ };
+
+ return SERVICE_NAMES[name as string] || name;
+}
diff --git a/frontend/eda/main/EdaMasthead.tsx b/frontend/eda/main/EdaMasthead.tsx
index 503c063a24..e62e5d6f0d 100644
--- a/frontend/eda/main/EdaMasthead.tsx
+++ b/frontend/eda/main/EdaMasthead.tsx
@@ -13,9 +13,10 @@ import { postRequest } from '../../common/crud/Data';
import { edaAPI } from '../common/eda-utils';
import { useEdaActiveUser } from '../common/useEdaActiveUser';
import { EdaRoute } from './EdaRoutes';
-
+import { useEdaProductVersionInfo } from './useEdaProductVersionInfo';
export function EdaMasthead() {
const { t } = useTranslation();
+ const versionInfo = useEdaProductVersionInfo();
const openAnsibleAboutModal = useAnsibleAboutModal();
const pageNavigate = usePageNavigate();
const { activeEdaUser, refreshActiveEdaUser } = useEdaActiveUser();
@@ -49,7 +50,13 @@ export function EdaMasthead() {
openAnsibleAboutModal({ brandImageSrc: '/assets/eda-logo.svg' })}
+ onClick={() =>
+ openAnsibleAboutModal({
+ brandImageSrc: '/assets/eda-icon.svg',
+ versionInfo,
+ userInfo: activeEdaUser?.username,
+ })
+ }
data-cy="masthead-about"
>
{t('About')}
diff --git a/frontend/eda/main/useEdaProductVersionInfo.tsx b/frontend/eda/main/useEdaProductVersionInfo.tsx
new file mode 100644
index 0000000000..fcaef15c3f
--- /dev/null
+++ b/frontend/eda/main/useEdaProductVersionInfo.tsx
@@ -0,0 +1,18 @@
+import { useEffect, useState } from 'react';
+import { edaAPI } from '../common/eda-utils';
+
+type ProductVersionInfo = Record>;
+
+export function useEdaProductVersionInfo() {
+ const [, setError] = useState();
+ const [productVersionInfo, setProductVersionInfo] = useState();
+ useEffect(() => {
+ fetch(edaAPI`/config/`)
+ .then((response) => response.json())
+ .then((data) => setProductVersionInfo(data as ProductVersionInfo))
+ .catch((err) => {
+ setError(err as Error);
+ });
+ }, []);
+ return productVersionInfo;
+}
diff --git a/frontend/hub/main/HubMasthead.tsx b/frontend/hub/main/HubMasthead.tsx
index 659eeda654..e0d5b999d4 100644
--- a/frontend/hub/main/HubMasthead.tsx
+++ b/frontend/hub/main/HubMasthead.tsx
@@ -19,9 +19,10 @@ import { useHubActiveUser } from '../common/useHubActiveUser';
import { useHubContext } from '../common/useHubContext';
import { HubItemsResponse } from '../common/useHubView';
import { HubRoute } from './HubRoutes';
-
+import { useHubProductVersionInfo } from './useHubProductVersionInfo';
export function HubMasthead() {
const { t } = useTranslation();
+ const versionInfo = useHubProductVersionInfo();
const openAnsibleAboutModal = useAnsibleAboutModal();
useHubNotifications();
const { activeHubUser, refreshActiveHubUser } = useHubActiveUser();
@@ -56,7 +57,13 @@ export function HubMasthead() {
<>>
openAnsibleAboutModal({ brandImageSrc: '/assets/galaxy-logo.svg' })}
+ onClick={() =>
+ openAnsibleAboutModal({
+ brandImageSrc: '/assets/galaxy-logo-ansibull.png',
+ versionInfo,
+ userInfo: activeHubUser?.username,
+ })
+ }
data-cy="masthead-about"
>
{t('About')}
@@ -84,20 +91,15 @@ export function HubMasthead() {
);
}
-
export function useHubNotifications() {
const { t } = useTranslation();
const getPageUrl = useGetPageUrl();
-
const { hasPermission } = useHubContext();
-
const canApprove = hasPermission('ansible.modify_ansible_repo_content');
-
const { data: result } = useGet>(
canApprove ? hubAPI`/v3/plugin/ansible/search/collection-versions/` : undefined,
{ page_size: 100, repository_label: 'pipeline=staging' }
);
-
const { setNotificationGroups } = usePageNotifications();
useEffect(() => {
setNotificationGroups((groups) => {
@@ -109,7 +111,6 @@ export function useHubNotifications() {
description: t('Namespace: ') + approval.collection_version?.namespace ?? '',
// timestamp: approval.created,
variant: 'info',
-
// TODO to should goto the specific approval page instead of the approvals page
to: getPageUrl(HubRoute.Approvals, { query: { status: 'pipeline=staging' } }),
})) ?? [],
@@ -117,6 +118,5 @@ export function useHubNotifications() {
return { ...groups };
});
}, [result, getPageUrl, setNotificationGroups, t]);
-
return result?.data ?? 0;
}
diff --git a/frontend/hub/main/useHubProductVersionInfo.tsx b/frontend/hub/main/useHubProductVersionInfo.tsx
new file mode 100644
index 0000000000..f53bbf2c94
--- /dev/null
+++ b/frontend/hub/main/useHubProductVersionInfo.tsx
@@ -0,0 +1,18 @@
+import { useEffect, useState } from 'react';
+import { hubAPI } from '../common/api/formatPath';
+
+type ProductVersionInfo = Record>;
+
+export function useHubProductVersionInfo() {
+ const [, setError] = useState();
+ const [productVersionInfo, setProductVersionInfo] = useState();
+ useEffect(() => {
+ fetch(hubAPI`/`)
+ .then((response) => response.json())
+ .then((data) => setProductVersionInfo(data as ProductVersionInfo))
+ .catch((err) => {
+ setError(err as Error);
+ });
+ }, []);
+ return productVersionInfo;
+}
diff --git a/frontend/icons/galaxy-logo-ansibull.png b/frontend/icons/galaxy-logo-ansibull.png
new file mode 100644
index 0000000000..0beac2d214
Binary files /dev/null and b/frontend/icons/galaxy-logo-ansibull.png differ