Skip to content

Commit

Permalink
Merge branch 'master' into columnmanager-persist
Browse files Browse the repository at this point in the history
  • Loading branch information
zburke authored Mar 15, 2024
2 parents 777007b + d3acab3 commit 821d76b
Show file tree
Hide file tree
Showing 72 changed files with 1,221 additions and 457 deletions.
3 changes: 3 additions & 0 deletions .stylelintrc
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
"extends": "stylelint-config-standard",
"rules": {
"import-notation": "string",
"value-keyword-case": ["lower", {
"ignoreProperties": ["composes"]
}],
"selector-pseudo-class-no-unknown": [true, {
"ignorePseudoClasses": [
"export",
Expand Down
32 changes: 30 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,45 @@
# Change history for stripes-smart-components

## 9.1.0 IN PROGRESS
## 9.2.0 IN PROGRESS

## [9.1.1] (IN PROGRESS)

* Fix incorrect state calculation in `<SearchAndSortQuery>`. Fixes STSMACOM-820.

## [9.1.0](https://github.com/folio-org/stripes-smart-components/tree/v9.1.0) (2024-03-13)
[Full Changelog](https://github.com/folio-org/stripes-smart-components/compare/v9.0.1...v9.1.0)

* Added `inputType` prop to `<SearchAndSort>` component to support both input and textarea search boxes. Refs STSMACOM-786.
* Export new `advancedSearchQueryToRows` helper to be used in Inventory app to reduce code duplication. Refs STSMACOM-787.
* Show the username in the "last updated" accordion in the Note editing pane. Fixes STSMACOM-748.
* Added `indexRef` and `inputRef` props to `<SearchAndSort>`. Refs STSMACOM-788.
* Extend NotesAccordion and NotesSmartAccodion components to accept a prop hideNewButton. Refs STSMACOM-789.
* Extend NotesAccordion and NotesSmartAccordion components to accept a prop hideNewButton. Refs STSMACOM-789.
* Extend `Tags` component to accept `mutateEntity` prop. Refs STSMACOM-792.
* Refactor CSS away from postcss-color-function. Refs STSMACOM-791.
* `<EditCustomFieldsSettings>` now passes the `entityType` when making PUT requests to `/custom-fields`. Refs FCFIELDS-44.
* Added `tenant` prop to `<ControlledVocab>`. Refs STSMACOM-794.
* Use the default match and search option in Advanced search when they are not entered. Refs STSMACOM-793.
* Show successful toast notifications for Create and Edit actions in `<ControlledVocab>`. Refs STSMACOM-796.
* `<ControlledVocab>` - last updated by column - show "System" when items are created by system user. Refs STSMACOM-797.
* Add field type `DATE_PICKER` to custom fields components. Refs STSMACOM-800.
* Make `helpText` prop as optional for all types of custom field components. Refs STSMACOM-799.
* Upgrade `stylelint` and associated dependencies. Refs STSMACOM-803.
* `<UserName>` must handle sparse data. Refs STSMACOM-802.
* `ViewCustomFieldRecord` - remove required validation from `expanded`, `onToggle` props. Refs STSMACOM-798.
* `<EditableList>` - added new `getReadOnlyFieldsForItem` prop to control read only fields for different items. Refs STSMACOM-801.
* `<EditableList>` - added confirmation modal when deleting items. Refs STSMACOM-807.
* Add `onComponentLoad` prop to `<EditCustomFieldsRecord>`. Refs STSMACOM-806.
* Keep final form state when update request fails in `<EditableList>`. Refs STSMACOM-809.
* Set default title for Accordion in `<EditCustomFieldsRecord>`. Refs STSMACOM-805.
* `<EditableList>` - make `confirmationMessage` prop accept a function. Refs STSMACOM-810.
* Don't use `form.getState` in `<EditableListForm>` because redux-form doesn't have this API. Initialization will happen automatically when fresh data has been loaded after edit. Fixes STSMACOM-813.
* `<EditableListForm>` - don't show an error after the user clicks on the edit icon. Fixes STSMACOM-812.
* Safely render user-provided markup in `<NotesView>` component. Fixes STSMACOM-816.

## [9.0.1](https://github.com/folio-org/stripes-smart-components/tree/v9.0.1) (2023-10-25)
[Full Changelog](https://github.com/folio-org/stripes-smart-components/compare/v9.0.0...v9.0.1)

* add default parameters to `onSubmit`, `submitAll` internal SASQ handlers. Refs STSMACOM-785, STSMACOM-775.

## [9.0.0](https://github.com/folio-org/stripes-smart-components/tree/v9.0.0) (2023-10-11)
[Full Changelog](https://github.com/folio-org/stripes-smart-components/compare/v8.0.0...v9.0.0)
Expand Down
88 changes: 60 additions & 28 deletions lib/ControlledVocab/ControlledVocab.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@ import EditableList from '../EditableList';
import css from './ControlledVocab.css';
import makeRefdataActuatorsBoundTo from './actuators-refdata';

const SYSTEM_USER_ID = '00000000-0000-0000-0000-000000000000';
const ACTIONS = {
CREATE: 'termCreated',
EDIT: 'termUpdated',
DELETE: 'termDeleted',
};

const getTenantFromRESTResource = (queryParams, pathComponents, resourceValues, logger, props) => {
const {
tenant,
Expand Down Expand Up @@ -114,9 +121,6 @@ class ControlledVocab extends React.Component {
GET: PropTypes.func,
reset: PropTypes.func,
}),
tenant: PropTypes.shape({
replace: PropTypes.func,
}),
values: PropTypes.shape({
DELETE: PropTypes.func,
GET: PropTypes.func,
Expand Down Expand Up @@ -159,7 +163,9 @@ class ControlledVocab extends React.Component {
cannotDeleteTermHeader: "Cannot delete patron group",
cannotDeleteTermMessage: "This patron group cannot be deleted, as it is in use by one or more records.",
deleteEntry: "Delete patron group",
termCreated: "The patron group <b>{term}</b> was successfully <b>created</b>",
termDeleted: "The patron group <b>{term}</b> was successfully <b>deleted</b>",
termUpdated: "The patron group <b>{term}</b> was successfully <b>updated</b>",
termWillBeDeleted: "The patron group <b>{term}</b> will be <b>deleted.</b>"
}
*/
Expand All @@ -169,6 +175,8 @@ class ControlledVocab extends React.Component {
cannotDeleteTermMessage: PropTypes.string,
deleteEntry: PropTypes.string,
termDeleted: PropTypes.string,
termCreated: PropTypes.string,
termUpdated: PropTypes.string,
termWillBeDeleted: PropTypes.string,
}),
/*
Expand Down Expand Up @@ -211,7 +219,8 @@ class ControlledVocab extends React.Component {
// !{limitParam:-limit}
// in the manifest above.
actuatorType: 'rest',
canCreate: true
canCreate: true,
translations: {},
};

constructor(props) {
Expand Down Expand Up @@ -274,7 +283,10 @@ class ControlledVocab extends React.Component {
}

onCreateItem(item) {
return this.props.mutator.values.POST(this.props.preCreateHook(item));
return this.props.mutator.values.POST(this.props.preCreateHook(item))
.then(() => {
this.showSuccessCallout(item, ACTIONS.CREATE);
});
}

onDeleteItem() {
Expand All @@ -284,7 +296,7 @@ class ControlledVocab extends React.Component {

return this.props.mutator.values.DELETE({ id: selectedItem.id })
.then(() => {
this.showDeletionSuccessCallout(selectedItem);
this.showSuccessCallout(selectedItem, ACTIONS.DELETE);
this.deleteItemResolve();
})
.catch(() => {
Expand All @@ -296,7 +308,10 @@ class ControlledVocab extends React.Component {

onUpdateItem(item) {
this.props.mutator.activeRecord.update({ id: item.id });
return this.props.mutator.values.PUT(this.props.preUpdateHook(item));
return this.props.mutator.values.PUT(this.props.preUpdateHook(item))
.then(() => {
this.showSuccessCallout(item, ACTIONS.EDIT);
});
}

filteredRows(rows) {
Expand Down Expand Up @@ -343,28 +358,43 @@ class ControlledVocab extends React.Component {
});
}

showDeletionSuccessCallout(item) {
if (this.callout) {
const { termDeleted } = this.props.translations || {};
const message = (
termDeleted ?
<FormattedMessage
id={termDeleted}
values={{
term: item[this.state.primaryField],
}}
/> :
<FormattedMessage
id="stripes-smart-components.cv.termDeleted"
values={{
type: this.props.labelSingular,
term: item[this.state.primaryField],
}}
/>
);

this.callout.sendCallout({ message });
showSuccessCallout(item, action) {
if (!this.callout) {
return;
}

const {
termCreated,
termDeleted,
termUpdated,
} = this.props.translations;

const translationByAction = {
[ACTIONS.CREATE]: termCreated,
[ACTIONS.DELETE]: termDeleted,
[ACTIONS.EDIT]: termUpdated,
};

const translation = translationByAction[action];

const message = (
translation ?
<FormattedMessage
id={translation}
values={{
term: item[this.state.primaryField],
}}
/> :
<FormattedMessage
id={`stripes-smart-components.cv.${action}`}
values={{
type: this.props.labelSingular,
term: item[this.state.primaryField],
}}
/>
);

this.callout.sendCallout({ message });
}

handlePaneFocus({ paneTitleRef }) {
Expand Down Expand Up @@ -444,6 +474,8 @@ class ControlledVocab extends React.Component {
const { firstName, lastName = '' } = record.personal;
const name = firstName ? `${lastName}, ${firstName}` : lastName;
user = <Link to={`/users/view/${metadata.updatedByUserId}`}>{name}</Link>;
} else if (metadata.updatedByUserId === SYSTEM_USER_ID) {
user = <FormattedMessage id="stripes-smart-components.system" />;
}

return (
Expand Down
50 changes: 45 additions & 5 deletions lib/ControlledVocab/tests/ControlledVocab-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
including,
MultiColumnList,
MultiColumnListCell,
Callout,
} from '@folio/stripes-testing';

import mountComponent from './mountComponent';
Expand Down Expand Up @@ -45,7 +46,7 @@ describe('ControlledVocab', () => {
// eslint-disable-next-line no-undef
beforeEach(() => mountComponent(true, server, { translations }));

it('should have row count 5', () => cv.has({ rowCount: 5 }));
it('should have row count 6', () => cv.has({ rowCount: 6 }));

describe('clicking Delete icon on first row', () => {
beforeEach(async () => {
Expand All @@ -59,7 +60,9 @@ describe('ControlledVocab', () => {
it('should display Delete button', () => cm.find(Button('Delete')).exists());

describe('click delete on confirmation modal', () => {
beforeEach(async () => {
beforeEach(async function () {
this.server.delete('location-units/institutions/:id', {}, 500);

await Button('Delete').click();
});

Expand All @@ -76,10 +79,12 @@ describe('ControlledVocab', () => {
// eslint-disable-next-line no-undef
beforeEach(() => mountComponent(true, server, { labelSingular }));

it('should have row count 5', () => cv.has({ rowCount: 5 }));
it('should have row count 6', () => cv.has({ rowCount: 6 }));

describe('clicking Delete icon on first row', () => {
beforeEach(async () => {
beforeEach(async function () {
this.server.delete('location-units/institutions/:id', {}, 500);

await firstRow.delete();
});

Expand All @@ -99,6 +104,15 @@ describe('ControlledVocab', () => {
it('cannot delete modal title', () => mo.has({ title: 'Cannot delete Institution' }));
});
});

describe('when deleting is successful', () => {
beforeEach(async () => {
await firstRow.delete();
await Button('Delete').click();
});

it('should display successful callout message', () => Callout('The Institution Bowdoin College was successfully deleted').exists());
});
});

describe('User can edit EditableListForm', () => {
Expand Down Expand Up @@ -167,6 +181,14 @@ describe('ControlledVocab', () => {
it('should not display the error message', () => firstRow.find(TextField(including('name'))).is({ valid: true }));

it('should enable Save button', () => firstRow.has({ saveDisabled: false }));

describe('when creating is successful', () => {
beforeEach(async () => {
await firstRow.save();
});

it('should display successful callout message', () => Callout('The Institution test was successfully created').exists());
});
});
});

Expand Down Expand Up @@ -200,6 +222,20 @@ describe('ControlledVocab', () => {

it('should enable Delete button', () => cv.has({ deleteDisabled: false }));
});

describe('when editing an item', () => {
beforeEach(async () => {
await firstRow.find(TextField(including('name'))).fillIn('Bowdoin College edit');
});

describe('when creating is successful', () => {
beforeEach(async () => {
await firstRow.save();
});

it('should display successful callout message', () => Callout('The Institution Bowdoin College edit was successfully updated').exists());
});
});
});
});

Expand Down Expand Up @@ -232,10 +268,14 @@ describe('ControlledVocab', () => {
await mountComponent(false, server, { listSuppressor });
});

it('should have row count 5', () => cv.has({ rowCount: 5 }));
it('should have row count 6', () => cv.has({ rowCount: 6 }));

it('should render the row with last updated by user-1 without user firstname or lastname', async () => {
await mcl.find(MultiColumnListCell({ row: 4, columnIndex: 3, content: '4/18/2019 by ' })).exists();
});

it('should render the row with last updated by system with "System" text', async () => {
await mcl.find(MultiColumnListCell({ row: 6, columnIndex: 3, content: '1/9/2024 by System' })).exists();
});
});
});
22 changes: 21 additions & 1 deletion lib/ControlledVocab/tests/ControlledVocabErrors-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,27 @@ describe('ControlledVocabErrors', () => {

function mount() {
// eslint-disable-next-line no-undef
beforeEach(() => mountComponent(true, server));
beforeEach(function () {
mountComponent(true, this.server);
this.server.post('location-units/institutions', {
'errors': [{
'message': 'Cannot create entity; name is not unique',
'code': 'name.duplicate',
'parameters': [{
'key': 'fieldLabel',
'value': 'name'
}]
},
{
'message': 'test',
'code': '-1',
'parameters': [{
'key': 'test',
'value': 'test'
}]
}]
}, 422);
});
beforeEach(async () => {
await cv.newButton().click();
await cv.fillInputField('test');
Expand Down
Loading

0 comments on commit 821d76b

Please sign in to comment.