Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(resource-adm): Fix misleading "Sist endret" field in resources table #14621

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -245,18 +245,6 @@ public async Task<ListviewServiceResource> MapServiceResourceToListViewResource(
}
}

if (string.IsNullOrEmpty(listviewResource.CreatedBy))
{
string localUserName = AuthenticationHelper.GetDeveloperUserName(_httpContextAccessor.HttpContext);
string userFullName = await GetCachedUserFullName(localUserName);
listviewResource.CreatedBy = userFullName;
}

if (listviewResource.LastChanged == null)
{
listviewResource.LastChanged = DateTime.Now;
}

return listviewResource;
}

Expand Down
2 changes: 1 addition & 1 deletion frontend/language/src/nb.json
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@
"dashboard.resource_status_label": "Driftsmeldinger",
"dashboard.resource_table_header_createdby": "Opprettet av",
"dashboard.resource_table_header_environment": "Miljø",
"dashboard.resource_table_header_last_changed": "Sist endret",
"dashboard.resource_table_header_last_changed": "Siste delte endringer",
"dashboard.resource_table_header_name": "Navn",
"dashboard.resource_table_header_resourceid": "Ressurs-id",
"dashboard.resource_table_no_resources_result": "Ingen ressurser funnet",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { ResourceTable } from './ResourceTable';
import type { ResourceListItem } from 'app-shared/types/ResourceAdm';
import { textMock } from '@studio/testing/mocks/i18nMock';
import userEvent from '@testing-library/user-event';
import { LOCAL_RESOURCE_CHANGED_TIME } from '../../utils/resourceListUtils';

