Skip to content

Commit

Permalink
Merge branch 'develop' into record-form-calculated-fields
Browse files Browse the repository at this point in the history
  • Loading branch information
awensaunders authored Sep 24, 2024
2 parents 29613e8 + 375cc8c commit 42b84b4
Show file tree
Hide file tree
Showing 89 changed files with 18,358 additions and 5,991 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/app.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ on:
branches:
- main
- 'release-*'
- develop_react_upgrade
- develop
workflow_dispatch:


Expand Down
3 changes: 2 additions & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ gem 'will_paginate', '~> 4.0' # Paginates ActiveRecord models TODO: Th
gem 'write_xlsx', '~> 1.11' # Exports XLSX

group :development, :test do
gem 'bundler-audit', '~> 0.8'
gem 'bundler-audit', '~> 0.9'
gem 'ci_reporter', '~> 2.0'
gem 'factory_bot', '~> 5.0'
gem 'foreman'
Expand All @@ -81,6 +81,7 @@ group :development, :test do
gem 'rspec-rails', '~> 6.0'
gem 'rubocop', '~> 1.54'
gem 'rubocop-performance', '~> 1.18'
gem 'ruby-lsp', '~> 0.17'
gem 'ruby-prof', '~> 0.17'
gem 'simplecov', '~> 0.18'
# TODO: Latest version (1.2.5) of this conflicts with sunspot gem. Upgrade when we upgrade sunspot
Expand Down
13 changes: 12 additions & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ GEM
listen (3.8.0)
rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10)
logger (1.6.1)
loofah (2.22.0)
crass (~> 1.0.2)
nokogiri (>= 1.12.0)
Expand Down Expand Up @@ -235,6 +236,7 @@ GEM
ttfunk (~> 1.7)
prawn-table (0.2.2)
prawn (>= 1.3.0, < 3.0.0)
prism (1.0.0)
pry (0.14.2)
coderay (~> 1.1)
method_source (~> 1.0)
Expand Down Expand Up @@ -297,6 +299,8 @@ GEM
ffi (~> 1.0)
rbnacl (7.1.1)
ffi
rbs (3.5.3)
logger
regexp_parser (2.8.1)
responders (3.1.1)
actionpack (>= 5.2)
Expand Down Expand Up @@ -355,6 +359,11 @@ GEM
rubocop-performance (1.20.2)
rubocop (>= 1.48.1, < 2.0)
rubocop-ast (>= 1.30.0, < 2.0)
ruby-lsp (0.17.17)
language_server-protocol (~> 3.17.0)
prism (~> 1.0)
rbs (>= 3, < 4)
sorbet-runtime (>= 0.5.10782)
ruby-ole (1.2.12.2)
ruby-prof (0.18.0)
ruby-progressbar (1.13.0)
Expand All @@ -369,6 +378,7 @@ GEM
simplecov_json_formatter (0.1.4)
simpleidn (0.2.1)
unf (~> 0.1.4)
sorbet-runtime (0.5.11566)
spreadsheet (1.3.0)
ruby-ole
sprockets (4.2.1)
Expand Down Expand Up @@ -429,7 +439,7 @@ DEPENDENCIES
activerecord-nulldb-adapter
aws-sdk-s3 (~> 1.130)
azure-storage-blob (~> 1.1)
bundler-audit (~> 0.8)
bundler-audit (~> 0.9)
cancancan (~> 3.5)
ci_reporter (~> 2.0)
csv-safe (~> 3.2)
Expand Down Expand Up @@ -478,6 +488,7 @@ DEPENDENCIES
rspec-rails (~> 6.0)
rubocop (~> 1.54)
rubocop-performance (~> 1.18)
ruby-lsp (~> 0.17)
ruby-prof (~> 0.17)
rubyzip (~> 2.3)
simplecov (~> 0.18)
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/api/v2/children_incidents_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def update_bulk
end

def permit_fields
@permitted_field_names = PermittedFieldService.new(current_user, Incident).permitted_field_names
@permitted_field_names = PermittedFieldService.new(current_user, Incident).permitted_field_names(module_unique_id)
end

def select_fields
Expand Down
19 changes: 15 additions & 4 deletions app/controllers/api/v2/concerns/record.rb
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ def json_validation_service
return @json_validation_service if @json_validation_service

