diff --git a/awx/ui_next/src/components/AppContainer/AppContainer.jsx b/awx/ui_next/src/components/AppContainer/AppContainer.jsx index 6da5aa74f092..4c290adb41fb 100644 --- a/awx/ui_next/src/components/AppContainer/AppContainer.jsx +++ b/awx/ui_next/src/components/AppContainer/AppContainer.jsx @@ -87,8 +87,9 @@ function useStorage(key) { function AppContainer({ i18n, navRouteConfig = [], children }) { const history = useHistory(); - const [config] = useConfig(); + const config = useConfig(); + const isReady = !!config.license_info; const isSidebarVisible = useAuthorizedPath(); const [isAboutModalOpen, setIsAboutModalOpen] = useState(false); @@ -153,7 +154,7 @@ function AppContainer({ i18n, navRouteConfig = [], children }) { /> ); - const simpleHeader = ( + const simpleHeader = config.isLoading ? null : ( } headerTools={ @@ -197,7 +198,7 @@ function AppContainer({ i18n, navRouteConfig = [], children }) { header={isSidebarVisible ? header : simpleHeader} sidebar={isSidebarVisible && sidebar} > - {Object.keys(config).length ? children : null} + {isReady ? children : null} ', () => { const version = '222'; - const config = { - ansible_version, - version, - }; beforeEach(() => { ConfigAPI.read.mockResolvedValue({ @@ -56,10 +52,7 @@ describe('', () => { {routeConfig.map(({ groupId }) => (
))} - , - { - context: { config }, - } + ); }); wrapper.update(); @@ -88,7 +81,7 @@ describe('', () => { let wrapper; await act(async () => { wrapper = mountWithContexts(, { - context: { config }, + context: { config: { version } }, }); }); @@ -116,12 +109,7 @@ describe('', () => { let wrapper; await act(async () => { - wrapper = mountWithContexts(, { - context: { - ansible_version, - version, - }, - }); + wrapper = mountWithContexts(); }); // open the user menu diff --git a/awx/ui_next/src/components/InstanceToggle/InstanceToggle.jsx b/awx/ui_next/src/components/InstanceToggle/InstanceToggle.jsx index cc9d06487169..f3c08f64a610 100644 --- a/awx/ui_next/src/components/InstanceToggle/InstanceToggle.jsx +++ b/awx/ui_next/src/components/InstanceToggle/InstanceToggle.jsx @@ -15,7 +15,7 @@ function InstanceToggle({ onToggle, i18n, }) { - const [{ me = {} }] = useConfig(); + const { me = {} } = useConfig(); const [isEnabled, setIsEnabled] = useState(instance.enabled); const [showError, setShowError] = useState(false); diff --git a/awx/ui_next/src/components/PromptDetail/PromptProjectDetail.jsx b/awx/ui_next/src/components/PromptDetail/PromptProjectDetail.jsx index 8302ad18e958..0ab2d6d31f66 100644 --- a/awx/ui_next/src/components/PromptDetail/PromptProjectDetail.jsx +++ b/awx/ui_next/src/components/PromptDetail/PromptProjectDetail.jsx @@ -95,7 +95,7 @@ function PromptProjectDetail({ i18n, resource }) { value={`${scm_update_cache_timeout} ${i18n._(t`Seconds`)}`} /> - {([{ project_base_dir }]) => ( + {({ project_base_dir }) => ( { const { error: configError, + isLoading, request, result: config, setValue: setConfig, @@ -58,8 +59,14 @@ export const ConfigProvider = withI18n()(({ i18n, children }) => { } }, [error]); + const value = useMemo(() => ({ ...config, isLoading, setConfig }), [ + config, + isLoading, + setConfig, + ]); + return ( - + {error && ( { }); export const useAuthorizedPath = () => { - const [config] = useConfig(); + const config = useConfig(); const subscriptionMgmtRoute = useRouteMatch({ path: '/subscription_management', }); - return !!config.license_info?.valid_key && !subscriptionMgmtRoute; }; diff --git a/awx/ui_next/src/screens/Credential/CredentialEdit/CredentialEdit.jsx b/awx/ui_next/src/screens/Credential/CredentialEdit/CredentialEdit.jsx index f3049d2fc114..507af7833455 100644 --- a/awx/ui_next/src/screens/Credential/CredentialEdit/CredentialEdit.jsx +++ b/awx/ui_next/src/screens/Credential/CredentialEdit/CredentialEdit.jsx @@ -18,7 +18,7 @@ import { useConfig } from '../../../contexts/Config'; function CredentialEdit({ credential }) { const history = useHistory(); const { id: credId } = useParams(); - const [{ me = {} }] = useConfig(); + const { me = {} } = useConfig(); const [isOrgLookupDisabled, setIsOrgLookupDisabled] = useState(false); const { error: submitError, request: submitRequest, result } = useRequest( diff --git a/awx/ui_next/src/screens/Credential/Credentials.jsx b/awx/ui_next/src/screens/Credential/Credentials.jsx index 1b54b71bdfe1..d883aa0dca3f 100644 --- a/awx/ui_next/src/screens/Credential/Credentials.jsx +++ b/awx/ui_next/src/screens/Credential/Credentials.jsx @@ -40,7 +40,7 @@ function Credentials({ i18n }) { /> - {([{ me }]) => } + {({ me }) => } diff --git a/awx/ui_next/src/screens/Host/Hosts.jsx b/awx/ui_next/src/screens/Host/Hosts.jsx index c9042465ed17..d8769b071e90 100644 --- a/awx/ui_next/src/screens/Host/Hosts.jsx +++ b/awx/ui_next/src/screens/Host/Hosts.jsx @@ -44,7 +44,7 @@ function Hosts({ i18n }) { - {([{ me }]) => ( + {({ me }) => ( )} diff --git a/awx/ui_next/src/screens/Inventory/Inventories.jsx b/awx/ui_next/src/screens/Inventory/Inventories.jsx index c3c83163da78..12178f667fc0 100644 --- a/awx/ui_next/src/screens/Inventory/Inventories.jsx +++ b/awx/ui_next/src/screens/Inventory/Inventories.jsx @@ -137,7 +137,7 @@ function Inventories({ i18n }) { - {([{ me }]) => ( + {({ me }) => ( )} diff --git a/awx/ui_next/src/screens/Inventory/InventorySources/InventorySources.jsx b/awx/ui_next/src/screens/Inventory/InventorySources/InventorySources.jsx index 67bfd67429a8..e55125187df3 100644 --- a/awx/ui_next/src/screens/Inventory/InventorySources/InventorySources.jsx +++ b/awx/ui_next/src/screens/Inventory/InventorySources/InventorySources.jsx @@ -13,7 +13,7 @@ function InventorySources({ inventory, setBreadcrumb }) { - {([{ me }]) => ( + {({ me }) => ( - {([{ me }]) => ( + {({ me }) => ( )} diff --git a/awx/ui_next/src/screens/Project/Project.jsx b/awx/ui_next/src/screens/Project/Project.jsx index 6b96a7428aab..5c3a5a7564dc 100644 --- a/awx/ui_next/src/screens/Project/Project.jsx +++ b/awx/ui_next/src/screens/Project/Project.jsx @@ -26,7 +26,7 @@ import ProjectJobTemplatesList from './ProjectJobTemplatesList'; import { OrganizationsAPI, ProjectsAPI } from '../../api'; function Project({ i18n, setBreadcrumb }) { - const [{ me = {} }] = useConfig(); + const { me = {} } = useConfig(); const { id } = useParams(); const location = useLocation(); diff --git a/awx/ui_next/src/screens/Project/ProjectDetail/ProjectDetail.jsx b/awx/ui_next/src/screens/Project/ProjectDetail/ProjectDetail.jsx index a4633f0fc9ec..f8bcd351b79b 100644 --- a/awx/ui_next/src/screens/Project/ProjectDetail/ProjectDetail.jsx +++ b/awx/ui_next/src/screens/Project/ProjectDetail/ProjectDetail.jsx @@ -135,7 +135,7 @@ function ProjectDetail({ project, i18n }) { isDefaultEnvironment /> - {([{ project_base_dir }]) => ( + {({ project_base_dir }) => ( diff --git a/awx/ui_next/src/screens/Setting/ActivityStream/ActivityStreamDetail/ActivityStreamDetail.jsx b/awx/ui_next/src/screens/Setting/ActivityStream/ActivityStreamDetail/ActivityStreamDetail.jsx index bf40a156d915..16391ab3d479 100644 --- a/awx/ui_next/src/screens/Setting/ActivityStream/ActivityStreamDetail/ActivityStreamDetail.jsx +++ b/awx/ui_next/src/screens/Setting/ActivityStream/ActivityStreamDetail/ActivityStreamDetail.jsx @@ -16,7 +16,7 @@ import { SettingsAPI } from '../../../../api'; import { SettingDetail } from '../../shared'; function ActivityStreamDetail({ i18n }) { - const [{ me }] = useConfig(); + const { me } = useConfig(); const { GET: options } = useSettings(); const { isLoading, error, request, result: activityStream } = useRequest( diff --git a/awx/ui_next/src/screens/Setting/AzureAD/AzureADDetail/AzureADDetail.jsx b/awx/ui_next/src/screens/Setting/AzureAD/AzureADDetail/AzureADDetail.jsx index 94ac9ae9f2ab..c93f9b8009f8 100644 --- a/awx/ui_next/src/screens/Setting/AzureAD/AzureADDetail/AzureADDetail.jsx +++ b/awx/ui_next/src/screens/Setting/AzureAD/AzureADDetail/AzureADDetail.jsx @@ -16,7 +16,7 @@ import { SettingsAPI } from '../../../../api'; import { SettingDetail } from '../../shared'; function AzureADDetail({ i18n }) { - const [{ me }] = useConfig(); + const { me } = useConfig(); const { GET: options } = useSettings(); const { isLoading, error, request, result: azure } = useRequest( diff --git a/awx/ui_next/src/screens/Setting/GitHub/GitHubDetail/GitHubDetail.jsx b/awx/ui_next/src/screens/Setting/GitHub/GitHubDetail/GitHubDetail.jsx index 247559ca0df0..fcea0d549cf0 100644 --- a/awx/ui_next/src/screens/Setting/GitHub/GitHubDetail/GitHubDetail.jsx +++ b/awx/ui_next/src/screens/Setting/GitHub/GitHubDetail/GitHubDetail.jsx @@ -16,7 +16,7 @@ import { SettingsAPI } from '../../../../api'; import { SettingDetail } from '../../shared'; function GitHubDetail({ i18n }) { - const [{ me }] = useConfig(); + const { me } = useConfig(); const { GET: options } = useSettings(); const baseURL = '/settings/github'; diff --git a/awx/ui_next/src/screens/Setting/GoogleOAuth2/GoogleOAuth2Detail/GoogleOAuth2Detail.jsx b/awx/ui_next/src/screens/Setting/GoogleOAuth2/GoogleOAuth2Detail/GoogleOAuth2Detail.jsx index 185862e74410..ff59e2604c0f 100644 --- a/awx/ui_next/src/screens/Setting/GoogleOAuth2/GoogleOAuth2Detail/GoogleOAuth2Detail.jsx +++ b/awx/ui_next/src/screens/Setting/GoogleOAuth2/GoogleOAuth2Detail/GoogleOAuth2Detail.jsx @@ -16,7 +16,7 @@ import { useSettings } from '../../../../contexts/Settings'; import { SettingDetail } from '../../shared'; function GoogleOAuth2Detail({ i18n }) { - const [{ me }] = useConfig(); + const { me } = useConfig(); const { GET: options } = useSettings(); const { isLoading, error, request, result: googleOAuth2 } = useRequest( diff --git a/awx/ui_next/src/screens/Setting/Jobs/JobsDetail/JobsDetail.jsx b/awx/ui_next/src/screens/Setting/Jobs/JobsDetail/JobsDetail.jsx index 2510af843f84..1e56a72b693f 100644 --- a/awx/ui_next/src/screens/Setting/Jobs/JobsDetail/JobsDetail.jsx +++ b/awx/ui_next/src/screens/Setting/Jobs/JobsDetail/JobsDetail.jsx @@ -17,7 +17,7 @@ import { sortNestedDetails } from '../../shared/settingUtils'; import { SettingDetail } from '../../shared'; function JobsDetail({ i18n }) { - const [{ me }] = useConfig(); + const { me } = useConfig(); const { GET: options } = useSettings(); const { isLoading, error, request, result: jobs } = useRequest( diff --git a/awx/ui_next/src/screens/Setting/LDAP/LDAPDetail/LDAPDetail.jsx b/awx/ui_next/src/screens/Setting/LDAP/LDAPDetail/LDAPDetail.jsx index 45c73aaa5055..ba1fe9df8e08 100644 --- a/awx/ui_next/src/screens/Setting/LDAP/LDAPDetail/LDAPDetail.jsx +++ b/awx/ui_next/src/screens/Setting/LDAP/LDAPDetail/LDAPDetail.jsx @@ -26,7 +26,7 @@ function filterByPrefix(data, prefix) { } function LDAPDetail({ i18n }) { - const [{ me }] = useConfig(); + const { me } = useConfig(); const { GET: options } = useSettings(); const { path, diff --git a/awx/ui_next/src/screens/Setting/Logging/Logging.jsx b/awx/ui_next/src/screens/Setting/Logging/Logging.jsx index d7dcc647cb0e..a4d60db55086 100644 --- a/awx/ui_next/src/screens/Setting/Logging/Logging.jsx +++ b/awx/ui_next/src/screens/Setting/Logging/Logging.jsx @@ -10,7 +10,7 @@ import LoggingEdit from './LoggingEdit'; function Logging({ i18n }) { const baseURL = '/settings/logging'; - const [{ me }] = useConfig(); + const { me } = useConfig(); return ( diff --git a/awx/ui_next/src/screens/Setting/Logging/LoggingDetail/LoggingDetail.jsx b/awx/ui_next/src/screens/Setting/Logging/LoggingDetail/LoggingDetail.jsx index 5ab4559e50b2..3a6850779b5d 100644 --- a/awx/ui_next/src/screens/Setting/Logging/LoggingDetail/LoggingDetail.jsx +++ b/awx/ui_next/src/screens/Setting/Logging/LoggingDetail/LoggingDetail.jsx @@ -17,7 +17,7 @@ import { SettingDetail } from '../../shared'; import { sortNestedDetails, pluck } from '../../shared/settingUtils'; function LoggingDetail({ i18n }) { - const [{ me }] = useConfig(); + const { me } = useConfig(); const { GET: options } = useSettings(); const { isLoading, error, request, result: logging } = useRequest( diff --git a/awx/ui_next/src/screens/Setting/MiscSystem/MiscSystem.jsx b/awx/ui_next/src/screens/Setting/MiscSystem/MiscSystem.jsx index 5b1d54967c7a..5fd118e3bd0b 100644 --- a/awx/ui_next/src/screens/Setting/MiscSystem/MiscSystem.jsx +++ b/awx/ui_next/src/screens/Setting/MiscSystem/MiscSystem.jsx @@ -10,7 +10,7 @@ import MiscSystemEdit from './MiscSystemEdit'; function MiscSystem({ i18n }) { const baseURL = '/settings/miscellaneous_system'; - const [{ me }] = useConfig(); + const { me } = useConfig(); return ( diff --git a/awx/ui_next/src/screens/Setting/MiscSystem/MiscSystemDetail/MiscSystemDetail.jsx b/awx/ui_next/src/screens/Setting/MiscSystem/MiscSystemDetail/MiscSystemDetail.jsx index b8fa820663aa..6b91aaa92197 100644 --- a/awx/ui_next/src/screens/Setting/MiscSystem/MiscSystemDetail/MiscSystemDetail.jsx +++ b/awx/ui_next/src/screens/Setting/MiscSystem/MiscSystemDetail/MiscSystemDetail.jsx @@ -17,7 +17,7 @@ import { SettingDetail } from '../../shared'; import { sortNestedDetails, pluck } from '../../shared/settingUtils'; function MiscSystemDetail({ i18n }) { - const [{ me }] = useConfig(); + const { me } = useConfig(); const { GET: allOptions } = useSettings(); const { isLoading, error, request, result: system } = useRequest( diff --git a/awx/ui_next/src/screens/Setting/RADIUS/RADIUSDetail/RADIUSDetail.jsx b/awx/ui_next/src/screens/Setting/RADIUS/RADIUSDetail/RADIUSDetail.jsx index e46f26f98ea1..589bae436874 100644 --- a/awx/ui_next/src/screens/Setting/RADIUS/RADIUSDetail/RADIUSDetail.jsx +++ b/awx/ui_next/src/screens/Setting/RADIUS/RADIUSDetail/RADIUSDetail.jsx @@ -16,7 +16,7 @@ import { useSettings } from '../../../../contexts/Settings'; import { SettingDetail } from '../../shared'; function RADIUSDetail({ i18n }) { - const [{ me }] = useConfig(); + const { me } = useConfig(); const { GET: options } = useSettings(); const { isLoading, error, request, result: radius } = useRequest( diff --git a/awx/ui_next/src/screens/Setting/SAML/SAMLDetail/SAMLDetail.jsx b/awx/ui_next/src/screens/Setting/SAML/SAMLDetail/SAMLDetail.jsx index 1d426c1ff1b5..baf7c3f57009 100644 --- a/awx/ui_next/src/screens/Setting/SAML/SAMLDetail/SAMLDetail.jsx +++ b/awx/ui_next/src/screens/Setting/SAML/SAMLDetail/SAMLDetail.jsx @@ -16,7 +16,7 @@ import { useSettings } from '../../../../contexts/Settings'; import { SettingDetail } from '../../shared'; function SAMLDetail({ i18n }) { - const [{ me }] = useConfig(); + const { me } = useConfig(); const { GET: options } = useSettings(); options.SOCIAL_AUTH_SAML_SP_PUBLIC_CERT.type = 'certificate'; diff --git a/awx/ui_next/src/screens/Setting/SettingList.jsx b/awx/ui_next/src/screens/Setting/SettingList.jsx index bb8ae60cbab8..c72e1a37142a 100644 --- a/awx/ui_next/src/screens/Setting/SettingList.jsx +++ b/awx/ui_next/src/screens/Setting/SettingList.jsx @@ -49,7 +49,7 @@ const CardDescription = styled.div` `; function SettingList({ i18n }) { - const [config] = useConfig(); + const config = useConfig(); const settingRoutes = [ { header: i18n._(t`Authentication`), diff --git a/awx/ui_next/src/screens/Setting/Settings.jsx b/awx/ui_next/src/screens/Setting/Settings.jsx index ce2512dea062..f359bbce1227 100644 --- a/awx/ui_next/src/screens/Setting/Settings.jsx +++ b/awx/ui_next/src/screens/Setting/Settings.jsx @@ -26,7 +26,7 @@ import { SettingsAPI } from '../../api'; import useRequest from '../../util/useRequest'; function Settings({ i18n }) { - const [{ license_info = {}, me }] = useConfig(); + const { license_info = {}, me } = useConfig(); const { request, result, isLoading, error } = useRequest( useCallback(async () => { diff --git a/awx/ui_next/src/screens/Setting/Subscription/SubscriptionDetail/SubscriptionDetail.jsx b/awx/ui_next/src/screens/Setting/Subscription/SubscriptionDetail/SubscriptionDetail.jsx index c99bd5c19e5b..f1f10677e347 100644 --- a/awx/ui_next/src/screens/Setting/Subscription/SubscriptionDetail/SubscriptionDetail.jsx +++ b/awx/ui_next/src/screens/Setting/Subscription/SubscriptionDetail/SubscriptionDetail.jsx @@ -19,7 +19,7 @@ import { } from '../../../../util/dates'; function SubscriptionDetail({ i18n }) { - const [{ license_info, version }] = useConfig(); + const { license_info, version } = useConfig(); const baseURL = '/settings/subscription'; const tabsArray = [ { diff --git a/awx/ui_next/src/screens/Setting/Subscription/SubscriptionEdit/AnalyticsStep.jsx b/awx/ui_next/src/screens/Setting/Subscription/SubscriptionEdit/AnalyticsStep.jsx index 3f17254cdae0..b33c38fd3886 100644 --- a/awx/ui_next/src/screens/Setting/Subscription/SubscriptionEdit/AnalyticsStep.jsx +++ b/awx/ui_next/src/screens/Setting/Subscription/SubscriptionEdit/AnalyticsStep.jsx @@ -13,7 +13,7 @@ import { useConfig } from '../../../../contexts/Config'; const ANALYTICSLINK = 'https://www.ansible.com/products/automation-analytics'; function AnalyticsStep({ i18n }) { - const [config] = useConfig(); + const config = useConfig(); const [manifest] = useField({ name: 'manifest_file', }); diff --git a/awx/ui_next/src/screens/Setting/Subscription/SubscriptionEdit/EulaStep.jsx b/awx/ui_next/src/screens/Setting/Subscription/SubscriptionEdit/EulaStep.jsx index 22defae23ada..06c8ee1ef581 100644 --- a/awx/ui_next/src/screens/Setting/Subscription/SubscriptionEdit/EulaStep.jsx +++ b/awx/ui_next/src/screens/Setting/Subscription/SubscriptionEdit/EulaStep.jsx @@ -8,7 +8,7 @@ import { useConfig } from '../../../../contexts/Config'; import { CheckboxField } from '../../../../components/FormField'; function EulaStep({ i18n }) { - const [{ eula, me }] = useConfig(); + const { eula, me } = useConfig(); const [, meta] = useField('eula'); const isValid = !(meta.touched && meta.error); return ( diff --git a/awx/ui_next/src/screens/Setting/Subscription/SubscriptionEdit/SubscriptionEdit.jsx b/awx/ui_next/src/screens/Setting/Subscription/SubscriptionEdit/SubscriptionEdit.jsx index ce88a388c122..68e4c48b6f38 100644 --- a/awx/ui_next/src/screens/Setting/Subscription/SubscriptionEdit/SubscriptionEdit.jsx +++ b/awx/ui_next/src/screens/Setting/Subscription/SubscriptionEdit/SubscriptionEdit.jsx @@ -13,7 +13,7 @@ import { WizardFooter, } from '@patternfly/react-core'; import { ConfigAPI, SettingsAPI, MeAPI, RootAPI } from '../../../../api'; -import useRequest from '../../../../util/useRequest'; +import useRequest, { useDismissableError } from '../../../../util/useRequest'; import ContentLoading from '../../../../components/ContentLoading'; import ContentError from '../../../../components/ContentError'; import { FormSubmitError } from '../../../../components/FormField'; @@ -25,7 +25,7 @@ import EulaStep from './EulaStep'; const CustomFooter = withI18n()(({ i18n, isSubmitLoading }) => { const { values, errors } = useFormikContext(); - const [{ me, license_info }] = useConfig(); + const { me, license_info } = useConfig(); const history = useHistory(); return ( @@ -92,8 +92,8 @@ const CustomFooter = withI18n()(({ i18n, isSubmitLoading }) => { function SubscriptionEdit({ i18n }) { const history = useHistory(); - const [config, setConfig] = useConfig(); - const hasValidKey = Boolean(config?.license_info?.valid_key); + const { license_info, setConfig } = useConfig(); + const hasValidKey = Boolean(license_info?.valid_key); const subscriptionMgmtRoute = useRouteMatch({ path: '/subscription_management', }); @@ -130,7 +130,7 @@ function SubscriptionEdit({ i18n }) { error: submitError, isLoading: submitLoading, result: submitSuccessful, - request: handleSubmit, + request: submitRequest, } = useRequest( useCallback(async form => { if (form.manifest_file) { @@ -192,6 +192,12 @@ function SubscriptionEdit({ i18n }) { } }, [submitSuccessful, history, subscriptionMgmtRoute]); + const { error, dismissError } = useDismissableError(submitError); + const handleSubmit = async values => { + dismissError(); + await submitRequest(values); + }; + if (isContentLoading) { return ; } @@ -252,9 +258,9 @@ function SubscriptionEdit({ i18n }) { footer={} height="fit-content" /> - {submitError && ( + {error && (
- +
)} diff --git a/awx/ui_next/src/screens/Setting/Subscription/SubscriptionEdit/SubscriptionModal.jsx b/awx/ui_next/src/screens/Setting/Subscription/SubscriptionEdit/SubscriptionModal.jsx index fd8c263861c7..c68c158a6a4a 100644 --- a/awx/ui_next/src/screens/Setting/Subscription/SubscriptionEdit/SubscriptionModal.jsx +++ b/awx/ui_next/src/screens/Setting/Subscription/SubscriptionEdit/SubscriptionModal.jsx @@ -111,7 +111,7 @@ function SubscriptionModal({ We were unable to locate licenses associated with this account. - + {' '}