Skip to content

Commit

Permalink
UIORGS-355 Display all versions in change log in fourth pane (#655)
Browse files Browse the repository at this point in the history
* UIORGS-355 Display all versions in change log in fourth pane

* add unit tests

* Map labels with the schema fields

* ignore sonar alert

* UIORGS-355 update

* UIORGS-355 Add new required okapi interface
  • Loading branch information
usavkov-epam authored Nov 25, 2024
1 parent 53cecbb commit 9a29cc4
Show file tree
Hide file tree
Showing 17 changed files with 555 additions and 2 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Change history for ui-organizations

## 5.3.0 (IN PROGRESS)
## 6.0.0 (IN PROGRESS)

* *BREAKING* Display all versions in change log in fourth pane. Refs UIORGS-355.

## [5.2.0](https://github.com/folio-org/ui-organizations/tree/v5.2.0) (2024-10-31)
[Full Changelog](https://github.com/folio-org/ui-organizations/compare/v5.1.1...v5.2.0)
Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@folio/organizations",
"version": "5.2.0",
"version": "6.0.0",
"description": "Organizations",
"main": "index.js",
"repository": "folio-org/ui-organizations",
Expand All @@ -19,6 +19,7 @@
"home": "/organizations",
"okapiInterfaces": {
"acquisition-methods": "1.0",
"acquisition-organization-events": "1.0",
"banking-information": "1.0",
"data-export-spring": "1.0 2.0",
"configuration": "2.0",
Expand Down Expand Up @@ -66,6 +67,7 @@
"replaces": ["ui-organizations.third-party-services"],
"visible": false,
"subPermissions": [
"acquisition.organization.events.get",
"acquisitions-units.memberships.collection.get",
"acquisitions-units.units.collection.get",
"configuration.entries.collection.get",
Expand Down
10 changes: 10 additions & 0 deletions src/Organizations/OrganizationDetails/OrganizationDetails.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,12 @@ import {
TagsPane,
useAcqRestrictions,
useModalToggle,
VersionHistoryButton,
} from '@folio/stripes-acq-components';

import {
NOTES_ROUTE,
ORGANIZATION_VERSIONS_VIEW_ROUTE,
ORGANIZATIONS_ROUTE,
} from '../../common/constants';
import {
Expand Down Expand Up @@ -135,6 +137,13 @@ const OrganizationDetails = ({
if (isDetailsPaneInFocus) paneTitleRef.current.focus();
}, [isDetailsPaneInFocus]);

const openVersionHistory = useCallback(() => {
history.push({
pathname: ORGANIZATION_VERSIONS_VIEW_ROUTE.replace(':id', organization.id),
search: location.search,
});
}, [history, location.search, organization.id]);

const getActionMenu = useCallback(
({ onToggle }) => {
return (
Expand Down Expand Up @@ -200,6 +209,7 @@ const OrganizationDetails = ({
tagsQuantity={get(organization, 'tags.tagList', []).length}
tagsToggle={toggleTagsPane}
/>
<VersionHistoryButton onClick={openVersionHistory} />
</PaneMenu>
);

Expand Down
111 changes: 111 additions & 0 deletions src/Organizations/OrganizationVersion/OrganizationVersion.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import get from 'lodash/get';
import {
memo,
useCallback,
useMemo,
} from 'react';
import ReactRouterPropTypes from 'react-router-prop-types';

import {
useOrganization,
VersionHistoryPane,
VersionView,
VersionViewContextProvider,
} from '@folio/stripes-acq-components';
import { TitleManager } from '@folio/stripes/core';

import {
ORGANIZATION_VERSIONS_VIEW_ROUTE,
ORGANIZATIONS_ROUTE,
VIEW_ORG_DETAILS,
} from '../../common/constants';
import { HIDDEN_FIELDS_FOR_ORGANIZATION_VERSION_HISTORY } from '../constants';
import { getOrganizationFieldsLabelMap } from './getOrganizationFieldsLabelMap';
import { useOrganizationVersions } from './hooks';

const OrganizationVersion = ({
history,
location,
match,
}) => {
const { id: organizationId, versionId } = match.params;
const snapshotPath = 'organizationSnapshot.map';

const {
isLoading: isOrganizationLoading,
organization,
} = useOrganization(organizationId);

const onHistoryClose = useCallback(() => history.push({
pathname: `${VIEW_ORG_DETAILS}${organizationId}`,
search: location.search,
}), [history, location.search, organizationId]);

const onVersionClose = useCallback(() => history.push({
pathname: ORGANIZATIONS_ROUTE,
search: location.search,
}), [history, location.search]);

const onSelectVersion = useCallback((_versionId) => {
history.push({
pathname: `${ORGANIZATION_VERSIONS_VIEW_ROUTE.replace(':id', organizationId)}/${_versionId}`,
search: location.search,
});
}, [history, location.search, organizationId]);

const {
versions,
isLoading: isHistoryLoading,
} = useOrganizationVersions(organizationId, {
onSuccess: ({ organizationAuditEvents }) => {
if (!versionId && organizationAuditEvents[0]?.id) onSelectVersion(organizationAuditEvents[0].id);
},
});

const isVersionLoading = (
isOrganizationLoading || isHistoryLoading
);

const labelsMap = useMemo(() => getOrganizationFieldsLabelMap(), []);

return (
<VersionViewContextProvider
snapshotPath={snapshotPath}
versions={versions}
versionId={versionId}
>
<TitleManager record={organization?.name} />
<VersionView
id="organization"
dismissible
isLoading={isVersionLoading}
onClose={onVersionClose}
paneTitle={organization?.name}
tags={get(organization, 'tags.tagList', [])}
versionId={versionId}
>
{/* TODO: https://folio-org.atlassian.net/browse/UIORGS-356 */}
</VersionView>

<VersionHistoryPane
currentVersion={versionId}
id="organization"
isLoading={isHistoryLoading}
onClose={onHistoryClose}
onSelectVersion={onSelectVersion}
snapshotPath={snapshotPath}
labelsMap={labelsMap}
versions={versions}
hiddenFields={HIDDEN_FIELDS_FOR_ORGANIZATION_VERSION_HISTORY}
/>
</VersionViewContextProvider>
);
};

OrganizationVersion.propTypes = {
history: ReactRouterPropTypes.history,
location: ReactRouterPropTypes.location,
match: ReactRouterPropTypes.match,
};

export default memo(OrganizationVersion);
141 changes: 141 additions & 0 deletions src/Organizations/OrganizationVersion/OrganizationVersion.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
import {
QueryClient,
QueryClientProvider,
} from 'react-query';
import {
MemoryRouter,
Route,
Switch,
withRouter,
} from 'react-router-dom';

import {
render,
screen,
} from '@folio/jest-config-stripes/testing-library/react';
import user from '@folio/jest-config-stripes/testing-library/user-event';
import { useOkapiKy } from '@folio/stripes/core';
import {
AUDIT_ACQ_EVENTS_API,
useOrganization,
} from '@folio/stripes-acq-components';

import {
organization,
organizationAuditEvent,
} from 'fixtures';
import { ORGANIZATION_VERSIONS_VIEW_ROUTE } from '../../common/constants';
import OrganizationVersion from './OrganizationVersion';

jest.mock('@folio/stripes-acq-components', () => ({
...jest.requireActual('@folio/stripes-acq-components'),
useOrganization: jest.fn(() => ({})),
}));

const { organizationSnapshot, ...auditEvent } = organizationAuditEvent;

const latestSnapshot = {
...organizationSnapshot,
edition: 'Second edition',
};
const originalSnapshot = { ...organizationSnapshot };

const versions = [
{
...auditEvent,
id: 'testAuditEventId',
organizationSnapshot: { map: latestSnapshot },
},
{
...auditEvent,
organizationSnapshot: { map: originalSnapshot },
},
];

const kyMock = {
get: jest.fn((url) => ({
json: async () => {
const result = {};

if (url.startsWith(`${AUDIT_ACQ_EVENTS_API}/organization/`)) {
result.organizationAuditEvents = versions;
}

return Promise.resolve({
isLoading: false,
...result,
});
},
})),
};

const queryClient = new QueryClient();
const wrapper = ({ children }) => (
<QueryClientProvider client={queryClient}>
<MemoryRouter
initialEntries={[{
pathname: ORGANIZATION_VERSIONS_VIEW_ROUTE.replace(':id', organization.id),
}]}
>
{children}
</MemoryRouter>
</QueryClientProvider>
);

const Component = withRouter(OrganizationVersion);
const mockDefaultContent = 'Hello world';

const renderOrganizationVersion = (props = {}) => render(
<Switch>
<Route
path={ORGANIZATION_VERSIONS_VIEW_ROUTE}
render={() => (
<Component
{...props}
/>
)}
/>
<Route
render={() => (
<div>{mockDefaultContent}</div>
)}
/>
</Switch>,
{ wrapper },
);

describe('OrganizationVersion', () => {
beforeEach(() => {
useOkapiKy.mockReturnValue(kyMock);
useOrganization.mockReturnValue({
isLoading: false,
organization,
});
});

it('should close version view when \'Version close\' button was clicked', async () => {
renderOrganizationVersion();

await screen.findAllByRole('button', { name: 'stripes-acq-components.versionHistory.card.select.tooltip' })
.then(async ([selectVersionBtn]) => user.click(selectVersionBtn));

await screen.findAllByRole('button', { name: 'stripes-components.closeItem' })
.then(async ([closeVersionBtn]) => user.click(closeVersionBtn));

expect(screen.queryByText(organization.name)).not.toBeInTheDocument();
expect(screen.getByText(mockDefaultContent)).toBeInTheDocument();
});

it('should close version view when \'History close\' button was clicked', async () => {
renderOrganizationVersion();

await screen.findAllByRole('button', { name: 'stripes-acq-components.versionHistory.card.select.tooltip' })
.then(async ([selectVersionBtn]) => user.click(selectVersionBtn));

await screen.findAllByRole('button', { name: 'stripes-components.closeItem' })
.then(async ([_, closeHistoryBtn]) => user.click(closeHistoryBtn));

expect(screen.queryByText(organization.name)).not.toBeInTheDocument();
expect(screen.getByText(mockDefaultContent)).toBeInTheDocument();
});
});
Loading

0 comments on commit 9a29cc4

Please sign in to comment.