permitted_fields = @permitted_form_fields_service.permitted_fields(
authorized_roles, model_class.parent_form, write?
authorized_roles, model_class.parent_form, module_unique_id, write?
)
action_fields = @permitted_field_service.permitted_fields_schema
@json_validation_service = RecordJsonValidatorService.new(fields: permitted_fields,
Expand All @@ -95,7 +95,9 @@ def authorized_roles
end

def permit_fields
@permitted_field_names = @permitted_field_service.permitted_field_names(write?, update?, authorized_roles)
@permitted_field_names = @permitted_field_service.permitted_field_names(
module_unique_id, write?, update?, authorized_roles
)
end

def select_fields_for_show
Expand Down Expand Up @@ -139,7 +141,10 @@ def instantiate_app_services
@record_data_service = RecordDataService.new
@permitted_form_fields_service = PermittedFormFieldsService.instance
@permitted_field_service = PermittedFieldService.new(
current_user, model_class, params[:record_action], params[:id_search], @permitted_form_fields_service
current_user,
model_class,
@permitted_form_fields_service,
{ action_name: params[:record_action], id_search: params[:id_search] }
)
end

Expand All @@ -155,6 +160,12 @@ def display_permitted_forms
@display_permitted_forms = false
end

def module_unique_id
return @record.module_id if @record.present?

params.dig(:data, :module_id)
end

private

def write?
Expand Down Expand Up @@ -188,7 +199,7 @@ def permitted_index_params(params)
end

def strip_location_prefix(param)
return param.delete_prefix('loc:') if param.start_with?('loc:')
return Field.remove_location_parts(param) if Field.location_prefix?(param)

param
end
Expand Down
6 changes: 6 additions & 0 deletions app/controllers/api/v2/record_resource_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@ def record_data_service
@record_data_service = RecordDataService.new
end

def module_unique_id
return @record.module_id if @record.present?

params.dig(:data, :module_id)
end

private

def record_updated_fields(record)
Expand Down
6 changes: 6 additions & 0 deletions app/javascript/components/change-logs/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,9 @@
.detailName {
font-style: italic;
}

@media (min-width:600px) {
.container {
min-width: 28em;
}
}
2 changes: 2 additions & 0 deletions app/javascript/components/i18n/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ export const getLocaleDir = locale => {
case "ar-IQ":
case "fa-AF":
case "ps-AF":
case "aeb":
case "ar-SY":
return ORIENTATION.rtl;
default:
return ORIENTATION.ltr;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,3 +100,7 @@ export const saveReferral = (recordId, recordType, body, message) => {
}
};
};

