Skip to content

Commit

Permalink
Merge branch 'master' of github.com:formio/core into tt-dev
Browse files Browse the repository at this point in the history
  • Loading branch information
travist committed Jun 7, 2024
2 parents 7018209 + 73c7c1e commit 6b7a91b
Show file tree
Hide file tree
Showing 16 changed files with 153 additions and 68 deletions.
7 changes: 6 additions & 1 deletion Changelog.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
## [Unreleased: 2.1.0-rc.1]
## [Unreleased: 2.2.0-rc.1]
### Changed
- FIO-8177: fix unsetting empty array values
- FIO-8185: Fixing issues with EditGrid and DataGrid clearOnHide with Conditionally visible elements
Expand All @@ -19,6 +19,11 @@
- FIO-8128: adds includeAll flag to eachComponentData and eachComponentDataAsync
- FIO-7507: publish-dev-tag-to-npm
- FIO-8264: update validate required
- FIO-8336 fix validation on multiple values
- FIO-8037: added number component normalization
- FIO-8288: do not validate dates in textfield components with calendar widgets
- FIO-8254 fixed available values validation error for Select component
- FIO-8281: fixed sync validation error for select component with url data src


## 2.0.0-rc.24
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
"./process": "./lib/process/index.js",
"./types": "./lib/types/index.js",
"./experimental": "./lib/experimental/index.js",
"./dist/formio.core.min.js": "./dist/formio.core.min.js"
"./dist/formio.core.min.js": "./dist/formio.core.min.js",
"./error": "./lib/error/index.js"
},
"scripts": {
"test": "TEST=1 mocha -r ts-node/register -r tsconfig-paths/register -r mock-local-storage -r jsdom-global/register -b -t 0 'src/**/__tests__/*.test.ts'",
Expand Down
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
export * from './modules';
export * from './utils';
export * from './process/validation';
export * from './process/validation/rules';
export * from './process';
export * from './sdk';
export * from './types';
export * from './error';
4 changes: 2 additions & 2 deletions src/process/__tests__/process.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,7 @@ describe('Process Tests', () => {
type: "address",
providerOptions: {
params: {
key: "AIzaSyBNL2e4MnmyPj9zN7SVAe428nCSLP1X144",
key: "",
region: "",
autocompleteOptions: {
},
Expand Down Expand Up @@ -721,7 +721,7 @@ describe('Process Tests', () => {
type: "address",
providerOptions: {
params: {
key: "AIzaSyBNL2e4MnmyPj9zN7SVAe428nCSLP1X144",
key: "",
region: "",
autocompleteOptions: {
},
Expand Down
3 changes: 0 additions & 3 deletions src/process/validation/i18n/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,6 @@ export const EN_ERRORS = {
invalidValueProperty: 'Invalid Value Property',
mask: '{{field}} does not match the mask.',
valueIsNotAvailable: '{{ field }} is an invalid value.',
captchaTokenValidation: 'ReCAPTCHA: Token validation error',
captchaTokenNotSpecified: 'ReCAPTCHA: Token is not specified in submission',
captchaFailure: 'ReCaptcha: Response token not found',
time: '{{field}} is not a valid time.',
invalidDate: '{{field}} is not a valid date',
number: '{{field}} is not a valid number.'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
simpleSelectOptions,
} from './fixtures/components';
import { generateProcessorContext } from './fixtures/util';
import { validateAvailableItems } from '../validateAvailableItems';
import { validateAvailableItems, validateAvailableItemsSync } from '../validateAvailableItems';

it('Validating a component without the available items validation parameter will return null', async () => {
const component = simpleTextField;
Expand Down Expand Up @@ -103,6 +103,28 @@ it('Validating a simple static values select component with the available items
expect(result).to.equal(null);
});

it('Validating a simple static values select component with the available items validation parameter will return null if the selected item is valid and dataSrc is not specified', async () => {
const component: SelectComponent = {
...simpleSelectOptions,
dataSrc: undefined,
data: {
values: [
{ label: 'foo', value: 'foo' },
{ label: 'bar', value: 'bar' },
{ label: 'baz', value: 'baz' },
{ label: 'baz', value: 'baz' },
],
},
validate: { onlyAvailableItems: true },
};
const data = {
component: 'foo',
};
const context = generateProcessorContext(component, data);
const result = await validateAvailableItems(context);
expect(result).to.equal(null);
});

it('Validating a simple URL select component without the available items validation parameter will return null', async () => {
const component: SelectComponent = {
...simpleSelectOptions,
Expand All @@ -120,6 +142,43 @@ it('Validating a simple URL select component without the available items validat
expect(result).to.equal(null);
});

it('Validating a simple URL select component synchronously will return null', async () => {
const component: SelectComponent = {
...simpleSelectOptions,
dataSrc: 'url',
data: {
url: 'http://localhost:8080/numbers',
headers: [],
},
validate: { onlyAvailableItems: true },
};
const data = {
component: 'foo',
};
const context = generateProcessorContext(component, data);
const result = validateAvailableItemsSync(context);
expect(result).to.equal(null);
});

it('Validating a multiple URL select component synchronously will return null', async () => {
const component: SelectComponent = {
...simpleSelectOptions,
dataSrc: 'url',
data: {
url: 'http://localhost:8080/numbers',
headers: [],
},
multiple: true,
validate: { onlyAvailableItems: true },
};
const data = {
component: ['foo'],
};
const context = generateProcessorContext(component, data);
const result = validateAvailableItemsSync(context);
expect(result).to.equal(null);
});

it('Validating a simple JSON select component (string JSON) without the available items validation parameter will return null', async () => {
const component: SelectComponent = {
...simpleSelectOptions,
Expand Down
2 changes: 0 additions & 2 deletions src/process/validation/rules/databaseRules.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import { ValidationRuleInfo } from "types";
import { validateUniqueInfo } from "./validateUnique";
import { validateCaptchaInfo } from "./validateCaptcha";
import { validateResourceSelectValueInfo } from "./validateResourceSelectValue";

// These are the validations that require a database connection.
export const databaseRules: ValidationRuleInfo[] = [
validateUniqueInfo,
validateCaptchaInfo,
validateResourceSelectValueInfo
];
10 changes: 9 additions & 1 deletion src/process/validation/rules/validateAvailableItems.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { isEmpty } from 'lodash';
import { isEmpty, isUndefined} from 'lodash';
import { FieldError, ProcessorError } from 'error';
import { Evaluator } from 'utils';
import { RadioComponent, SelectComponent, RuleFn, RuleFnSync, ValidationContext } from 'types';
Expand Down Expand Up @@ -37,6 +37,9 @@ function mapStaticValues(values: { label: string; value: string }[]) {
}

async function getAvailableSelectValues(component: SelectComponent, context: ValidationContext) {
if (isUndefined(component.dataSrc) && component.data.hasOwnProperty('values')) {
component.dataSrc = 'values';
};
switch (component.dataSrc) {
case 'values':
if (Array.isArray(component.data.values)) {
Expand Down Expand Up @@ -107,6 +110,9 @@ async function getAvailableSelectValues(component: SelectComponent, context: Val
}

function getAvailableSelectValuesSync(component: SelectComponent, context: ValidationContext) {
if (isUndefined(component.dataSrc) && component.data.hasOwnProperty('values')) {
component.dataSrc = 'values';
};
switch (component.dataSrc) {
case 'values':
if (Array.isArray(component.data?.values)) {
Expand Down Expand Up @@ -156,6 +162,8 @@ function getAvailableSelectValuesSync(component: SelectComponent, context: Valid
'validate:validateAvailableItems'
);
}
case 'url':
return null;
default:
throw new ProcessorError(
`Failed to validate available values in select component '${component.key}': data source ${component.dataSrc} is not valid}`,
Expand Down
42 changes: 0 additions & 42 deletions src/process/validation/rules/validateCaptcha.ts

This file was deleted.

14 changes: 7 additions & 7 deletions src/process/validation/rules/validateRequired.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ import {
DayComponent
} from 'types';
import { isEmptyObject } from '../util';
<<<<<<< HEAD
import { isComponentNestedDataType } from 'utils/formUtil'
=======
import { isComponentNestedDataType } from 'utils/formUtil';
>>>>>>> 73c7c1ec076f88b1d3ef940f41422f04a3aaaafa
import { ProcessorInfo } from 'types/process/ProcessorInfo';

const isAddressComponent = (component: any): component is AddressComponent => {
Expand All @@ -29,11 +33,7 @@ const isComponentThatCannotHaveFalseValue = (component: any): boolean => {
return component.type === 'checkbox' || component.type === 'selectboxes'
}

const valueIsPresent = (
value: any,
considerFalseTruthy: boolean,
isNestedDataType?: boolean
): boolean => {
const valueIsPresent = (value: any, considerFalseTruthy: boolean, isNestedDatatype?: boolean): boolean => {
// Evaluate for 3 out of 6 falsy values ("", null, undefined), don't check for 0
// and only check for false under certain conditions
if (value === null || value === undefined || value === "" || (!considerFalseTruthy && value === false)) {
Expand All @@ -48,8 +48,8 @@ const valueIsPresent = (
return false;
}
// Recursively evaluate
else if (typeof value === 'object' && !isNestedDataType) {
return Object.values(value).some((val) => valueIsPresent(val, considerFalseTruthy, isNestedDataType));
else if (typeof value === 'object' && !isNestedDatatype) {
return Object.values(value).some((val) => valueIsPresent(val, considerFalseTruthy, isNestedDatatype));
}
return true;
}
Expand Down
6 changes: 3 additions & 3 deletions src/sdk/Formio.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1566,13 +1566,13 @@ export class Formio {
if (!response.ok) {
if (response.status === 440) {
Formio.setToken(null, opts);
Formio.events.emit('formio.sessionExpired', response.body);
Formio.events.emit('formio.sessionExpired', response.body || response);
}
else if (response.status === 401) {
Formio.events.emit('formio.unauthorized', response.body);
Formio.events.emit('formio.unauthorized', response.body || response);
}
else if (response.status === 416) {
Formio.events.emit('formio.rangeIsNotSatisfiable', response.body);
Formio.events.emit('formio.rangeIsNotSatisfiable', response.body || response);
}
else if (response.status === 504) {
return Promise.reject(new Error('Network request failed'));
Expand Down
56 changes: 56 additions & 0 deletions src/sdk/__tests__/Formio.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2173,4 +2173,60 @@ describe('Formio.js Tests', () => {
assert.ok(plugin.wrapStaticRequestPromise.calledOnce, 'wrapStaticRequestPromise should be called once');
});
});
describe('Formio.request', () => {
it('should emit a formio.sessionExpired event when the response status is 440 and the response object should exist', (done) => {
let eventFired = false
let responseNotUndefined = false
setTimeout(()=>{
assert(eventFired, 'formio.sessionExpired event was not called');
assert(responseNotUndefined, 'a response was not passed into the event');
fetchMock.restore()
done()
},200)
Formio.events.on('formio.sessionExpired', (response: any) => {
eventFired = true
if (response){
responseNotUndefined = true
}
})
fetchMock.mock('http://localhost:8080/test', 440);
Formio.request('http://localhost:8080/test');
});
it('should emit a formio.unauthorized event when the response status is 401', (done) => {
let eventFired = false
let responseNotUndefined = false
setTimeout(()=>{
assert(eventFired, 'formio.unauthorized event was not called');
assert(responseNotUndefined, 'a response was not passed into the event');
fetchMock.restore()
done()
},200);
Formio.events.on('formio.unauthorized', (response: any) => {
eventFired = true;
if (response){
responseNotUndefined = true;
}
})
fetchMock.mock('http://localhost:8080/test', 401);
Formio.request('http://localhost:8080/test');
});
it('should emit a formio.rangeIsNotSatisfiable event when the response status is 416', (done) => {
let eventFired = false;
let responseNotUndefined = false;
setTimeout(()=>{
assert(eventFired, 'formio.rangeIsNotSatisfiable event was not called');
assert(responseNotUndefined, 'a response was not passed into the event');
fetchMock.restore()
done()
},200);
Formio.events.on('formio.rangeIsNotSatisfiable', (response) => {
eventFired = true;
if (response) {
responseNotUndefined = true;
}
})
fetchMock.mock('http://localhost:8080/test', 416);
Formio.request('http://localhost:8080/test');
});
});
});
2 changes: 1 addition & 1 deletion src/types/Component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,7 @@ type StaticValuesSelectData = {
data: {
values: { label: string; value: string }[];
};
dataSrc: 'values';
dataSrc?: undefined | 'values';
};

type JsonValuesSelectData = {
Expand Down
5 changes: 3 additions & 2 deletions src/types/project/settings/ProjectSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
ProjectFileStorageConfig,
ProjectGoogleDriveConfig,
ProjectKickboxConfig,
ProjectReCaptchaConfig,
ProjectCaptchaConfig,
ProjectSQLConnectorConfig,
} from './integrations';

Expand Down Expand Up @@ -39,7 +39,8 @@ export type ProjectSettings = {

// Integrations
email?: ProjectEmailConfig;
recaptcha?: ProjectReCaptchaConfig;
captcha?: ProjectCaptchaConfig;
recaptcha?: ProjectCaptchaConfig;
esign?: ProjectESignConfig;
google?: ProjectGoogleDriveConfig;
kickbox?: ProjectKickboxConfig;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export type ProjectReCaptchaConfig = {
export type ProjectCaptchaConfig = {
siteKey: string;
secretKey: string;
};
2 changes: 1 addition & 1 deletion src/types/project/settings/integrations/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ export * from './dataConnections';
export * from './email';
export * from './eSign';
export * from './fileStorage';
export * from './reCaptcha';
export * from './captcha';

0 comments on commit 6b7a91b

Please sign in to comment.