Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
2339afc
implemented admin roles configuration
MatteoGuarnaccia5 Sep 23, 2025
ffe0838
implemented authprovider component
MatteoGuarnaccia5 Sep 24, 2025
e235afe
add admin functionality to units table
MatteoGuarnaccia5 Sep 24, 2025
f3e78c0
admin functionality for usage statuses table
MatteoGuarnaccia5 Sep 24, 2025
9397913
rename admin pages to settings pages
MatteoGuarnaccia5 Sep 25, 2025
8570752
fix unit tests
MatteoGuarnaccia5 Sep 25, 2025
5166aa0
fix e2e tests
MatteoGuarnaccia5 Sep 25, 2025
edbdf88
added status indicator for users with privileged role
MatteoGuarnaccia5 Sep 29, 2025
94b39ac
fixed e2e tests ()ith mock data)
MatteoGuarnaccia5 Sep 29, 2025
61be913
refactored unit tests
MatteoGuarnaccia5 Sep 29, 2025
32c0c70
added missing localstorage function in e2e api tests
MatteoGuarnaccia5 Sep 29, 2025
0674d5b
Merge branch 'apply-rules-to-delete-dialog-1500' into refactor-admin-…
MatteoGuarnaccia5 Oct 2, 2025
d1c08df
Merge branch 'apply-rules-to-delete-dialog-1500' into refactor-admin-…
MatteoGuarnaccia5 Oct 6, 2025
53351cc
switch to single role per user
MatteoGuarnaccia5 Oct 8, 2025
1eb6a46
change token in e2e tests
MatteoGuarnaccia5 Oct 8, 2025
c3fc466
Merge branch 'develop' into refactor-admin-page-to-utilise-authorisat…
MatteoGuarnaccia5 Oct 15, 2025
37c1289
change isUserAuthorised variable to isUserAdmin and update readme
MatteoGuarnaccia5 Oct 15, 2025
cff12d2
fix tests
MatteoGuarnaccia5 Oct 15, 2025
1cfeebf
fix cy.visit url in e2e api tests
MatteoGuarnaccia5 Oct 15, 2025
e04d1d9
Merge branch 'develop' into refactor-admin-page-to-utilise-authorisat…
MatteoGuarnaccia5 Oct 15, 2025
c194e64
fix e2e api test
MatteoGuarnaccia5 Oct 16, 2025
912363f
Merge branch 'develop' into refactor-admin-page-to-utilise-authorisat…
MatteoGuarnaccia5 Oct 16, 2025
05c07cd
refacot auth provider component to use config provider context for se…
MatteoGuarnaccia5 Oct 16, 2025
4141544
update tokens in tests to reflect new userIsAdmin field
MatteoGuarnaccia5 Oct 16, 2025
67bd92d
fix unit test
MatteoGuarnaccia5 Oct 20, 2025
ff1ec3d
refactor useAuthorisation return
MatteoGuarnaccia5 Oct 20, 2025
809b8cf
addressed comments
MatteoGuarnaccia5 Oct 21, 2025
f4aa8d2
updated snapshots
MatteoGuarnaccia5 Oct 21, 2025
7186838
addressed comments
MatteoGuarnaccia5 Oct 27, 2025
f9864bf
refactored auth status banner to reflect imeplemtation in datagateway
MatteoGuarnaccia5 Oct 29, 2025
5ec391e
updated snapshots
MatteoGuarnaccia5 Oct 29, 2025
2dd4580
addressed comments refactoring auth banner, documentation and dev adm…
MatteoGuarnaccia5 Oct 30, 2025
e593f2b
Merge branch 'develop' into refactor-admin-page-to-utilise-authorisat…
MatteoGuarnaccia5 Oct 30, 2025
ed4ed06
update snapshot
MatteoGuarnaccia5 Oct 30, 2025
5db5d40
undo snapshot change
MatteoGuarnaccia5 Oct 30, 2025
00f0802
ensure breadcumbs and auth banner are inline
MatteoGuarnaccia5 Oct 30, 2025
98157a3
Merge branch 'develop' into refactor-admin-page-to-utilise-authorisat…
MatteoGuarnaccia5 Oct 30, 2025
b53e519
update snapshot
MatteoGuarnaccia5 Oct 30, 2025
819cd09
fix type and remove whitespace above banner in scigateway
MatteoGuarnaccia5 Nov 4, 2025
2cf42b2
Merge branch 'develop' into refactor-admin-page-to-utilise-authorisat…
MatteoGuarnaccia5 Nov 4, 2025
00aeb7b
update snapshots
MatteoGuarnaccia5 Nov 4, 2025
7d3f1c0
refactor authProvider to useCallback as well to avoid multiple event …
MatteoGuarnaccia5 Nov 5, 2025
5636d80
dynamically adjust page height based on authState
MatteoGuarnaccia5 Nov 10, 2025
f7e596c
update snapshots
MatteoGuarnaccia5 Nov 10, 2025
879af08
refactor padding for app bar which removes need for dynamic page height
MatteoGuarnaccia5 Nov 11, 2025
b772c23
fix text colour on auth banner
MatteoGuarnaccia5 Nov 11, 2025
531b222
Merge branch 'develop' into refactor-admin-page-to-utilise-authorisat…
MatteoGuarnaccia5 Nov 12, 2025
b6563fe
Merge branch 'develop' into implement-base-authorisation-#1472
MatteoGuarnaccia5 Nov 12, 2025
31f1ab9
Merge branch 'develop' into implement-base-authorisation-#1472
MatteoGuarnaccia5 Nov 13, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Dockerfile.prod
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ ENV MAX_ATTACHMENT_SIZE_BYTES=104857600
ENV ATTACHMENT_ALLOWED_FILE_EXTENSIONS='[".csv", ".doc", ".docx", ".pdf", ".rtf", ".txt", ".xls", ".xlsx"]'
ENV IMAGE_ALLOWED_FILE_EXTENSIONS='[".bmp", ".jpe", ".jpeg", ".jpg", ".png", ".tif", ".tiff", ".webp"]'
ENV MAX_IMAGE_SIZE_BYTES=52428800
ENV PRIVILEGED_ROLES='["admin"]'

