Skip to content

Commit

Permalink
feat(Designer): Tenant selection support for OAuth connection creation (
Browse files Browse the repository at this point in the history
#4999)

* Added tenant service and support for the tenant parameter on oauth connections

* Fixed small tenant value issue

* Fixed tests, added test over legay multi-auth / oauth / tenant-id

* Added tests for code coverage

* Added test for designer options slice
  • Loading branch information
rllyy97 committed Jun 19, 2024
1 parent ce2ecb5 commit 14b7b9c
Show file tree
Hide file tree
Showing 27 changed files with 728 additions and 280 deletions.
2 changes: 2 additions & 0 deletions Localize/lang/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -793,6 +793,7 @@
"UnrrzF": "Source schema",
"UnytRl": "The type for ''{authenticationKey}'' is ''{propertyType}''.",
"Ur+wph": "Click to delete item",
"UsEvG2": "Tenant ID",
"UtyRCH": "Enter a name for the connection",
"Uxckds": "Suggested flow",
"V+/c21": "General",
Expand Down Expand Up @@ -1729,6 +1730,7 @@
"_UnrrzF.comment": "Label to inform the below schema name is for source schema",
"_UnytRl.comment": "Error message when having invalid authentication property types",
"_Ur+wph.comment": "Label for delete button",
"_UsEvG2.comment": "tenant dropdown label",
"_UtyRCH.comment": "Placeholder text for connection name input",
"_Uxckds.comment": "Title for the suggested flow section",
"_V+/c21.comment": "title for general setting section",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,12 @@ export class HttpClient implements IHttpClient {
async get<ReturnType>(options: HttpRequestOptions<any>): Promise<ReturnType> {
const isArmId = isArmResourceId(options.uri);
const requestUrl = getRequestUrl(options);
const auth = isArmId
? {
Authorization: `Bearer ${environment.armToken}`,
}
: {};
const auth =
isArmId || options.includeAuth
? {
Authorization: `Bearer ${environment.armToken}`,
}
: {};

const response = await axios.get(requestUrl, {
headers: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ export class StandaloneOAuthPopup implements IOAuthPopup {
width: windowWidth,
height: windowHeight,
popup: true,
top: screen.height / 2 - 600 / 2,
left: screen.width / 2 - 600 / 2,
})
.map(([key, value]) => `${key}=${value}`)
.join(',');
Expand All @@ -96,9 +98,6 @@ export class StandaloneOAuthPopup implements IOAuthPopup {
throw new Error('The browser has blocked the popup window.');
}

// eslint-disable-next-line no-restricted-globals
this._popupWindow?.moveBy((screen.width - windowWidth) / 2, (screen.height - windowHeight) / 2);

let timeoutCounter = 0;
const listener = (event: MessageEvent) => {
const origin = event.origin;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import {
BaseChatbotService,
BaseFunctionService,
BaseGatewayService,
BaseTenantService,
StandardConnectionService,
StandardConnectorService,
StandardCustomCodeService,
Expand Down Expand Up @@ -599,6 +600,12 @@ const getDesignerServices = (
},
});

const tenantService = new BaseTenantService({
baseUrl: armUrl,
apiVersion: '2017-08-01',
httpClient,
});

const operationManifestService = new StandardOperationManifestService(defaultServiceParams);
const searchService = new StandardSearchService({
...defaultServiceParams,
Expand Down Expand Up @@ -694,6 +701,7 @@ const getDesignerServices = (
connectionService,
connectorService,
gatewayService,
tenantService,
operationManifestService,
searchService,
loggerService: null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
BaseAppServiceService,
BaseFunctionService,
BaseGatewayService,
BaseTenantService,
ConsumptionConnectionService,
ConsumptionConnectorService,
ConsumptionOperationManifestService,
Expand Down Expand Up @@ -297,6 +298,7 @@ const getDesignerServices = (
tenantId,
httpClient,
});

const apimService = new BaseApiManagementService({
...defaultServiceParams,
apiVersion: '2019-12-01',
Expand All @@ -311,6 +313,7 @@ const getDesignerServices = (
apiVersion: '2022-03-01',
subscriptionId,
});

const connectorService = new ConsumptionConnectorService({
...defaultServiceParams,
clientSupportedOperations: [
Expand Down Expand Up @@ -383,6 +386,7 @@ const getDesignerServices = (
apiVersion: '2018-07-01-preview',
workflowReferenceId: workflowId,
});

const gatewayService = new BaseGatewayService({
baseUrl,
httpClient,
Expand All @@ -392,12 +396,18 @@ const getDesignerServices = (
},
});

const tenantService = new BaseTenantService({
...defaultServiceParams,
apiVersion: '2017-08-01',
});

const operationManifestService = new ConsumptionOperationManifestService({
...defaultServiceParams,
apiVersion: '2022-09-01-preview',
subscriptionId,
location: location || 'location',
});

const searchService = new ConsumptionSearchService({
...defaultServiceParams,
openApiConnectionMode: false, // This should be turned on for Open Api testing.
Expand Down Expand Up @@ -474,6 +484,7 @@ const getDesignerServices = (
connectionService,
connectorService,
gatewayService,
tenantService,
operationManifestService,
searchService,
loggerService,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
ConsumptionConnectionService,
StandardCustomCodeService,
ResourceIdentityType,
BaseTenantService,
} from '@microsoft/logic-apps-shared';
import type { ContentType } from '@microsoft/logic-apps-shared';
import { DesignerProvider, BJSWorkflowProvider, Designer } from '@microsoft/logic-apps-designer';
Expand Down Expand Up @@ -106,6 +107,12 @@ const gatewayService = new BaseGatewayService({
},
});

const tenantService = new BaseTenantService({
baseUrl: '/url',
apiVersion: '2017-08-01',
httpClient,
});

const functionService = new BaseFunctionService({
baseUrl: '/url',
apiVersion: '2018-11-01',
Expand Down Expand Up @@ -177,6 +184,7 @@ export const LocalDesigner = () => {
searchService: isConsumption ? searchServiceConsumption : searchServiceStandard,
oAuthService,
gatewayService,
tenantService,
functionService,
appServiceService,
workflowService,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import type { RootState } from '../state/Store';
import { TemplatesDesigner, TemplatesDesignerProvider } from '@microsoft/logic-apps-designer';
import { useQuery } from '@tanstack/react-query';
import { useSelector } from 'react-redux';
import { BaseGatewayService, StandardConnectionService } from '@microsoft/logic-apps-shared';
import { BaseGatewayService, BaseTenantService, StandardConnectionService } from '@microsoft/logic-apps-shared';
import {
useAppSettings,
useConnectionsData,
Expand Down Expand Up @@ -223,6 +223,11 @@ const getServices = (
gateway: '2016-06-01',
},
});
const tenantService = new BaseTenantService({
baseUrl: armUrl,
httpClient,
apiVersion: '2017-08-01',
});
const oAuthService = new StandaloneOAuthService({
...defaultServiceParams,
apiVersion: '2018-07-01-preview',
Expand All @@ -236,6 +241,7 @@ const getServices = (
return {
connectionService,
gatewayService,
tenantService,
oAuthService,
};
};
9 changes: 9 additions & 0 deletions apps/vs-code-react/src/app/designer/servicesHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
BaseAppServiceService,
HTTP_METHODS,
clone,
BaseTenantService,
} from '@microsoft/logic-apps-shared';
import type {
ApiHubServiceDetails,
Expand Down Expand Up @@ -48,6 +49,7 @@ export const getDesignerServices = (
searchService: StandardSearchService;
oAuthService: BaseOAuthService;
gatewayService: BaseGatewayService;
tenantService: BaseTenantService;
workflowService: IWorkflowService;
hostService: IHostService;
runService: StandardRunService;
Expand Down Expand Up @@ -241,6 +243,12 @@ export const getDesignerServices = (
},
});

const tenantService = new BaseTenantService({
baseUrl: armUrl,
httpClient,
apiVersion: '2017-08-01',
});

// Workflow service needs to be implemented to get the callback url for azure resources
const workflowService: IWorkflowService = {
getCallbackUrl: async () => {
Expand Down Expand Up @@ -302,6 +310,7 @@ export const getDesignerServices = (
searchService,
oAuthService,
gatewayService,
tenantService,
workflowService,
hostService,
runService,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import reducer, { initDesignerOptions, initialDesignerOptionsState } from '../designerOptions/designerOptionsSlice';
import { describe, it, expect } from 'vitest';

describe('designer options slice reducers', () => {
it('should initialize designer options state', async () => {
const initialOptions = {
readOnly: true,
hostOptions: {
displayRuntimeInfo: false,
suppressCastingForSerialize: undefined,
recurrenceInterval: undefined,
maxWaitingRuns: undefined,
forceEnableSplitOn: undefined,
hideUTFExpressions: undefined,
stringOverrides: undefined,
},
};

const state = reducer(initialDesignerOptionsState, initDesignerOptions(initialOptions));

expect(state.readOnly).toEqual(true);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
isServiceProviderOperation,
getRecordEntry,
type Connector,
TenantService,
} from '@microsoft/logic-apps-shared';
import { useMemo } from 'react';
import type { UseQueryResult } from '@tanstack/react-query';
Expand Down Expand Up @@ -62,20 +63,17 @@ export const useConnectorAndSwagger = (connectorId: string | undefined, enabled
);
};

export const useGateways = (subscriptionId: string, connectorName: string): UseQueryResult<Gateway[], unknown> => {
return useQuery(
['gateways', { subscriptionId }, { connectorName }],
async () => GatewayService().getGateways(subscriptionId, connectorName),
{
enabled: !!connectorName,
}
);
};
export const useGateways = (subscriptionId: string, connectorName: string): UseQueryResult<Gateway[], unknown> =>
useQuery(['gateways', { subscriptionId }, { connectorName }], async () => GatewayService().getGateways(subscriptionId, connectorName), {
enabled: !!connectorName,
});

export const useSubscriptions = () => useQuery(['subscriptions'], async () => GatewayService().getSubscriptions());

export const useGatewayServiceConfig = () => useMemo(() => GatewayService().getConfig?.() ?? {}, []);

export const useTenants = () => useQuery(['tenants'], async () => TenantService().getTenants?.());

export const useConnectorByNodeId = (nodeId: string): Connector | undefined => {
const connectorFromManifest = useOperationManifest(useOperationInfo(nodeId)).data?.properties.connector;
const storeConnectorId = useNodeConnectorId(nodeId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type {
IConnectionService,
IConnectorService,
IGatewayService,
ITenantService,
ILoggerService,
IOperationManifestService,
ISearchService,
Expand Down Expand Up @@ -53,6 +54,7 @@ export interface ServiceOptions {
searchService: ISearchService;
connectorService?: IConnectorService;
gatewayService?: IGatewayService;
tenantService?: ITenantService;
loggerService?: ILoggerService;
oAuthService: IOAuthService;
workflowService: IWorkflowService;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
InitConnectionService,
InitConnectorService,
InitGatewayService,
InitTenantService,
InitOperationManifestService,
InitSearchService,
InitOAuthService,
Expand All @@ -23,7 +24,7 @@ import {
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';
import type { PayloadAction } from '@reduxjs/toolkit';

const initialState: DesignerOptionsState = {
export const initialDesignerOptionsState: DesignerOptionsState = {
readOnly: false,
isMonitoringView: false,
isDarkMode: false,
Expand All @@ -49,6 +50,7 @@ export const initializeServices = createAsyncThunk(
connectorService,
oAuthService,
gatewayService,
tenantService,
loggerService,
functionService,
appServiceService,
Expand Down Expand Up @@ -81,6 +83,9 @@ export const initializeServices = createAsyncThunk(
if (gatewayService) {
InitGatewayService(gatewayService);
}
if (tenantService) {
InitTenantService(tenantService);
}
if (apimService) {
InitApiManagementService(apimService);
}
Expand Down Expand Up @@ -114,7 +119,7 @@ export const initializeServices = createAsyncThunk(

export const designerOptionsSlice = createSlice({
name: 'designerOptions',
initialState,
initialState: initialDesignerOptionsState,
reducers: {
initDesignerOptions: (state: DesignerOptionsState, action: PayloadAction<Omit<DesignerOptionsState, 'servicesInitialized'>>) => {
state.readOnly = action.payload.readOnly;
Expand Down
5 changes: 5 additions & 0 deletions libs/designer/src/lib/core/state/templates/templateSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
InitConnectionService,
InitFunctionService,
InitGatewayService,
InitTenantService,
InitOAuthService,
getIntl,
getRecordEntry,
Expand Down Expand Up @@ -54,6 +55,7 @@ export const initializeTemplateServices = createAsyncThunk(
connectionService,
oAuthService,
gatewayService,
tenantService,
apimService,
functionService,
appServiceService,
Expand All @@ -65,6 +67,9 @@ export const initializeTemplateServices = createAsyncThunk(
if (gatewayService) {
InitGatewayService(gatewayService);
}
if (tenantService) {
InitTenantService(tenantService);
}
if (apimService) {
InitApiManagementService(apimService);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import type {
IConnectionService,
IFunctionService,
IGatewayService,
ITenantService,
ILoggerService,
IOAuthService,
} from '@microsoft/logic-apps-shared';
Expand All @@ -17,6 +18,7 @@ export interface TemplatesDesignerContext {
export interface TemplateServiceOptions {
connectionService: IConnectionService;
gatewayService?: IGatewayService;
tenantService?: ITenantService;
loggerService?: ILoggerService;
oAuthService: IOAuthService;
apimService?: IApiManagementService;
Expand Down
Loading

0 comments on commit 14b7b9c

Please sign in to comment.