Skip to content

Commit b9c8b17

Browse files
committed
Implement Latest Change History on Stop Area Details page
1 parent e3c016f commit b9c8b17

21 files changed

Lines changed: 426 additions & 98 deletions

cypress/e2e/stop-registry/stopAreaDetails.cy.ts

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,15 @@ function mapToShortDate(date: DateTime | null) {
4646
return date.setLocale('fi').toFormat('d.L.yyyy');
4747
}
4848

49+
function assertLatestChange(name: string, oldValue: string, newValue: string) {
50+
const { changes } = StopAreaDetailsPage.latestChangeHistory;
51+
return () =>
52+
changes.byName(name).within(() => {
53+
changes.oldValue().shouldHaveText(oldValue);
54+
changes.newValue().shouldHaveText(newValue);
55+
});
56+
}
57+
4958
describe('Stop area details', { tags: Tag.StopRegistry }, () => {
5059
let dbResources: SupportedResources;
5160
let dbIds: InsertedStopRegistryIds;
@@ -974,4 +983,102 @@ describe('Stop area details', { tags: Tag.StopRegistry }, () => {
974983
);
975984
});
976985
});
986+
987+
describe('Latest change history', { tags: Tag.ChangeHistory }, () => {
988+
it('should show last 5 changes', () => {
989+
StopAreaDetailsPage.visit('X0003');
990+
991+
cy.section('Change: Move a stop to the area', () => {
992+
StopAreaDetailsPage.memberStops.getAddStopButton().click();
993+
StopAreaDetailsPage.memberStops.modal.modal().shouldBeVisible();
994+
SelectStopDropdown.dropdownButton().click();
995+
SelectStopDropdown.getInput().click();
996+
SelectStopDropdown.getInput().clearAndType('E2E003');
997+
SelectStopDropdown.common.getMemberOptions().should('have.length', 1);
998+
SelectStopDropdown.common
999+
.getMemberOptions()
1000+
.eq(0)
1001+
.should('contain.text', 'E2E003')
1002+
.click();
1003+
1004+
StopAreaDetailsPage.memberStops.modal
1005+
.getTransferDateInput()
1006+
.shouldBeVisible();
1007+
StopAreaDetailsPage.memberStops.modal.setTransferDate(
1008+
DateTime.now().toISODate() ?? '',
1009+
);
1010+
StopAreaDetailsPage.memberStops.modal.getStopVersionsButton().click();
1011+
1012+
StopAreaDetailsPage.memberStops.modal
1013+
.getStopVersionsList()
1014+
.shouldBeVisible();
1015+
1016+
StopAreaDetailsPage.memberStops.modal.saveButton().click();
1017+
Toast.expectSuccessToast('Pysäkki siirretty pysäkkialueelle.');
1018+
});
1019+
1020+
cy.section('Change: Validity period', () => {
1021+
StopAreaDetailsPage.details.getEditButton().click();
1022+
setValidity(DateTime.fromISO('2030-01-01'), null);
1023+
StopAreaDetailsPage.details.edit.getSaveButton().click();
1024+
waitForSaveToBeFinished();
1025+
});
1026+
1027+
cy.section('Change: Change name', () => {
1028+
StopAreaDetailsPage.details.getEditButton().click();
1029+
StopAreaDetailsPage.details.edit.getName().clearAndType('Uusi nimi');
1030+
StopAreaDetailsPage.details.edit.getSaveButton().click();
1031+
waitForSaveToBeFinished();
1032+
});
1033+
1034+
cy.section('Change: Change Swedish name', () => {
1035+
StopAreaDetailsPage.details.getEditButton().click();
1036+
StopAreaDetailsPage.details.edit
1037+
.getNameSwe()
1038+
.clearAndType('Nya namnet');
1039+
StopAreaDetailsPage.details.edit.getSaveButton().click();
1040+
waitForSaveToBeFinished();
1041+
});
1042+
1043+
cy.section('Change: Change English name', () => {
1044+
StopAreaDetailsPage.details.getEditButton().click();
1045+
AlternativeNamesEdit.getNameEng().clearAndType('New name');
1046+
StopAreaDetailsPage.details.edit.getSaveButton().click();
1047+
waitForSaveToBeFinished();
1048+
});
1049+
1050+
StopAreaDetailsPage.latestChangeHistory
1051+
.getItems()
1052+
.should('have.length', 5);
1053+
1054+
cy.section('Assert changed values', () => {
1055+
StopAreaDetailsPage.latestChangeHistory
1056+
.getNthItem(0)
1057+
.within(assertLatestChange('NameEng', 'Annas street 15', 'New name'));
1058+
1059+
StopAreaDetailsPage.latestChangeHistory
1060+
.getNthItem(1)
1061+
.within(assertLatestChange('NameSwe', 'Annasgatan 15', 'Nya namnet'));
1062+
1063+
StopAreaDetailsPage.latestChangeHistory
1064+
.getNthItem(2)
1065+
.within(assertLatestChange('NameFin', 'Annankatu 15', 'Uusi nimi'));
1066+
1067+
StopAreaDetailsPage.latestChangeHistory.getNthItem(3).within(() => {
1068+
assertLatestChange('ValidityStart', '1.1.2000', '1.1.2030')();
1069+
assertLatestChange('ValidityEnd', '1.1.2052', '')();
1070+
});
1071+
1072+
StopAreaDetailsPage.latestChangeHistory
1073+
.getNthItem(4)
1074+
.within(
1075+
assertLatestChange(
1076+
'Stops',
1077+
['E2E001', 'E2E009'].join(''),
1078+
['E2E001', 'E2E003', 'E2E009'].join(''),
1079+
),
1080+
);
1081+
});
1082+
});
1083+
});
9771084
});

