import { CustomField, CustomFieldFromYAML, CustomFieldInput, CustomFieldType, CustomFields, } from '@atlassian/forge-graphql-types'; import { hasValue } from '../../../helpers/isCustomFieldValueEqual'; import { isCompassCustomBooleanField, isCompassCustomMultiSelectField, isCompassCustomNumberField, isCompassCustomSingleSelectField, isCompassCustomTextField, isCompassCustomUserField, } from './typeGuards'; export const isCustomFieldYamlSelectField = ( configCustomFieldType: CustomFieldType, ): boolean => [CustomFieldType.SINGLE_SELECT, CustomFieldType.MULTI_SELECT].includes( configCustomFieldType, ); /** * Retrieves the optionId from the displayValue of a select field. * This is used when the config file has a select field with a displayValue but no value. * * @param configCustomField - The custom field from the config file. * @param filteredComponentCustomField - The custom field from the component. * @returns The optionId of the displayValue if it exists, otherwise null. */ export const getValueFromDisplayValue = ( configCustomField: CustomFieldFromYAML, filteredComponentCustomField: CustomField, ): string | string[] | null => { if ( isCustomFieldYamlSelectField(configCustomField.type) && !hasValue(configCustomField.value) && hasValue(configCustomField.displayValue) ) { if (isCompassCustomSingleSelectField(filteredComponentCustomField)) { return ( filteredComponentCustomField.definition.options.find( (option) => option.value === configCustomField.displayValue, )?.id ?? null ); } if (isCompassCustomMultiSelectField(filteredComponentCustomField)) { // Ensure displayValue is an array const displayValues = Array.isArray(configCustomField.displayValue) ? configCustomField.displayValue : [configCustomField.displayValue]; const matchingIds = filteredComponentCustomField.definition.options .filter((option) => displayValues.includes(option.value)) .map((option) => option.id); // Return null if no matches found, otherwise return the array of ids return matchingIds.length > 0 ? matchingIds : null; } } return null; }; /** * Builds the custom field input format to update a component based on chosen * custom fields from the config file. * * This function only filters out select-type custom fields have mismatching * values i.e. differing displayValue in config versus the available options * in the actual component custom field. * * @param configCustomFields - The custom fields from the config file. * @param componentCustomFields - The custom fields from the component. * @returns The custom fields in the format required to update a component. */ export const buildCustomFieldToUpdateFormat = ( configCustomFields: CustomFieldFromYAML[], componentCustomFields: CustomFields, ): CustomFieldInput[] => configCustomFields.reduce( (customFieldsToUpdate, currentCustomField) => { const filteredComponentCustomField = componentCustomFields.find( (componentCustomField) => currentCustomField.name === componentCustomField.definition.name, ); const valueFromDisplayValue = getValueFromDisplayValue( currentCustomField, filteredComponentCustomField, ); const finalValue = valueFromDisplayValue ?? currentCustomField.value; const isSingleOrMultiSelect = currentCustomField.type === CustomFieldType.MULTI_SELECT || currentCustomField.type === CustomFieldType.SINGLE_SELECT; const isValuePresent = finalValue !== null && finalValue !== undefined; if (!isSingleOrMultiSelect || isValuePresent) { customFieldsToUpdate.push({ definitionId: filteredComponentCustomField.definition.id, value: finalValue, type: currentCustomField.type.toLocaleLowerCase(), } as CustomFieldInput); } return customFieldsToUpdate; }, [], ); export const mappedCustomFieldsToYamlFormat = ( customFieldInComponent: CustomField, ): CustomFieldFromYAML => { const mappedCustomFieldToYamlFormat = { name: customFieldInComponent.definition.name, type: null, value: null, } as CustomFieldFromYAML; if (isCompassCustomTextField(customFieldInComponent)) { mappedCustomFieldToYamlFormat.type = CustomFieldType.TEXT; mappedCustomFieldToYamlFormat.value = customFieldInComponent.textValue; } if (isCompassCustomBooleanField(customFieldInComponent)) { mappedCustomFieldToYamlFormat.type = CustomFieldType.BOOLEAN; mappedCustomFieldToYamlFormat.value = customFieldInComponent.booleanValue; } if (isCompassCustomNumberField(customFieldInComponent)) { mappedCustomFieldToYamlFormat.type = CustomFieldType.NUMBER; mappedCustomFieldToYamlFormat.value = customFieldInComponent.numberValue; } if (isCompassCustomUserField(customFieldInComponent)) { mappedCustomFieldToYamlFormat.type = CustomFieldType.USER; mappedCustomFieldToYamlFormat.value = customFieldInComponent.userIdValue ?? null; } if (isCompassCustomSingleSelectField(customFieldInComponent)) { mappedCustomFieldToYamlFormat.type = CustomFieldType.SINGLE_SELECT; mappedCustomFieldToYamlFormat.value = customFieldInComponent.option?.id; mappedCustomFieldToYamlFormat.displayValue = customFieldInComponent.option?.value; } if (isCompassCustomMultiSelectField(customFieldInComponent)) { mappedCustomFieldToYamlFormat.type = CustomFieldType.MULTI_SELECT; mappedCustomFieldToYamlFormat.value = customFieldInComponent.options?.map( (option) => option.id, ); mappedCustomFieldToYamlFormat.displayValue = customFieldInComponent.options?.map((option) => option.value); } return mappedCustomFieldToYamlFormat; };