COPY docker/docker-entrypoint.sh /usr/local/bin/
ENTRYPOINT ["docker-entrypoint.sh"]
Expand Down
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,3 +127,16 @@ This guide outlines the steps to perform end-to-end testing for the Inventory Ma
By following these instructions, you can effectively conduct end-to-end testing for the Inventory Management System. Choose the method that best suits your testing requirements and development environment.

**Note:** On the CI environment, the IMS-API is accessed via `127.0.0.1` due to issues with `localhost`.

### Authorisation

The system checks the role associated with the access token against the `privilegedRoles`. This determines whether the current user is a privileged user, and so has extra functionality available to them (see below).

**Note** Currently the only privileged role is `admin`.

For development an admin access token can be set via the `Privileged user` toggle (top right-hand corner of screen in dev mode), or through SciGateway authentication. To setup admin users please follow the instructions on [ldap-jwt-auth](https://github.com/ral-facilities/ldap-jwt-auth?tab=readme-ov-file#how-to-add-or-remove-a-user-from-the-system) and [inventory-management-system-api](https://github.com/ral-facilities/inventory-management-system-api?tab=readme-ov-file#jwt-authenticationauthorization)

**Privileged users have the following functionality avaiable to them**

- Create and delete units and usage statuses
- Bypass rules when creating, deleting, editing, or moving items
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {

describe('Catalogue Category', () => {
beforeEach(() => {
cy.setCurrentUserToAdmin();
cy.dropIMSCollections(['catalogue_categories', 'units']);
cy.visit('/catalogue');
});
Expand All @@ -20,7 +21,7 @@ describe('Catalogue Category', () => {

it('CRUD for catalogue categories', () => {
//Prepare data for catalogue categories
cy.visit('/admin-ims/units');
cy.visit('/settings/units');
addUnits(['mm', 'nm'], true);
cy.visit('/catalogue');
addCatalogueCategories();
Expand Down
3 changes: 2 additions & 1 deletion cypress/e2e/with_api/catalogueItems/catalogueItems.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {

describe('catalogue items', () => {
beforeEach(() => {
cy.setCurrentUserToAdmin();
cy.dropIMSCollections([
'catalogue_categories',
'catalogue_items',
Expand All @@ -33,7 +34,7 @@ describe('catalogue items', () => {
// Prepare relevant data for catalogue items
cy.visit('/manufacturers');
addManufacturer(true);
cy.visit('/admin-ims/units');
cy.visit('/settings/units');
addUnits(['mm', 'nm'], true);
cy.visit('/catalogue');
addCatalogueCategories(true);
Expand Down
3 changes: 2 additions & 1 deletion cypress/e2e/with_api/items/items.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {

describe('items', () => {
beforeEach(() => {
cy.setCurrentUserToAdmin();
cy.dropIMSCollections([
'catalogue_categories',
'catalogue_items',
Expand All @@ -25,7 +26,7 @@ describe('items', () => {
// Prepare relevant data for items
cy.visit('/manufacturers');
addManufacturer(true);
cy.visit('/admin-ims/units');
cy.visit('/settings/units');
addUnits(['mm', 'nm'], true);
cy.visit('/systems');
addSystems(true);
Expand Down
9 changes: 5 additions & 4 deletions cypress/e2e/with_api/systemTypes/systemTypes.cy.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
describe('Usage Statuses', () => {
describe('System Types', () => {
beforeEach(() => {
cy.visit('/admin-ims/system-types');
cy.setCurrentUserToAdmin();
cy.visit('/settings/system-types');
});
afterEach(() => {
cy.clearMocks();
Expand All @@ -19,9 +20,9 @@ describe('Usage Statuses', () => {
cy.findByText('Scrapped').should('not.exist');
cy.findByText('Storage').should('exist');

// filters by spares defintion from the admin page
// filters by spares defintion from the settings page

cy.findByRole('button', { name: 'navigate to admin home' }).click();
cy.findByRole('button', { name: 'navigate to settings home' }).click();
cy.findByText('Spares Definition').click();
cy.findByText('Operational').should('not.exist');
cy.findByText('Scrapped').should('not.exist');
Expand Down
3 changes: 2 additions & 1 deletion cypress/e2e/with_api/systems/systems.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {

describe('systems', () => {
beforeEach(() => {
cy.setCurrentUserToAdmin();
cy.dropIMSCollections([
'catalogue_categories',
'catalogue_items',
Expand All @@ -28,7 +29,7 @@ describe('systems', () => {
// Prepare relevant data for systems
cy.visit('/manufacturers');
addManufacturer(true);
cy.visit('/admin-ims/units');
cy.visit('/settings/units');
addUnits(['mm', 'nm'], true);
cy.visit('/systems');
addSystems();
Expand Down
3 changes: 2 additions & 1 deletion cypress/e2e/with_api/units/units.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ import { addUnits, deleteUnits } from './functions';

describe('Units', () => {
beforeEach(() => {
cy.setCurrentUserToAdmin();
cy.dropIMSCollections(['units']);
cy.visit('/admin-ims/units');
cy.visit('/settings/units');
});
afterEach(() => {
cy.clearMocks();
Expand Down
3 changes: 2 additions & 1 deletion cypress/e2e/with_api/usageStatuses/usageStatuses.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import { addUsageStatuses, deleteUsageStatuses } from './functions';

describe('Usage Statuses', () => {
beforeEach(() => {
cy.visit('/admin-ims/usage-statuses');
cy.setCurrentUserToAdmin();
cy.visit('/settings/usage-statuses');
});
afterEach(() => {
cy.clearMocks();
Expand Down
2 changes: 1 addition & 1 deletion cypress/e2e/with_mock_data/rules.cy.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
describe('Rules page', () => {
beforeEach(() => {
cy.visit('/admin-ims/rules');
cy.visit('/settings/rules');
});

it('renders table correctly', () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
describe('Admin Page', () => {
describe('Settings Page', () => {
beforeEach(() => {
cy.visit('/admin-ims');
cy.visit('/settings');
});

it('should render admin page correctly', () => {
it('should render settings page correctly', () => {
cy.findByText('Units').should('be.visible');
cy.findByText('Usage Statuses').should('be.visible');
cy.findByText('System Types').should('be.visible');
});

it('display 404 page for invalid route', () => {
cy.visit('/admin-ims/not_exist');
cy.visit('/settings/not_exist');
cy.findByText(
`We're sorry, the page you requested was not found on the server. If you entered the URL manually please check your spelling and try again. Otherwise, return to the`,
{ exact: false }
).should('exist');

cy.findByRole('link', { name: 'admin home page' }).should('exist');
cy.findByRole('link', { name: 'settings home page' }).should('exist');
});

it('should navigate to the filtered systems types page for the spares definition', () => {
Expand Down
2 changes: 1 addition & 1 deletion cypress/e2e/with_mock_data/systemTypes.cy.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
describe('System Types', () => {
beforeEach(() => {
cy.visit('/admin-ims/system-types');
cy.visit('/settings/system-types');
});
afterEach(() => {
cy.clearMocks();
Expand Down
3 changes: 2 additions & 1 deletion cypress/e2e/with_mock_data/units.cy.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
describe('Units', () => {
beforeEach(() => {
cy.visit('/admin-ims/units');
cy.setCurrentUserToAdmin();
cy.visit('/settings/units');
});
afterEach(() => {
cy.clearMocks();
Expand Down
3 changes: 2 additions & 1 deletion cypress/e2e/with_mock_data/usageStatus.cy.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
describe('UsageStatus', () => {
beforeEach(() => {
cy.visit('/admin-ims/usage-statuses');
cy.setCurrentUserToAdmin();
cy.visit('/settings/usage-statuses');
});
afterEach(() => {
cy.clearMocks();
Expand Down
20 changes: 20 additions & 0 deletions cypress/support/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,20 @@ Cypress.Commands.add('findBrowserMockedRequests', ({ method, url }) => {
});
});

/**
* Sets the current token in localstorage to one that contains an admin role
* The relevant part of the token's payload is: {role: 'admin', userIsAdmin: false}
* This is used wherever specific admin functionality needs to be tested
*/
Cypress.Commands.add('setCurrentUserToAdmin', () => {
cy.window().then((win) => {
win.localStorage.setItem(
'scigateway:token',
'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InVzZXJuYW1lIiwicm9sZSI6ImFkbWluIiwidXNlcklzQWRtaW4iOmZhbHNlLCJleHAiOjI1MzQwMjMwMDc5OX0.FrsDUqnKskhIvmIjtYVgC9im-cSu1dFlwVQ4cFJf2BgCaSh82XuEngOLkbtQuuXWC1wiipsGP4Y-usq7Q_R68vwXqGYusHo4fXw6AcBcwplgXZ3n60wsTegpBxKZY5foOre0Ng1GpK-7rrx9H-YQUCHSBOtzWOw_eLzu-eNTwMnMnnpGM9L91_hj0dAKiP90Z3Hp0UelnYydc0sf6msOs7RKI2Sij-13vFSL8LToIbfUTZYwKZHbBPD5glce_gsW6_W5W-iGemt7yyhfyf7IxKWq3Q02HCiSkI0uCcBal44sabPrsQ4EaPRwyUnH0X25MC00IAPRHh-1KqabV7IA9w'
);
});
});

declare global {
interface Window {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
Expand Down Expand Up @@ -193,6 +207,12 @@ declare global {
* @example cy.dropIMSCollections(['catalogue_categories']);
*/
dropIMSCollections(collections: string[]): Chainable<unknown>;
/**
* Sets the token in localstorage to admin role token
*
* @example cy.setCurrentUserToAdmin()
*/
setCurrentUserToAdmin(): Chainable<unknown>;
}
}
}
2 changes: 2 additions & 0 deletions docker/docker-entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@ jq \
--argjson attachmentAllowedFileExtensions "$ATTACHMENT_ALLOWED_FILE_EXTENSIONS" \
--argjson imageAllowedFileExtensions "$IMAGE_ALLOWED_FILE_EXTENSIONS" \
--argjson maxImageSizeBytes $MAX_IMAGE_SIZE_BYTES \
--argjson privilegedRoles $PRIVILEGED_ROLES \
--arg pluginHost "$PLUGIN_HOST" \
'.imsApiUrl = $imsApiUrl |
.osApiUrl = $osApiUrl |
.maxAttachmentSizeBytes = $maxAttachmentSizeBytes |
.attachmentAllowedFileExtensions = $attachmentAllowedFileExtensions |
.imageAllowedFileExtensions = $imageAllowedFileExtensions |
.maxImageSizeBytes = $maxImageSizeBytes |
.privilegedRoles = $privilegedRoles |
.pluginHost = $pluginHost' \
/usr/local/apache2/htdocs/inventory-management-system-settings.json > "$TEMPFILE"

Expand Down
5 changes: 3 additions & 2 deletions public/inventory-management-system-settings.example.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
".webp"
],
"maxImageSizeBytes": 52428800,
"privilegedRoles": ["admin"],
"routes": [
{
"section": "homepage",
Expand Down Expand Up @@ -52,8 +53,8 @@
},
{
"section": "Inventory Management System",
"link": "/admin-ims",
"displayName": "Admin",
"link": "/settings",
"displayName": "Settings",
"order": 4
}
],
Expand Down
1 change: 1 addition & 0 deletions server/e2e-settings-with-api.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
".webp"
],
"maxImageSizeBytes": 52428800,
"privilegedRoles": ["admin"],
"routes": [
{
"section": "Inventory Management System",
Expand Down
1 change: 1 addition & 0 deletions server/e2e-settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
".webp"
],
"maxImageSizeBytes": 52428800,
"privilegedRoles": ["admin"],
"routes": [
{
"section": "Inventory Management System",
Expand Down
59 changes: 31 additions & 28 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ import {
createBrowserRouter,
type RouteObject,
} from 'react-router';
import AdminCardView from './admin/adminCardView.component';
import AdminLayout, {
AdminErrorComponent,
} from './admin/adminLayout.component';
import Rules from './admin/rules/rules.component';
import SystemTypes from './admin/systemTypes/systemTypes.component';
import Units from './admin/units/units.component';
import UsageStatuses from './admin/usageStatuses/usageStatuses.component';
import SettingsCardView from './settings/settingsCardView.component';
import SettingsLayout, {
SettingsErrorComponent,
} from './settings/settingsLayout.component';
import Rules from './settings/rules/rules.component';
import SystemTypes from './settings/systemTypes/systemTypes.component';
import Units from './settings/units/units.component';
import UsageStatuses from './settings/usageStatuses/usageStatuses.component';
import {
clearFailedAuthRequestsQueue,
retryFailedAuthRequests,
Expand Down Expand Up @@ -68,6 +68,7 @@ import SystemsLayout, {
systemsLayoutLoader,
} from './systems/systemsLayout.component';
import ViewTabs from './view/viewTabs.component';
import { AuthProvider } from './authProvider.component';

export const queryClient = new QueryClient({
queryCache: new QueryCache({
Expand Down Expand Up @@ -107,17 +108,17 @@ const routeObject: RouteObject[] = [
],
},
{
path: paths.admin,
Component: AdminLayout,
path: paths.settings,
Component: SettingsLayout,
children: [
{ index: true, Component: AdminCardView },
{ path: paths.adminUnits, Component: Units },
{ path: paths.adminUsageStatuses, Component: UsageStatuses },
{ path: paths.adminSystemTypes, Component: SystemTypes },
{ path: paths.adminRules, Component: Rules },
{ index: true, Component: SettingsCardView },
{ path: paths.settingsUnits, Component: Units },
{ path: paths.settingsUsageStatuses, Component: UsageStatuses },
{ path: paths.settingsSystemTypes, Component: SystemTypes },
{ path: paths.settingsRules, Component: Rules },
{
path: '*',
Component: AdminErrorComponent,
Component: SettingsErrorComponent,
},
],
},
Expand Down Expand Up @@ -275,18 +276,20 @@ export function Layout() {
<LocalizationProvider adapterLocale={enGB} dateAdapter={AdapterDateFns}>
<IMSThemeProvider>
<ConfigProvider>
<QueryClientProvider client={queryClient}>
<APIConfigProvider>
<React.Suspense
fallback={
<Preloader loading={true}>Finished loading</Preloader>
}
>
<ViewTabs />
<ReactQueryDevtools initialIsOpen={false} />
</React.Suspense>
</APIConfigProvider>
</QueryClientProvider>
<AuthProvider>
<QueryClientProvider client={queryClient}>
<APIConfigProvider>
<React.Suspense
fallback={
<Preloader loading={true}>Finished loading</Preloader>
}
>
<ViewTabs />
<ReactQueryDevtools initialIsOpen={false} />
</React.Suspense>
</APIConfigProvider>
</QueryClientProvider>
</AuthProvider>
</ConfigProvider>
</IMSThemeProvider>
</LocalizationProvider>
Expand Down
Loading