cypress/pageObjects/stop-registry/StopAreaDetailsPage.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,27 @@ export class StopAreaDetailsPage {
2828
`/stop-registry/stop-areas/${netexId}${observationDate ? `?observationDate=${observationDate}` : ''}`,
2929
);
3030
}
31+
32+
static latestChangeHistory = {
33+
container: () =>
34+
cy.getByTestId('LatestStopAreaChangeHistoryTable::Container'),
35+
title: () => cy.getByTestId('LatestStopAreaChangeHistoryTable::Title'),
36+
showAllLink: () =>
37+
cy.getByTestId('LatestStopAreaChangeHistoryTable::ShowAllLink'),
38+
getItems: () =>
39+
cy.get('[data-testid^="LatestStopAreaChangeHistoryTable::Item"]'),
40+
getNthItem: (index: number) =>
41+
cy
42+
.get('[data-testid^="LatestStopAreaChangeHistoryTable::Item"]')
43+
.eq(index),
44+
45+
changes: {
46+
byName: (changeName: string) =>
47+
cy.getByTestId(`LatestChangeHistoryItemChange::${changeName}`),
48+
fieldName: () =>
49+
cy.getByTestId('LatestChangeHistoryItemChange::FieldName'),
50+
oldValue: () => cy.getByTestId('LatestChangeHistoryItemChange::OldValue'),
51+
newValue: () => cy.getByTestId('LatestChangeHistoryItemChange::NewValue'),
52+
} as const,
53+
} as const;
3154
}

