Skip to content

Commit

Permalink
Merge pull request #23449 from department-of-veterans-affairs/release…
Browse files Browse the repository at this point in the history
…/FY25Q1.2.2

Release R3.2.2
  • Loading branch information
craigrva authored Nov 7, 2024
2 parents 6ab824e + 5e38f6f commit 57e0f68
Show file tree
Hide file tree
Showing 20 changed files with 86 additions and 156 deletions.
10 changes: 0 additions & 10 deletions app/models/request_issue.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,6 @@ class RequestIssue < CaseflowRecord
# don't need to try as frequently as default 3 hours
DEFAULT_REQUIRES_PROCESSING_RETRY_WINDOW_HOURS = 12

# contested issue description pattern
DESC_ALLOWED_CHARACTERS_REGEX = /\A[a-zA-Z0-9\s.\-_|\/\\@#~=%,;?!'"`():$+*^\[\]&><{}]+\z/.freeze

belongs_to :decision_review, polymorphic: true
belongs_to :end_product_establishment, dependent: :destroy
has_many :request_decision_issues, dependent: :destroy
Expand All @@ -46,13 +43,6 @@ class RequestIssue < CaseflowRecord
# enum is symbol, but validates requires a string
validates :ineligible_reason, exclusion: { in: ["untimely"] }, if: proc { |reqi| reqi.untimely_exemption }

# only allow specified characters for description
validates(
:contested_issue_description,
format: { with: DESC_ALLOWED_CHARACTERS_REGEX, message: "invalid characters used" },
allow_blank: true
)

enum ineligible_reason: {
duplicate_of_nonrating_issue_in_active_review: "duplicate_of_nonrating_issue_in_active_review",
duplicate_of_rating_issue_in_active_review: "duplicate_of_rating_issue_in_active_review",
Expand Down
6 changes: 3 additions & 3 deletions app/models/vacols/aoj_case_docket.rb
Original file line number Diff line number Diff line change
Expand Up @@ -555,7 +555,7 @@ def self.distribute_priority_appeals(judge, genpop, limit, dry_run = false)
aoj_aod_affinity_lever_value == Constants.ACD_LEVERS.infinite
<<-SQL
#{SELECT_PRIORITY_APPEALS_ORDER_BY_BFD19}
where (((VLJ = ? or #{ineligible_judges_sattyid_cache}) and 1 = ?) or (VLJ is null and 1 = ?)
where ((((VLJ = ? or #{ineligible_judges_sattyid_cache}) and 1 = ?) or (VLJ is null and 1 = ?))
and (PREV_TYPE_ACTION = '7' or AOD = '1')
or ((PREV_DECIDING_JUDGE = ? or #{ineligible_judges_sattyid_cache(true)}
or #{vacols_judges_with_exclude_appeals_from_affinity(excluded_judges_attorney_ids)})
Expand All @@ -564,14 +564,14 @@ def self.distribute_priority_appeals(judge, genpop, limit, dry_run = false)
elsif use_by_docket_date?
<<-SQL
#{SELECT_PRIORITY_APPEALS_ORDER_BY_BFD19}
where ((VLJ = ? or #{ineligible_judges_sattyid_cache}) and 1 = ?) or (VLJ is null and 1 = ?)
where (((VLJ = ? or #{ineligible_judges_sattyid_cache}) and 1 = ?) or (VLJ is null and 1 = ?))
and (PREV_TYPE_ACTION = '7' or AOD = '1')
or #{priority_aoj_cdl_query} or #{priority_cdl_aoj_aod_query}
SQL
else
<<-SQL
#{SELECT_PRIORITY_APPEALS}
where ((VLJ = ? or #{ineligible_judges_sattyid_cache}) and 1 = ?) or (VLJ is null and 1 = ?)
where (((VLJ = ? or #{ineligible_judges_sattyid_cache}) and 1 = ?) or (VLJ is null and 1 = ?))
and (PREV_TYPE_ACTION = '7' or AOD = '1')
or #{priority_aoj_cdl_query} or #{priority_cdl_aoj_aod_query}
SQL
Expand Down
1 change: 1 addition & 0 deletions client/app/components/CopyTextButton.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export default {
decorators: [],
args: {
text: 'Lorem ipsum',
textToCopy: 'Lorem ipsum',
label: 'accessible label text'
}
};
Expand Down
2 changes: 1 addition & 1 deletion client/app/components/TitleDetailsSubheader.stories.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ Subheader that can be used to display an overview of data for a given page.
},
{
label: "Column 3",
value: <CopyTextButton text="12345678" />
value: <CopyTextButton text="12345678" textToCopy="12345678"/>
}
]}
/>
Expand Down
2 changes: 1 addition & 1 deletion client/app/hearings/components/details/DetailsHeader.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ export const DetailsHeader = (
{`${veteranFirstName} ${veteranLastName}'s Hearing Details`}
</h1>
<div>
Veteran ID: <CopyTextButton text={veteranFileNumber} label="Veteran ID" />
Veteran ID: <CopyTextButton text={veteranFileNumber} textToCopy={veteranFileNumber} label="Veteran ID" />
</div>
<div style={{ display: 'inline-flex' }}>
<MstBadge appeal={hearing} />
Expand Down
17 changes: 4 additions & 13 deletions client/app/intake/components/NonratingRequestIssueModal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import { formatDateStr } from 'app/util/DateUtil';
import { VHA_PRE_DOCKET_ISSUE_BANNER, VHA_ADMIN_DECISION_DATE_REQUIRED_BANNER } from 'app/../COPY';
import Checkbox from '../../components/Checkbox';
import { generateSkipButton } from '../util/buttonUtils';
import descriptionValidator from '../../util/validators/DescriptionValidator';

const NO_MATCH_TEXT = 'None of these match';

Expand Down Expand Up @@ -56,8 +55,7 @@ class NonratingRequestIssueModal extends React.Component {
isTaskInProgress: props.intakeData.taskInProgress,
mstChecked: false,
pactChecked: false,
dateError: '',
descriptionError: ''
dateError: ''
};
}

Expand Down Expand Up @@ -103,8 +101,7 @@ class NonratingRequestIssueModal extends React.Component {

descriptionOnChange = (value) => {
this.setState({
description: value,
descriptionError: descriptionValidator()(value)
description: value
});
};

Expand Down Expand Up @@ -232,7 +229,7 @@ class NonratingRequestIssueModal extends React.Component {
classNames: ['usa-button', 'add-issue'],
name: this.props.submitText,
onClick: this.onAddIssue,
disabled: this.requiredFieldsMissing() || Boolean(this.state.dateError) || Boolean(this.state.descriptionError)
disabled: this.requiredFieldsMissing() || Boolean(this.state.dateError)
}
];

Expand Down Expand Up @@ -317,13 +314,7 @@ class NonratingRequestIssueModal extends React.Component {
/>
</div>

<TextField
name="Issue description"
strongLabel
value={description}
onChange={this.descriptionOnChange}
errorMessage={this.state.descriptionError}
/>
<TextField name="Issue description" strongLabel value={description} onChange={this.descriptionOnChange} />
</React.Fragment>
);
}
Expand Down
20 changes: 11 additions & 9 deletions client/app/intake/components/UnidentifiedIssuesModal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import Checkbox from '../../components/Checkbox';
import { generateSkipButton } from '../util/buttonUtils';
import Alert from 'app/components/Alert';
import { VHA_ADMIN_DECISION_DATE_REQUIRED_BANNER } from 'app/../COPY';
import descriptionValidator from '../../util/validators/DescriptionValidator';

class UnidentifiedIssuesModal extends React.Component {
constructor(props) {
Expand All @@ -21,8 +20,7 @@ class UnidentifiedIssuesModal extends React.Component {
verifiedUnidentifiedIssue: false,
userIsVhaAdmin: props.intakeData.userIsVhaAdmin,
isTaskInProgress: props.intakeData.taskInProgress,
benefitType: props.intakeData.benefitType,
descriptionError: ''
benefitType: props.intakeData.benefitType
};
}

Expand Down Expand Up @@ -51,10 +49,14 @@ class UnidentifiedIssuesModal extends React.Component {
this.props.onSubmit({ currentIssue });
};

isDescriptionValid = (description) => {
// make sure description has some characters in it
return (/[a-zA-Z]+/).test(description);
};

onDescriptionChange = (value) => {
this.setState({
description: value,
descriptionError: descriptionValidator()(value)
description: value
});
};

Expand Down Expand Up @@ -88,7 +90,7 @@ class UnidentifiedIssuesModal extends React.Component {

saveDisabled = () => {

const descriptionIsValid = Boolean(this.state.description) && Boolean(!this.state.descriptionError);
const descriptionIsValid = this.isDescriptionValid(this.state.description);
const decisionDateIsValid = Boolean(this.state.decisionDate) && !this.errorOnDecisionDate(this.state.decisionDate);
const isDecisionDateRequired = this.vhaHlrOrSC() && this.state.userIsVhaAdmin && this.state.isTaskInProgress;
const notes = this.state.notes;
Expand All @@ -99,8 +101,9 @@ class UnidentifiedIssuesModal extends React.Component {

// if Decision date is not required then we need to verify if there is any error in the decision date field
// this.errorOnDecisionDate returns null if no error is present.
return !descriptionIsValid ||
(isDecisionDateRequired ? !decisionDateIsValid : this.errorOnDecisionDate(this.state.decisionDate));
return isDecisionDateRequired ?
!(descriptionIsValid && decisionDateIsValid) :
!(descriptionIsValid && !this.errorOnDecisionDate(this.state.decisionDate));
}

getModalButtons() {
Expand Down Expand Up @@ -190,7 +193,6 @@ class UnidentifiedIssuesModal extends React.Component {
strongLabel
value={this.state.description}
onChange={this.onDescriptionChange}
errorMessage={this.state.descriptionError}
/>
{this.getDecisionDate()}
<TextField name="Notes"
Expand Down
2 changes: 1 addition & 1 deletion client/app/queue/CaseTitle.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ class CaseTitle extends React.PureComponent {
<CaseTitleScaffolding heading={this.props.titleHeader === '' ? appeal.veteranFullName : this.props.titleHeader}>
<React.Fragment>
Veteran ID:&nbsp;
<CopyTextButton text={appeal.veteranFileNumber} label="Veteran ID" />
<CopyTextButton text={appeal.veteranFileNumber} textToCopy={appeal.veteranFileNumber} label="Veteran ID" />
</React.Fragment>

{ !this.props.hideCaseView &&
Expand Down
1 change: 1 addition & 0 deletions client/app/queue/CaseTitleDetails.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ export class CaseTitleDetails extends React.PureComponent {
<div id="document-id">
<CopyTextButton
text={appeal.documentID}
textToCopy={appeal.documentID}
label={COPY.TASK_SNAPSHOT_DECISION_DOCUMENT_ID_LABEL}
/>
{appeal.canEditDocumentId && (
Expand Down
1 change: 1 addition & 0 deletions client/app/reader/PdfViewer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,7 @@ export class PdfViewer extends React.Component {
title="Share Comment">
<CopyTextButton
text={`${location.origin}${location.pathname}?annotation=${this.props.shareAnnotationModalIsOpenFor}`}
textToCopy={`${location.origin}${location.pathname}?annotation=${this.props.shareAnnotationModalIsOpenFor}`}
label="Link to annotation"
/>
</Modal>}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ const ShareModal = () => {
>
<CopyTextButton
text={`${location.origin}${location.pathname}?annotation=${shareAnnotationModalIsOpenFor}`}
textToCopy={`${location.origin}${location.pathname}?annotation=${shareAnnotationModalIsOpenFor}`}
label="Link to annotation"
/>
</Modal>
Expand Down
13 changes: 0 additions & 13 deletions client/app/util/validators/DescriptionValidator.js

This file was deleted.

22 changes: 18 additions & 4 deletions client/test/app/components/CopyTextButton.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { render } from '@testing-library/react';

import { axe } from 'jest-axe';

Expand All @@ -17,17 +16,32 @@ describe('CopyTextButton', () => {
const setup = (props) => {

const utils = render(
<CopyTextButton {...defaults} {...props} />
<CopyTextButton {...props} />
);

const button = utils.getByRole('button');

return { ...utils, button };
};

describe('Button', () => {
it('is enabled', async() => {
const { button } = setup(defaults);

expect(button).toBeEnabled();
});
it('is disabled', async() => {
const text = 'some text';
const label = 'Label';
const { button } = setup({ text, label });

expect(button).toBeDisabled();
});
});

describe('aria-label', () => {
it('passes a11y testing', async () => {
const { container } = setup();
const { container } = setup(defaults);

const results = await axe(container);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2079,7 +2079,6 @@ exports[`Details Displays VirtualHearing details when there is a virtual hearing
data-event-off="mouseleave keydown"
data-for="tooltip-500000003"
data-tip="true"
disabled=""
tabindex="0"
type="submit"
>
Expand Down Expand Up @@ -4081,7 +4080,6 @@ exports[`Details Does not display EmailConfirmationModal when updating transcrip
data-event-off="mouseleave keydown"
data-for="tooltip-500000003"
data-tip="true"
disabled=""
tabindex="0"
type="submit"
>
Expand Down Expand Up @@ -6082,7 +6080,6 @@ exports[`Details Matches snapshot with default props 1`] = `
data-event-off="mouseleave keydown"
data-for="tooltip-100000005"
data-tip="true"
disabled=""
tabindex="0"
type="submit"
>
Expand Down Expand Up @@ -7924,7 +7921,6 @@ exports[`Details TranscriptiomFormSection pexip hearing Does not display transcr
data-event-off="mouseleave keydown"
data-for="tooltip-100000005"
data-tip="true"
disabled=""
tabindex="0"
type="submit"
>
Expand Down
75 changes: 0 additions & 75 deletions client/test/app/intake/NonratingRequestIssueModal-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,81 +99,6 @@ describe('NonratingRequestIssueModal', () => {
submitBtn = screen.getByRole('button', { name: /Add this issue/i });
expect(submitBtn).not.toBeDisabled();
});

it('does not disable button when valid description entered', () => {
const { container, rerender } = setup();

let submitBtn = screen.getByRole('button', { name: /Add this issue/i });
expect(submitBtn).toBeDisabled();

rerender(
<NonratingRequestIssueModal
{...defaultProps}
category={{
label: 'Apportionment',
value: 'Apportionment'
}}
decisionDate={'2019-06-01'}
dateError={false}
description={''}
/>
);

let issueCategoryInput = screen.getByRole('combobox', { name: /Issue category/i });
userEvent.click(issueCategoryInput); // open the dropdown menu
userEvent.type(issueCategoryInput, 'Apportionment{enter}'); // select the option

// Fill out Decision Date
let decisionDateInput = container.querySelector('input[id="decision-date"]');
fireEvent.change(decisionDateInput, { target: { value: '2019-06-01' } });

// Fill out Issue description
let inputElement = container.querySelector('input[id="Issue description"]');
fireEvent.change(inputElement, { target: { value: '1234567890-=`~!@#$%^&*()_+[]{}\\|;:' } });

submitBtn = screen.getByRole('button', { name: /Add this issue/i });
expect(submitBtn).not.toBeDisabled();
});

it('disables button when invalid description entered', () => {
const { container, rerender } = setup();

let submitBtn = screen.getByRole('button', { name: /Add this issue/i });
expect(submitBtn).toBeDisabled();

rerender(
<NonratingRequestIssueModal
{...defaultProps}
benefitType= 'compensation'
category={{
label: 'Apportionment',
value: 'Apportionment'
}}
decisionDate={'2019-06-01'}
dateError={false}
description={''}
/>
);

// Simulate user input of invalid characters
let issueCategoryInput = screen.getByRole('combobox', { name: /Issue category/i });
userEvent.click(issueCategoryInput); // open the dropdown menu
userEvent.type(issueCategoryInput, 'Apportionment{enter}'); // select the option

// Fill out Decision Date
let decisionDateInput = container.querySelector('input[id="decision-date"]');
fireEvent.change(decisionDateInput, { target: { value: '2019-06-01' } });

// Fill out Issue description
let inputElement = container.querySelector('input[id="Issue description"]');
fireEvent.change(inputElement, { target: { value: 'Not safe: \u{00A7} \u{2600} \u{2603} \u{260E} \u{2615}' } });

submitBtn = screen.getByRole('button', { name: /Add this issue/i });
expect(submitBtn).toBeDisabled();

expect(screen.getByText('Invalid character')).toBeInTheDocument();
expect(container.querySelector('.usa-input-error-message')).toBeInTheDocument();
});
});

describe('on appeal, with EMO Pre-Docket', () => {
Expand Down
Loading

0 comments on commit 57e0f68

Please sign in to comment.