/** * Copyright (c) 2020-present, Goldman Sachs * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import { CaretDownIcon, clsx, ContextMenu, CustomSelectorInput, ControlledDropdownMenu, LockIcon, MenuContent, MenuContentItem, Panel, PanelContent, PanelHeader, PlusIcon, ResizablePanel, ResizablePanelGroup, ResizablePanelSplitter, ResizablePanelSplitterLine, TimesIcon, } from '@finos/legend-art'; import { ExternalFormatData } from '@finos/legend-graph'; import { guaranteeNonEmptyString, guaranteeNonNullable, prettyCONSTName, } from '@finos/legend-shared'; import { ExternalFormatDataEditor, externalFormatData_setContentType, externalFormatData_setData, useEditorStore, ExternalFormatDataState, } from '@finos/legend-application-studio'; import { observer } from 'mobx-react-lite'; import { EqualToJsonPattern } from '../../graph/metamodel/pure/model/data/contentPattern/STO_ServiceStore_EqualToJsonPattern.js'; import { EqualToPattern } from '../../graph/metamodel/pure/model/data/contentPattern/STO_ServiceStore_EqualToPattern.js'; import type { StringValuePattern } from '../../graph/metamodel/pure/model/data/contentPattern/STO_ServiceStore_StringValuePattern.js'; import { ServiceRequestPattern } from '../../graph/metamodel/pure/model/data/STO_ServiceStore_ServiceRequestPattern.js'; import { ServiceResponseDefinition } from '../../graph/metamodel/pure/model/data/STO_ServiceStore_ServiceResponseDefinition.js'; import { ServiceStubMapping } from '../../graph/metamodel/pure/model/data/STO_ServiceStore_ServiceStubMapping.js'; import { HTTP_METHOD } from '../../graph/metamodel/pure/model/packageableElements/store/serviceStore/model/STO_ServiceStore_ServiceStoreService.js'; import { serviceStore_embeddedData_addServiceStubMapping, serviceStore_embeddedData_deleteServiceStubMapping, serviceStore_serviceRequestPattern_addBodyPatterns, serviceStore_serviceRequestPattern_addHeaderParams, serviceStore_serviceRequestPattern_addQueryParams, serviceStore_serviceRequestPattern_deleteBodyPatterns, serviceStore_serviceRequestPattern_deleteHeaderParams, serviceStore_serviceRequestPattern_deleteQueryParams, serviceStore_serviceRequestPattern_setMethod, serviceStore_serviceRequestPattern_setUrl, serviceStore_serviceRequestPattern_setUrlPath, serviceStore_serviceRequestPattern_updateBodyPattern, serviceStore_serviceRequestPattern_updateHeaderParameterName, serviceStore_serviceRequestPattern_updateHeaderParamValue, serviceStore_serviceRequestPattern_updateQueryParameterName, serviceStore_serviceRequestPattern_updateQueryParamValue, serviceStore_serviceResponseDefinition_setBody, serviceStore_serviceStubMapping_setServiceRequestPattern, serviceStore_serviceStubMapping_setServiceResponseDefinition, serviceStore_stringValuePattern_setExpectedValue, } from '../../stores/studio/STO_ServiceStore_GraphModifierHelper.js'; import { type ServiceStoreEmbeddedDataState, ServiceStubMappingState, SERVICE_REQUEST_PATTERN_TAB_TYPE, SERVICE_STUB_MAPPING_TAB_TYPE, } from '../../stores/studio/STO_ServiceStore_ServiceStoreEmbeddedDataEditorState.js'; import { CODE_EDITOR_LANGUAGE } from '@finos/legend-code-editor'; import { CodeEditor } from '@finos/legend-lego/code-editor'; import { useApplicationStore } from '@finos/legend-application'; export type StringValuePatternOption = { value: string; label: string; }; export enum StringValuePatternType { EQUAL_TO_PATTERN = 'equalTo', EQUAL_TO_JSON_PATTERN = 'equalToJson', } export const QueryParamsEditor = observer( (props: { serviceRequestPattern: ServiceRequestPattern; isReadOnly: boolean; }) => { const { serviceRequestPattern, isReadOnly } = props; const applicationStore = useApplicationStore(); const stringValuePatternOptions = Object.values(StringValuePatternType).map( (stringValuePatternType) => ({ value: stringValuePatternType, label: stringValuePatternType, }), ); const onStringValuePatternChange = ( val: StringValuePatternOption, key: string, ): void => { let stringValuePattern: StringValuePattern; if (val.value === StringValuePatternType.EQUAL_TO_JSON_PATTERN) { stringValuePattern = new EqualToJsonPattern(); serviceStore_stringValuePattern_setExpectedValue( stringValuePattern, '', ); serviceStore_serviceRequestPattern_updateQueryParamValue( serviceRequestPattern, key, stringValuePattern, ); } else { stringValuePattern = new EqualToPattern(); serviceStore_stringValuePattern_setExpectedValue( stringValuePattern, '', ); serviceStore_serviceRequestPattern_updateQueryParamValue( serviceRequestPattern, key, stringValuePattern, ); } }; const addQueryParam = (): void => { const equalToPattern = new EqualToPattern(); serviceStore_stringValuePattern_setExpectedValue(equalToPattern, ''); serviceStore_serviceRequestPattern_addQueryParams( serviceRequestPattern, '', equalToPattern, ); }; return (
Query Params
{Array.from(serviceRequestPattern.queryParams?.values() ?? []).map( (queryParam: StringValuePattern, index: number) => (
serviceStore_serviceRequestPattern_updateQueryParameterName( serviceRequestPattern, guaranteeNonNullable( Array.from( serviceRequestPattern.queryParams?.keys() ?? [], )[index], ), event.target.value, ) } /> onStringValuePatternChange( val, guaranteeNonNullable( Array.from( serviceRequestPattern.queryParams?.keys() ?? [], )[index], ), ) } value={ queryParam instanceof EqualToPattern ? stringValuePatternOptions.at(0) : stringValuePatternOptions.at(1) } placeholder="Choose a string value pattern type" darkMode={ !applicationStore.layoutService .TEMPORARY__isLightColorThemeEnabled } />
serviceStore_stringValuePattern_setExpectedValue( queryParam, val, ) } hideGutter={true} />
), )}
); }, ); export const HeaderParamsEditor = observer( (props: { serviceRequestPattern: ServiceRequestPattern; isReadOnly: boolean; }) => { const { serviceRequestPattern, isReadOnly } = props; const applicationStore = useApplicationStore(); const stringValuePatternOptions = Object.values(StringValuePatternType).map( (stringValuePatternType) => ({ value: stringValuePatternType, label: stringValuePatternType, }), ); const onStringValuePatternChange = ( val: StringValuePatternOption, key: string, ): void => { let stringValuePattern: StringValuePattern; if (val.value === StringValuePatternType.EQUAL_TO_JSON_PATTERN) { stringValuePattern = new EqualToJsonPattern(); serviceStore_stringValuePattern_setExpectedValue( stringValuePattern, '', ); serviceStore_serviceRequestPattern_updateHeaderParamValue( serviceRequestPattern, key, stringValuePattern, ); } else { stringValuePattern = new EqualToPattern(); serviceStore_stringValuePattern_setExpectedValue( stringValuePattern, '', ); serviceStore_serviceRequestPattern_updateHeaderParamValue( serviceRequestPattern, key, stringValuePattern, ); } }; const addHeaderParam = (): void => { const equalToPattern = new EqualToPattern(); serviceStore_stringValuePattern_setExpectedValue(equalToPattern, ''); serviceStore_serviceRequestPattern_addHeaderParams( serviceRequestPattern, '', equalToPattern, ); }; return (
Header Params
{Array.from(serviceRequestPattern.headerParams?.values() ?? []).map( (headerParam: StringValuePattern, index: number) => (
serviceStore_serviceRequestPattern_updateHeaderParameterName( serviceRequestPattern, guaranteeNonNullable( Array.from( serviceRequestPattern.headerParams?.keys() ?? [], )[index], ), event.target.value, ) } /> onStringValuePatternChange( val, guaranteeNonNullable( Array.from( serviceRequestPattern.headerParams?.keys() ?? [], )[index], ), ) } value={ headerParam instanceof EqualToPattern ? stringValuePatternOptions.at(0) : stringValuePatternOptions.at(1) } placeholder="Choose a string value pattern type" darkMode={ !applicationStore.layoutService .TEMPORARY__isLightColorThemeEnabled } />
serviceStore_stringValuePattern_setExpectedValue( headerParam, val, ) } hideGutter={true} />
), )}
); }, ); export const BodyPatternsEditor = observer( (props: { serviceRequestPattern: ServiceRequestPattern; isReadOnly: boolean; }) => { const { serviceRequestPattern, isReadOnly } = props; const applicationStore = useApplicationStore(); const stringValuePatternOptions = Object.values(StringValuePatternType).map( (stringValuePatternType) => ({ value: stringValuePatternType, label: stringValuePatternType, }), ); const onStringValuePatternChange = ( val: StringValuePatternOption, index: number, ): void => { let stringValuePattern: StringValuePattern; if (val.value === StringValuePatternType.EQUAL_TO_JSON_PATTERN) { stringValuePattern = new EqualToJsonPattern(); serviceStore_stringValuePattern_setExpectedValue( stringValuePattern, '', ); serviceStore_serviceRequestPattern_updateBodyPattern( serviceRequestPattern, index, stringValuePattern, ); } else { stringValuePattern = new EqualToPattern(); serviceStore_stringValuePattern_setExpectedValue( stringValuePattern, '', ); serviceStore_serviceRequestPattern_updateBodyPattern( serviceRequestPattern, index, stringValuePattern, ); } }; const addBodyPattern = (): void => { const equalToPattern = new EqualToPattern(); serviceStore_stringValuePattern_setExpectedValue(equalToPattern, ''); serviceStore_serviceRequestPattern_addBodyPatterns( serviceRequestPattern, equalToPattern, ); }; return (
Body Patterns
{serviceRequestPattern.bodyPatterns.map( (bodyPattern: StringValuePattern, index: number) => (
onStringValuePatternChange(val, index) } value={ bodyPattern instanceof EqualToPattern ? stringValuePatternOptions.at(0) : stringValuePatternOptions.at(1) } placeholder="Choose a string value pattern type" darkMode={ !applicationStore.layoutService .TEMPORARY__isLightColorThemeEnabled } />
serviceStore_stringValuePattern_setExpectedValue( bodyPattern, val, ) } hideGutter={true} />
), )}
); }, ); export const ServiceRequestPatternEditor = observer( (props: { serviceStubMappingState: ServiceStubMappingState; serviceRequestPattern: ServiceRequestPattern; isReadOnly: boolean; }) => { const { serviceStubMappingState, serviceRequestPattern, isReadOnly } = props; const httpMethodOptions = Object.values(HTTP_METHOD).map( (method) => method, ); const onHttpMethodChange = (val: HTTP_METHOD): void => serviceStore_serviceRequestPattern_setMethod(serviceRequestPattern, val); const selectedTab = serviceStubMappingState.selectedServiceRequestPatternTab; const changeTab = (tab: SERVICE_REQUEST_PATTERN_TAB_TYPE): (() => void) => (): void => serviceStubMappingState.setSelectedServiceRequestPatternTab(tab); const changeUrlPathValue: React.ChangeEventHandler = ( event, ) => { const stringValue = event.target.value; serviceStubMappingState.setUrlPath(stringValue); const updatedValue = stringValue ? stringValue : undefined; if (!updatedValue) { serviceStore_serviceRequestPattern_setUrlPath( serviceRequestPattern, updatedValue, ); serviceStore_serviceRequestPattern_setUrl( serviceRequestPattern, updatedValue, ); } else if (updatedValue.includes('?')) { serviceStore_serviceRequestPattern_setUrl( serviceRequestPattern, updatedValue, ); serviceStore_serviceRequestPattern_setUrlPath( serviceRequestPattern, undefined, ); } else { serviceStore_serviceRequestPattern_setUrlPath( serviceRequestPattern, updatedValue, ); serviceStore_serviceRequestPattern_setUrl( serviceRequestPattern, undefined, ); } }; return (
{isReadOnly && (
)}
ServiceRequestPattern
{httpMethodOptions.map((httpMethod) => ( onHttpMethodChange(httpMethod)} > {httpMethod} ))} } menuProps={{ anchorOrigin: { vertical: 'bottom', horizontal: 'right' }, transformOrigin: { vertical: 'top', horizontal: 'right' }, }} >
{serviceRequestPattern.method}
UrlPath
{(serviceRequestPattern.method === HTTP_METHOD.GET ? Object.values(SERVICE_REQUEST_PATTERN_TAB_TYPE).filter( (tab) => tab !== SERVICE_REQUEST_PATTERN_TAB_TYPE.BODY_PATTERNS, ) : Object.values(SERVICE_REQUEST_PATTERN_TAB_TYPE) ).map((tab) => (
{prettyCONSTName(tab)}
))}
{selectedTab === SERVICE_REQUEST_PATTERN_TAB_TYPE.BODY_PATTERNS && serviceRequestPattern.method === HTTP_METHOD.POST && ( )} {selectedTab === SERVICE_REQUEST_PATTERN_TAB_TYPE.HEADER_PARAMS && ( )} {selectedTab === SERVICE_REQUEST_PATTERN_TAB_TYPE.QUERY_PARAMS && ( )}
); }, ); export const ServiceStubMappingEditor = observer( (props: { serviceStubMappingState: ServiceStubMappingState; isReadOnly: boolean; }) => { const { serviceStubMappingState, isReadOnly } = props; const editorStore = useEditorStore(); const selectedTab = serviceStubMappingState.selectedTab; const changeTab = (tab: SERVICE_STUB_MAPPING_TAB_TYPE): (() => void) => (): void => serviceStubMappingState.setSelectedTab(tab); return (
{Object.values(SERVICE_STUB_MAPPING_TAB_TYPE).map((tab) => (
{prettyCONSTName(tab)}
))}
{selectedTab === SERVICE_STUB_MAPPING_TAB_TYPE.SERVICE_RESPONSE_DEFINITION && serviceStubMappingState.serviceStubMapping && ( )} {selectedTab === SERVICE_STUB_MAPPING_TAB_TYPE.SERVICE_REQUEST_PATTERN && serviceStubMappingState.serviceStubMapping && ( )}
); }, ); export const ServiceStoreEmbeddedDataEditor = observer( (props: { serviceStoreEmbeddedDataState: ServiceStoreEmbeddedDataState; isReadOnly: boolean; }) => { const { serviceStoreEmbeddedDataState, isReadOnly } = props; const editorStore = useEditorStore(); const currentServiceStubMapping = serviceStoreEmbeddedDataState.currentServiceStubMappingState ?.serviceStubMapping; const changeState = (val: ServiceStubMapping): (() => void) => (): void => { serviceStoreEmbeddedDataState.setCurrentServiceStubMappingState( new ServiceStubMappingState(editorStore, val), ); }; const addServiceStubMapping = (): void => { if (!isReadOnly) { const serviceStubMapping = new ServiceStubMapping(); const responseDefinition = new ServiceResponseDefinition(); const externalFormatData = new ExternalFormatData(); externalFormatData_setData(externalFormatData, ''); externalFormatData_setContentType( externalFormatData, guaranteeNonEmptyString( editorStore.graphState.graphGenerationState.externalFormatState .formatContentTypes[0], ), ); serviceStore_serviceResponseDefinition_setBody( responseDefinition, externalFormatData, ); serviceStore_serviceStubMapping_setServiceResponseDefinition( serviceStubMapping, responseDefinition, ); const requestPattern = new ServiceRequestPattern(); serviceStore_serviceRequestPattern_setMethod( requestPattern, HTTP_METHOD.GET, ); serviceStore_serviceStubMapping_setServiceRequestPattern( serviceStubMapping, requestPattern, ); serviceStore_embeddedData_addServiceStubMapping( serviceStoreEmbeddedDataState.embeddedData, serviceStubMapping, ); serviceStoreEmbeddedDataState.setCurrentServiceStubMappingState( new ServiceStubMappingState(editorStore, serviceStubMapping), ); } }; const deleteServiceStubMapping = (val: ServiceStubMapping): (() => void) => (): void => { serviceStore_embeddedData_deleteServiceStubMapping( serviceStoreEmbeddedDataState.embeddedData, val, ); if ( serviceStoreEmbeddedDataState.embeddedData.serviceStubMappings .length !== 0 ) { serviceStoreEmbeddedDataState.setCurrentServiceStubMappingState( new ServiceStubMappingState( editorStore, serviceStoreEmbeddedDataState.embeddedData.serviceStubMappings[ serviceStoreEmbeddedDataState.embeddedData.serviceStubMappings .length - 1 ], ), ); } if ( serviceStoreEmbeddedDataState.embeddedData.serviceStubMappings .length === 0 ) { serviceStoreEmbeddedDataState.setCurrentServiceStubMappingState( undefined, ); } }; const getIndex = (value: ServiceStubMapping): number => guaranteeNonNullable( serviceStoreEmbeddedDataState.embeddedData.serviceStubMappings.findIndex( (serviceStubMapping: ServiceStubMapping) => value === serviceStubMapping, ), `Can't find service stub mapping '${value}' in service store embedded data`, ); return (
ServiceStubMapping
{serviceStoreEmbeddedDataState.embeddedData.serviceStubMappings.map( (serviceStubMapping: ServiceStubMapping, index: number) => ( Delete } menuProps={{ elevation: 7 }} >
ServiceStubMapping{index + 1}
), )}
{serviceStoreEmbeddedDataState.currentServiceStubMappingState && currentServiceStubMapping !== undefined && ( )}
); }, );