ui/src/components/forms/stop-area/useUpsertStopArea.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,12 @@ export const useUpsertStopArea = () => {
131131
const tryHandleApolloError = useStopAreaDetailsApolloErrorHandler();
132132
const [upsertStopAreaMutation] = useUpsertStopAreaMutation({
133133
awaitRefetchQueries: true,
134-
refetchQueries: ['GetStopAreasByLocation', 'GetLatestStopPlaceChange'],
134+
refetchQueries: [
135+
'GetStopAreasByLocation',
136+
'GetLatestStopPlaceChange',
137+
'getStopPlaceDetails',
138+
'getStopPlaceChangeHistory',
139+
],
135140
});
136141

137142
/**

ui/src/components/stop-registry/stop-areas/change-history/components/StopAreaChangeHistoryDataRows.tsx

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,13 @@ import { FC } from 'react';
22
import { StopPlaceChangeHistoryItem } from '../../../../../generated/graphql';
33
import { GetUserNameById } from '../../../../../hooks';
44
import { PagingInfo } from '../../../../../types';
5-
import { NoEarlierVersionExists } from '../../../../common/ChangeHistory';
6-
import { PreviousStopPlaceChangeHistoryItem } from '../types';
5+
import { findPreviousTiamatHistoryItemVersion } from '../../../utils';
76
import { StopAreaChangeHistoryItemSections } from './StopAreaChangeHistoryItemSections';
87

98
const testIds = {
109
group: (id: string) => `ChangeHistory::Group::${id}`,
1110
};
1211

13-
function findPreviousVersion(
14-
historyItemsSortedByVersion: ReadonlyArray<StopPlaceChangeHistoryItem>,
15-
item: StopPlaceChangeHistoryItem,
16-
): PreviousStopPlaceChangeHistoryItem {
17-
const previous = historyItemsSortedByVersion.find(
18-
(other) =>
19-
other.netexId === item.netexId &&
20-
Number(other.version) < Number(item.version),
21-
);
22-
23-
return previous ?? NoEarlierVersionExists;
24-
}
25-
2612
type StopPlaceChangeHistoryDataRowsProps = {
2713
readonly getUserNameById: GetUserNameById;
2814
readonly historyItems: ReadonlyArray<StopPlaceChangeHistoryItem>;
@@ -57,7 +43,10 @@ export const StopPlaceChangeHistoryDataRows: FC<
5743
<StopAreaChangeHistoryItemSections
5844
getUserNameById={getUserNameById}
5945
historyItem={historyItem}
60-
previousHistoryItem={findPreviousVersion(historyItems, historyItem)}
46+
previousHistoryItem={findPreviousTiamatHistoryItemVersion(
47+
historyItems,
48+
historyItem,
49+
)}
6150
/>
6251
</tbody>
6352
);

ui/src/components/stop-registry/stop-areas/change-history/queries/useGetStopPlaceChangeHistory.ts

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@ import {
66
useGetStopPlaceChangeHistoryQuery,
77
} from '../../../../../generated/graphql';
88
import { GetUserNameById } from '../../../../../hooks';
9+
import { SortOrder } from '../../../../../types';
910
import {
1011
ChangeHistoryFilters,
1112
ChangeHistorySortingInfo,
1213
} from '../../../../common/ChangeHistory';
1314
import { sortByVersion, useSortTiamatHistoryItems } from '../../../utils';
15+
import { sortByChangedTime } from '../../../utils/sortTiamatChangeHistoryItems';
1416

1517
const GQL_GET_STOP_PLACE_CHANGE_HISTORY_QUERY = gql`
1618
query getStopPlaceChangeHistory($privateCode: String!) {
@@ -50,12 +52,7 @@ type GetStopPlaceChangeHistoryOptions = {
5052
readonly sortingInfo: ChangeHistorySortingInfo;
5153
};
5254

53-
export function useGetStopPlaceChangeHistory({
54-
filters,
55-
getUserNameById,
56-
privateCode,
57-
sortingInfo,
58-
}: GetStopPlaceChangeHistoryOptions) {
55+
function useGetStopPlaceChangeHistoryItemsSortedByVersion(privateCode: string) {
5956
const { data, ...rest } = useGetStopPlaceChangeHistoryQuery({
6057
variables: { privateCode },
6158
});
@@ -72,13 +69,40 @@ export function useGetStopPlaceChangeHistory({
7269
[rawHistoryItems],
7370
);
7471

75-
const sortedHistoryItems: ReadonlyArray<StopPlaceChangeHistoryItem> =
76-
useSortTiamatHistoryItems(
77-
historyItems,
72+
return { ...rest, historyItems };
73+
}
74+
75+
export function useGetStopPlaceChangeHistory({
76+
filters,
77+
getUserNameById,
78+
privateCode,
79+
sortingInfo,
80+
}: GetStopPlaceChangeHistoryOptions) {
81+
const base = useGetStopPlaceChangeHistoryItemsSortedByVersion(privateCode);
82+
return {
83+
...base,
84+
sortedHistoryItems: useSortTiamatHistoryItems(
85+
base.historyItems,
7886
filters,
7987
sortingInfo,
8088
getUserNameById,
81-
);
89+
),
90+
};
91+
}
92+
93+
const latestChangesLimit = 5;
94+
const compareByChangedTime = sortByChangedTime(SortOrder.DESCENDING);
8295

83-
return { ...rest, historyItems, sortedHistoryItems };
96+
export function useGetLatestStopPlaceChangeHistory(privateCode: string) {
97+
const base = useGetStopPlaceChangeHistoryItemsSortedByVersion(privateCode);
98+
return {
99+
...base,
100+
latestHistoryItems: useMemo(
101+
() =>
102+
base.historyItems
103+
.toSorted(compareByChangedTime)
104+
.slice(0, latestChangesLimit),
105+
[base.historyItems],
106+
),
107+
};
84108
}

ui/src/components/stop-registry/stop-areas/stop-area-details/MoveQuayToStopArea/MoveQuayToStopAreaHeader.tsx

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,10 @@ const testIds = {
1010

1111
type MoveQuayToStopAreaHeaderProps = {
1212
readonly area: EnrichedStopPlace;
13-
readonly refetch: () => Promise<unknown>;
1413
};
1514

1615
export const MoveQuayToStopAreaHeader: FC<MoveQuayToStopAreaHeaderProps> = ({
1716
area,
18-
refetch,
1917
}) => {
2018
const { t } = useTranslation();
2119
const [isModalOpen, setIsModalOpen] = useState(false);
@@ -50,7 +48,6 @@ export const MoveQuayToStopAreaHeader: FC<MoveQuayToStopAreaHeaderProps> = ({
5048
onSave={handleCloseModal}
5149
areaId={area.id}
5250
areaPrivateCode={area.privateCode.value}
53-
refetch={refetch}
5451
/>
5552
</>
5653
);

ui/src/components/stop-registry/stop-areas/stop-area-details/MoveQuayToStopArea/MoveQuayToStopAreaModal.tsx

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ type MoveQuayToStopAreaModalProps = {
3535
readonly onSave: () => void;
3636
readonly areaId: string;
3737
readonly areaPrivateCode: string;
38-
readonly refetch: () => Promise<unknown>;
3938
};
4039

4140
type ModalState = {
@@ -94,7 +93,6 @@ export const MoveQuayToStopAreaModal: FC<MoveQuayToStopAreaModalProps> = ({
9493
onSave,
9594
areaId,
9695
areaPrivateCode,
97-
refetch,
9896
}) => {
9997
const { t } = useTranslation();
10098
const [state, setState] = useState<ModalState>(initialState);
@@ -159,7 +157,6 @@ export const MoveQuayToStopAreaModal: FC<MoveQuayToStopAreaModalProps> = ({
159157

160158
try {
161159
await moveQuayToStopPlace(saveParams);
162-
await refetch();
163160

164161
showSuccessToast(t(($) => $.stopAreaDetails.memberStops.moveSuccess));
165162

ui/src/components/stop-registry/stop-areas/stop-area-details/MoveQuayToStopArea/useMoveQuayToStopPlace.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,10 @@ import { MoveQuayParams, QuayInfo } from './utils/types';
2323
export const useMoveQuayToStopPlace = () => {
2424
const { t } = useTranslation();
2525
const [moveQuayMutation, { loading: moveLoading, error: moveError, reset }] =
26-
useMoveQuayToStopPlaceMutation();
26+
useMoveQuayToStopPlaceMutation({
27+
awaitRefetchQueries: true,
28+
refetchQueries: ['getStopPlaceDetails', 'getStopPlaceChangeHistory'],
29+
});
2730
const [getStopPointsByQuayId] = useGetStopPointsByQuayIdLazyQuery();
2831
const [insertStopPointMutation] = useInsertStopPointMutation();
2932
const [updateStopPointMutation] = useUpdateStopPointMutation();

ui/src/components/stop-registry/stop-areas/stop-area-details/StopAreaDetailsPage.tsx

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
1-
import { FC, useEffect, useState } from 'react';
1+
import { FC, useEffect } from 'react';
22
import { useTranslation } from 'react-i18next';
33
import { MdWarning } from 'react-icons/md';
44
import { Container } from '../../../../layoutComponents';
55
import { LoadingState, Operation } from '../../../../redux';
66
import { useLoader } from '../../../common/hooks';
77
import {
88
StopAreaDetailsAndMap,
9+
StopAreaLatestChanges,
910
StopAreaMemberStops,
1011
StopAreaTitleRow,
1112
StopAreaVersioningRow,
1213
} from './components';
13-
import { StopAreaEditableBlock } from './StopAreaEditableBlock';
1414
import { useGetStopPlaceDetails } from './useGetStopAreaDetails';
1515

1616
const testIds = {
@@ -19,15 +19,11 @@ const testIds = {
1919

2020
export const StopAreaDetailsPage: FC<Record<string, never>> = () => {
2121
const { t } = useTranslation();
22-
const [blockInEdit, setBlockInEdit] = useState<StopAreaEditableBlock | null>(
23-
null,
24-
);
2522

2623
const {
2724
stopPlaceDetails,
2825
loading,
2926
error,
30-
refetch,
3127
isValidOnObservationDate = false,
3228
} = useGetStopPlaceDetails();
3329
const { setLoadingState } = useLoader(Operation.FetchStopAreaPageDetails, {
@@ -57,18 +53,18 @@ export const StopAreaDetailsPage: FC<Record<string, never>> = () => {
5753
)}
5854
{stopPlaceDetails && !error && isValidOnObservationDate && (
5955
<>
60-
<StopAreaDetailsAndMap
61-
area={stopPlaceDetails}
62-
blockInEdit={blockInEdit}
63-
onEditBlock={setBlockInEdit}
64-
refetch={refetch}
65-
/>
66-
<StopAreaMemberStops
67-
area={stopPlaceDetails}
68-
blockInEdit={blockInEdit}
69-
onEditBlock={setBlockInEdit}
70-
refetch={refetch}
71-
/>
56+
<StopAreaDetailsAndMap area={stopPlaceDetails} />
57+
<div className="flex flex-col gap-3 lg:flex-row">
58+
<StopAreaMemberStops
59+
className="w-full lg:w-[70%]"
60+
area={stopPlaceDetails}
61+
/>
62+
63+
<StopAreaLatestChanges
64+
privateCode={stopPlaceDetails.privateCode?.value ?? ''}
65+
className="w-full border-b pb-2 lg:w-[30%]"
66+
/>
67+
</div>
7268
</>
7369
)}
7470
{(!stopPlaceDetails ||

0 commit comments

Comments
 (0)