diff --git a/articles/Extensibility/api/Extensibility-API.v1.json b/articles/Extensibility/api/Extensibility-API.v1.json index 10b3c5d..46b6a2d 100644 --- a/articles/Extensibility/api/Extensibility-API.v1.json +++ b/articles/Extensibility/api/Extensibility-API.v1.json @@ -1,8 +1,8 @@ { "openapi": "3.1.0", "info": { - "title": "Extensibility API", - "description": "The Extensibility API that must be implemented by 3rd party apps.\n\n**Important:** all relative paths in the Descriptor must begin with a slash (character \"/\"), otherwise the authentication on those calls will fail.", + "title": "App API", + "description": "App API that must be implemented by 3rd party apps.\n\n**Important:** all relative paths in the Descriptor must begin with a slash (character \"/\"), otherwise the authentication on those calls will fail.", "contact": { "name": " " }, @@ -47,7 +47,7 @@ "Standard" ], "summary": "Descriptor", - "description": "This endpoint provides the descriptor for the app.", + "description": "This endpoint provides the descriptor for the app. ", "operationId": "descriptor", "parameters": [ { @@ -388,6 +388,16 @@ } } } + }, + "413": { + "description": "This should be returned when the payload is too large and the app can't process it. For instance, for the `html` format, the contents list will be halved upon retrying the request.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } } }, "x-codegen-request-body-name": "body", @@ -861,7 +871,7 @@ } } }, - "description": "This endpoint initiates the preview generation. It initiates an asynchronous background job to generate the preview. The timeout for this request which initiates the background job should be 10 seconds. The Response will be sent on the callbackUrl and not from this request.\n [Callback Response](App-API.v1.json/components/schemas/PreviewProvider.MainResponse)", + "description": "This endpoint initiates the preview generation. It initiates an asynchronous background job to generate the preview. The timeout for this request which initiates the background job should be 10 seconds. The Response will be sent on the callbackUrl and not from this request.\n [Callback Response](#/schemas/PreviewProvider.MainResponse)", "tags": [ "Preview Provider" ], @@ -921,7 +931,7 @@ } } }, - "description": "This endpoint refreshes the preview. This initiates an asynchronous background job to generate the preview. The timeout for this request which initiates the background job should be 10 seconds - the background job might run longer than this. The Response will be sent on the callbackUrl and not from this request. [Callback Response](App-API.v1.json/components/schemas/PreviewProvider.MainResponse)", + "description": "This endpoint refreshes the preview. This initiates an asynchronous background job to generate the preview. The timeout for this request which initiates the background job should be 10 seconds - the background job might run longer than this. The Response will be sent on the callbackUrl and not from this request. [Callback Response](#/schemas/PreviewProvider.MainResponse)", "tags": [ "Preview Provider" ], @@ -1061,244 +1071,6 @@ ] } }, - "/lc.preview.startpreview.v2": { - "post": { - "summary": "Start Preview", - "operationId": "StartPreviewV2", - "responses": { - "202": { - "description": "Accepted" - }, - "400": { - "description": "Bad Request", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "401": { - "description": "Unauthorized", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - } - }, - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PreviewProvider.MainRequestV2" - } - } - } - }, - "description": "This endpoint initiates the preview generation. It initiates an asynchronous background job to generate the preview. The timeout for this request which initiates the background job should be 10 seconds. The Response will be sent on the callbackUrl and not from this request.\n [Callback Response](App-API.v1.json/components/schemas/PreviewProvider.MainResponse)", - "tags": [ - "Preview Provider V2" - ], - "security": [ - { - "LanguageCloudJWSToken": [] - } - ], - "parameters": [ - { - "$ref": "#/components/parameters/X-LC-ExtensionPointVersion" - }, - { - "$ref": "#/components/parameters/X-LC-ExtensionId" - }, - { - "$ref": "#/components/parameters/X-LC-AppVersion" - } - ] - } - }, - "/lc.preview.refreshpreview.v2": { - "put": { - "summary": "Refresh Preview", - "operationId": "RefreshPreviewV2", - "responses": { - "202": { - "description": "Accepted" - }, - "400": { - "description": "Bad Request", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "401": { - "description": "Unauthorized", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - } - }, - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PreviewProvider.MainRequestV2" - } - } - } - }, - "description": "This endpoint refreshes the preview. This initiates an asynchronous background job to generate the preview. The timeout for this request which initiates the background job should be 10 seconds - the background job might run longer than this. The Response will be sent on the callbackUrl and not from this request. [Callback Response](App-API.v1.json/components/schemas/PreviewProvider.MainResponse)", - "tags": [ - "Preview Provider V2" - ], - "security": [ - { - "LanguageCloudJWSToken": [] - } - ], - "parameters": [ - { - "$ref": "#/components/parameters/X-LC-ExtensionPointVersion" - }, - { - "$ref": "#/components/parameters/X-LC-ExtensionId" - }, - { - "$ref": "#/components/parameters/X-LC-AppVersion" - } - ] - } - }, - "/lc.preview.updatesegment.v2": { - "post": { - "summary": "Update Segment", - "operationId": "UpdateSegmentV2", - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PreviewProvider.UpdateSegmentResponse" - } - } - } - }, - "400": { - "description": "Bad Request", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "401": { - "description": "Unauthorized", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - } - }, - "description": "This endpoint generates a rendered HTML fragment from a BCM document fragment. The timeout for this request should be 10 seconds.", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PreviewProvider.UpdateSegmentRequest" - } - } - } - }, - "tags": [ - "Preview Provider V2" - ], - "security": [ - { - "LanguageCloudJWSToken": [] - } - ], - "parameters": [ - { - "$ref": "#/components/parameters/X-LC-ExtensionPointVersion" - }, - { - "$ref": "#/components/parameters/X-LC-ExtensionId" - }, - { - "$ref": "#/components/parameters/X-LC-AppVersion" - } - ] - } - }, - "/lc.preview.endpreview.v2": { - "post": { - "summary": "End Preview", - "operationId": "EndPreviewV2", - "responses": { - "200": { - "description": "OK" - }, - "400": { - "description": "Bad Request", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "401": { - "description": "Unauthorized", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - } - }, - "description": "This endpoint finishes the preview.", - "tags": [ - "Preview Provider V2" - ], - "security": [ - { - "LanguageCloudJWSToken": [] - } - ], - "parameters": [ - { - "$ref": "#/components/parameters/X-LC-ExtensionPointVersion" - }, - { - "$ref": "#/components/parameters/X-LC-ExtensionId" - }, - { - "$ref": "#/components/parameters/X-LC-AppVersion" - } - ] - } - }, "/lc.verification.startverification/{requestId}": { "post": { "summary": "Start Verification", @@ -1337,7 +1109,7 @@ } } }, - "description": "This endpoint initiates the background job for verification. The background job will push messages back to the Verification Service via a publish message URL and then send an asynchronous response once the job has completed.\nThe response for the callback is given here:\n[CallbackResponse](AddOn-API.v1.json/components/schemas/VerificationProvider.MainResponse)", + "description": "This endpoint initiates the background job for verification. The background job will push messages back to the Verification Service via a publish message URL and then send an asynchronous response once the job has completed.\nThe response for the callback is given here:\n[CallbackResponse](#/schemas/VerificationProvider.MainResponse)", "security": [ { "Trados Cloud Platform JWS Token": [] @@ -1560,268 +1332,6 @@ "content": {} } } - }, - "/lc.verification.startverification.v2/{requestId}": { - "post": { - "summary": "Start Verification", - "operationId": "VerificationProviderStartVerificationV2", - "responses": { - "201": { - "description": "Created" - }, - "400": { - "description": "Bad Request", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "401": { - "description": "Unauthorized", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - } - }, - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/VerificationProvider.MainRequest" - } - } - } - }, - "description": "This endpoint initiates the background job for verification. The background job will push messages back to the Verification Service via a publish message URL and then send an asynchronous response once the job has completed.\nThe response for the callback is given here:\n[CallbackResponse](AddOn-API.v1.json/components/schemas/VerificationProvider.MainResponse)", - "security": [ - { - "Trados Cloud Platform JWS Token": [] - } - ], - "tags": [ - "Verification Provider V2" - ], - "parameters": [] - }, - "parameters": [ - { - "schema": { - "type": "string" - }, - "name": "requestId", - "in": "path", - "required": true - } - ] - }, - "/lc.verification.verifysegment.v2": { - "post": { - "summary": "Verify Segment", - "operationId": "VerificationProviderVerifySegmentV2", - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/VerificationProvider.VerifySegmentResponse" - } - } - } - }, - "400": { - "description": "Bad Request", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "401": { - "description": "Unauthorized", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - } - }, - "description": "This endpoint verifies the content of a single segment", - "security": [ - { - "Trados Cloud Platform JWS Token": [] - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/VerificationProvider.VerifySegmentRequest" - } - } - }, - "description": "" - }, - "tags": [ - "Verification Provider V2" - ] - }, - "parameters": [] - }, - "/lc.verification.getmessagesbyculture.v2/{culture}": { - "get": { - "summary": "Get Messages By Culture", - "tags": [ - "Verification Provider V2" - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/VerificationProvider.MessageResourceResponse" - } - }, - "application/xml": { - "schema": { - "$ref": "#/components/schemas/VerificationProvider.MessageResourceResponse" - } - } - } - }, - "400": { - "description": "Bad Request", - "content": { - "application/json": { - "schema": { - "type": "object", - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "401": { - "description": "Unauthorized", - "content": { - "application/json": { - "schema": { - "type": "object", - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - } - }, - "operationId": "VerificationProviderGetMessagesByCultureV2", - "description": "Gets localized resources for message types defined by the app extension", - "parameters": [] - }, - "parameters": [ - { - "schema": { - "type": "string", - "enum": [ - "de-DE", - "es-ES", - "fr-CA", - "fr-FR", - "it-IT", - "ja-JP", - "nl-NL", - "zh-CN" - ] - }, - "name": "culture", - "in": "path", - "required": true, - "description": "Culture of retrieved resources" - } - ] - }, - "/lc.verification.getsettingsschema.v2": { - "get": { - "summary": "Get Settings Schema", - "tags": [ - "Verification Provider V2" - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "group": { - "type": "string", - "x-stoplight": { - "id": "kc1t8wfl70ace" - }, - "description": "group name for settings. Must be \"sdl.project.verification.qaChecker.addon\"", - "enum": [ - "sdl.project.verfication.qaChecker.addon" - ] - }, - "systemId": { - "type": "string", - "x-stoplight": { - "id": "rwwuwxs8iz7jw" - }, - "description": "extension ID" - }, - "schema": { - "type": "object", - "x-stoplight": { - "id": "58sw7o5udooku" - }, - "description": "full json schema for the settings associated with this extension" - } - } - } - } - } - }, - "400": { - "description": "Bad Request", - "content": { - "application/json": { - "schema": { - "type": "object", - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "401": { - "description": "Unauthorized", - "content": { - "application/json": { - "schema": { - "type": "object", - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - } - }, - "operationId": "VerificationProviderGetSettingsSchemaV2", - "description": "Returns a JSON schema for the settings associated with this app\nThe JSON schema can must only use specific pre-defined types relating to \"string\", \"number\", \"integer\", \"boolean\", \"datetime\" and \"file\" - for complex types, objects are used with internal properties.", - "requestBody": { - "content": {} - } - } } }, "components": { @@ -1888,9 +1398,6 @@ { "$ref": "#/components/schemas/PreviewProviderExtension" }, - { - "$ref": "#/components/schemas/PreviewProviderExtensionV2" - }, { "$ref": "#/components/schemas/VerificationProviderExtension" } @@ -2078,6 +1585,9 @@ "x-stoplight": { "id": "oiz0xiltgshgm" } + }, + { + "$ref": "#/components/schemas/InstalledEvent" } ] } @@ -2138,6 +1648,19 @@ } } }, + "InstalledEvent": { + "title": "InstalledEvent", + "x-stoplight": { + "id": "doncfjujsw5a9" + }, + "type": "object", + "properties": { + "region": { + "description": "Tenant region.", + "type": "string" + } + } + }, "sdl.lc.extensionpoint.machinetranslationprovider.translate.request": { "title": "TranslateRequest", "type": "object", @@ -2333,167 +1856,45 @@ "properties": { "endpoints": { "type": "object", - "description": "The required endpoints for the MT extension", - "required": [ - "lc.mtprovider.translate", - "lc.mtprovider.engines" - ], - "properties": { - "lc.mtprovider.translate": { - "type": "string", - "description": "The endpoint used to receive and translate content from the Trados Cloud Platform. It must begin with a slash \"/\"" - }, - "lc.mtprovider.engines": { - "type": "string", - "description": "The endpoint used to retrieve the available translation engines (the supported language pairs). It must begin with a slash \"/\" character." - } - } - }, - "format": { - "type": "string", - "description": "The content's format supported by the app on the translate endpoint.", - "enum": [ - "html", - "bcm" - ] - } - } - } - } - }, - "PreviewProviderExtension": { - "title": "PreviewProviderExtension", - "type": "object", - "description": "Extension that provides for preview generation", - "required": [ - "extensionPointId", - "id", - "name", - "description", - "extensionPointVersion", - "configuration" - ], - "properties": { - "extensionPointId": { - "type": "string", - "description": "The extension point id corresponding to this extensionType: lc.previewprovider", - "enum": [ - "lc.previewprovider" - ] - }, - "id": { - "type": "string", - "description": "Unique extension ID provided by the app developer" - }, - "name": { - "type": "string", - "description": "Provide a user friendly and unique name. It might be shown to the end user, and it may be useful to help the user distinguish between multiple extensions." - }, - "description": { - "type": "string", - "description": "The PreviewProvider extension description" - }, - "extensionPointVersion": { - "type": "string", - "description": "The version of the extension point that is implemented in the Extension.\r\n\r\nCurrently supported version is \"1\".", - "enum": [ - "1.0" - ] - }, - "configuration": { - "type": "object", - "required": [ - "endpoints", - "requiredInputFiles", - "outputType", - "supportedFileTypes" - ], - "properties": { - "endpoints": { - "type": "object", - "description": "The required endpoints for the PreviewProvider extension", + "description": "The required endpoints for the MT extension", "required": [ - "lc.preview.startpreview", - "lc.preview.endpreview", - "lc.preview.refreshpreview", - "lc.preview.updatesegment" + "lc.mtprovider.translate", + "lc.mtprovider.engines" ], "properties": { - "lc.preview.startpreview": { - "type": "string", - "description": "The endpoint used initiate the preview generation - must start with a slash \"/\"", - "readOnly": true - }, - "lc.preview.endpreview": { - "type": "string", - "description": "The endpoint used to end the preview request. Any cleanup can be done via this call. Must start with a slash \"/\"", - "readOnly": true - }, - "lc.preview.refreshpreview": { + "lc.mtprovider.translate": { "type": "string", - "description": "The endpoint used to refresh the preview. Must start with a slash \"/\"", - "readOnly": true + "description": "The endpoint used to receive and translate content from the Trados Cloud Platform. It must begin with a slash \"/\"" }, - "lc.preview.updatesegment": { + "lc.mtprovider.engines": { "type": "string", - "description": "The endpoint used to update a segment. Must start with a slash \"/\"", - "readOnly": true - } - }, - "readOnly": true - }, - "requiredInputFiles": { - "type": "object", - "required": [ - "previewPackageTemplate", - "bilingualDocument", - "nativeFile", - "nativeAnnotatedFile" - ], - "properties": { - "previewPackageTemplate": { - "type": "boolean", - "description": "If true, a OneTimeDownloadUrl will be provided to the extension allowing the retrieval of a preview package template containing the files required to generate the preview", - "readOnly": true - }, - "bilingualDocument": { - "type": "boolean", - "description": "If true, a OneTimeDownloadUrl will be provided to the extension for retrieving a translated BCM document", - "readOnly": true - }, - "nativeFile": { - "type": "boolean", - "description": "If true, a OneTimeDownloadUrl will be provided to the extension allowing for the retrieval of the nativeSourceFile or nativeTargetFile depending on the generation scope", - "readOnly": true - }, - "nativeAnnotatedFile": { - "type": "boolean", - "description": "If true, a OneTimeDownloadUrl will be provided to the extension allowing for the retrieval of the nativeAnnotatedSourceFile or nativeAnnotatedTargetFile depending on the generation scope", - "readOnly": true + "description": "The endpoint used to retrieve the available translation engines (the supported language pairs). It must begin with a slash \"/\" character." } - }, - "readOnly": true + } }, - "outputType": { + "format": { "type": "string", - "description": "Must define one of the following values: previewPackage, previewHtmlFile or previewUrl.", - "readOnly": true + "description": "The content's format supported by the app on the translate endpoint.", + "enum": [ + "html", + "bcm" + ] }, - "supportedFileTypes": { - "type": "array", - "description": "An array listing one or more FileTypeDefinitionIds definining FileTypes to which this preview extension may be assigned.", - "items": { - "type": "string", - "readOnly": true + "segmentBatchSize": { + "type": "integer", + "x-stoplight": { + "id": "ntd72gzs0cw8x" }, - "readOnly": true + "description": "The maximum number of segments supported by the app on the `lc.mtprovider.translate` endpoint. Applicable only for the `html` format.", + "default": 200, + "minimum": 1 } } } } }, - "PreviewProviderExtensionV2": { - "title": "PreviewProviderExtensionV2", + "PreviewProviderExtension": { + "title": "PreviewProviderExtension", "type": "object", "description": "Extension that provides for preview generation", "required": [ @@ -2526,9 +1927,9 @@ }, "extensionPointVersion": { "type": "string", - "description": "The version of the extension point that is implemented in the Extension.\r\n\r\nCurrently supported version is \"1\" or \"2\".", + "description": "The version of the extension point that is implemented in the Extension.\r\n\r\nCurrently supported version is \"1\".", "enum": [ - "2.0" + "1.0" ] }, "configuration": { @@ -2544,28 +1945,28 @@ "type": "object", "description": "The required endpoints for the PreviewProvider extension", "required": [ - "lc.preview.startpreview.v2", - "lc.preview.endpreview.v2", - "lc.preview.refreshpreview.v2", - "lc.preview.updatesegment.v2" + "lc.preview.startpreview", + "lc.preview.endpreview", + "lc.preview.refreshpreview", + "lc.preview.updatesegment" ], "properties": { - "lc.preview.startpreview.v2": { + "lc.preview.startpreview": { "type": "string", "description": "The endpoint used initiate the preview generation - must start with a slash \"/\"", "readOnly": true }, - "lc.preview.endpreview.v2": { + "lc.preview.endpreview": { "type": "string", "description": "The endpoint used to end the preview request. Any cleanup can be done via this call. Must start with a slash \"/\"", "readOnly": true }, - "lc.preview.refreshpreview.v2": { + "lc.preview.refreshpreview": { "type": "string", "description": "The endpoint used to refresh the preview. Must start with a slash \"/\"", "readOnly": true }, - "lc.preview.updatesegment.v2": { + "lc.preview.updatesegment": { "type": "string", "description": "The endpoint used to update a segment. Must start with a slash \"/\"", "readOnly": true @@ -2578,9 +1979,8 @@ "required": [ "previewPackageTemplate", "bilingualDocument", - "nativeSourceFile", - "nativeTargetFile", - "nativeAnnotatedTargetFile" + "nativeFile", + "nativeAnnotatedFile" ], "properties": { "previewPackageTemplate": { @@ -2608,7 +2008,7 @@ }, "outputType": { "type": "string", - "description": "Must be of type previewUrl.", + "description": "Must define one of the following values: previewPackage, previewHtmlFile or previewUrl.", "readOnly": true }, "supportedFileTypes": { @@ -2960,48 +2360,6 @@ "callbackUrl" ] }, - "PreviewProvider.MainRequestV2": { - "title": "PreviewProvider.MainRequestV2", - "type": "object", - "description": "Request for StartPreview or RefreshPreview", - "properties": { - "previewSessionId": { - "type": "string", - "description": "Unique identifier for the given Preview Session." - }, - "projectId": { - "type": "string", - "description": "Trados Enterprise Project ID" - }, - "scope": { - "type": "string", - "enum": [ - "source", - "target" - ], - "description": "It indicates whether the source or the target is being generated." - }, - "fileInformation": { - "$ref": "#/components/schemas/PreviewProvider.FileInformation" - }, - "inputFiles": { - "$ref": "#/components/schemas/PreviewProvider.InputFilesV2" - }, - "previewResultFileUrl": { - "type": "string", - "description": "Defines the one time upload URL to upload either a generated previewPackage or a previewHtmlFile." - }, - "callbackUrl": { - "type": "string", - "description": "This is the URL detailing endpoint to call when the asynchronous job has completed." - } - }, - "required": [ - "previewSessionId", - "inputFiles", - "callbackUrl" - ] - }, "PreviewProvider.FileInformation": { "title": "PreviewProvider.FileInformation", "x-stoplight": { @@ -3041,27 +2399,6 @@ } } }, - "PreviewProvider.InputFilesV2": { - "title": "PreviewProvider.InputFilesV2", - "type": "object", - "properties": { - "bilingualDocument": { - "$ref": "#/components/schemas/PreviewProvider.FileDetails" - }, - "previewPackageTemplate": { - "$ref": "#/components/schemas/PreviewProvider.FileDetails" - }, - "nativeSourceFile": { - "$ref": "#/components/schemas/PreviewProvider.FileDetails" - }, - "nativeTargetFile": { - "$ref": "#/components/schemas/PreviewProvider.FileDetails" - }, - "nativeAnnotatedTargetFile": { - "$ref": "#/components/schemas/PreviewProvider.FileDetails" - } - } - }, "PreviewProvider.MainResponse": { "title": "PreviewProvider.MainResponse", "x-stoplight": { @@ -3093,14 +2430,14 @@ "id": "8j8v4sxg1flul" }, "type": "object", - "description": "The fragment object is described here: https://developers.rws.com/languagecloud-api-docs/api/BCM/Sdl.Core.Bcm.BcmModel.Fragment.html", + "description": "The fragment object is described here: https://developers.rws.com/languagecloud-api-docs/api/bcm/Sdl.Core.Bcm.BcmModel.Fragment.html", "properties": { "segmentId": { "type": "string" }, "fragment": { "type": "object", - "description": "This object represents a BCM fragment. The documentation for the BCM fragment can be found here: https://developers.rws.com/languagecloud-api-docs/api/BCM/Sdl.Core.Bcm.BcmModel.Fragment.html" + "description": "This object represents a BCM fragment. The documentation for the BCM fragment can be found here: https://developers.rws.com/languagecloud-api-docs/api/bcm/Sdl.Core.Bcm.BcmModel.Fragment.html" } } }, @@ -3307,153 +2644,6 @@ "configuration" ] }, - "VerificationProviderExtensionV2": { - "title": "VerificationProviderExtensionV2", - "type": "object", - "description": "Extension that provides for verification message generation", - "examples": [ - { - "extensionPointId": "lc.verificationprovider", - "id": "string", - "name": "string", - "description": "string", - "extensionPointVersion": "2.0", - "configuration": { - "endpoints": { - "lc.verification.startverification.v2": "string", - "lc.verification.verifysegment.v2": "string", - "lc.verification.getmessagesbyculture.v2": "string", - "lc.verification.getsettingsschema.v2": "string" - }, - "validationInputFiles": "string" - } - } - ], - "properties": { - "id": { - "type": "string", - "description": "Unique extension ID provided by the app developer" - }, - "extensionPointId": { - "type": "string", - "description": "The extension point id corresponding to this extensionType: lc.verificationprovider", - "enum": [ - "lc.verificationprovider" - ] - }, - "name": { - "type": "string", - "description": "Provide a user friendly and unique name. It might be shown to the end user, and it may be useful to help the user distinguish between multiple extensions." - }, - "description": { - "type": "string", - "description": "The VerificationProvider extension description" - }, - "extensionPointVersion": { - "type": "string", - "description": "The version of the extension point that is implemented in the Extension", - "enum": [ - "2.0" - ] - }, - "configuration": { - "type": "object", - "required": [ - "endpoints", - "validationInputType", - "validationInputFiles", - "validatorType", - "supportedFileTypes" - ], - "properties": { - "endpoints": { - "type": "object", - "description": "The required endpoints for the VerificationProvider extension", - "required": [ - "lc.verification.startverification" - ], - "properties": { - "lc.verification.startverification.v2": { - "type": "string", - "description": "The endpoint used to start the verification process. Must start with a slash \"/\"", - "x-stoplight": { - "id": "r1njwi093d1qd" - }, - "readOnly": true - }, - "lc.verification.verifysegment.v2": { - "type": "string", - "description": "verifies an individual segment", - "x-stoplight": { - "id": "h4e4zzme66f3y" - } - }, - "lc.verification.getmessagesbyculture.v2": { - "type": "string", - "description": "gets the localized resources for message types", - "x-stoplight": { - "id": "a2ymt9fc9pqw7" - } - }, - "lc.verification.getsettingsschema.v2": { - "type": "string", - "x-stoplight": { - "id": "yky262mpfn26a" - }, - "description": "Gets the JSON schema which defines the settings this extension uses" - } - }, - "readOnly": true - }, - "validationInputFiles": { - "type": "array", - "items": { - "type": "string", - "enum": [ - "BilingualDocument", - "NativeSource", - "NativeTarget", - "NativeAnnotatedTarget" - ] - }, - "description": "An array specifying the type of input files used for the validation - NativeSource and NativeTarget are mutually exclusive", - "readOnly": true - }, - "validatorType": { - "type": "string", - "items": { - "type": "string", - "enum": [ - "BilingualDocumentValidator", - "NativeSourceValidator", - "NativeTargetValidator", - "NativeAnnotatedTargetValidator" - ] - }, - "description": "A field specifying the validator type. Can be BilingualDocumentValidator, NativeSourceValidator, NativeTargetValidator or NativeAnnotatedTargetValidator", - "readOnly": true - }, - "supportedFileTypes": { - "type": "array", - "description": "An array listing one or more FileTypeDefinitionIds definining FileTypes to which this verification extension may be assigned.", - "items": { - "type": "string", - "readOnly": true - }, - "readOnly": true - } - } - } - }, - "required": [ - "id", - "extensionPointId", - "name", - "description", - "extensionPointVersion", - "configuration" - ] - }, "VerificationProvider.MainRequest": { "title": "VerificationProvider.MainRequest", "type": "object", diff --git a/articles/Extensibility/docs/Whats-New.md b/articles/Extensibility/docs/Whats-New.md index d9f65f6..48a70bf 100644 --- a/articles/Extensibility/docs/Whats-New.md +++ b/articles/Extensibility/docs/Whats-New.md @@ -1,5 +1,18 @@ # What's New +## July 2025 + +- We've expanded support for custom tabs to additional [locations](../docs/development/UI-App-custom-elements-locations.md). You can now use them in the following views: + - tasks list + - orders list + - projects list + - reports list + +## April 2025 + +- To facilitate the management of large translation requests, batching support has been added for MT provider apps. This update includes the introduction of a new parameter, `extensions.configuration.segmentBatchSize`, which can be added to your [descriptor](../api/Extensibility-API.v1-fv.html#/operations/descriptor), along with a new error response featuring status code [413](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/413) on the translation [endpoint](../api/Extensibility-API.v1-fv.html#/operations/MachineTranslationProviderTranslateBCM). +- A new option has been introduced on the app registration [page](../docs/appManagement/Registering.md), allowing users to designate their app for development purposes by selecting a checkbox. + ## December 2024 - We have officially rebranded from RWS Language Cloud API to Trados Cloud Platform API. All references to our previous brand name will now reflect our new identity, Trados. @@ -12,7 +25,7 @@ - With this release we deliver a new extension point designed to allow developers to extend and customize the UI elements of our platform. This extension point is being released as BETA. For more details see this [page](../docs/development/UI-App-development-guide.md). - We unified the Preview documentation pages into a single comprehensive [page](../docs/development/Preview-App-development-guide.md). We have introduced a new version, known as V2, of our Preview APIs. - We extended the information available under Verification Provider [page](../docs/development/Verification-App-development-guide.md). We have introduced a new version, known as V2, of our Verification APIs. -- You can now add comments to [Submit Task Outcome](../App-API.v1.json/paths/~1external-job~1v1~1callback/post) for the automatic task extensions. +- You can now add comments to [Submit Task Outcome](../api/Extensibility-API.v1-fv.html#/operations/automatiktasktypecallback) for the automatic task extensions. ## June 2024 - With this release, we have migrated from the Add-Ons concept to Apps. This significant first step sets the stage for expanding this concept to multiple areas that facilitate integrations. @@ -25,12 +38,12 @@ ## August 2023 -- With this release we introduced a folder identifier where the translation engines will be added. This can be used to filter the [engines](../App-API.v1.json/paths/~1lc.mtprovider.engines/get) by folder. +- With this release we introduced a folder identifier where the translation engines will be added. This can be used to filter the [engines](../api/Extensibility-API.v1-fv.html#/operations/GetMachineTranslationProviderEngines) by folder. - We also added recommendations on [best practices](../docs/development/Tehnical-Requirements-And-Best-Practices.md) for a secure application development. - We made additional smaller improvements and corrections to our documentation. ## April 2023 -- We added details for the `engineId`, `projectId`, `sourceFileId` and `targetFileId` parameters of the [Translate](../App-API.v1.json/paths/~1lc.mtprovider.translate/post) endpoint. +- We added details for the `engineId`, `projectId`, `sourceFileId` and `targetFileId` parameters of the [Translate](../api/Extensibility-API.v1-fv.html#/operations/MachineTranslationProviderTranslateBCM) endpoint. - We updated the [Registering the app](../docs/appManagement/Registering.md) page. @@ -38,7 +51,7 @@ - We introduced requirements that become mandatory for all future apps, namely: acceptance of Terms & Conditions and the Privacy Policy, along with the provisioning of the app's release notes, documentation link and the developer's contact details, starting with descriptor version `1.3`. - We published newer blueprints for both Java and .NET. - We made available headers for developers to implement custom functionality based on the current version of the installed apps: `appVersion`, `extensionPointVersion` and `extensionId`. -- Added `projectId`, `sourceFileId` and `targetFileId` on the [translate](../App-API.v1.json/paths/~1lc.mtprovider.translate/post) request. +- Added `projectId`, `sourceFileId` and `targetFileId` on the [translate](../api/Extensibility-API.v1-fv.html#/operations/MachineTranslationProviderTranslateBCM) request. ## January 2023 - We published new pages with our recommendations for implementing Dynamic Preview. diff --git a/articles/Extensibility/docs/appManagement/Approvals.md b/articles/Extensibility/docs/appManagement/Approvals.md index b464bb0..a345ff9 100644 --- a/articles/Extensibility/docs/appManagement/Approvals.md +++ b/articles/Extensibility/docs/appManagement/Approvals.md @@ -15,6 +15,7 @@ focus: false --> ![Comment](https://github.com/RWS/language-cloud-public-api-doc-resources/blob/main/extensibility/app-management/Comment.gif?raw=true) +> [!NOTE] > This is not a live chat, and you should refresh to check for replies. However, you don't need to keep an eye on it always, as we have email notifications in place for both roles: the developer and the support team member. The comments panel is also used to track the **approval requests**. These requests can only be triggered by the app's developer in one of the following scenarios: @@ -37,6 +38,7 @@ The **Approval Process** ends with one of the following: 1. The request is **approved** or **rejected** by the RWS Support team. 2. The request is **canceled** by the developer. +> [!NOTE] > During the Approval Process you can still use your app as usual. ## App Suspended diff --git a/articles/Extensibility/docs/appManagement/Installing.md b/articles/Extensibility/docs/appManagement/Installing.md index dc40d35..f8ee9d1 100644 --- a/articles/Extensibility/docs/appManagement/Installing.md +++ b/articles/Extensibility/docs/appManagement/Installing.md @@ -9,7 +9,7 @@ After the app is successfully registered, you can proceed to install it. The ins To install the app you need to: 1. Find your app in the **My Apps** tab and select the **Install** button. -2. When prompted with a form containing placeholders for the account settings details, remember that these are the configuration settings exposed through the [descriptor](../../App-API.v1.json/paths/~1descriptor/get). All mandatory fields will be marked with '*'. +2. When prompted with a form containing placeholders for the account settings details, remember that these are the configuration settings exposed through the [descriptor](../../api/Extensibility-API.v1-fv.html#/operations/descriptor). All mandatory fields will be marked with '*'. 3. Pay attention if the app advertises any [scopes](../../docs/development/Authentication-Overview.md), you will be notified by the installation form. ![Install](https://github.com/RWS/language-cloud-public-api-doc-resources/blob/main/extensibility/app-management/InstallApp.gif?raw=true) +> [!NOTE] > The configuration settings can be modified anytime by clicking the **Edit App Configuration** button. \ No newline at end of file diff --git a/articles/Extensibility/docs/appManagement/Publishing.md b/articles/Extensibility/docs/appManagement/Publishing.md index a8b810c..37eb698 100644 --- a/articles/Extensibility/docs/appManagement/Publishing.md +++ b/articles/Extensibility/docs/appManagement/Publishing.md @@ -20,4 +20,5 @@ focus: false --> ![Publish](https://github.com/RWS/language-cloud-public-api-doc-resources/blob/main/extensibility/app-management/Publish.gif?raw=true) +> [!NOTE] > Publishing a private app will always publish its latest version. \ No newline at end of file diff --git a/articles/Extensibility/docs/appManagement/Registering.md b/articles/Extensibility/docs/appManagement/Registering.md index 1c6e626..7c233c8 100644 --- a/articles/Extensibility/docs/appManagement/Registering.md +++ b/articles/Extensibility/docs/appManagement/Registering.md @@ -16,13 +16,14 @@ focus: false 2. Go to **My Apps** tab, select **New App** and provide the following details: - the *Development Name* and *Development Description*, which will only be visible to the developer tenant (do not confuse them with the name and the description of the app descriptor) - - the *App Descriptor URL* is the app's [descriptor](../../App-API.v1.json/paths/~1descriptor/get) address. This must be a secure URL. + - the *App Descriptor URL* is the app's [descriptor](../../api/Extensibility-API.v1-fv.html#/operations/descriptor) address. This must be a secure URL. + - the *Development App* checkbox represents whether your app is intended for development and testing purposes. Development apps cannot be published. 3. After filling in these fields, finish the registration by clicking the **Register** button. -![Register](https://github.com/RWS/language-cloud-public-api-doc-resources/blob/main/extensibility/app-management/RegisterApp.gif?raw=true) +![Register](https://github.com/RWS/language-cloud-public-api-doc-resources/blob/main/extensibility/app-management/RegisterAppDevCheckbox.gif?raw=true) Common issues that may occur during registration include: @@ -32,4 +33,4 @@ Issue | Fix suggestion Invalid Descriptor URL | Make sure the provided URL is formed correctly and it points to your descriptor endpoint. Incorrect `BaseUrl` | If you are using one of our blueprints, check the blueprint guides ([.NET](../development/blueprints/Dot-Net-Blueprint.md#appsettingsjson) or [Java](../development/blueprints/Java-Blueprint.md#applicationyml)) on how to set up the `BaseUrl` field. Already registered | This would normally occur if you already registered your app. If so, you can [unregister](./Retiring.md) the old version and perform the registration once again. - Descriptor does not comply with the [contract](../../App-API.v1.json/paths/~1descriptor/get) | Make sure the required fields are returned and the allowed values correspond to the ones from the contract. \ No newline at end of file + Descriptor does not comply with the [contract](../../api/Extensibility-API.v1-fv.html#/operations/descriptor) | Make sure the required fields are returned and the allowed values correspond to the ones from the contract. \ No newline at end of file diff --git a/articles/Extensibility/docs/appManagement/Retiring.md b/articles/Extensibility/docs/appManagement/Retiring.md index 471a918..6d80b95 100644 --- a/articles/Extensibility/docs/appManagement/Retiring.md +++ b/articles/Extensibility/docs/appManagement/Retiring.md @@ -27,6 +27,7 @@ focus: false After the app becomes private, the only active instances left should be the developer's one and the shared ones (if the app had been previously shared). You can either uninstall them manually or unregister the app directly. The second option will automatically uninstall the instances left, before removing the app. +> [!NOTE] > An app can only be deleted when there are no other installed instances. To unregister the app, you need to: diff --git a/articles/Extensibility/docs/appManagement/Sharing.md b/articles/Extensibility/docs/appManagement/Sharing.md index aa5e268..30ade2e 100644 --- a/articles/Extensibility/docs/appManagement/Sharing.md +++ b/articles/Extensibility/docs/appManagement/Sharing.md @@ -5,6 +5,8 @@ stoplight-id: ruuiy7dsn27on # Sharing the App By default, a newly registered app is private, meaning that only the developer tenant has access to it. However, you can share your app with other tenants even if it hasn't been published yet. +A private version of a public app can also be shared prior to its publication. Please note that once the app is published, the Share button will no longer be visible. + To share the app you need to: 1. Test that it works as expected. 2. Select your app from the **My Apps** tab and click the **Share** button. @@ -16,4 +18,5 @@ focus: false --> ![Share](https://github.com/RWS/language-cloud-public-api-doc-resources/blob/main/extensibility/app-management/Share.gif?raw=true) +> [!NOTE] > The number of sharing links and shared installed instances is restricted by the sharing benefit quota from your account subscription. \ No newline at end of file diff --git a/articles/Extensibility/docs/appManagement/Updating.md b/articles/Extensibility/docs/appManagement/Updating.md index 3ecfbc0..2a0ea73 100644 --- a/articles/Extensibility/docs/appManagement/Updating.md +++ b/articles/Extensibility/docs/appManagement/Updating.md @@ -7,7 +7,7 @@ stoplight-id: b7cdff09ad767 There might be times when you need to make changes to your app. Whether you want to fix bugs, correct flaws, or add new functionality, the changes should eventually reach your registered app instance. That's why RWS Trados supports app versioning. To update the app you need to: -1. Increment the `version` field in the app's [descriptor](../../App-API.v1.json/paths/~1descriptor/get), as Trados relies on it to detect the newer versions. +1. Increment the `version` field in the app's [descriptor](../../api/Extensibility-API.v1-fv.html#/operations/descriptor), as Trados relies on it to detect the newer versions. 2. Wait for Trados to detect the new version. It could take up to 2 minutes to detect it. 3. You should also receive an email notification informing you that there's a new app version available. 4. Check the new version on the app details page. If you don't see it, please contact our support team. diff --git a/articles/Extensibility/docs/consumer/Automatic-Task-App-consumer-guide.md b/articles/Extensibility/docs/consumer/Automatic-Task-App-consumer-guide.md index 3b8d905..15453bd 100644 --- a/articles/Extensibility/docs/consumer/Automatic-Task-App-consumer-guide.md +++ b/articles/Extensibility/docs/consumer/Automatic-Task-App-consumer-guide.md @@ -35,6 +35,7 @@ To benefit from the app's functionality, you first have to install it on your ac Some apps also support validation of the configured settings. The first validation is automatically performed at installation time. If the provided settings are invalid, you will be prompted with an error message letting you know that the settings are incorrect. +> [!NOTE] > The configuration settings can be modified at any time by clicking the **Edit App Configuration** button. ## Using the Automatic Task App @@ -59,6 +60,7 @@ To use the app's automatic task(s) within your projects, first, you will need a 5. Click **Save configurations** and complete your template. 6. When finished, click **Save & Activate**. +> [!NOTE] > The above illustrations are based on a template draft. You may need to create the new template from scratch. ### Creating a New Workflow @@ -82,4 +84,5 @@ After creating the project, you can track the progress in the **Task History** t ![AutomaticTaskProjectHistory](https://github.com/RWS/language-cloud-public-api-doc-resources/blob/main/extensibility/guides/consumer/ConsumerATTaskHistory-app.png?raw=true) +> [!NOTE] > The app task illustrated above is just a mockup task that does not have a real purpose. \ No newline at end of file diff --git a/articles/Extensibility/docs/consumer/MT-App-consumer-guide.md b/articles/Extensibility/docs/consumer/MT-App-consumer-guide.md index 194d547..958feeb 100644 --- a/articles/Extensibility/docs/consumer/MT-App-consumer-guide.md +++ b/articles/Extensibility/docs/consumer/MT-App-consumer-guide.md @@ -26,6 +26,7 @@ To benefit from the app's functionality first you have to install it on your acc Some apps also support validation of the configured settings. The first validation is automatically performed at installation time. If the provided settings are invalid, you will be prompted with an error message letting you know that the settings are incorrect. +> [!NOTE] > The configuration settings can be modified at any time by clicking the **Edit App Configuration** button. ## Using the Machine Translation App @@ -62,10 +63,12 @@ To create a **Project** with the new resources you can either have them in a **P ![MTProject](https://github.com/RWS/language-cloud-public-api-doc-resources/blob/main/extensibility/guides/consumer/ConsumerCreateMTAppProject.gif?raw=true) +> [!NOTE] > The project language pair also has to match the ones from the engine and the workflow. Once the project reaches the **Translation** step, you can open it in **Online Editor** and check the translated segments from the MT app. You also have the possibility to search for Lookups in order to receive alternative translations. ![OEtranslations](https://github.com/RWS/language-cloud-public-api-doc-resources/blob/main/extensibility/guides/MTAppOELookup.gif?raw=true) +> [!NOTE] > The translations illustrated above are just some demonstrative mock-ups. \ No newline at end of file diff --git a/articles/Extensibility/docs/development/App-Descriptor.md b/articles/Extensibility/docs/development/App-Descriptor.md index 93991bf..b464343 100644 --- a/articles/Extensibility/docs/development/App-Descriptor.md +++ b/articles/Extensibility/docs/development/App-Descriptor.md @@ -10,7 +10,7 @@ The app developer must accurately fill in all the details within the descriptor, ## Basic Information -The descriptor model defines attributes that provide basic information like `name`, `description`, `releaseNotes`. The [model](../../App-API.v1.json/paths/~1descriptor/get) provides documentation for all the fields. +The descriptor model defines attributes that provide basic information like `name`, `description`, `releaseNotes`. The [model](../../api/Extensibility-API.v1-fv.html#/operations/descriptor) provides documentation for all the fields. ## Version @@ -56,8 +56,9 @@ Standard endpoints are defined under the `Standard` tag. The actual path should ### Lifecycle Endpoint Additionally, in the `standardEnpoints` section we can find the lifecycle endpoint. This endpoint needs to handle different events sent by Trados (similar to webhooks). For instance, when the app is being installed on a certain account, Trados will send an `INSTALLED` event along with some data for that account. The app should react and save the received data. -- `appLifecycle` - is used for all types of events: `REGISTERED`, `UNREGISTERED`, `INSTALLED`, and `UNINSTALLED`. See the contract [here](../../App-API.v1.json/paths/~1app-lifecycle/post). +- `appLifecycle` - is used for all types of events: `REGISTERED`, `UNREGISTERED`, `INSTALLED`, and `UNINSTALLED`. See the contract [here](../../api/Extensibility-API.v1-fv.html#/operations/Lifecycle). +> [!NOTE] > If your app is built from our blueprints, you shouldn't have to change anything, as these endpoints work out of the box. ## Extensions @@ -90,12 +91,13 @@ Any extension will have the generic set of properties: Read more on how to define the extensions for your app in our development guides: 1. Automatic Task [guide](./Automatic-Task-App-development-guide.md). 2. Machine Translation [guide](./MT-App-development-guide.md). -3. Preview [guide](./Dynamic-Preview-guide.md). +3. Preview [guide](./Preview-App-development-guide.md). ## Configuration An app can request configuration details at installation time (and it can be edited later). +> [!NOTE] > On an update, new configuration settings can be added, and the user will be requested to enter the newer configuration values. Configurations are app scoped. If you need to assign configuration values for individual extensions within the app, use clear and explicit naming conventions so users understand what information to input into each field. Additionally, tooltips can be provided by setting the description attribute. @@ -121,6 +123,8 @@ Example: ... } ``` + +> [!NOTE] > Note that in the example the `optional` and `defaultValue` properties have not been specified, so these will be set to their default values, as specified in the contract ( false for `optional` and undefined for `defaultValue`). Moreover, you have the option to define a list of choices using the `options` field. When this field is filled, the values will be presented in a dropdown menu. It's important to note that the only acceptable `dataType` in this scenario is `string`. @@ -134,6 +138,7 @@ The scopes advised in the descriptor will be presented to the consumers during i Once access is granted, the app will be able to perform authorized requests to the Trados Cloud Platform API. +> [!NOTE] > If the app doesn't make requests to Trados Cloud Platform API, no scopes should be specified. ## Webhooks diff --git a/articles/Extensibility/docs/development/App-Versioning.md b/articles/Extensibility/docs/development/App-Versioning.md index d8a4308..0f1e8f7 100644 --- a/articles/Extensibility/docs/development/App-Versioning.md +++ b/articles/Extensibility/docs/development/App-Versioning.md @@ -9,7 +9,7 @@ This article explains how the app versions work and how to use multiple versions ## Versions in Trados -When registering the app, the descriptor is saved in Trados as the initial version. The [descriptor](../../App-API.v1.json/paths/~1descriptor/get) includes a `version` field, which indicates the app's version. This version number should be incremented each time changes are made to the descriptor (such as endpoints or naming) to ensure Trados detects the new version. Newly detected versions are added alongside existing ones. This enables the installed instances to be associated with a particular version of the app. +When registering the app, the descriptor is saved in Trados as the initial version. The [descriptor](../../api/Extensibility-API.v1-fv.html#/operations/descriptor) includes a `version` field, which indicates the app's version. This version number should be incremented each time changes are made to the descriptor (such as endpoints or naming) to ensure Trados detects the new version. Only descriptors with higher version numbers are detected and added alongside existing ones. This enables the installed instances to be associated with a particular version of the app. Throughout an app's lifespan, it can be installed in various versions across different tenants. For instance, one tenant might install version 1.0.1, another 1.0.2, and a third 1.0.3. Although they expect to use the app at these particular versions, if no special actions are taken by the developer, they will probably all be using the same instance, which probably has a single implementation and does not take into consideration the expected version. @@ -21,7 +21,7 @@ Your app has a public version installed across multiple tenants. Eventually, you ## Versioning Your App -To ensure that new behavior only affects new installations and tenants updating to the latest version, you can version the extension endpoints. For example, suppose your app implements an Automatic Task Extension with a [submit](../../App-API.v1.json/paths/~1lc.automatictask.submit/post) endpoint like `{baseUrl}/v1/submit`, as specified in the contract. To prevent older versions from accessing the new functionality, create a new set of endpoints labeled with a new version, such as `{baseUrl}/v2/submit`, exclusively available in the updated descriptor version. Consequently, older versions won't recognize the existence of the v2 endpoint and will continue to use the v1 endpoint. Ensure that the v1 endpoint remains accessible at the same path defined in the older descriptor. +To ensure that new behavior only affects new installations and tenants updating to the latest version, you can version the extension endpoints. For example, suppose your app implements an Automatic Task Extension with a [submit](../../api/Extensibility-API.v1-fv.html#/operations/automatictasktypeexecutetask) endpoint like `{baseUrl}/v1/submit`, as specified in the contract. To prevent older versions from accessing the new functionality, create a new set of endpoints labeled with a new version, such as `{baseUrl}/v2/submit`, exclusively available in the updated descriptor version. Consequently, older versions won't recognize the existence of the v2 endpoint and will continue to use the v1 endpoint. Ensure that the v1 endpoint remains accessible at the same path defined in the older descriptor. For more details on version updates, refer to this dedicated [guide](../appManagement/Updating.md). diff --git a/articles/Extensibility/docs/development/Automatic-Task-App-development-guide.md b/articles/Extensibility/docs/development/Automatic-Task-App-development-guide.md index ec7136d..2189c9d 100644 --- a/articles/Extensibility/docs/development/Automatic-Task-App-development-guide.md +++ b/articles/Extensibility/docs/development/Automatic-Task-App-development-guide.md @@ -19,7 +19,7 @@ In order to build a new Automatic Task extension we recommend to start by using ## Automatic Task Extension -For an app to offer Automatic Task functionality, it must define at least one Automatic Task extension within its [descriptor](../../App-API.v1.json/paths/~1descriptor/get). +For an app to offer Automatic Task functionality, it must define at least one Automatic Task extension within its [descriptor](../../api/Extensibility-API.v1-fv.html#/operations/descriptor). For example: ```json @@ -216,7 +216,7 @@ The blueprints contain placeholders from where you can start implementing the en - [.NET blueprint](https://github.com/RWS/language-cloud-extensibility/blob/main/blueprints/dotNetAppBlueprint/Rws.LC.AppBlueprint/Controllers/AutomaticTaskController.cs#L36) - [Java blueprint](https://github.com/RWS/language-cloud-extensibility/blob/main/blueprints/javaAppBlueprint/src/main/java/com/rws/lt/lc/blueprint/web/AutomaticTaskController.java#L16) -Please refer to the endpoint's [documentation](../../App-API.v1.json/paths/~1lc.automatictask.submit/post) for further details. +Please refer to the endpoint's [documentation](../../api/Extensibility-API.v1-fv.html#/operations/automatictasktypeexecutetask) for further details. ### Callback Endpoint @@ -239,4 +239,4 @@ X-LC-Tenant: LC-TENANT_ID - The `token` should be already present in the received `callbackUrl` on the submit endpoint. -Please refer to the endpoint's [documentation](../../App-API.v1.json/paths/~1external-job~1v1~1callback/post) for further details. \ No newline at end of file +Please refer to the endpoint's [documentation](../../api/Extensibility-API.v1-fv.html#/operations/automatiktasktypecallback) for further details. \ No newline at end of file diff --git a/articles/Extensibility/docs/development/Deployment-Strategy.md b/articles/Extensibility/docs/development/Deployment-Strategy.md index 83ed4d8..b6b0166 100644 --- a/articles/Extensibility/docs/development/Deployment-Strategy.md +++ b/articles/Extensibility/docs/development/Deployment-Strategy.md @@ -18,6 +18,7 @@ We suggest using a distinctive **development name** and **description** to diffe ![RegisterPreview](https://github.com/RWS/language-cloud-public-api-doc-resources/blob/main/extensibility/guides/developer/RegisterPreview.gif?raw=true) +> [!NOTE] > Make sure you use a **descriptor URL** different from the one you need for the live instance. You cannot register two apps with the same descriptor URL. ## The Live Instance diff --git a/articles/Extensibility/docs/development/MT-App-development-guide.md b/articles/Extensibility/docs/development/MT-App-development-guide.md index f64bf0c..d077c7b 100644 --- a/articles/Extensibility/docs/development/MT-App-development-guide.md +++ b/articles/Extensibility/docs/development/MT-App-development-guide.md @@ -12,7 +12,7 @@ To build a new MT app we recommend starting by using the provided [app blueprint ## Machine Translation Extension -An MT app needs to define at least one MT extension within its [descriptor](../../App-API.v1.json/paths/~1descriptor/get). +An MT app needs to define at least one MT extension within its [descriptor](../../api/Extensibility-API.v1-fv.html#/operations/descriptor). For example: ```json @@ -111,7 +111,7 @@ The blueprints contain placeholders from where you can start implementing the en - [.NET blueprint](https://github.com/RWS/language-cloud-extensibility/blob/main/blueprints/dotNetAppBlueprint/Rws.LC.AppBlueprint/Controllers/TranslationController.cs#L52) - [Java blueprint](https://github.com/RWS/language-cloud-extensibility/blob/main/blueprints/javaAppBlueprint/src/main/java/com/rws/lt/lc/blueprint/web/TranslationEnginesController.java#L21) -Please refer to the endpoint's [documentation](../../App-API.v1.json/paths/~1lc.mtprovider.engines/get) for further details. +Please refer to the endpoint's [documentation](../../api/Extensibility-API.v1-fv.html#/operations/GetMachineTranslationProviderEngines) for further details. ### Translate Endpoint @@ -167,4 +167,4 @@ The blueprints contain placeholders from where you can start implementing the en - [.NET blueprint](https://github.com/RWS/language-cloud-extensibility/blob/main/blueprints/dotNetAppBlueprint/Rws.LC.AppBlueprint/Controllers/TranslationController.cs#L35) - [Java blueprint](https://github.com/RWS/language-cloud-extensibility/blob/main/blueprints/javaAppBlueprint/src/main/java/com/rws/lt/lc/blueprint/web/TranslateController.java#L22) -Please refer to the endpoint's [documentation](../../App-API.v1.json/paths/~1lc.mtprovider.translate/post) for further details. +Please refer to the endpoint's [documentation](../../api/Extensibility-API.v1-fv.html#/operations/MachineTranslationProviderTranslateBCM) for further details. diff --git a/articles/Extensibility/docs/development/Multi-Region.md b/articles/Extensibility/docs/development/Multi-Region.md index 597d45d..fc3dd7d 100644 --- a/articles/Extensibility/docs/development/Multi-Region.md +++ b/articles/Extensibility/docs/development/Multi-Region.md @@ -7,8 +7,9 @@ tags: [Development] To fulfill the requirements of our customers, Trados Enterprise allows multi-region deployments of your app. -To enable multi-region on your app you must provide regional instances of your app and include their `regionalBaseUrls` in your [descriptor](../../App-API.v1.json/paths/~1descriptor/get). +To enable multi-region on your app you must provide regional instances of your app and include their `regionalBaseUrls` in your [descriptor](../../api/Extensibility-API.v1-fv.html#/operations/descriptor). +> [!NOTE] > Multi-Region is only supported on apps starting with `decriptorVersion: 1.4` > [!WARNING] @@ -16,6 +17,9 @@ To enable multi-region on your app you must provide regional instances of your a Currently, the supported regions are Europe(`eu`) and Canada(`ca`). Depending on where your app is deployed you can choose either one or both of them. This will tell Trados what endpoints to invoke based on where the consumer tenant is living. +> [!WARNING] +> All instances, in all regions should provide the exact same descriptor. + ## Installing an App with Multi-Region support When a consumer installs an app, if `regionalBaseUrls` is present and same region as consumer's is available, that region will be used. @@ -31,7 +35,10 @@ The `INSTALLED` lifecycle event now includes the region information for the acco ## Base URL vs Multi-Region Base URLs -The `baseUrl` property from [descriptor](../../App-API.v1.json/paths/~1descriptor/get) remains mandatory even if you add the `regionalBaseUrls` property(which is optional). +The `baseUrl` property from [descriptor](../../api/Extensibility-API.v1-fv.html#/operations/descriptor) remains mandatory even if you add the `regionalBaseUrls` property(which is optional). + +> [!WARNING] +> The `baseUrl` in your app should stay fixed and not change based on region. When an App is registered, `baseUrl` from that initial descriptor is used for setting audience for all future authentication requests, independent of regions (it is possible to change it later, see [Changing Base URL](App-Descriptor.md#changing-base-url). Your "multi-region descriptor" should look something like this: ```json @@ -45,12 +52,15 @@ Your "multi-region descriptor" should look something like this: //.. } ``` + +> [!NOTE] > It is also acceptable to have the same URL in `baseUrl` as for one of regions in your `regionalBaseUrls` property. The `baseUrl` is treated as a global region URL and is still used in the following scenarios even if `regionalBaseUrls` is also defined: 1. Health checks - the `/health` endpoint that is periodically invoked to check the health status of your app 2. Version checks - the `/descriptor` endpoint that is periodically invoked to check for new versions(by the `version` property). + > [!NOTE] > It is the developer's responsibility to keep the version of the regional instances in sync. 3. `UPDATED` lifecycle event - explained below in the [Special Case](#special-case) section. diff --git a/articles/Extensibility/docs/development/Preview-App-development-guide.md b/articles/Extensibility/docs/development/Preview-App-development-guide.md index f340195..49bc2a7 100644 --- a/articles/Extensibility/docs/development/Preview-App-development-guide.md +++ b/articles/Extensibility/docs/development/Preview-App-development-guide.md @@ -10,13 +10,13 @@ stoplight-id: i7ib8ruwpxdxr Preview apps offer the possibility to use external preview providers within the Trados Enterprise platform. -The type of preview generated is known as "Dynamic Preview" as it can dynamically adjust depending on choices the user might make in the browser, for instance, selecting different preview sections or views from the rendered preview. The extension acts as a webserver which implements custom endpoints to serve the content to the browser. This content can be anything which the browser is able to parse and display accordingly. For more details on Dynamic Preview Concepts, please see the second section towards the end of this document. +The type of preview generated is known as "Dynamic Preview" as it can dynamically adjust depending on choices the user might make in the browser, for instance, selecting different preview sections or views from the rendered preview. The extension acts as a webserver which implements custom endpoints to serve the content to the browser. This content can be anything which the browser is able to parse and display accordingly. To build a new preview app we recommend to start by using the provided [app blueprints](https://github.com/RWS/language-cloud-extensibility/tree/main/blueprints). ## Preview App Extension -A preview app needs to define at least one preview extension within its [descriptor](../../App-API.v1.json/paths/~1descriptor/get). +A preview app needs to define at least one preview extension within its [descriptor](../../api/Extensibility-API.v1-fv.html#/operations/descriptor). For example: ```json @@ -38,13 +38,12 @@ For example: }, "supportedFileTypes": "html", "requiredInputFiles": { - "bilingualDocument": false, - "previewPackageTemplate": false, - "nativeSourceFile": false, - "nativeTargetFile": false, - "nativeAnnotatedTargetFile": true + "bilingualDocument": true, + "previewPackageTemplate": true, + "nativeFile": true, + "nativeAnnotatedFile": true }, - "outputType": "previewUrl" + "outputType": "previewPackage" } } ] @@ -58,26 +57,18 @@ For example: - `extensionPointId` - the extension point identifier corresponding to this extensionType: **lc.previewprovider**. - `description` - the preview extension description - `configuration` - the extension configuration. - - `endpoints` - the required endpoints for the preview extension. - - `lc.previewprovider.startpreview` - the endpoint used to start the preview generation. - - `lc.previewprovider.refreshpreview` - the endpoint used to refresh the existing preview session. - - `lc.previewprovider.updatesegment` - the endpoint used to update a segment based on a BCM document fragment. - - `lc.previewprovider.endpreview` - the endpoint used to clean up any state associated with a given preview session. - - For the V2 API, they are: - - `lc.previewprovider.startpreview.v2` - - `lc.previewprovider.refreshpreview.v2` - - `lc.previewprovider.updatesegment.v2` - - `lc.previewprovider.endpreview.v2` - + - `endpoints` - the required endpoints for the preview extension, should be relative to your `baseUrl`. + - `lc.previewprovider.startpreview` - the endpoint used to start the preview generation. For ex: `/start-preview`. + - `lc.previewprovider.refreshpreview` - the endpoint used to refresh the existing preview session. For ex: `refresh-preview`. + - `lc.previewprovider.updatesegment` - the endpoint used to update a segment based on a BCM document fragment. For ex: `update-segment`. + - `lc.previewprovider.endpreview` - the endpoint used to clean up any state associated with a given preview session. For ex: `end-preview`. - `supportedFileTypes` - A list of FileTypeDefinitionIds which this app may be associated with - `requiredInputFiles` - provides details about which types of input files this extension will require for generating a preview. - `bilingualDocument` - request an endpoint for downloading a BCM document. - `previewPackageTemplate` - request an endpoint for downloading a preview Package Template. - - `nativeSourceFile` - request an endpoint for downloading a native source file. - - `nativeTargetFile` - request an endpoint for downloading a native target file. - - `nativeAnnotatedTargetFile` - request an endpoint for downloading a native annotated target file. - - `outputType` - Indicates which type of output is generated by the extension. Dynamic previews only support a URL endpoint result and thus this should be set to **previewUrl** + - `nativeFile` - request an endpoint for downloading a native file. + - `nativeAnnotatedFile` - request an endpoint for downloading a native annotated file. + - `outputType` - Indicates which type of output is generated by the extension. For v1, this can be "previewPackage" for package-based previews or "previewUrl" for dynamic URL-based previews. ### Preview App Endpoints @@ -87,18 +78,14 @@ and returns after creating the background worker which generates the actual prev If the app needs to store any state, it should associate it with this identifier. The very first call for a given session should always be _startPreview_. If other endpoints are called before this, they should return an error. -The preview content is served by the app via one or more endpoints the app implements. The content can be any format, as long as the browser hosting the preview can parse and display that content. This includes, HTML, PDF, streamed video etc. -The resulting resource identifier returned from this call should be set in the `previewResult` field of the callback response. This will be a URL pointing to the initial endpoint implementation on the extension which the Browser hosting the preview will use to retrieve the preview content. As mentioned, the preview extension can implement additional endpoints which can then be called from the hosted portion in the Browser via AJAX calls or similar. +If the app is generating a previewPackage or standalone HTML result, it should be uploaded via the URL defined in the `previewResultFileUrl` field. +The resulting resource identifier returned from this call should be set in the `previewResult` field of the callback response. -There are currently 2 versions of the Preview API supported by Extensions: +For dynamic previews (outputType: "previewUrl"), the preview content is served by the app via one or more endpoints the app implements. The content can be any format, as long as the browser hosting the preview can parse and display that content. This includes HTML, PDF, streamed video etc. The resulting URL returned from this call should be set in the `previewResult` field of the callback response. -## APIs - -### API V1 - - Examples: + Example: ```html -POST /v1/start-preview +POST https://your-app.com/start-preview ``` - The request is as follows: @@ -166,7 +153,7 @@ This endpoint is used to initiate a preview session on the app. When this endpoi This should be the first endpoint called for any given session - if another endpoint is called for a given session ID before this one, an error should be returned. -Please refer to the endpoint's [documentation](../../App-API.v1.json/paths/~1lc.preview.startpreview/post) for further details. +Please refer to the endpoint's [documentation](../../api/Extensibility-API.v1-fv.html#/operations/StartPreview) for further details. #### RefreshPreview The _refreshPreview_ endpoint refreshes an existing preview. The mechanism for this in entirely up to the Extension implementation in that it might keep state from the initial preview generation from _startPreview_ in order to speed up the refresh. @@ -175,20 +162,20 @@ The request and responses (REST and Callback) are identical to the _startPreview Example: ```html -POST /v1/refresh-preview +POST https://your-app.com/refresh-preview ``` Endpoint usage: This endpoint is called when a preview refresh is requested by the user. Any state the app holds from the initial preview generation may be used to speed up the refresh. -Please refer to the endpoint's [documentation](../../App-API.v1.json/paths/~1lc.preview.refreshpreview/put) for further details. +Please refer to the endpoint's [documentation](../../api/Extensibility-API.v1-fv.html#/operations/RefreshPreview) for further details. #### UpdateSegment The _updateSegment_ endpoint accepts a list of BCM document fragments along with their associated segment IDs. The Extension will generate and return an HTML rendered fragment for each BCM document fragment sent in this manner. Example: ```html -POST /v1/update-segment +POST https://your-app.com/update-segment ``` - The request is as follows: @@ -239,14 +226,14 @@ POST /v1/update-segment Endpoint usage: This endpoint is called when the user is updating one or more segments in the Editor. For each segment, the extension will render an equivalent HTML fragment based on the input BCM document fragment. -Please refer to the endpoint's [documentation](../../App-API.v1.json/paths/~1lc.preview.updatesegment/post) for further details. +Please refer to the endpoint's [documentation](../../api/Extensibility-API.v1-fv.html#/operations/UpdateSegment) for further details. #### EndPreview The _endPreview_ endpoint is called when a given preview session associated with the previewSessionId is finished. This is called so that the app may perform any required cleanup. Example: ```html -POST /v1/end-preview +POST https://your-app.com/end-preview ``` ```json @@ -258,248 +245,13 @@ POST /v1/end-preview Endpoint usage: Called to indicate a preview session has terminated. Any required cleanup should be performed by the app. -Please refer to the endpoint's [documentation](../../App-API.v1.json/paths/~1lc.preview.endpreview/post) for further details. - -### API V2 - - Examples: -```html -POST /v2/start-preview -``` - -- The request is as follows: +Please refer to the endpoint's [documentation](../../api/Extensibility-API.v1-fv.html#/operations/EndPreview) for further details. -```json -{ - "previewSessionId": "string", - "projectId": "string", - "scope": "target", - "fileInformation": { - "name": "string", - "sourceLanguage": "string", - "targetLanguage": "string" - }, - "inputFiles": { - "bilingualDocument": {"id": "string", "version": "int", "url": "string"}, - "previewPackageTemplate": {"id": "string", "version": "int", "url": "string"}, - "nativeSourceFile": {"id": "string", "version": "int", "url": "string"}, - "nativeTargetFile": {"id": "string", "version": "int", "url": "string"}, - "nativeAnnotatedTargetFile": {"id": "string", "version": "int", "url": "string"} - }, - "callbackUrl": "string", -} -``` -- The response after setting up the background worker, would look like this: -```json -{ - "errorCode": "string", - "message": "string", - "details": [ - { - "name": "string", - "code": "string", - "value": "string" - } - ] -} -``` - -- The final result, which is sent on the callback, is shown below: - -```json -{ - "previewSessionId": "string", - "previewResult": "string", - "errors": [ - { - "errorCode": "string", - "message": "string", - "details": [ - { - "name": "string", - "code": "string", - "value": "string" - } - ] - } - ] -} -``` - -Endpoint usage: - -This endpoint is used to initiate a preview session on the app. When this endpoint is called, the app should generate the initial preview and associate it (internally, if any state is kept) - with the `previewSessionId`. - -This should be the first endpoint called for any given session - if another endpoint is called for a given session ID before this one, an error should be returned. +### Javascript Communication Protocol +The Online Editor Container communicates with the Preview Viewer iframe using the Javascript postMessage mechanism. The API is detailed below: -Please refer to the endpoint's [documentation](../../App-API.v1.json/paths/~1lc.preview.startpreview.v2/post) for further details. - -#### RefreshPreview -The _refreshPreview_ endpoint refreshes an existing preview. The mechanism for this in entirely up to the Extension implementation in that it might keep state from the initial preview generation from _startPreview_ in order to speed up the refresh. - -The request and responses (REST and Callback) are identical to the _startPreview_ endpoint. - - Example: -```html -POST /v2/refresh-preview -``` - -Endpoint usage: -This endpoint is called when a preview refresh is requested by the user. Any state the app holds from the initial preview generation may be used to speed up the refresh. - -Please refer to the endpoint's [documentation](../../App-API.v1.json/paths/~1lc.preview.refreshpreview.v2/put) for further details. - -#### UpdateSegment -The _updateSegment_ endpoint accepts a list of BCM document fragments along with their associated segment IDs. The Extension will generate and return an HTML rendered fragment for each BCM document fragment sent in this manner. - -Example: -```html -POST /v2/update-segment -``` - -- The request is as follows: - -```json -{ - "previewSessionId": "string", - "segments": [ - { - "segmentId": "string", - "fragment": {} - } - ], - "fileInformation": { - "name": "string", - "sourceLanguage": "string", - "targetLanguage": "string" - }, - "scope": "source" -} -``` -- `previewSessionId` - unique ID of current preview session. -- `segments` - an array of segments with the following details: - - `segmentId` - ID of segment being rendered. - - `fragment` - BCM document JSON fragment. -- `fileInformation` - provides information relating to the file for which the rendered HTML is being generated. -- `scope` - indicates whether the generation is happening for source or target content. - -- The response would look like this: -```json -{ - "previewSessionId": "string", - "renderedTranslations": [ - { - "html": "string", - "segmentId": "string", - "errorCode": "string" - } - ] -} -``` -- `previewSessionId` - unique ID of current preview session. -- `renderedTranslations` - an array of rendered translations with the following details: - - `html` - rendered HTML content for this segment. - - `segmentId` - ID of this segment. - - `errorCode` - Error code for this segment (App/Extension specific). - -Endpoint usage: -This endpoint is called when the user is updating one or more segments in the Editor. For each segment, the extension will render an equivalent HTML fragment based on the input BCM document fragment. - -Please refer to the endpoint's [documentation](../../App-API.v1.json/paths/~1lc.preview.updatesegment.v2/post) for further details. - -#### EndPreview -The _endPreview_ endpoint is called when a given preview session associated with the previewSessionId is finished. This is called so that the app may perform any required cleanup. - -Example: -```html -POST /v2/end-preview -``` - -```json -{ - "previewSessionId": "string" -} -``` - -Endpoint usage: -Called to indicate a preview session has terminated. Any required cleanup should be performed by the app. - -Please refer to the endpoint's [documentation](../../App-API.v1.json/paths/~1lc.preview.endpreview.v2/post) for further details. - - -## Session Management and Tenant Separation -It is up to the app to manage any session state internally and have an expiry mechanism for this. -Also, any data which is tenant specific needs to be kept separate from any other data and the app also needs to manage tenant separation concerns internally. -
-
-
- - -# Dynamic Preview Concepts - -Dynamic Preview concepts are explained a little more in this section. The Preview Container/Viewer (which hosts its content in an iframe) can dynamically update parts of the preview when the user selects different "pages" inside it via a selection mechanism, such as a drop-down or something similar. The app implements an endpoint which will initially serve the starting content and also any additional "dynamic" content requested via an AJAX call or similar. In general, the content generated dynamically will be a different rendering or view of the same BCM document content. For example, applying different XSLTs to an XML could provide such dynamic content (if the native file is XML based). It might also be different sections of the previewed document, or indeed, streamed video snippets, depending on which segments etc are selected in the previewed document. - - -Please refer also to this document before continuing: -[Preview Provider](../../docs/development/Preview-App-development-guide.md). - - -The app acts as a web server for this dynamic content. Some of the concepts around this are defined here: - -- Custom Preview Endpoint(s) - this is a custom endpoint on the app which supports TLS and which is used to serve the Initial Preview Content and the subsequent Dynamic Preview Content. Depending on the implementation, the app might specify one or more of these. -- Initial Preview Content - this is the HTML/Javascript content which is first served from the custom preview endpoint. It consists of some basic HTML and Javascript content which initializes the preview and loads an initial dynamic page. The URL for this initial call is set as the value for the "src" attribute on the iframe and is in the following format: - -```json -https://my.extension/custom-endpoint?sessionId={sessionId}&tenant={tenantId}&accessToken={hard-to-guess-access-token}&page={pageId} -``` -An example of such a URL is: - -```json -https://0ba1-212-17-60-65.ngrok.io/api/dynamic/v1/preview/endpoint?sessionId=1234567892&tenantId=12345&accessToken=a6f56954-7f55-440a-9919-160a2c4af91c&page=initial -``` - -The returned HTML/Javascript will be embedded in an iframe and there should be some Javascript mechanism to extract the access token from the current URL of the iframe and next pass it as a header in subsequent dynamic calls made from the iframe during dynamic content selection. -- Dynamic Preview Content - this is the dynamic content which is loaded based on a page selection. This can be loaded initially as part of the initialization routine of the Initial Preview Content after it checks for the hash fragment, and then also, when a user selects a given page using the page selection mechanism (via drop-down or similar). Loading the dynamic content involves making a dynamic call to the app on one of the Custom Preview Endpoints and must pass in the hash fragment as a header to the call. Mechanisms for initiating the call and updating the content might involve AJAX/JQuery or similar. -- TLS (Transport Layer Security) - the app should enable the TLS protocol on all custom endpoints. A valid certificate will be needed for this. -- Authorization/Access token - this is a hard-to-guess value which the app must generate and return as a response to the initial StartPreview request. It should be set as a hash fragment value on the returned URL. The app should provide for a TTL on this access token so that it will expire after a pre-determined time. The app should manage the TTL and any requirements around expiry of this. -- Preview Session - This is a session related to a given preview. Each session has a unique ID associated with it called "Preview Session ID" and it is sent to the app during various requests, including StartPreview. The app should use this to keep track of content related to a specific session when storing it locally. -- App storage - this could be a database or local disk-based storage etc. It is used by the app to store preview related content for specific sessions, such as files used to generate the preview, generated preview content, and any other specific data the app needs to store to work. -- Input Files - these files represent the initial data used to generate the preview. They might be a PreviewPackageTemplate, Native Source or Target files or Annotated Native Source or Target files. These files are described in more detail here: - - PreviewPackageTemplate - this file is a zip package containing different content which is used in the generation of preview content. Examples include XML, HTML, images, CSS, XSLT, Javascript etc. The content of this file is specific to the native file format used to generate the preview. - - Native File - this represents the native format which is being translated or previewed. Examples would be Word documents, Excel documents, XML documents, text documents etc. These files can be source or target, where the source represents the language which is being translated into other languages and the target represents the translated file (for example, source might be Japanese, and target might be French.) - This is a one-to-many relationship type, meaning that there is only one source language but possibly many more target languages. - - Annotated Native File - This is a native source or target file which has been annotated with special characters which encode a segment identifier in the annotation. The annotations also indicate where the segment boundaries are. These are used for segment navigation between the Editor and the Preview and for updating of segments inside the preview when content has changed in the Editor. -- Output Preview Content - The generated content is stored by the app locally and a URL is created allowing access to the stored content via a Custom Preview Endpoint on the app. In essence, the app acts like a web server. -- CORS (Cross Origin Resource Sharing) - Please see https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS . -- iframe - Please see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe. - - -## Creating a Preview Provider App - -The following steps should be considered when creating a Dynamic Preview App: - -- Add one or more custom endpoints in the PreviewController class -- Ensure the TLS security protocol is enabled on the app endpoints. A certificate from a trusted CA is required for this. -- Implement the endpoint functionality in the PreviewService class. -- Implement a mechanism for generating and storing hard-to-guess tokens with TTL support. When any of the custom endpoints are called, the TTL associated with that session's access token should be refreshed. When RefreshPreview is called, a new custom URL and access token with a new TTL should be generated. -- Implement the code to generate the preview from the initial files downloaded from the Trados Cloud Platform API. -- In the StartPreview implementation in the PreviewService class, ensure the background job is set up to call the preview generation implementation. -- Store the resulting initial files and the generated preview content from the above preview implementation locally or in a database. -- The response from the background job (StartPreview/RefreshPreview) should generate a URL as detailed in the previous section which points to the custom endpoint and includes the hard-to-guess access token as a hash fragment. This response should return the Initial Preview Content. -- Subsequent Dynamic Preview Content requests should respond with the relevant dynamic content after authorizing the access token sent in a header in the request. The header name can be decided by the app developer as it will be present in the Initial Preview Content HTML/Javascript and will be sent by the dynamic request (AJAX/JQuery etc) from there. -- If the access token has expired, the app should respond with a 401. -- Any calls to RefreshPreview should generate a new access token. -- Any calls to EndPreview should clean up all local data related to the given Preview Session ID. -- Implement a TTL on the local data. If EndPreview has not been called before the TTL expires, clean up all local data related to the given Preview Session ID. -- Implement UpdateSegment endpoint. -- Ensure UpdateSegment updates ALL dynamic pages generated by the app so that when a particular page is selected, it will have the updated content inside the segment. -- Implement a background job which cleans up sessions after a set interval. -- The TTLs associated with the access tokens and session cleanup should be configurable. - - -## Javascript API details -The Online Editor Container communicates with the Preview Viewer iframe using the Javascript postMessage mechanism. The API is detailed here in this Javascript file: -```js +```javascript "use strict"; /* Communication Protocol between the RWS Online Editor and the preview loaded into it. @@ -525,284 +277,101 @@ The Online Editor Container communicates with the Preview Viewer iframe using th } if (!window.sdlPreviewScriptIncludeGuard) { + // when the preview package gets inlined into a single html file, the script can + // get included multiple times; we use this guard to only subscribe to the events + // once + window.sdlPreviewScriptIncludeGuard = true; + //state var selectedSegmentId = ""; var segmentIdToSigCache = {}; var initialized = false; - // events ---------------------------------------------------------------------- - + // names of the events var PREVIEW_SEGMENT_SELECTED = "Preview:segmentSelected"; var PREVIEW_SHOW_MESSAGE = "Preview:showMessage"; var UE_SEGMENT_SELECTED = "UE:segmentSelected"; var UE_UPDATE_SEGMENT = "UE:updateSegment"; -} - - // communication --------------------------------------------------------------- - - function onSegmentSelectedInEditor(segmentId) { - setActiveSegment(segmentId); -} - - function onUpdateSegmentWithTranslation(payload) { - var segmentId = payload.segmentId; - var segmentSnippet = payload.snippet; - updateSegmentWithTranslation(segmentId, segmentSnippet); -} - - function onSegmentSelectedInPreview(segmentId) { - if (window.chrome && window.chrome.webview) { - window.chrome.webview.postMessage({ - "type": "selectSegment", - "segmentId": segmentId - }); - } else { - emitEvent(PREVIEW_SEGMENT_SELECTED, segmentId); - } -} - - function notifyPreviewControlToApplyInitialSelection() { - if (window.chrome && window.chrome.webview) { - window.chrome.webview.postMessage({ - "type": "applyInitialSelection" - }); - } -} - - function notifyNavigationFailure(segmentId) { - if (window.chrome && window.chrome.webview) { - window.chrome.webview.postMessage({ - "type": "cannotNavigateToSegment", - "segmentId": segmentId - }); - } - else - emitEvent(PREVIEW_SHOW_MESSAGE, "CannotNavigateToSegment"); -} - - function notifyPreviewUpdateFailure() { - emitEvent(PREVIEW_SHOW_MESSAGE, "PreviewCannotUpdate"); -} - - function emitEvent(eventName, parameter) { - window.parent.postMessage({ - "eventName": eventName, - "payload": parameter - }, '*'); -} - - // for scroll sync on side-by-side preview - if (window.chrome && window.chrome.webview) { - window.onscroll = () => window.chrome.webview.postMessage({ - "type": "windowScrolled", - "x": window.scrollX, - "y": window.scrollY - }); -} - - // segment update -------------------------------------------------------------- - - function updateSegmentWithTranslation(segmentId, segmentSnippet) { - var sigs = segmentIdToSigCache[segmentId]; - if (!sigs || !sigs.length || sigs.length > 1) { - notifyPreviewUpdateFailure(); - return; - }; - - var sigToReplace = sigs[0]; - var segmentSnippetDom = new DOMParser().parseFromString(segmentSnippet, "text/html"); - updateImagesInSnippet(segmentSnippetDom, sigToReplace); - updateFieldsInSnippet(segmentSnippetDom, sigToReplace); - sigToReplace.innerHTML = ""; - - var updatedSegment = segmentSnippetDom.getElementsByTagName("segment")[0]; - - while (updatedSegment.hasChildNodes()) { - sigToReplace.appendChild(updatedSegment.firstChild); - } -} - - function updateImagesInSnippet(segmentSnippetDom, sigToReplace) { - var snippetImgs = segmentSnippetDom.getElementsByTagName("img"); - var sigImgs = sigToReplace.getElementsByTagName("img"); - - if (snippetImgs.length > sigImgs.length) { - notifyPreviewUpdateFailure(); - return; - } - - if (snippetImgs.length > 0 && snippetImgs[0].dataset.preserveallimages) { - // object and it might have multiple images - for (let i = sigImgs.length - 1; i >= 0; i--) { - snippetImgs[0].parentElement.insertBefore(sigImgs[i], snippetImgs[0].nextSibling); - } - snippetImgs[0].remove(); - } else { - for (let i = 0; i < snippetImgs.length; i++) { - var currentImg = snippetImgs[i]; - cloneAttributes(currentImg, sigImgs[i]); - } - } -} - - function updateFieldsInSnippet(segmentSnippetDom, sigToReplace) { - - var snippetSpans = segmentSnippetDom.getElementsByTagName("span"); - - for (var i = 0; i < snippetSpans.length; i++) { - var currentSpan = snippetSpans[i]; - if (currentSpan.dataset.field) { - var fieldType = currentSpan.dataset.field; - var fieldInDom = sigToReplace.getElementsByTagName(fieldType); - - if (fieldInDom.length !== 1) { - notifyPreviewUpdateFailure(); - return; - } - - currentSpan.parentElement.insertBefore(fieldInDom[0], currentSpan); - currentSpan.remove(); - } - } -} - - function cloneAttributes(element, sourceNode) { - var attr; - var attributes = Array.prototype.slice.call(sourceNode.attributes); - while ((attr = attributes.pop())) { - element.setAttribute(attr.nodeName, attr.nodeValue); - } -} - // navigation ------------------------------------------------------------------ + document.addEventListener("DOMContentLoaded", function (event) { + /* preparations can be done here */ + }); - function setActiveSegment(segmentId) { - clearSegmentHighlight(selectedSegmentId); - selectedSegmentId = segmentId; + window.addEventListener(UE_SEGMENT_SELECTED, function (event) { + // event.detail will contain the id of the segment we need to navigate to + // the segment with this id can be highlighted and scrolled into view - highlightSegment(segmentId, "selected"); - scrollSegmentIntoView(segmentId); -} - - function highlightSegment(segmentId, className) { - var elements = segmentIdToSigCache[segmentId]; - if (!elements) { - if (initialized) notifyNavigationFailure(segmentId); - return; - } + // if the segment cannot be highlighted on the preview: + reportError("CannotNavigateToSegment"); + }); - for (var i = 0; i < elements.length; i++) { - var sig = elements[i]; - sig.setAttribute("class", className); - } -} + window.addEventListener(UE_UPDATE_SEGMENT, function(event) { + // the id of the segment being updated + var segmentId = event.detail.segmentId; - function clearSegmentHighlight(segmentId) { - if (!segmentId) return; + // the string (html snippet) returned by the segment updater + var segmentSnippet = event.detail.snippet; - var elements = segmentIdToSigCache[segmentId]; - if (!elements) return; + /* the contents of the corresponding page element can be changed + * here according to the snippet + */ - for (var i = 0; i < elements.length; i++) { - var sig = elements[i]; - sig.setAttribute("class", ""); - } + // if the update cannot be done: + reportError("PreviewCannotUpdate"); + }); } - function scrollSegmentIntoView(segmentId) { - var elements = segmentIdToSigCache[segmentId]; - if (!elements) return; +function reportError(type) { + // types currently being used are "CannotNavigateToSegment" and "PreviewCannotUpdate" + // TBD if we can support custom messages being sent in the detail attribute here - scrollIntoViewIfNeeded(elements[0]); + window.dispatchEvent(new CustomEvent( + PREVIEW_SHOW_MESSAGE, + { detail: type } + )); } - function scrollIntoViewIfNeeded(element) { - if (!element) return; - - var bottomLimit = Math.min( - document.documentElement.clientHeight, - document.body.clientHeight - ); - var rect = element.getBoundingClientRect(); - - var overTop = rect.top < 0; - var overBottom = rect.top + rect.height > bottomLimit; +function somethingWasClicked() { + // can be handler of onclick on page elements corresponding to segments - if (overTop || overBottom) { - element.scrollIntoView({ block: "center", inline: "center" }); - } -} + var previousSelection = "..."; + var segmentId = "..."; - //Finds y value of given object - function findPos(obj) { - var curtop = 0; - if (obj.offsetParent) { - do { - curtop += obj.offsetTop; - } while ((obj = obj.offsetParent)); - return [curtop]; + if (segmentId !== previousSelection) { + window.dispatchEvent(new CustomEvent( + PREVIEW_SEGMENT_SELECTED, + { detail: segmentId } // this informs the editor which segment it should navigate to + )); } - - return [curtop]; -} - - // others ---------------------------------------------------------------------- - - function onLoad() { - var sigs = document.getElementsByTagName("sig"); - segmentIdToSigCache = {}; - - for (var i = 0; i < sigs.length; ++i) { - var current = sigs[i]; - var id = current.getAttribute("data-segment-id"); - - if (id) { - current.onclick = onSigClick; - current.onmouseover = onSigMouseOver; - current.onmouseout = onSigMouseOut; - - if (segmentIdToSigCache[id]) { - segmentIdToSigCache[id].push(current); - } else { - segmentIdToSigCache[id] = [current]; - } - } - } - - if (selectedSegmentId) setActiveSegment(selectedSegmentId); - - notifyPreviewControlToApplyInitialSelection(); - - initialized = true; -} - function onSigClick() { - var id = this.getAttribute("data-segment-id"); - setActiveSegment(id); - onSegmentSelectedInPreview(id); -} - - function onSigMouseOver() { - var id = this.getAttribute("data-segment-id"); - if (id !== selectedSegmentId) highlightSegment(id, "highlighted"); } +``` - function onSigMouseOut() { - var id = this.getAttribute("data-segment-id"); - if (id !== selectedSegmentId) clearSegmentHighlight(id); -} +For dynamic previews, a more comprehensive Javascript API is available that handles communication via postMessage between the iframe and the Online Editor. This includes: +- Navigation between segments +- Segment updates with translation changes +- Error messaging +- Scroll synchronization for side-by-side preview +- Segment highlighting and selection +### Session Management and Tenant Separation +It is up to the app to manage any session state internally and have an expiry mechanism for this. +Also, any data which is tenant specific needs to be kept separate from any other data and the app also needs to manage tenant separation concerns internally. - // entry point - window.addEventListener("message", function (event) { - switch(event.data.eventName) { - case UE_SEGMENT_SELECTED: - onSegmentSelectedInEditor(event.data.payload); - break; - case UE_UPDATE_SEGMENT: - onUpdateSegmentWithTranslation(event.data.payload); - break; - default: - console.log("No handler for event: ", event.data.eventName); - } -}); - document.addEventListener("DOMContentLoaded", onLoad); \ No newline at end of file +### Input Files +The preview provider works with various types of input files: +- **PreviewPackageTemplate** - a zip package containing content used in preview generation (XML, HTML, images, CSS, XSLT, Javascript etc.) +- **Native File** - the native format being translated or previewed (Word, Excel, XML documents etc.) +- **Annotated Native File** - a native file annotated with special characters encoding segment identifiers and boundaries + +### Dynamic Preview Concepts (for outputType: "previewUrl") +When implementing dynamic previews: +- The app acts as a web server implementing custom endpoints +- TLS (Transport Layer Security) must be enabled on all custom endpoints +- Authorization via hard-to-guess access tokens with TTL support +- Content can be dynamically updated based on user selections +- Support for different renderings or views of the same BCM document content + +The URL format for dynamic preview endpoints: +``` +https://my.extension/custom-endpoint?sessionId={sessionId}&tenant={tenantId}&accessToken={hard-to-guess-access-token}&page={pageId} +``` \ No newline at end of file diff --git a/articles/Extensibility/docs/development/Request-Authentication.md b/articles/Extensibility/docs/development/Request-Authentication.md index 056297e..9425ea8 100644 --- a/articles/Extensibility/docs/development/Request-Authentication.md +++ b/articles/Extensibility/docs/development/Request-Authentication.md @@ -8,6 +8,7 @@ All but a few of the endpoints are required to check for valid Authentication. T Trados might send the Authorization header even on the endpoints that do not need authentication, but the app is not required to validate them. If the header is sent, the app should either ignore it or validate it. But if the token is not valid, then this should result in a 401/403 result. +> [!NOTE] > Note: the provided blueprints (both Java and .NET Core) have authentication implemented and working out of the box. You can skip the rest of this document unless you're interested in the technical details. ## Authorization header diff --git a/articles/Extensibility/docs/development/Tehnical-Requirements-And-Best-Practices.md b/articles/Extensibility/docs/development/Tehnical-Requirements-And-Best-Practices.md new file mode 100644 index 0000000..0f1e89f --- /dev/null +++ b/articles/Extensibility/docs/development/Tehnical-Requirements-And-Best-Practices.md @@ -0,0 +1,70 @@ +# Technical Requirements And Best Practices + +## Technical requirements for Apps + +Most technical requirements are driven by the app's developer. For example, CPU/Memory requirements should be decided by the developer after taking into consideration the particular functionality of the app and its expected load. + +For reference, a typical machine translation app built on the .NET Core Blueprint, which adapts a third party translation engine, with 250,000 transactions per month, only requires very minimal hardware resources, with 0.1 CPU and 500 MB RAM. + +But there are certain aspects that still need to be covered to ensure secure and resilient operations. + +## Framework + +Apps can be developed using any framework, but we provide two blueprints to help you get started: one for .NET Core 8 and the other for Java. + +## Redundancy + +A load balanced, two instance deployment is recommended to ensure there are no interruptions in operation in case of failures, or more importantly, no downtime when a new version is deployed (by using rolling deployments). + +This recommended setup can be easily achieved if the application is deployed on a cloud platform. + +## Security +All communication should be secured against interfering and eavesdropping. This includes the communication between the Trados platform and the App, and also between the app and the resources it uses: third party Machine Translation Engines, databases and other resources. + +Trados uses two mechanisms to secure the apps communication: +- HTTPS support is mandatory, and Trados will not communicate with the app over an unsecured HTTP channel, or via a channel with expired or invalid certificates. +- The app can also validate that the caller is indeed Trados, by verifying the signature in each call with the [Public Key](https://languagecloud.sdl.com/lc/api-docs/8c6f7b35af0ea-list-public-keys) available from Trados on an HTTPS endpoint. + +An additional security mechanism used by Trados is signing the request body. This provides an extra layer of validation, but it can also be used in case the application gets compromised, and an analysis is required to identify which messages are authentic and which aren't. For that, all incoming messages need to be logged or audited in some form. + +By following these guidelines, app developers can ensure that their code is secure and resistant to attacks, protecting sensitive data and maintaining the confidentiality, integrity, and availability of their applications, while also staying aware of and addressing any potential vulnerabilities in their dependencies: + +- Input Validation: Always validate user inputs to ensure they are within the expected range and format. This helps to prevent injection attacks such as SQL injection or Cross-Site Scripting (XSS). +- Secure Configuration: Configure your app securely by avoiding default settings and keeping all passwords and sensitive information out of code. +- Secure Coding Practices: Follow secure coding practices such as avoiding hardcoded passwords, using secure coding patterns and libraries, and avoiding dynamic code execution. +- Access Control: Ensure that access controls are in place to prevent unauthorized access to sensitive data or functions within the application. +- Error Handling: Implement proper error handling to prevent sensitive information from being exposed to attackers. +- Manage Vulnerable Dependencies: Keep track of the dependencies used in your application and regularly check for any known vulnerabilities in those dependencies. Update to the latest version of the dependency as soon as possible to reduce the risk of exploitation. + +## Logging + +Logging is required for tracking the flow of operations and for debugging any possible issues. Logging is already set up for both blueprints, but you need to adjust the template of the logs and their destinations. + +Important components in the logs, already present in the blueprints, include: +- timestamp - this should have a timezone, to avoid any confusion of whether it's local time or UTC. +- trace id - each request sent from Trados contains a trace id which can be used to track a complete flow. This is also propagated in the code from the moment a request is performed until a response is returned. +- thread id +- host/node name - this depends on your infrastructure setup, and we recommend having it logged, especially if you have more than one instance running. +- account id +- message - an informative description of what is happening +- error and stack trace + +Do not log sensitive information in the logs, like personal identification information, API keys, incoming authentication details or signatures. + +## Metrics + +Metrics help answer questions like: +- Usage - how many/how much? +- Hardware requirements - are the currently allocated resources enough? Do we need to scale up or can we scale down to save on running costs? + +This is not a strict requirement, but it is strongly recommended to have some form of metrics set up. This should be set up in such a way to enable you to: +- Track the number of failed request/errors. +- Track the total number of transactions. +- Track the timing of the transactions/requests (this can be addressed by various metrics like `max`, `min`, `median`, `percentile`). +- Monitor CPU and Memory utilization. This should be used to correlate transactions with resource usage. + +## Error Responses + +It's important to follow the specification for the endpoints when it comes to returning error responses. Each endpoint defines a set of expected error responses and the error response model. Implementing the contract correctly allows Trados to parse the response correctly and, in some situations, to handle the error and make decisions on it. + +Endpoints can have a set of predefined error codes that Trados can interpret. One such example would be the `invalidConfiguration`. Error responses can even pinpoint further the source of the problem, in the `details` array that might indicate, for example, the actual field with the incorrect value, along with a corresponding code, for example, `invalidValue` or `nullValue`. \ No newline at end of file diff --git a/articles/Extensibility/docs/development/Trados-Cloud-API.md b/articles/Extensibility/docs/development/Trados-Cloud-API.md index 0652eb8..4e6b403 100644 --- a/articles/Extensibility/docs/development/Trados-Cloud-API.md +++ b/articles/Extensibility/docs/development/Trados-Cloud-API.md @@ -8,7 +8,7 @@ Communication to Trados Cloud Platform API is also authenticated and the process ## Credentials -When an app is registered, credentials (`clientId` and `clientSecret`) are sent to the app with the `REGISTERED` lifecycle event on the [App Lifecycle endpoint](../../App-API.v1.json/paths/~1app-lifecycle/post). +When an app is registered, credentials (`clientId` and `clientSecret`) are sent to the app with the `REGISTERED` lifecycle event on the [App Lifecycle endpoint](../../api/Extensibility-API.v1-fv.html#/operations/Lifecycle). An example payload: @@ -27,7 +27,7 @@ An example payload: Here `clientId` and `clientSecret` represent the credentials for the Trados Cloud Platform API and can be used for getting a token for communicating with the Trados Cloud Platform API, as described by the [Trados Cloud Platform API documentation](https://languagecloud.sdl.com/lc/api-docs/ZG9jOjExMDcyMQ-authentication). -When an app is installed on an account, a service user will be created in Trados and an event will be sent on the [App Lifecycle endpoint](../../App-API.v1.json/paths/~1app-lifecycle/post) with event `id` being `INSTALLED`. +When an app is installed on an account, a service user will be created in Trados and an event will be sent on the [App Lifecycle endpoint](../../api/Extensibility-API.v1-fv.html#/operations/Lifecycle) with event `id` being `INSTALLED`. Account ID should always be used from the request authentication header token. This is built in in the provided blueprints. diff --git a/articles/Extensibility/docs/development/UI-App-custom-elements-locations.md b/articles/Extensibility/docs/development/UI-App-custom-elements-locations.md index 8b141e9..b0a5e82 100644 --- a/articles/Extensibility/docs/development/UI-App-custom-elements-locations.md +++ b/articles/Extensibility/docs/development/UI-App-custom-elements-locations.md @@ -6,7 +6,7 @@ tags: [Development] # Custom Elements and Locations The platform supports the addition of various UI elements, including **buttons** (generic, link, and dropdown) and **panels** (generic, sidebar, and tab). -These elements can be incorporated into specific sections of the user interface in the **Inbox** and **Projects** areas. +These elements can be incorporated into specific sections of the user interface in the **Inbox, Orders, Projects and Reports** areas. @@ -21,7 +21,17 @@ These elements can be incorporated into specific sections of the user interface - + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + +
InboxInboxTasks list + tasks-list-tabpanel + tasks-list-tabpanel location + tab
New tasks list new-tasks-list-sidebar @@ -135,8 +145,28 @@ These elements can be incorporated into specific sections of the user interface
ProjectsProjects listOrdersOrders list + orders-list-tabpanel + orders-list-tabpanel location + tab
ProjectsProjects list + projects-list-tabpanel + projects-list-tabpanel location + tab
projects-list-toolbar projects-list-toolbar location @@ -236,6 +266,17 @@ These elements can be incorporated into specific sections of the user interface projectDetailsActiveTab, projectDetails, projectTaskHistory
ReportsReports list + reports-list-tabpanel + reports-list-tabpanel location + tab
diff --git a/articles/Extensibility/docs/development/UI-App-development-guide.md b/articles/Extensibility/docs/development/UI-App-development-guide.md index 2f7e227..1b3ba36 100644 --- a/articles/Extensibility/docs/development/UI-App-development-guide.md +++ b/articles/Extensibility/docs/development/UI-App-development-guide.md @@ -7,8 +7,7 @@ tags: [Development] UI extensions offer the possibility to add custom user interface elements and functionality. Custom [buttons and panels can be added to specific places](UI-App-custom-elements-locations.md) within the user interface. - - +> [!CAUTION] > #### This feature is currently in BETA. > Please note that in a future phase, we will introduce significant changes as we move towards the official release: > * The current implementation utilizes the authorization token of the logged-in Trados user for the Trados Cloud Platform API and the app's own API calls. In a future update, a different authorization token will be introduced for these operation. @@ -16,7 +15,7 @@ UI extensions offer the possibility to add custom user interface elements and fu > * A UI extension's JavaScript file will be loaded in an isolated context, independent from Trados. > * The communication model between App UI and Backend will change in the final version and will have to be redesigned. -A UI extension is defined in the app [descriptor](../../App-API.v1.json/paths/\~1descriptor/get) in the `extensions` array. +A UI extension is defined in the app [descriptor](../../api/Extensibility-API.v1-fv.html#/operations/descriptor) in the `extensions` array. ```json { @@ -40,7 +39,7 @@ A UI extension is defined in the app [descriptor](../../App-API.v1.json/paths/\~ The `extensionPointId` is always **"lc.ui"**. -The `configuration`'s `scriptPath` is the path of the JavaScript file which will be loaded in the Trados user interface. The path is relative to the `basePath` in the [descriptor](../../App-API.v1.json/paths/\~1descriptor/get). This JavaScript file contains the code describing the custom elements that will be added to the user interface and their functionality. +The `configuration`'s `scriptPath` is the path of the JavaScript file which will be loaded in the Trados user interface. The path is relative to the `basePath` in the [descriptor](../../api/Extensibility-API.v1-fv.html#/operations/descriptor). This JavaScript file contains the code describing the custom elements that will be added to the user interface and their functionality. ## Prerequisites @@ -50,7 +49,7 @@ If you don't already have Node.js installed, you can download the most recent LT ### Dependencies -- [@trados/trados-ui-extensibility](https://www.npmjs.com/package/@trados/trados-ui-extensibility) v0.1.4 +- [@trados/trados-ui-extensibility](https://www.npmjs.com/package/@trados/trados-ui-extensibility) v0.1.5 - [GitHub repository](https://github.com/RWS/trados-ui-extensibility) - [GitHub wiki](https://github.com/RWS/trados-ui-extensibility/wiki) @@ -62,6 +61,7 @@ If you don't already have Node.js installed, you can download the most recent LT ## Getting started +> [!NOTE] > Make sure you are familiar with Trados app development and testing presented in the [Getting Started with Blueprints](blueprints/Getting-Started.md) and [Testing](blueprints/Testing.md) articles. 1. Download the [.NET sample app which contains a UI extension](https://github.com/RWS/language-cloud-extensibility/tree/main/samples/dotnet/UISampleApp). @@ -85,11 +85,12 @@ If you don't already have Node.js installed, you can download the most recent LT npm run build-dev ``` - - The `build` (or `build-dev`) command will create a `my-ui-extension-script.js` file in `Rws.LC.UISampleApp/Resources/frontend/dist/`. This is the path you need to use in the [descriptor](../../App-API.v1.json/paths/\~1descriptor/get) for your extension's configuration `scriptPath`, for example `Rws.LC.UISampleApp/Resources/frontend/dist/my-ui-extension-script.js`. + - The `build` (or `build-dev`) command will create a `my-ui-extension-script.js` file in `Rws.LC.UISampleApp/Resources/frontend/dist/`. This is the path you need to use in the [descriptor](../../api/Extensibility-API.v1-fv.html#/operations/descriptor) for your extension's configuration `scriptPath`, for example `Rws.LC.UISampleApp/Resources/frontend/dist/my-ui-extension-script.js`. - You can change the `my-ui-extension-script.js` file name by editing - the `module.exports`' `output.filename` property in `Rws.LC.UISampleApp/Resources/frontend/webpack.config.js` and - the extension's configuration `scriptPath` field. + > [!NOTE] > If your app is already registered, after changing the extension's configuration `scriptPath` field you need to [update](../appManagement/Updating.md) your app to a new version. - Once you have built your new JavaScript file, refresh the Trados browser tab to see your changes. @@ -235,7 +236,6 @@ Note that adding `script` tags is not allowed and scripts from sources that are ### Notes > [!NOTE] - > #### Custom elements display order > Within a single UI extension: custom elements in your extension that have the same `location` are displayed in the same order in which they are present in your `ExtensionElement`s array. > @@ -243,6 +243,5 @@ Note that adding `script` tags is not allowed and scripts from sources that are > [!NOTE] - > #### Unexpected re-renders > A custom element's `onrender` event can be triggered multiple times depending on state changes in the Trados UI and depending on user's interactions with Trados UI. Subsequently, the corresponding `eventHandler` gets executed multiple times. You can add logic specific to you use-case to protect your UI extension against unneeded execution of `onrender` `eventHandler`. \ No newline at end of file diff --git a/articles/Extensibility/docs/development/Verification-App-development-guide.md b/articles/Extensibility/docs/development/Verification-App-development-guide.md index 6b41ea4..b6a79f4 100644 --- a/articles/Extensibility/docs/development/Verification-App-development-guide.md +++ b/articles/Extensibility/docs/development/Verification-App-development-guide.md @@ -1,28 +1,31 @@ --- -stoplight-id: 0rl7inhtg6utq +stoplight-id: 9r7ku59767q11 --- # Verification Provider ## Overview + Trados provides verification functionality on translatable content (source and/or target) in several ways: + - Batch Verification Task (set in project workflows) - Editor Document Verification Task - Editor Segment-level Verification operation + The first two verification tasks validate the whole document, whereas the last operation, validates a single segment. For document validation, native verification is also possible. This allows for validation of a native file or a native annotated file. The difference between an annotated file and a non-annotated file is that the first allows for the generation of location information and the second does not. For native verification, a verification resource package may also be retrieved by the extension. This would contain ancillary files such as schemas, for example, in the case of XML validation. Trados supports a set of internal verifiers which are fixed in nature and the user can decide, through settings, what will be verified using these. Some of them are, for example: + - QA Checker - Tag Verifier + To allow for extending of the verification functionality, Trados supports the creation of extensible or external verifiers. These are hosted in apps which are essentially a self-contained serviced offering the verification functionality. Extensible verifiers would normally only support a small set of verification types, such as a target segment length check (against the length of the source) for example, or perhaps, a punctuation checker. -Each verifier will generate a set of error or warning messages based on the type of validation they perform. The user can change validation settings in the LC UI Project Settings which will affect how or when the messages are generated. External verifiers also have the option to specify resource packages in the settings which will allow the user to upload support files required during the validation process. This option is verifier specific as not all verifiers might require a package. - There are 2 types of verification which are supported by extensibility: - Bilingual Document Verification - Native File Verification @@ -31,6 +34,8 @@ There are 2 types of verification which are supported by extensibility: Native File Verification validates the native source or target file. This file might also be annotated to allow for the easy determination of segment identifiers. An example of native file verification would be schema validation on an XML file. The aim of native verification is to establish if the translation process has broken any of the document structure and rendered an invalid document. +Each verifier will generate a set of error or warning messages based on the type of validation they perform. The user can change validation settings in the LC UI Project Settings which will affect how or when the messages are generated. External verifiers also have the option to specify resource packages in the settings which will allow the user to upload support files required during the validation process. This option is verifier specific as not all verifiers might require a package. + The user can see generated verification messages in the Editor UI and can choose to ignore certain messages by message type or individually, depending on their needs. They can subsequently un-ignore them at a later stage if desired. Verifiers may also provide localized messages which can be displayed in the same language the Editor UI is presenting in. @@ -40,9 +45,7 @@ Flows: ![Verification Flow 2](https://github.com/RWS/language-cloud-public-api-doc-resources/blob/main/extensibility/verification-flow2.png?raw=true) - - -#### Notes on the above Flow Diagrams +#### Notes on the Flow Diagrams The ***StartVerification*** request initiates the background job on the extension. The background job will be responsible for generating the verification messages. @@ -57,21 +60,16 @@ The app receives a VerifyDocument request from Trados. The request specifies cer These resources are downloaded to the app via the Trados Cloud Platform API and can be stored locally during the verification operation. -When the request is received, the app responds with 201(Created) and starts a background job which will generate the verification messages. For each verification error or warning the app creates, it needs to send this back to Trados via the Trados Cloud Platform API. These messages may grouped into batches to minimize chatty behaviour between the app and the Trados Cloud Platform API. +When the request is received, the app responds with 201(Created) and starts a background job which will generate the verification messages. For each verification error or warning the app creates, it needs to send this back to Trados via the Trados Cloud Platform API. These messages may be grouped into batches to minimize chatty behavior between the app and the Trados Cloud Platform API. The app may also receive a request to verify a single segment. All interactions between the app and Trados Cloud Platform API are via REST calls. -## APIs -The extensible verifier API consists of a number of endpoints - an overview of their purpose is given here - there are currently two versions of the API - +### API Overview +The extensible verifier API consists of a number of endpoints - an overview of their purpose is given here: -### API V1 - -A verification extension defines the following in its descriptor - and specific details are shown below which are defined inside the `extensions` array +A verification extension defines the following in its descriptor: ```json -... -"extensions": [ { "extensionPointId": "lc.verificationprovider", "id": "string", @@ -88,7 +86,6 @@ A verification extension defines the following in its descriptor - and specific "validationInputType": "string", } } -] ``` The extensionPointId must always be ***"lc.verificationprovider"*** @@ -100,90 +97,11 @@ The validationInputType defines which type of validation will happen based on th The respective download URL(s) will be provided in the *StartVerification* request and the extension must download and store these resources as required. -The endpoints for V1 are: - -VerifyDocument: -```html -POST /v1/verify/document -``` -VerifySegment: -```html -POST /v1/verify/segment -``` -GetMessagesByCulture: -```html -GET /v1/messages -``` -GetSettingsSchema: -```html -GET /v1/schemas -``` - -### API V2 -The only difference between the V1 and V2 APIs is in the descriptor where the validationInputType has changed its name to validationInputFiles and its type to an array of strings in addition to versioning and the addition of the validatorType and supportedFileTypes fields - -```json -... -"extensions": [ -{ - "extensionPointId": "lc.verificationprovider", - "id": "string", - "name": "string", - "description": "string", - "extensionPointVersion": "2.0", - "configuration": { - "endpoints": { - "lc.verification.startverification.v2": "string", - "lc.verification.verifysegment.v2": "string", - "lc.verification.getmessagesbyculture.v2": "string", - "lc.verification.getsettingsschema.v2": "string" - }, - "validationInputFiles": ["string"], - "validatorType": "string", - "supportedFileTypes": ["string"]} - } -] -``` -The extensionPointId must always be `lc.verificationprovider` - -The `validationInputFiles` defines which files should be provided for the validation and can be one or more of the following, having unique entries in the array - NativeSource and NativeTarget are mutually exclusive selections: -- BilingualDocument -- NativeSource -- NativeTarget -- NativeAnnotatedTarget - -The `validatorType` defines which type of validator should be used. It can be one of the following: -- BilingualDocumentValidator -- NativeSourceValidator -- NativeTargetValidator -- NativeAnnotatedTargetValidator - -The `supportedFileTypes` field defines an array of FileTypeDefinitionIds to which this validator may be assigned to. - -The respective download URL(s) will be provided in the *StartVerification* request and the extension must download and store these resources as required. - -The endpoints for V2 are: - -VerifyDocument: -```html -POST /v2/verify/document -``` -VerifySegment: -```html -POST /v2/verify/segment -``` -GetMessagesByCulture: -```html -GET /v2/messages -``` -GetSettingsSchema: -```html -GET /v2/schemas -``` - - - -### API V1 and V2 Common +- `endpoints` - the required endpoints for the verification extension, should be relative to your `baseUrl`. + - `lc.verification.startverification` - the endpoint used to start the verification operation. For ex: `/verify/document`. + - `lc.verification.verifysegment` - the endpoint used to verify a single segment. For ex: `/verify/segment`. + - `lc.verification.getmessagesbyculture` - the endpoint used to retrieve localized messages. For ex: `/messages`. + - `lc.verification.getsettingsschema` - the endpoint used to retrieve the settings schema. For ex: `/schemas`. There are four endpoints which the extension supports: @@ -197,7 +115,12 @@ There are described in a little more detail here: ##### StartVerification This endpoint is called by Trados to initiate the document verification operation. Generally, a background job is started when this call is made and it returns 201(Created) The background job then prepares batches of verification messages which it then publishes to Trados via the Trados Cloud Platform API using the PublishMessages endpoint URL which is provided in the initial StartVerification request. Please see the API documentation for more details: -[StartVerification](../../App-API.v1.json/paths/~1lc.verification.startverification.v2~1{requestId}/post) +[StartVerification](../../api/Extensibility-API.v1-fv.html#/operations/VerificationProviderStartVerification) + +Example: +```html +POST https://your-app.com/verify/document +``` The request for StartVerification is shown below: @@ -304,11 +227,14 @@ Each message contains the following fields: `messageLocation` - the offsets within the segment representing the error span - - ##### VerifySegment This endpoint is called by Trados to validate an individual segment. This endpoint responds with a collection of messages which relate to any issues found for this segment. Please see the API documentation for more details: -[VerifySegment](../../App-API.v1.json/paths/~1lc.verification.verifysegment.v2/post) +[VerifySegment](../../api/Extensibility-API.v1-fv.html#/operations/VerificationProviderVerifySegment) + +Example: +```html +POST https://your-app.com/verify/segment +``` The request is structured as follows: @@ -341,11 +267,21 @@ The request is structured as follows: ##### GetMessagesByCulture This endpoint is called by Trados to retrieve localized resources for the messages. The culture is specified in the call as a URL parameter. The app can support localized resources for various languages which will allow the messages to be displayed in the native language of the user in the UI. Please see the API documentation for more details: -[GetMessagesByCulture](../../App-API.v1.json/paths/~1lc.verification.getmessagesbyculture.v2~1{culture}/get) +[GetMessagesByCulture](../../api/Extensibility-API.v1-fv.html#/operations/VerificationProviderGetMessagesByCulture) + +Example: +```html +GET https://your-app.com/messages/es-ES +``` ##### GetSettingsSchema -This endpoint is called by Trados to retrieve the schema related to any settings which the extension supports. **A note on schemas - once you define your settings schema for the extension, it should only be modified in a backwards compatible way, i.e. only adding of additional fields is allowed, not removing or renaming existing fields.** Please see the API documentation for more details: -[GetSettingsSchema](../../App-API.v1.json/paths/~1lc.verification.getsettingsschema.v2/get) +This endpoint is called by Trados to retrieve the schema related to any settings which the extension supports. **A note on schemas - once you define your settings schema for the extension, it should only be modified in a backwards compatible way, i.e. only adding of extra fields is allowed, not removing or renaming existing fields.** Please see the API documentation for more details: +[GetSettingsSchema](../../api/Extensibility-API.v1-fv.html#/operations/VerificationProviderGetSettingsSchema) + +Example: +```html +GET https://your-app.com/schemas +``` An example schema is shown below: ```json @@ -362,6 +298,7 @@ An example schema is shown below: }, "verificationResourcePackage": { "type": "object", + "properties": { "platformSettingType": { "type": "string", "enum": [ diff --git a/articles/Extensibility/docs/development/Webhooks.md b/articles/Extensibility/docs/development/Webhooks.md index 775f56b..38fdf6d 100644 --- a/articles/Extensibility/docs/development/Webhooks.md +++ b/articles/Extensibility/docs/development/Webhooks.md @@ -11,13 +11,16 @@ Apps can specify a list of webhooks that will be registered automatically when t Not all accounts have webhooks enabled. Installing of the app requiring webhooks will be disabled (grayed out in UI) on accounts that don't have webhooks enabled. +> [!WARNING] +> Webhooks require one of the following [scopes](./Trados-Cloud-API.md#scopes) to be delivered: `TENANT` or `TENANT_READ`. + ## Setup The required list of webhooks must be specified in the descriptor in the `webhooks` property. `webhooks` is an array of URLs and corresponding event types. You can specify a single URL for all webhook event types, or one URL for each event type, or any combination. This is done for maximum flexibility so you can decide if you want to ingest all webhooks through a single endpoint or have multiple endpoints maybe by event type or category, etc. -`url` can be an absolute URL or a path relative to `basePath`. +`url` can be an absolute URL or a path relative to `basePath`. Example of a `webhooks` property in the app descriptor: ```json @@ -26,7 +29,14 @@ Example of a `webhooks` property in the app descriptor: "webhooks": [ { "url": "/webhooks-endpoint", - "events": ["PROJECT.TASK.ACCEPTED", "PROJECT.TASK.CREATED"] + "evenTypes": [ + { + "eventType": "PROJECT.TASK.ACCEPTED" + }, + { + "eventType": "PROJECT.TASK.CREATED" + } + ] } ] ... @@ -42,6 +52,7 @@ The webhook payload description can be found in our [Trados Cloud Platform API d Webhooks are grouped in batches by callback URL, so it is likely that events from different tenants will be included in the same batch. It is the responsability of the app developer to handle the events from the batch accordingly to their `accountId` from the event body. +> [!NOTE] > **Note:** For *Webhook Authenticity*, ignore the described behavior in the above link and only consider the following chapter about *Signature Validation*. diff --git a/articles/Extensibility/docs/development/blueprints/Dot-Net-Migration-Blueprint.md b/articles/Extensibility/docs/development/blueprints/Dot-Net-Migration-Blueprint.md index 6b235b2..caa6a2d 100644 --- a/articles/Extensibility/docs/development/blueprints/Dot-Net-Migration-Blueprint.md +++ b/articles/Extensibility/docs/development/blueprints/Dot-Net-Migration-Blueprint.md @@ -12,6 +12,7 @@ There are a couple of main points to consider when doing the upgrade: First and foremost you'll need to change the `descriptorVersion` field to `1.4` in the descriptor JSON. This is the version that tells Trados Enterprise that your add-on has became an app and needs to be handled accordingly. +> [!NOTE] > In addition to `descriptorVersion`, the `version` field also needs to be updated to signal Trados Enterprise that there's a new descriptor available, as per usual. ### App Lifecycle Endpoint @@ -52,7 +53,7 @@ AppRegistrationEntity appRegistration = await _appRegistrationRepository.GetRegi ClientCredentialsEntity clientCredentials = appRegistration.ClientCredentials; ``` -For more details see the [Trados Cloud Platform API guide](../Language-Cloud-API.md#Credentials). +For more details see the [Trados Cloud Platform API guide](../Trados-Cloud-API.md#credentials). ## Summary diff --git a/articles/Extensibility/docs/development/blueprints/Java-Migration-Blueprint.md b/articles/Extensibility/docs/development/blueprints/Java-Migration-Blueprint.md index 28cce76..b8ac051 100644 --- a/articles/Extensibility/docs/development/blueprints/Java-Migration-Blueprint.md +++ b/articles/Extensibility/docs/development/blueprints/Java-Migration-Blueprint.md @@ -12,6 +12,7 @@ There are a couple of main points to consider when doing the upgrade: First and foremost you'll need to change the `descriptorVersion` field to `1.4` in the descriptor JSON. This is the version that tells Trados Enterprise that your add-on has became an app and needs to be handled accordingly. +> [!NOTE] > In addition to `descriptorVersion`, the `version` field also needs to be updated to signal Trados Enterprise that there's a new descriptor available, as per usual. ### App Lifecycle Endpoint @@ -52,7 +53,7 @@ AppRegistration entity = appRegistrationRepository.findFirst(); ClientCredentials clientCredentials = entity.getClientCredentials(); ``` -For more details see the [Trados Cloud Platform API guide](../Language-Cloud-API.md#Credentials). +For more details see the [Trados Cloud Platform API guide](../Trados-Cloud-API.md#credentials). ## Summary diff --git a/articles/Extensibility/docs/development/blueprints/Testing-with-Docker.md b/articles/Extensibility/docs/development/blueprints/Testing-with-Docker.md index 84215ef..c9e21fa 100644 --- a/articles/Extensibility/docs/development/blueprints/Testing-with-Docker.md +++ b/articles/Extensibility/docs/development/blueprints/Testing-with-Docker.md @@ -6,6 +6,7 @@ Before continuing here, we recommend reading the [basic testing guide](./Testing The only additional prerequisite to Ngrok and MongoDB (which we mention in the basic guide) is [Docker Desktop](https://www.docker.com/products/docker-desktop). You can find a setup guide [here](https://docs.docker.com/get-docker/). +> [!NOTE] > Please note that Docker Desktop is no longer free for large businesses. ## Docker files diff --git a/articles/Extensibility/docs/development/blueprints/Testing.md b/articles/Extensibility/docs/development/blueprints/Testing.md index f8f0840..f5bdfc1 100644 --- a/articles/Extensibility/docs/development/blueprints/Testing.md +++ b/articles/Extensibility/docs/development/blueprints/Testing.md @@ -77,6 +77,7 @@ You can find a quick guide on how to install and set up Ngrok [here](https://ngr 4. [Register](../../appManagement/Registering.md) the app in Trados using the URL provided by Ngrok. +> [!NOTE] > You can restart the app application anytime while running a Ngrok session, without having to start a new session. ## MongoDB diff --git a/articles/Extensibility/toc.yml b/articles/Extensibility/toc.yml index 37e3d1c..90afa12 100644 --- a/articles/Extensibility/toc.yml +++ b/articles/Extensibility/toc.yml @@ -101,4 +101,4 @@ - name: APIs items: - name: Extensibility API - href: api/Extensibility-API.v1.md \ No newline at end of file + href: api/Extensibility-API.v1-fv.html \ No newline at end of file