/// import { ApiPayload, ComponentPayload, ComponentState, ComponentSyncEventStatus, CreateCompassComponentInput, CreateComponentInput, CreateComponentOptions, SdkError, } from '@atlassian/forge-graphql-types'; import { CompassRequests } from '../../compass-requests'; import { COMPOUND_MUTATION_NAME, FORGE_GRAPHQL_SDK_ERROR_SOURCE, concatGqlSegments, mapGqlErrors, parseCompoundMutationErrors, prefixMutation, transformFieldsToGql, } from '../../helpers'; import { TIER_MISSING_VALUE } from '../../helpers/constants'; import { updateDataManagerSegment, updateLabelsSegment, updateLinksSegment, updateRelationshipsSegment, } from '../../helpers/gql-segments'; import { transformCustomFieldsToGql } from '../../helpers/transformFields'; declare module '../../compass-requests' { interface CompassRequests { /** * Creates a new component. * * **Required Oauth Scopes:** `write:component:compass` */ createComponent( input: CreateComponentInput, ): Promise>; } } async function createBaseComponent( api: CompassRequests, input: CreateComponentInput, ) { const { cloudId, name, description, slug, type, typeId, fields, customFields, ownerId, options, state = ComponentState.PENDING, } = input; let baseComponentInput: CreateCompassComponentInput & { options?: CreateComponentOptions; }; try { baseComponentInput = { name, description, slug, type, typeId, ownerId, options, state, }; const transformedFields = transformFieldsToGql(fields); if (transformedFields.length > 0) { baseComponentInput.fields = transformedFields; } if (customFields && customFields.length) { baseComponentInput.customFields = transformCustomFieldsToGql(customFields); } } catch (e) { if (e.message === TIER_MISSING_VALUE) { return { errors: e.message, componentId: null as string }; } throw e; } const { data, errors } = await api.createBaseComponent( cloudId, baseComponentInput, ); let id; try { ({ component: { id }, } = data); } catch { console.error( `Error: Could not get component id in createComponent response`, ); } return { errors, componentId: errors.length === 0 ? id : null, }; } async function createComponentWithExternalAlias( api: CompassRequests, input: CreateComponentInput, ) { const { externalAlias } = input; let errorsAcc = [] as Array; /* eslint-disable prefer-const */ let componentId; let errors = []; ({ errors, componentId } = await createBaseComponent(api, input)); /* eslint-enable prefer-const */ if (errors.length === 0) { try { const { errors: createExternalAliasErrors } = await api.createExternalAlias({ componentId, externalAlias, }); errorsAcc = errorsAcc.concat(createExternalAliasErrors); if (createExternalAliasErrors && createExternalAliasErrors.length > 0) { const { errors: deleteComponentErrors } = await api.deleteComponent({ id: componentId, }); errorsAcc = errorsAcc.concat(deleteComponentErrors); } } catch (e) { errorsAcc.push({ message: e.message, errorSource: FORGE_GRAPHQL_SDK_ERROR_SOURCE, errorType: e.constructor.name, }); const { errors: deleteComponentErrors } = await api.deleteComponent({ id: componentId, }); errorsAcc = errorsAcc.concat(deleteComponentErrors); } } else { errorsAcc = errorsAcc.concat(errors); } return { errors: errorsAcc, componentId, }; } CompassRequests.prototype.createComponent = async function ( this: CompassRequests, input: CreateComponentInput, ) { const { links, relationships, labels, dataManager, externalAlias } = input; let errorsAcc = [] as Array; let errors = []; let componentId; let createdComponent = {}; if (externalAlias) { ({ componentId, errors } = await createComponentWithExternalAlias( this, input, )); errorsAcc = errorsAcc.concat(errors); } else { ({ componentId, errors } = await createBaseComponent(this, input)); errorsAcc = errorsAcc.concat(errors); } if (componentId) { // Generate update component round trip request const gqlSegments = []; if (dataManager) { gqlSegments.push( updateDataManagerSegment(componentId, null, dataManager), ); } gqlSegments.push(updateLinksSegment(componentId, [], links || [])); gqlSegments.push( updateRelationshipsSegment(componentId, [], relationships), ); gqlSegments.push(updateLabelsSegment(componentId, [], labels || [])); const { mutation, variables, parameters } = concatGqlSegments(gqlSegments); if (mutation.trim() !== '') { const resp = await this.api.requestGraph( prefixMutation(mutation, COMPOUND_MUTATION_NAME, parameters), variables, 'createComponent', ); const { errors: createComponentErrors, data } = await resp.json(); errorsAcc = errorsAcc.concat( parseCompoundMutationErrors(data, variables), ); errorsAcc = errorsAcc.concat(mapGqlErrors(createComponentErrors)); } if (dataManager) { // TODO: Make ServerError distinct from UserError const { errors: updateDataManagerErrors } = await this.updateDataManager({ componentId, externalSourceURL: dataManager.externalSourceURL, lastSyncEvent: { status: errorsAcc.length > 0 ? ComponentSyncEventStatus.UserError : ComponentSyncEventStatus.Success, lastSyncErrors: errorsAcc.map((error) => error.message), }, }); errorsAcc = errorsAcc.concat(updateDataManagerErrors); } /* eslint-disable prefer-const */ let getComponentErrors; ({ errors: getComponentErrors, data: { component: createdComponent }, } = await this.getComponent({ componentId, })); errorsAcc = errorsAcc.concat(getComponentErrors); /* eslint-enable prefer-const */ } return { errors: errorsAcc, data: { component: createdComponent || {} }, success: errorsAcc.length === 0, } as ApiPayload; };