Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Display error w/o token on auth failure #6576

Merged
merged 10 commits into from
Mar 31, 2021
19 changes: 16 additions & 3 deletions extensions/azurePublish/src/components/api.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Licensed under the MIT License.
/* eslint-disable no-underscore-dangle */
import axios from 'axios';
import formatMessage from 'format-message';
import { SubscriptionClient } from '@azure/arm-subscriptions';
import { Subscription } from '@azure/arm-subscriptions/esm/models';
import { ResourceManagementClient } from '@azure/arm-resources';
Expand All @@ -27,6 +28,11 @@ import * as Images from './images';

const logger = debug('composer:extension:azureProvision');

/**
* Retrieves the list of subscriptions from Azure
* @param token The authentication token
* @returns The list of subscriptions or throws
*/
export const getSubscriptions = async (token: string): Promise<Array<Subscription>> => {
const tokenCredentials = new TokenCredentials(token);
try {
Expand All @@ -37,15 +43,22 @@ export const getSubscriptions = async (token: string): Promise<Array<Subscriptio
status: AzureAPIStatus.ERROR,
message: subscriptionsResult._response.bodyAsText,
});
return [];
throw new Error(subscriptionsResult._response.bodyAsText);
}
return subscriptionsResult._response.parsedBody;
} catch (err) {
let message = JSON.stringify(err, Object.getOwnPropertyNames(err));
if (err?.code === 12 && err?.message?.match(/Bearer/gi)) {
message = formatMessage(
'There was an authentication problem retrieving subscriptions. Verify your login session has not expired and you have permission to list subscriptions in this account.'
);
}

logger({
status: AzureAPIStatus.ERROR,
message: JSON.stringify(err, Object.getOwnPropertyNames(err)),
message,
});
return [];
throw new Error(message);
}
};

Expand Down
58 changes: 38 additions & 20 deletions extensions/azurePublish/src/components/azureProvisionDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@ const AddResourcesSectionName = styled(Text)`
font-size: ${FluentTheme.fonts.mediumPlus.fontSize};
`;

const labelTooltipStyles = {
root: {
userSelect: 'none',
},
};

const iconStyle = (required) => {
return {
root: {
Expand Down Expand Up @@ -124,7 +130,7 @@ const onRenderLabel = (props) => {
{' '}
{props.label}{' '}
</div>
<TooltipHost content={props.ariaLabel}>
<TooltipHost content={props.ariaLabel} styles={labelTooltipStyles}>
<Icon iconName="Info" styles={iconStyle(props.required)} />
</TooltipHost>
</div>
Expand Down Expand Up @@ -229,6 +235,7 @@ export const AzureProvisionDialog: React.FC = () => {
const extensionState = { ...defaultExtensionState, ...getItem(profileName) };

const [subscriptions, setSubscriptions] = useState<Subscription[] | undefined>();
const [subscriptionsErrorMessage, setSubscriptionsErrorMessage] = useState<string>();
const [deployLocations, setDeployLocations] = useState<DeployLocation[]>([]);
const [luisLocations, setLuisLocations] = useState<DeployLocation[]>([]);

Expand Down Expand Up @@ -376,11 +383,24 @@ export const AzureProvisionDialog: React.FC = () => {

useEffect(() => {
if (token) {
getSubscriptions(token).then((data) => {
if (isMounted.current) {
setSubscriptions(data);
}
});
setSubscriptionsErrorMessage(undefined);
getSubscriptions(token)
.then((data) => {
if (isMounted.current) {
setSubscriptions(data);
if (data.length === 0) {
setSubscriptionsErrorMessage(
formatMessage(
'Your subscription list is empty, please add your subscription, or login with another account.'
)
);
}
}
})
.catch((err) => {
setSubscriptionsErrorMessage(err.message);
GeoffCoxMSFT marked this conversation as resolved.
Show resolved Hide resolved
});

getResources();
}
}, [token]);
Expand All @@ -407,7 +427,7 @@ export const AzureProvisionDialog: React.FC = () => {
loadResourceGroups();
}, [token, currentSubscription]);

const subscriptionOption = useMemo(() => {
const subscriptionOptions = useMemo(() => {
return subscriptions?.map((t) => ({ key: t.subscriptionId, text: t.displayName }));
}, [subscriptions]);

Expand Down Expand Up @@ -563,6 +583,7 @@ export const AzureProvisionDialog: React.FC = () => {
!currentResourceGroupName ||
!currentHostName ||
!currentLocation ||
subscriptionsErrorMessage ||
errorResourceGroupName ||
errorHostName !== ''
);
Expand Down Expand Up @@ -599,10 +620,12 @@ export const AzureProvisionDialog: React.FC = () => {
</div>
<div style={{ flex: 1, height: '100%' }}>
<Suspense fallback={<Spinner label={formatMessage('Loading')} />}>
{subscriptionOption?.length > 0 && choice.key === 'create' && (
{choice.key === 'create' && (
<form style={{ width: '100%' }}>
<Dropdown
required
ariaLabel={formatMessage(
'The Azure AD directory includes the tenant’s users, groups, and apps and is used to perform identity and access management functions for tenant resources.'
)}
disabled={allTenants.length === 1 || currentConfig?.tenantId}
errorMessage={loginErrorMsg}
label={formatMessage('Azure Directory')}
Expand All @@ -612,22 +635,17 @@ export const AzureProvisionDialog: React.FC = () => {
onChange={(_e, o) => {
setSelectedTenant(o.key as string);
}}
onRenderLabel={onRenderLabel}
/>
<Dropdown
required
ariaLabel={formatMessage('All resources in an Azure subscription are billed together')}
defaultSelectedKey={currentSubscription}
disabled={currentConfig?.subscriptionId}
errorMessage={
currentUser && subscriptionOption?.length < 1
? formatMessage(
'Your subscription list is empty, please add your subscription, or login with another account.'
)
: undefined
}
errorMessage={subscriptionsErrorMessage}
label={formatMessage('Subscription')}
options={subscriptionOption}
options={subscriptionOptions}
placeholder={formatMessage('Select one')}
selectedKey={currentSubscription}
styles={{ root: { paddingBottom: '8px' } }}
onChange={(_e, o: IDropdownOption) => {
setCurrentSubscription(o.key as string);
Expand Down Expand Up @@ -766,7 +784,7 @@ export const AzureProvisionDialog: React.FC = () => {
items={optionalListItems}
selectedKeys={selectedResourceKeys}
onSelectionChanged={(keys) => {
const newSelection = listItems.filter((item) => item.required === true || keys.includes(item.key));
const newSelection = optionalListItems.filter((item) => keys.includes(item.key));
setEnabledResources(newSelection);
}}
/>
Expand Down Expand Up @@ -885,7 +903,7 @@ export const AzureProvisionDialog: React.FC = () => {
onClick={() => {
setPage(PageTypes.ReviewResource);
setTitle(DialogTitle.REVIEW);
let selectedResources = enabledResources.slice();
let selectedResources = requireResources.concat(enabledResources);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: [...arr1, ...arr2]

selectedResources = selectedResources.map((item) => {
let region = currentConfig?.region || currentLocation;
if (item.key.includes('luis')) {
Expand Down