const resource1Title = 'tittel 1';
const mockResourceListItem1: ResourceListItem = {
Expand All @@ -25,15 +26,24 @@ const mockResourceListItem2: ResourceListItem = {
const resource3Title = 'tittel 3';
const mockResourceListItem3: ResourceListItem = {
title: { nb: resource3Title, en: '', nn: '' },
createdBy: 'John Doe',
createdBy: '',
lastChanged: null,
identifier: 'resource-3',
environments: ['at22'],
};
const resource4Title = 'tittel 4';
const mockResourceListItem4: ResourceListItem = {
title: { nb: resource4Title, en: '', nn: '' },
createdBy: '',
lastChanged: LOCAL_RESOURCE_CHANGED_TIME,
identifier: 'resource-4',
environments: ['gitea'],
};
const mockResourceList: ResourceListItem[] = [
mockResourceListItem1,
mockResourceListItem2,
mockResourceListItem3,
mockResourceListItem4,
];

describe('ResourceTable', () => {
Expand Down Expand Up @@ -98,6 +108,13 @@ describe('ResourceTable', () => {
expect(lastChangedCell).toBeInTheDocument();
});

it('displays last changed date blank if resource has last changed date in the future', () => {
render(<ResourceTable {...defaultProps} list={[mockResourceListItem4]} />);

const lastChangedCell = screen.queryByText('31.12.9999');
expect(lastChangedCell).not.toBeInTheDocument();
});

it('displays environments for resource', () => {
render(<ResourceTable {...defaultProps} />);

Expand Down
26 changes: 18 additions & 8 deletions frontend/resourceadm/components/ResourceTable/ResourceTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { StudioButton, StudioSpinner, StudioTableLocalPagination } from '@studio
import type { Columns } from '@studio/components';
import type { ResourceListItem } from 'app-shared/types/ResourceAdm';
import { useTranslation } from 'react-i18next';
import { LOCAL_RESOURCE_CHANGED_TIME } from '../../utils/resourceListUtils';

export type ResourceTableProps = {
/**
Expand Down Expand Up @@ -145,14 +146,23 @@ export const ResourceTable = ({
accessor: 'lastChanged',
heading: t('dashboard.resource_table_header_last_changed'),
sortable: true,
bodyCellFormatter: (value: string) =>
value
? new Date(value).toLocaleDateString('no-NB', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
})
: '',
bodyCellFormatter: (value: string) => {
if (!value) return '';
const date = new Date(value);
// Compare only the date components
if (
date.getFullYear() === LOCAL_RESOURCE_CHANGED_TIME.getFullYear() &&
date.getMonth() === LOCAL_RESOURCE_CHANGED_TIME.getMonth() &&
date.getDate() === LOCAL_RESOURCE_CHANGED_TIME.getDate()
) {
return '';
}
return date.toLocaleDateString('no-NB', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
});
},
},
{
accessor: 'environments',
Expand Down
7 changes: 4 additions & 3 deletions frontend/resourceadm/hooks/queries/useGetResourceListQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ import { useQuery } from '@tanstack/react-query';
import { useServicesContext } from 'app-shared/contexts/ServicesContext';
import { QueryKey } from 'app-shared/types/QueryKey';
import type { ResourceListItem } from 'app-shared/types/ResourceAdm';
import { sortResourceListByDate } from '../../utils/mapperUtils';
import { setLastChangedAndSortResourceListByDate } from '../../utils/mapperUtils';

/**
* Query to get the list of resources. It maps the date to correct display format
* and sorts the list before it is being returned.
* and sorts the list before it is being returned. For resources not checked into
* Gitea, it sets a special last changed date to prioritize them in the sorted list.
*
* @param org the organisation of the user
*
Expand All @@ -23,7 +24,7 @@ export const useGetResourceListQuery = (
queryKey: [QueryKey.ResourceList, org],
queryFn: () => getResourceList(org),
select: (resourceListItems: ResourceListItem[]) =>
resourceListItems && sortResourceListByDate(resourceListItems),
resourceListItems && setLastChangedAndSortResourceListByDate(resourceListItems),
enabled: !disabled,
});
};
2 changes: 1 addition & 1 deletion frontend/resourceadm/utils/mapperUtils/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export {
sortResourceListByDate,
setLastChangedAndSortResourceListByDate,
mapAltinn2LinkServiceToSelectOption,
mapSelectOptiontoAltinn2LinkService,
} from './mapperUtils';
81 changes: 80 additions & 1 deletion frontend/resourceadm/utils/mapperUtils/mapperUtils.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import type { Altinn2LinkService } from 'app-shared/types/Altinn2LinkService';
import { mapAltinn2LinkServiceToSelectOption } from './mapperUtils';
import {
mapAltinn2LinkServiceToSelectOption,
setLastChangedAndSortResourceListByDate,
} from './mapperUtils';
import { LOCAL_RESOURCE_CHANGED_TIME } from '../resourceListUtils';

describe('mapperUtils', () => {
describe('mapAltinn2LinkServiceToSelectOption', () => {
Expand All @@ -26,4 +30,79 @@ describe('mapperUtils', () => {
expect(result[0].label).toBe('name1 (code1/edition1)');
});
});

describe('setLastChangedAndSortResourceListByDate', () => {
it('should sort the list by date', () => {
const resource1Id = 'resource-1';
const resource2Id = 'resource-2';
const resource3Id = 'resource-3';
const resource4Id = 'resource-4';
const loadedResourceList = [
{
title: { nb: resource1Id, en: '', nn: '' },
createdBy: '',
lastChanged: null,
identifier: resource1Id,
environments: ['tt02'],
},
{
title: { nb: resource2Id, en: '', nn: '' },
createdBy: '',
lastChanged: null,
identifier: resource2Id,
environments: ['gitea'],
},
{
title: { nb: resource3Id, en: '', nn: '' },
createdBy: 'ulrik user',
lastChanged: new Date('2023-08-29'),
identifier: resource3Id,
environments: ['gitea', 'tt02'],
},
{
title: { nb: resource4Id, en: '', nn: '' },
createdBy: 'ulrik user',
lastChanged: new Date('2023-08-30'),
identifier: resource4Id,
environments: ['tt02', 'gitea'],
},
];
const resultResourceList = setLastChangedAndSortResourceListByDate(loadedResourceList);
// Verify that Gitea resources with LOCAL_RESOURCE_CHANGED_TIME appear first
expect(resultResourceList[0].identifier).toBe(resource2Id);
// Verify that resources with actual dates are sorted in descending order
expect(resultResourceList[1].identifier).toBe(resource4Id);
expect(resultResourceList[2].identifier).toBe(resource3Id);
// Verify that resources with null dates appear last
expect(resultResourceList[3].identifier).toBe(resource1Id);
});

it('should set lastChanged to static value if lastChanged is null and environments includes gitea', () => {
const loadedResourceList = [
{
title: { nb: 'resource-1', en: '', nn: '' },
createdBy: '',
lastChanged: null,
identifier: 'resource-1',
environments: ['gitea'],
},
];
const resultResourceList = setLastChangedAndSortResourceListByDate(loadedResourceList);
expect(resultResourceList[0].lastChanged).toBe(LOCAL_RESOURCE_CHANGED_TIME);
});

it('should sort environments', () => {
const loadedResourceList = [
{
title: { nb: 'resource-1', en: '', nn: '' },
createdBy: '',
lastChanged: null,
identifier: 'resource-1',
environments: ['gitea', 'at24', 'at22', 'prod', 'tt02'],
},
];
const resultResourceList = setLastChangedAndSortResourceListByDate(loadedResourceList);
expect(resultResourceList[0].environments).toEqual(['prod', 'tt02', 'at22', 'at24', 'gitea']);
});
});
});
16 changes: 14 additions & 2 deletions frontend/resourceadm/utils/mapperUtils/mapperUtils.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,30 @@
import type { Altinn2LinkService } from 'app-shared/types/Altinn2LinkService';
import type { ResourceListItem } from 'app-shared/types/ResourceAdm';
import { LOCAL_RESOURCE_CHANGED_TIME } from '../../utils/resourceListUtils';

const EnvOrder = ['prod', 'tt02', 'at22', 'at23', 'at24', 'gitea'];

const setLastChangedDate = (resource: ResourceListItem): Date => {
return resource.lastChanged === null && resource.environments.includes('gitea')
? LOCAL_RESOURCE_CHANGED_TIME
: new Date(resource.lastChanged);
};

/**
* Sorts a resource list by the date so the newest is at the top
* Sets a special last changed date for resources not checked into Gitea and
* sorts the resource list by date so the newest is at the top.
*
* @param resourceList the list to sort
*
* @returns the sorted list
*/
export const sortResourceListByDate = (resourceList: ResourceListItem[]): ResourceListItem[] => {
export const setLastChangedAndSortResourceListByDate = (
resourceList: ResourceListItem[],
): ResourceListItem[] => {
const listWithSortedEnvs = resourceList.map((resource) => {
return {
...resource,
lastChanged: setLastChangedDate(resource),
environments: resource.environments.sort((a, b) => EnvOrder.indexOf(a) - EnvOrder.indexOf(b)),
};
});
Expand Down
2 changes: 1 addition & 1 deletion frontend/resourceadm/utils/resourceListUtils/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export { filterTableData } from './resourceListUtils';
export { filterTableData, LOCAL_RESOURCE_CHANGED_TIME } from './resourceListUtils';
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import type { ResourceListItem } from 'app-shared/types/ResourceAdm';

export const LOCAL_RESOURCE_CHANGED_TIME = new Date('9999-12-31');

/**
* Filter the list based on what is typed in the search box
*/
Expand Down