diff --git a/awx/ui_next/public/index.html b/awx/ui_next/public/index.html index 564369ef99..301f9bf209 100644 --- a/awx/ui_next/public/index.html +++ b/awx/ui_next/public/index.html @@ -37,7 +37,6 @@ name="description" content="AWX" /> - AWX diff --git a/awx/ui_next/src/App.jsx b/awx/ui_next/src/App.jsx index 1ca84a2872..88c91406c0 100644 --- a/awx/ui_next/src/App.jsx +++ b/awx/ui_next/src/App.jsx @@ -12,7 +12,6 @@ import { ErrorBoundary } from 'react-error-boundary'; import { I18nProvider } from '@lingui/react'; import { i18n } from '@lingui/core'; import { Card, PageSection } from '@patternfly/react-core'; - import { ConfigProvider, useAuthorizedPath } from './contexts/Config'; import { SessionProvider, useSession } from './contexts/Session'; import AppContainer from './components/AppContainer'; @@ -20,15 +19,14 @@ import Background from './components/Background'; import ContentError from './components/ContentError'; import NotFound from './screens/NotFound'; import Login from './screens/Login'; - import { isAuthenticated } from './util/auth'; import { getLanguageWithoutRegionCode } from './util/language'; import { dynamicActivate, locales } from './i18nLoader'; import Metrics from './screens/Metrics'; - import getRouteConfig from './routeConfig'; import SubscriptionEdit from './screens/Setting/Subscription/SubscriptionEdit'; import { SESSION_REDIRECT_URL } from './constants'; +import { RootAPI } from './api'; function ErrorFallback({ error }) { return ( @@ -113,10 +111,22 @@ function App() { // preferred language, default to one that has strings. language = 'en'; } + useEffect(() => { dynamicActivate(language); }, [language]); + useEffect(() => { + async function fetchBrandName() { + const { + data: { BRAND_NAME }, + } = await RootAPI.readAssetVariables(); + + document.title = BRAND_NAME; + } + fetchBrandName(); + }, []); + const redirectURL = window.sessionStorage.getItem(SESSION_REDIRECT_URL); if (redirectURL) { window.sessionStorage.removeItem(SESSION_REDIRECT_URL); diff --git a/awx/ui_next/src/App.test.jsx b/awx/ui_next/src/App.test.jsx index 0e732b1574..805cbdc639 100644 --- a/awx/ui_next/src/App.test.jsx +++ b/awx/ui_next/src/App.test.jsx @@ -1,12 +1,21 @@ import React from 'react'; import { act } from 'react-dom/test-utils'; import { mountWithContexts } from '../testUtils/enzymeHelpers'; +import { RootAPI } from './api'; import * as SessionContext from './contexts/Session'; import App from './App'; jest.mock('./api'); describe('', () => { + beforeEach(() => { + RootAPI.readAssetVariables.mockResolvedValue({ + data: { + BRAND_NAME: 'AWX', + }, + }); + }); + test('renders ok', async () => { const contextValues = { setAuthRedirectTo: jest.fn(), diff --git a/awx/ui_next/src/components/About/About.jsx b/awx/ui_next/src/components/About/About.jsx index f0730742e2..09a3d11e91 100644 --- a/awx/ui_next/src/components/About/About.jsx +++ b/awx/ui_next/src/components/About/About.jsx @@ -2,12 +2,12 @@ import React from 'react'; import PropTypes from 'prop-types'; import { t } from '@lingui/macro'; import { AboutModal } from '@patternfly/react-core'; - -import { BrandName } from '../../variables'; +import useBrandName from '../../util/useBrandName'; function About({ version, isOpen, onClose }) { + const brandName = useBrandName(); const createSpeechBubble = () => { - let text = `${BrandName} ${version}`; + let text = `${brandName.current} ${version}`; let top = ''; let bottom = ''; @@ -31,7 +31,7 @@ function About({ version, isOpen, onClose }) { ({ ...jest.requireActual('react-router-dom'), @@ -40,6 +42,11 @@ const adHocItems = [ describe('', () => { beforeEach(() => { + RootAPI.readAssetVariables.mockResolvedValue({ + data: { + BRAND_NAME: 'AWX', + }, + }); InventoriesAPI.readAdHocOptions.mockResolvedValue({ data: { actions: { diff --git a/awx/ui_next/src/components/AdHocCommands/AdHocCommandsWizard.test.jsx b/awx/ui_next/src/components/AdHocCommands/AdHocCommandsWizard.test.jsx index bfa9c154ca..1393a94ebf 100644 --- a/awx/ui_next/src/components/AdHocCommands/AdHocCommandsWizard.test.jsx +++ b/awx/ui_next/src/components/AdHocCommands/AdHocCommandsWizard.test.jsx @@ -4,13 +4,14 @@ import { mountWithContexts, waitForElement, } from '../../../testUtils/enzymeHelpers'; -import { CredentialsAPI, ExecutionEnvironmentsAPI } from '../../api'; +import { CredentialsAPI, ExecutionEnvironmentsAPI, RootAPI } from '../../api'; import AdHocCommandsWizard from './AdHocCommandsWizard'; jest.mock('../../api/models/CredentialTypes'); jest.mock('../../api/models/Inventories'); jest.mock('../../api/models/Credentials'); jest.mock('../../api/models/ExecutionEnvironments'); +jest.mock('../../api/models/Root'); const verbosityOptions = [ { value: '0', key: '0', label: '0 (Normal)' }, @@ -32,6 +33,11 @@ describe('', () => { let wrapper; const onLaunch = jest.fn(); beforeEach(async () => { + RootAPI.readAssetVariables.mockResolvedValue({ + data: { + BRAND_NAME: 'AWX', + }, + }); await act(async () => { wrapper = mountWithContexts( } > diff --git a/awx/ui_next/src/components/AdHocCommands/AdHocDetailsStep.test.jsx b/awx/ui_next/src/components/AdHocCommands/AdHocDetailsStep.test.jsx index 406769feeb..e71759f3cd 100644 --- a/awx/ui_next/src/components/AdHocCommands/AdHocDetailsStep.test.jsx +++ b/awx/ui_next/src/components/AdHocCommands/AdHocDetailsStep.test.jsx @@ -2,9 +2,11 @@ import React from 'react'; import { act } from 'react-dom/test-utils'; import { Formik } from 'formik'; import { mountWithContexts } from '../../../testUtils/enzymeHelpers'; +import { RootAPI } from '../../api'; import DetailsStep from './AdHocDetailsStep'; jest.mock('../../api/models/Credentials'); +jest.mock('../../api/models/Root'); const verbosityOptions = [ { key: -1, value: '', label: '', isDisabled: false }, @@ -32,6 +34,14 @@ const initialValues = { describe('', () => { let wrapper; + beforeEach(() => { + RootAPI.readAssetVariables.mockResolvedValue({ + data: { + BRAND_NAME: 'AWX', + }, + }); + }); + test('should mount properly', async () => { await act(async () => { wrapper = mountWithContexts( diff --git a/awx/ui_next/src/index.jsx b/awx/ui_next/src/index.jsx index 827d708961..fb7fe4450f 100644 --- a/awx/ui_next/src/index.jsx +++ b/awx/ui_next/src/index.jsx @@ -3,9 +3,6 @@ import ReactDOM from 'react-dom'; import './setupCSP'; import '@patternfly/react-core/dist/styles/base.css'; import App from './App'; -import { BrandName } from './variables'; - -document.title = `${BrandName}`; ReactDOM.render( diff --git a/awx/ui_next/src/screens/Project/ProjectEdit/ProjectEdit.test.jsx b/awx/ui_next/src/screens/Project/ProjectEdit/ProjectEdit.test.jsx index 6e7b4b22f1..7e7b141892 100644 --- a/awx/ui_next/src/screens/Project/ProjectEdit/ProjectEdit.test.jsx +++ b/awx/ui_next/src/screens/Project/ProjectEdit/ProjectEdit.test.jsx @@ -6,7 +6,7 @@ import { waitForElement, } from '../../../../testUtils/enzymeHelpers'; import ProjectEdit from './ProjectEdit'; -import { ProjectsAPI, CredentialTypesAPI } from '../../../api'; +import { ProjectsAPI, CredentialTypesAPI, RootAPI } from '../../../api'; jest.mock('../../../api'); @@ -83,6 +83,11 @@ describe('', () => { }; beforeEach(async () => { + RootAPI.readAssetVariables.mockResolvedValue({ + data: { + BRAND_NAME: 'AWX', + }, + }); await ProjectsAPI.readOptions.mockImplementation( () => projectOptionsResolve ); diff --git a/awx/ui_next/src/screens/Project/shared/ProjectForm.test.jsx b/awx/ui_next/src/screens/Project/shared/ProjectForm.test.jsx index 0a34bde6ea..8c99c0b6c7 100644 --- a/awx/ui_next/src/screens/Project/shared/ProjectForm.test.jsx +++ b/awx/ui_next/src/screens/Project/shared/ProjectForm.test.jsx @@ -5,7 +5,7 @@ import { waitForElement, } from '../../../../testUtils/enzymeHelpers'; import ProjectForm from './ProjectForm'; -import { CredentialTypesAPI, ProjectsAPI } from '../../../api'; +import { CredentialTypesAPI, ProjectsAPI, RootAPI } from '../../../api'; jest.mock('../../../api'); @@ -81,6 +81,11 @@ describe('', () => { }; beforeEach(async () => { + RootAPI.readAssetVariables.mockResolvedValue({ + data: { + BRAND_NAME: 'AWX', + }, + }); await ProjectsAPI.readOptions.mockImplementation( () => projectOptionsResolve ); diff --git a/awx/ui_next/src/screens/Project/shared/ProjectSubForms/ManualSubForm.jsx b/awx/ui_next/src/screens/Project/shared/ProjectSubForms/ManualSubForm.jsx index e15e5147d3..0e7185284e 100644 --- a/awx/ui_next/src/screens/Project/shared/ProjectSubForms/ManualSubForm.jsx +++ b/awx/ui_next/src/screens/Project/shared/ProjectSubForms/ManualSubForm.jsx @@ -1,6 +1,5 @@ import 'styled-components/macro'; import React from 'react'; - import { t } from '@lingui/macro'; import { useField } from 'formik'; import { FormGroup, Alert } from '@patternfly/react-core'; @@ -8,18 +7,14 @@ import { required } from '../../../../util/validators'; import AnsibleSelect from '../../../../components/AnsibleSelect'; import FormField from '../../../../components/FormField'; import Popover from '../../../../components/Popover'; -import { BrandName } from '../../../../variables'; - -// Setting BrandName to a variable here is necessary to get the jest tests -// passing. Attempting to use BrandName in the template literal results -// in failing tests. -const brandName = BrandName; +import useBrandName from '../../../../util/useBrandName'; const ManualSubForm = ({ localPath, project_base_dir, project_local_paths, }) => { + const brandName = useBrandName(); const localPaths = [...new Set([...project_local_paths, localPath])]; const options = [ { @@ -54,7 +49,7 @@ const ManualSubForm = ({ Either that directory is empty, or all of the contents are already assigned to other projects. Create a new directory there and make sure the playbook files can be read by the "awx" system user, - or have ${brandName} directly retrieve your playbooks from + or have ${brandName.current} directly retrieve your playbooks from source control using the Source Control Type option above.`} )} diff --git a/awx/ui_next/src/screens/Setting/SettingList.jsx b/awx/ui_next/src/screens/Setting/SettingList.jsx index d42eaa2b10..61fe2352a8 100644 --- a/awx/ui_next/src/screens/Setting/SettingList.jsx +++ b/awx/ui_next/src/screens/Setting/SettingList.jsx @@ -1,6 +1,5 @@ import React from 'react'; import { Link } from 'react-router-dom'; - import { t } from '@lingui/macro'; import { Card as _Card, @@ -14,14 +13,9 @@ import { PageSection, } from '@patternfly/react-core'; import styled from 'styled-components'; -import { BrandName } from '../../variables'; import { useConfig } from '../../contexts/Config'; import ContentLoading from '../../components/ContentLoading/ContentLoading'; - -// Setting BrandName to a variable here is necessary to get the jest tests -// passing. Attempting to use BrandName in the template literal results -// in failing tests. -const brandName = BrandName; +import useBrandName from '../../util/useBrandName'; const SplitLayout = styled(PageSection)` column-count: 1; @@ -50,10 +44,11 @@ const CardDescription = styled.div` function SettingList() { const config = useConfig(); + const brandName = useBrandName(); const settingRoutes = [ { header: t`Authentication`, - description: t`Enable simplified login for your ${brandName} applications`, + description: t`Enable simplified login for your ${brandName.current} applications`, id: 'authentication', routes: [ { @@ -88,7 +83,7 @@ function SettingList() { }, { header: t`Jobs`, - description: t`Update settings pertaining to Jobs within ${brandName}`, + description: t`Update settings pertaining to Jobs within ${brandName.current}`, id: 'jobs', routes: [ { diff --git a/awx/ui_next/src/screens/Setting/Settings.test.jsx b/awx/ui_next/src/screens/Setting/Settings.test.jsx index 11a89e5e58..3de824527c 100644 --- a/awx/ui_next/src/screens/Setting/Settings.test.jsx +++ b/awx/ui_next/src/screens/Setting/Settings.test.jsx @@ -5,7 +5,7 @@ import { mountWithContexts, waitForElement, } from '../../../testUtils/enzymeHelpers'; -import { SettingsAPI } from '../../api'; +import { SettingsAPI, RootAPI } from '../../api'; import mockAllOptions from './shared/data.allSettingOptions.json'; import Settings from './Settings'; @@ -19,6 +19,11 @@ describe('', () => { let wrapper; beforeEach(() => { + RootAPI.readAssetVariables.mockResolvedValue({ + data: { + BRAND_NAME: 'AWX', + }, + }); SettingsAPI.readAllOptions.mockResolvedValue({ data: mockAllOptions, }); diff --git a/awx/ui_next/src/screens/Template/JobTemplateAdd/JobTemplateAdd.test.jsx b/awx/ui_next/src/screens/Template/JobTemplateAdd/JobTemplateAdd.test.jsx index 9df1247d0c..517194a8c3 100644 --- a/awx/ui_next/src/screens/Template/JobTemplateAdd/JobTemplateAdd.test.jsx +++ b/awx/ui_next/src/screens/Template/JobTemplateAdd/JobTemplateAdd.test.jsx @@ -12,6 +12,7 @@ import { JobTemplatesAPI, LabelsAPI, ProjectsAPI, + RootAPI, } from '../../../api'; jest.mock('../../../api'); @@ -67,6 +68,11 @@ describe('', () => { }; beforeEach(() => { + RootAPI.readAssetVariables.mockResolvedValue({ + data: { + BRAND_NAME: 'AWX', + }, + }); CredentialsAPI.read.mockResolvedValue({ data: { results: [], diff --git a/awx/ui_next/src/screens/Template/JobTemplateEdit/JobTemplateEdit.test.jsx b/awx/ui_next/src/screens/Template/JobTemplateEdit/JobTemplateEdit.test.jsx index b7dfb74864..7eb653e225 100644 --- a/awx/ui_next/src/screens/Template/JobTemplateEdit/JobTemplateEdit.test.jsx +++ b/awx/ui_next/src/screens/Template/JobTemplateEdit/JobTemplateEdit.test.jsx @@ -14,6 +14,7 @@ import { InventoriesAPI, ExecutionEnvironmentsAPI, InstanceGroupsAPI, + RootAPI, } from '../../../api'; import JobTemplateEdit from './JobTemplateEdit'; import useDebounce from '../../../util/useDebounce'; @@ -27,6 +28,7 @@ jest.mock('../../../api/models/Projects'); jest.mock('../../../api/models/Inventories'); jest.mock('../../../api/models/ExecutionEnvironments'); jest.mock('../../../api/models/InstanceGroups'); +jest.mock('../../../api/models/Root'); const mockJobTemplate = { allow_callbacks: false, @@ -203,6 +205,11 @@ const mockExecutionEnvironment = [ describe('', () => { beforeEach(() => { + RootAPI.readAssetVariables.mockResolvedValue({ + data: { + BRAND_NAME: 'AWX', + }, + }); JobTemplatesAPI.readCredentials.mockResolvedValue({ data: mockRelatedCredentials, }); diff --git a/awx/ui_next/src/screens/Template/shared/JobTemplateForm.jsx b/awx/ui_next/src/screens/Template/shared/JobTemplateForm.jsx index 877c0cabb3..856dc6516d 100644 --- a/awx/ui_next/src/screens/Template/shared/JobTemplateForm.jsx +++ b/awx/ui_next/src/screens/Template/shared/JobTemplateForm.jsx @@ -13,11 +13,10 @@ import { } from '@patternfly/react-core'; import ContentError from '../../../components/ContentError'; import ContentLoading from '../../../components/ContentLoading'; -import { BrandName } from '../../../variables'; import AnsibleSelect from '../../../components/AnsibleSelect'; import { TagMultiSelect } from '../../../components/MultiSelect'; import useRequest from '../../../util/useRequest'; - +import useBrandName from '../../../util/useBrandName'; import FormActionGroup from '../../../components/FormActionGroup'; import FormField, { CheckboxField, @@ -67,6 +66,7 @@ function JobTemplateForm({ Boolean(template.webhook_service) ); const isMounted = useIsMounted(); + const brandName = useBrandName(); const [askInventoryOnLaunchField] = useField('ask_inventory_on_launch'); const [jobTypeField, jobTypeMeta, jobTypeHelpers] = useField({ @@ -567,7 +567,7 @@ function JobTemplateForm({   diff --git a/awx/ui_next/src/screens/Template/shared/JobTemplateForm.test.jsx b/awx/ui_next/src/screens/Template/shared/JobTemplateForm.test.jsx index 882aa1de96..81d80ddd1d 100644 --- a/awx/ui_next/src/screens/Template/shared/JobTemplateForm.test.jsx +++ b/awx/ui_next/src/screens/Template/shared/JobTemplateForm.test.jsx @@ -15,6 +15,7 @@ import { CredentialsAPI, CredentialTypesAPI, InventoriesAPI, + RootAPI, } from '../../../api'; jest.mock('../../../api'); @@ -95,6 +96,11 @@ describe('', () => { beforeEach(() => { consoleError = global.console.error; global.console.error = jest.fn(); + RootAPI.readAssetVariables.mockResolvedValue({ + data: { + BRAND_NAME: 'AWX', + }, + }); LabelsAPI.read.mockReturnValue({ data: mockData.summary_fields.labels, }); diff --git a/awx/ui_next/src/util/useBrandName.js b/awx/ui_next/src/util/useBrandName.js new file mode 100644 index 0000000000..f8d0a80aef --- /dev/null +++ b/awx/ui_next/src/util/useBrandName.js @@ -0,0 +1,19 @@ +import { useEffect, useRef } from 'react'; +import { RootAPI } from '../api'; + +export default function useBrandName() { + const brandName = useRef(''); + + useEffect(() => { + async function fetchBrandName() { + const { + data: { BRAND_NAME }, + } = await RootAPI.readAssetVariables(); + + brandName.current = BRAND_NAME; + } + fetchBrandName(); + }, []); + + return brandName; +} diff --git a/awx/ui_next/src/variables.js b/awx/ui_next/src/variables.js deleted file mode 100644 index 001c1c5e16..0000000000 --- a/awx/ui_next/src/variables.js +++ /dev/null @@ -1,2 +0,0 @@ -export const BrandName = 'AWX'; -export const PendoAPIKey = '';