/**
* 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 (
{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 (
{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 (
{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}
{(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 (
{serviceStoreEmbeddedDataState.embeddedData.serviceStubMappings.map(
(serviceStubMapping: ServiceStubMapping, index: number) => (
Delete
}
menuProps={{ elevation: 7 }}
>
ServiceStubMapping{index + 1}
),
)}
{serviceStoreEmbeddedDataState.currentServiceStubMappingState &&
currentServiceStubMapping !== undefined && (
)}
);
},
);