export const resetReferralSuccess = () => ({
type: actions.REFER_USER_SUCCESS_FINISHED
});
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ describe("<Transitions /> - Action Creators", () => {
delete creators.fetchTransitionData;
delete creators.fetchReferralUsers;
delete creators.saveReferral;
delete creators.resetReferralSuccess;

expect(creators).to.deep.equal({});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ const actions = namespaceActions(NAMESPACE, [
"TRANSFER_USERS_FETCH_SUCCESS",
"TRANSFER_USER_FAILURE",
"TRANSFER_USER_STARTED",
"TRANSFER_USER_SUCCESS"
"TRANSFER_USER_SUCCESS",
"REFER_USER_SUCCESS_FINISHED"
]);

export default {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ describe("<Transitions /> - Actions", () => {
"TRANSFER_USER_SUCCESS",
"USERS_ASSIGN_TO",
"USERS_REFER_TO",
"USERS_TRANSFER_TO"
"USERS_TRANSFER_TO",
"REFER_USER_SUCCESS_FINISHED"
].forEach(property => {
expect(cloneActions).to.have.property(property);
expect(cloneActions[property]).to.be.a("string");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ export default (state = DEFAULT_STATE, { type, payload }) => {
.update("data", data => {
return data.unshift(TransitionRecord(payload.data));
});
case Actions.REFER_USER_FINISHED:
case Actions.REFER_USER_SUCCESS_FINISHED:
return state.setIn(["referral", "success"], false);
default:
return state;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import Form, { OPTION_TYPES } from "../../../form";
import { useI18n } from "../../../i18n";
import { RECORD_TYPES } from "../../../../config";
import { getRecordForms, getServiceToRefer } from "../../../record-form/selectors";
import { saveReferral } from "../action-creators";
import { resetReferralSuccess, saveReferral } from "../action-creators";
import { getErrorsByTransitionType } from "../selectors";
import { setServiceToRefer } from "../../../record-form/action-creators";
import PdfExporter from "../../../pdf-exporter";
Expand Down Expand Up @@ -107,6 +107,7 @@ function Referrals({
useEffect(() => {
if (submittedSuccessfully && formValues.remote) {
pdfExporterRef.current.savePdf({ setPending, close: handleClose, values: formValues });
dispatch(resetReferralSuccess());
}
}, [submittedSuccessfully]);

Expand Down
16 changes: 16 additions & 0 deletions app/javascript/components/record-form/form/components/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,19 @@ export const buildLabelSync = (syncedStatus, syncedAt, i18n) => {
return i18n.t(`sync_record.last`, { date_time: lastDate });
}
};

export function buildErrorOutput(formErrors, field, locale) {
const fieldError = formErrors[field.get("name")];

if (Array.isArray(fieldError)) {
if (fieldError.every(error => typeof error === "object")) {
return formErrors[field.get("name")]
.map((error, index) => `(${index + 1}) ${field.getIn(["display_name", locale])}: ${Object.values(error)}`)
.join("\n");
}

return fieldError.join("");
}

return fieldError;
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { getValidationErrors } from "../../selectors";
import { setValidationErrors } from "../../action-creators";
import { useMemoizedSelector } from "../../../../libs";

import { removeEmptyArrays } from "./utils";
import { buildErrorOutput, removeEmptyArrays } from "./utils";
import { VALIDATION_ERRORS_NAME } from "./constants";

function ValidationErrors({ formErrors, forms, submitCount }) {
Expand All @@ -30,7 +30,7 @@ function ValidationErrors({ formErrors, forms, submitCount }) {
const formsWithErrors = forms.filter(value => {
return value
.get("fields", fromJS([]))
.filter(field => !field.get("disabled"))
.filter(field => !field.get("disabled") && field.get("visible"))
.map(field => field.get("name"))
.some(fieldName => fieldNames.includes(fieldName));
});
Expand All @@ -45,9 +45,7 @@ function ValidationErrors({ formErrors, forms, submitCount }) {
.get("fields")
.filter(field => fieldNames.includes(field.get("name")))
.map(field => ({
[field.get("name")]: Array.isArray(formErrors[field.get("name")])
? formErrors[field.get("name")].join("")
: formErrors[field.get("name")]
[field.get("name")]: buildErrorOutput(formErrors, field, i18n.locale)
}))
.reduce((acc, subCurrent) => ({ ...acc, ...subCurrent }), {})
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ function SelectFieldContainer({

const fieldProps = {
id: name,
error: error && touched ? error : null,
error: error || null,
name,
isDisabled: !filteredOptions || mode.isShow || disabled || apiSelectOptionsOffline,
helperText: inputHelperText(),
Expand All @@ -196,7 +196,7 @@ function SelectFieldContainer({
multiple: multiSelect,
TextFieldProps: {
label,
error: error && touched,
error,
InputProps
},
onOpen: () => {
Expand Down
2 changes: 1 addition & 1 deletion app/javascript/components/record-form/form/record-form.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ function RecordForm({
return (
<>
<Formik
initialValues={initialValues}
initialValues={{ ...initialValues }}
validationSchema={validationSchema}
validateOnBlur={false}
validateOnChange={false}
Expand Down
34 changes: 25 additions & 9 deletions app/javascript/components/record-form/form/validations.js
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ export const fieldValidations = (field, { i18n, online = false }) => {
validations[name] = bool().oneOf([true], requiredMessage);
break;
case type === SELECT_FIELD && multiSelect:
validations[name] = array().min(1, requiredMessage);
validations[name] = array();
break;
default:
validations[name] = (validations[name] || string()).nullable();
Expand All @@ -162,14 +162,26 @@ export const fieldValidations = (field, { i18n, online = false }) => {
[relatedField]: relatedFieldValue
});
},
then:
type !== TALLY_FIELD
? schema.required(requiredMessage)
: currentSchema =>
currentSchema.test(name, requiredMessage, value => {
return compact(Object.values(value)).length > 0;
}),
otherwise: type !== TALLY_FIELD ? schema.notRequired() : currentSchema => currentSchema.notRequired()
then: $schema => {
if (type === SELECT_FIELD && multiSelect) {
return $schema.min(1, requiredMessage).default([]);
}

if (type === TALLY_FIELD) {
return $schema.test(name, requiredMessage, value => {
return compact(Object.values(value)).length > 0;
});
}

return $schema.required(requiredMessage);
},
otherwise: $schema => {
if (type === SELECT_FIELD && multiSelect) {
return $schema.min(0);
}

return $schema.notRequired();
}
});
} else {
if (!([TICK_FIELD, SELECT_FIELD, TALLY_FIELD].includes(type) || (type !== SELECT_FIELD && multiSelect))) {
Expand All @@ -180,6 +192,10 @@ export const fieldValidations = (field, { i18n, online = false }) => {
validations[name] = schema.required(requiredMessage);
}

if (type === SELECT_FIELD && multiSelect) {
validations[name] = schema.min(1, requiredMessage).required(requiredMessage).default([]);
}

if (type === TALLY_FIELD) {
validations[name] = schema.test(name, requiredMessage, value => {
return compact(Object.values(value)).length > 0;
Expand Down
Loading

0 comments on commit 42b84b4

Please sign in to comment.