Only one marker for submission
') .openOn(map); } else { @@ -55,7 +53,8 @@ class MapService { } initializeMap(options: MapServiceOptions) { - let { mapContainer, center, drawOptions, form, defaultZoom, readOnlyMap } = options; + let { mapContainer, center, drawOptions, form, defaultZoom, readOnlyMap } = + options; if (drawOptions.rectangle) { drawOptions.rectangle.showArea = false; } @@ -72,7 +71,7 @@ class MapService { map.addLayer(drawnItems); // Add Drawing Controllers - if(!readOnlyMap){ + if (!readOnlyMap) { let drawControl = new L.Control.Draw({ draw: drawOptions, edit: { @@ -82,20 +81,20 @@ class MapService { map.addControl(drawControl); } - //Checking to see if the map should be interactable - const componentEditNode = document.getElementsByClassName(COMPONENT_EDIT_CLASS) + // Checking to see if the map should be interactable + const componentEditNode = + document.getElementsByClassName(COMPONENT_EDIT_CLASS); if (form) { if (form[0]?.classList.contains('formbuilder')) { - map.dragging.disable(); - map.scrollWheelZoom.disable(); - if (this.hasChildNode(componentEditNode[0], mapContainer)) { - map.dragging.enable(); - map.scrollWheelZoom.enable(); - } + map.dragging.disable(); + map.scrollWheelZoom.disable(); + if (this.hasChildNode(componentEditNode[0], mapContainer)) { + map.dragging.enable(); + map.scrollWheelZoom.enable(); + } } - } + } - // Attach Controls to map return { map, drawnItems }; } @@ -132,7 +131,6 @@ class MapService { loadDrawnItems(items: any) { const { drawnItems } = this; - // Ensure drawnItems is defined before attempting to clear layers if (!drawnItems) { console.error('drawnItems is undefined'); return; @@ -140,7 +138,6 @@ class MapService { drawnItems.clearLayers(); - // Check if items is an array if (!Array.isArray(items)) { items = [items]; } @@ -172,12 +169,11 @@ class MapService { } for (let i = 0; i < parent?.childNodes?.length; i++) { if (this.hasChildNode(parent.childNodes[i], targetNode)) { - return true + return true; } } return false; } - } export default MapService; diff --git a/components/src/components/SimpleBCAddress/Component.ts b/components/src/components/SimpleBCAddress/Component.ts index b9b03ccce..df0fb9c8c 100644 --- a/components/src/components/SimpleBCAddress/Component.ts +++ b/components/src/components/SimpleBCAddress/Component.ts @@ -1,6 +1,5 @@ - /* tslint:disable */ -import {Components} from 'formiojs'; +import { Components } from 'formiojs'; import { Constants } from '../Common/Constants'; import editForm from './Component.form'; import _ from 'lodash'; @@ -16,83 +15,83 @@ const ID = 'simplebcaddress'; const DISPLAY = 'Simple BC Address'; export default class Component extends (ParentComponent as any) { - static schema(...extend) { - - return ParentComponent.schema({ - label: DISPLAY, - type: ID, - key: ID, - provider: 'custom', - providerOptions: { - queryProperty: 'addressString', - url:import.meta.env.VITE_CHEFS_ADVANCE_GEO_ADDRESS_APIURL}, - - queryParameters:{"echo": false, - "brief": true, - "minScore": 55, - "onlyCivic": true, - "maxResults": 15, - "autocomplete": true, - "matchAccuracy": 100, - "matchPrecision": "occupant, unit, site, civic_number, intersection, block, street, locality, province", - "precisionPoints": 100,} - - }, ...extend); - } - - static get builderInfo() { - return { - title: DISPLAY, - group: 'advanced', - icon: 'address-book', - weight: 90, - documentation: Constants.DEFAULT_HELP_LINK, - schema: Component.schema(), - - }; - } - - public static editForm = editForm; - - async init(){ - super.init(); - } - - async attach(element) { - super.attach(element); - try { - - let { - providerOptions, - queryParameters, - - } = this.component; - - if(providerOptions) { - if(!providerOptions.params) { - providerOptions["params"]={} - } - if(queryParameters) { - providerOptions.params ={...providerOptions.params,...queryParameters} - } - } - - } catch (err) { - console.log(`This error is from Custom BC Address component in form.io: Failed to acquire configuration: ${err.message}`); + static schema(...extend) { + return ParentComponent.schema( + { + label: DISPLAY, + type: ID, + key: ID, + provider: 'custom', + providerOptions: { + queryProperty: 'addressString', + url: import.meta.env.VITE_CHEFS_GEO_ADDRESS_APIURL, + }, + + queryParameters: { + echo: false, + brief: true, + minScore: 55, + onlyCivic: true, + maxResults: 15, + autocomplete: true, + matchAccuracy: 100, + matchPrecision: + 'occupant, unit, site, civic_number, intersection, block, street, locality, province', + precisionPoints: 100, + }, + }, + ...extend + ); + } + + static get builderInfo() { + return { + title: DISPLAY, + group: 'advanced', + icon: 'address-book', + weight: 90, + documentation: Constants.DEFAULT_HELP_LINK, + schema: Component.schema(), + }; + } + + public static editForm = editForm; + + async init() { + super.init(); + } + + async attach(element) { + super.attach(element); + try { + let { providerOptions, queryParameters } = this.component; + + if (providerOptions) { + if (!providerOptions.params) { + providerOptions['params'] = {}; + } + if (queryParameters) { + providerOptions.params = { + ...providerOptions.params, + ...queryParameters, + }; } + } + } catch (err) { + console.log( + `This error is from Custom BC Address component in form.io: Failed to acquire configuration: ${err.message}` + ); } + } - mergeSchema(component = {}) { - - let components = component['components']; + mergeSchema(component = {}) { + let components = component['components']; - if (components) { - return _.omit(component, 'components'); - } - - return component; + if (components) { + return _.omit(component, 'components'); } - + return component; + } } export {}; diff --git a/docs/chefs-external-api-configuration.md b/docs/chefs-external-api-configuration.md index 12c421214..fbf46df5b 100644 --- a/docs/chefs-external-api-configuration.md +++ b/docs/chefs-external-api-configuration.md @@ -78,7 +78,7 @@ The user information initially comes from the user's token, as such the values f ## Configuring Form Component -For this example, we assume populating a drop down/select component... +For this example, we assume populating a drop-down/select component... **Data Source Type** = URL @@ -92,7 +92,7 @@ For this example, we assume populating a drop down/select component... | X-CHEFS-EXTERNAL-API-NAME | example-api - External API.name | | X-CHEFS-EXTERNAL-API-PATH | optional - add this value to External API.endpointUrl | -**Value Property**, **Item Template** and all other configuration is up to the Form Designer. +**Value Property**, **Item Template** and all other configurations are up to the Form Designer. `sessionStorage.getItem('X-CHEFS-PROXY-DATA')` is the User Info object in encrypted form that only CHEFS can decrypt. This is generated and stored on the form load. A call is made to the CHEFS backend using the current user's token (similar to fetching the form schema for rendering the form) and CHEFS encrypts the information. This prevents malicious form designers from having access to the user token but allows the form designer to provide context for their External API. @@ -101,3 +101,18 @@ The `sessionStorage` is cleared when the user navigates away from the form. The component will call the CHEFS proxy `{chefs host}/app/api/v1/proxy/external` with the headers, the proxy can decrypt the `X-CHEFS-PROXY-DATA` and formulate the call according to the External API configuration. It is expected that the External API endpoint is a `GET`. + +## HTTP Responses and errors + +Since formio components will make calls during the form design and configuration of the formio components (ie when the Datasource is URL and the URL has been populated), there will be many failed attempts calling the proxy. The most common failures will happen when the headers have not been added to the component configuration, or the `X-CHEFS-EXTERNAL-API-NAME` header has been set but the External API has not been configured. + +The following table will help you understand the HTTP statuses returned when calling `/api/v1/proxy/external`. + +| Http Status | Meaning | +| ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| 400 | Generally, the formio component has not been completely configured (missing headers) or the External API has not been configured. | +| 407 | The External API is configured and exists but has not been approved. | +| 502 | Call has gone through the CHEFS proxy but failed on the external server (ie 404 not found on your server). Check the message for information on the underlying HTTP Error. | +| 500 | Unexpected CHEFS server error. | + +A successful call through the CHEFS proxy to your External API will return the status code from your External API. diff --git a/openshift/app.dc.yaml b/openshift/app.dc.yaml index 31f9b42dc..198f0e966 100644 --- a/openshift/app.dc.yaml +++ b/openshift/app.dc.yaml @@ -166,7 +166,6 @@ objects: secretKeyRef: key: email name: "${APP_NAME}-contact-secret" - - name: VITE_HOWTOURL valueFrom: secretKeyRef: @@ -177,16 +176,6 @@ objects: secretKeyRef: key: chefstourvideourl name: "${APP_NAME}-landingpagevideourls-secret" - - name: VITE_CHEFS_GEO_ADDRESS_APIURL - valueFrom: - secretKeyRef: - key: chefsgeoaddressapiurl - name: "${APP_NAME}-bcgeoaddress-secret" - - name: VITE_CHEFS_ADVANCE_GEO_ADDRESS_APIURL - valueFrom: - secretKeyRef: - key: chefsadvancegeoaddressapiurl - name: "${APP_NAME}-bcgeoaddress-secret" - name: VITE_BC_GEO_ADDRESS_APIURL valueFrom: secretKeyRef: