diff --git a/.github/workflows/ci-build.yml b/.github/workflows/ci-build.yml index 7ce396ac..db19ee0f 100644 --- a/.github/workflows/ci-build.yml +++ b/.github/workflows/ci-build.yml @@ -38,32 +38,32 @@ jobs: run: yarn e2e docker: - # This job triggers only if all the other jobs succeed. It builds the Docker image and if successful, - # it pushes it to Harbor. + # This job triggers only if all the other jobs succeed. It builds the Docker image to ensure it builds correctly. needs: [test] name: Docker runs-on: ubuntu-20.04 steps: - name: Checkout repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Login to Harbor - uses: docker/login-action@465a07811f14bebb1938fbed4728c6a1ff8901fc # v2.2.0 + uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0 with: registry: ${{ secrets.HARBOR_URL }} username: ${{ secrets.HARBOR_USERNAME }} password: ${{ secrets.HARBOR_TOKEN }} - - name: Extract metadata (tags, labels) for Docker + - name: Extract metadata (tags, labels, annotations) for Docker id: meta - uses: docker/metadata-action@818d4b7b91585d195f67373fd9cb0332e31a7175 # v4.6.0 + uses: docker/metadata-action@8e5442c4ef9f78752691e2d8f8d19755c6f78e81 # v5.5.1 with: images: ${{ secrets.HARBOR_URL }}/scigateway - - name: Build and push Docker image to Harbor - uses: docker/build-push-action@0a97817b6ade9f46837855d676c4cca3a2471fc9 # v4.2.1 + - name: Build Docker image + uses: docker/build-push-action@4f58ea79222b3b9dc2c8bbdd6debcef730109a75 # v6.9.0 with: context: . - push: true + push: false tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} + annotations: ${{ steps.meta.outputs.annotations }} diff --git a/.github/workflows/docker-release-build.yml b/.github/workflows/docker-release-build.yml new file mode 100644 index 00000000..307c66e2 --- /dev/null +++ b/.github/workflows/docker-release-build.yml @@ -0,0 +1,40 @@ +name: Docker Release Build +on: + push: + tags: '*' + +jobs: + docker: + # This job builds the Docker image and if successful, it pushes it to Harbor. + name: Docker + runs-on: ubuntu-latest + steps: + - name: Checkout repo + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - name: Login to Harbor + uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0 + with: + registry: ${{ secrets.HARBOR_URL }} + username: ${{ secrets.HARBOR_USERNAME }} + password: ${{ secrets.HARBOR_TOKEN }} + + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@8e5442c4ef9f78752691e2d8f8d19755c6f78e81 # v5.5.1 + with: + images: ${{ secrets.HARBOR_URL }}/scigateway + tags: | + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=ref,event=tag,pattern={{ref}} + + - name: Build and push Docker image to Harbor + uses: docker/build-push-action@4f58ea79222b3b9dc2c8bbdd6debcef730109a75 # v6.9.0 + with: + context: . + file: ./Dockerfile + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + annotations: ${{ steps.meta.outputs.annotations }} diff --git a/.gitignore b/.gitignore index 86281662..343d0d06 100644 --- a/.gitignore +++ b/.gitignore @@ -31,5 +31,6 @@ npm-debug.log* yarn-debug.log* yarn-error.log* -public/settings.json +**/public/*settings*.json +!**/public/*settings.example.json public/*.js \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index bcd3fdfc..1dd40e51 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,38 @@ # Changelog +## [v3.0.0](https://github.com/ral-facilities/scigateway/tree/v3.0.0) (2024-11-27) + +## What's Changed + +### Features + +* add darkBlue colour to theming by @joshuadkitenge in https://github.com/ral-facilities/scigateway/pull/1375 +* Increase toast functionailty #355 by @joshuadkitenge in https://github.com/ral-facilities/scigateway/pull/1376 +* Print improvement for IMS by @joelvdavies in https://github.com/ral-facilities/scigateway/pull/1385 +* Change accessibility page variable to be more general #356 by @joshuadkitenge in https://github.com/ral-facilities/scigateway/pull/1377 +* Fix error colour inconsistency for IMS by @joelvdavies in https://github.com/ral-facilities/scigateway/pull/1393 +* Ims maintenance endpoints by @MatteoGuarnaccia5 in https://github.com/ral-facilities/scigateway/pull/1398 +* Add docker image push when tags pushed #1390 by @joelvdavies in https://github.com/ral-facilities/scigateway/pull/1420 +* Generate custom admin tabs from plugin routes #1418 by @joshuadkitenge in https://github.com/ral-facilities/scigateway/pull/1419 +* React 18 #1205 by @louise-davies in https://github.com/ral-facilities/scigateway/pull/1275 + +### Dependencies + +* Bump webpack from 5.76.1 to 5.94.0 by @dependabot in https://github.com/ral-facilities/scigateway/pull/1408 +* Update dependency axios to v1.7.4 [SECURITY] by @renovate in https://github.com/ral-facilities/scigateway/pull/1407 +* Update Node.js to v20.17.0 by @renovate in https://github.com/ral-facilities/scigateway/pull/1411 +* Update httpd:2.4.59-alpine3.20 Docker image to http:2.4.62-alpine3.20 by @renovate in https://github.com/ral-facilities/scigateway/pull/1410 +* Update dependency express to v4.20.0 [SECURITY] by @renovate in https://github.com/ral-facilities/scigateway/pull/1414 +* Bump rollup from 2.79.1 to 2.79.2 by @dependabot in https://github.com/ral-facilities/scigateway/pull/1416 +* Bump http-proxy-middleware from 2.0.6 to 2.0.7 by @dependabot in https://github.com/ral-facilities/scigateway/pull/1417 +* Bump cross-spawn from 7.0.3 to 7.0.6 by @dependabot in https://github.com/ral-facilities/scigateway/pull/1421 + +## New Contributors + +* @MatteoGuarnaccia5 made their first contribution in https://github.com/ral-facilities/scigateway/pull/1398 + +**Full Changelog**: https://github.com/ral-facilities/scigateway/compare/v2.0.0...v3.0.0 + ## [v2.0.0](https://github.com/ral-facilities/scigateway/tree/v2.0.0) (2024-07-24) ## What's Changed diff --git a/Dockerfile b/Dockerfile index ebcf5089..04070e53 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,7 @@ # Dockerfile to build and serve scigateway # Build stage -FROM node:20.14.0-alpine3.20@sha256:928b24aaadbd47c1a7722c563b471195ce54788bf8230ce807e1dd500aec0549 as builder +FROM node:20.17.0-alpine3.20@sha256:2d07db07a2df6830718ae2a47db6fedce6745f5bcd174c398f2acdda90a11c03 as builder WORKDIR /scigateway-build @@ -24,7 +24,7 @@ COPY docker/settings.json public/settings.json RUN yarn build # Run stage -FROM httpd:2.4.59-alpine3.20@sha256:554f25b8496f360a58febaaa5df9effb8e037cc1b70b27d40b7353a85e8edbf0 +FROM httpd:2.4.62-alpine3.20@sha256:66c49302c02430619abb84240a438bcfc083015661009fcaaeaac931450f62cd WORKDIR /usr/local/apache2/htdocs diff --git a/cypress/e2e/login.cy.ts b/cypress/e2e/login.cy.ts index 9bd106b5..c884d136 100644 --- a/cypress/e2e/login.cy.ts +++ b/cypress/e2e/login.cy.ts @@ -185,6 +185,24 @@ describe('Login', () => { cy.url().should('eq', 'http://127.0.0.1:3000/login'); }); + it('should redirect to login page when navigating to a plugin then back to the plugin after login', () => { + cy.visit('/plugin1'); + + cy.contains('Sign in').should('be.visible'); + + cy.contains('Username*').parent().find('input').type(' username '); + cy.contains('Password*').parent().find('input').type('password'); + + cy.contains('Username*') + .parent() + .parent() + .contains('button', 'Sign in') + .click(); + + cy.url().should('eq', 'http://127.0.0.1:3000/plugin1'); + cy.get('#demo_plugin').contains('Demo Plugin').should('be.visible'); + }); + it('should not be logged in if invalid or unsigned token in localStorage', () => { // if token cannot be deciphered cy.contains('Sign in').should('be.visible'); @@ -320,10 +338,10 @@ describe('Login', () => { ]); cy.intercept('POST', '/login', (req) => { req.reply(loginResponse); - }); + }).as('login'); cy.intercept('POST', '/verify', (req) => { req.reply(verifyResponse); - }); + }).as('verify'); }); it('should allow access to plugins and yet still show the Sign in button', () => { @@ -331,6 +349,8 @@ describe('Login', () => { loginResponse = loginSuccess; cy.visit('/plugin1'); + cy.wait('@login'); + cy.get('#demo_plugin').contains('Demo Plugin').should('be.visible'); cy.contains('Sign in').should('be.visible'); @@ -340,9 +360,13 @@ describe('Login', () => { cy.contains('Sign in').should('be.visible'); // test that autologin works after token validation + refresh fail - verifyResponse = failure; + cy.window().then(() => { + // use cy.window command just so that this line is async and executed at the right time + verifyResponse = failure; + }); cy.intercept('POST', '/refresh', { statusCode: 403 }); cy.reload(); + cy.wait('@login'); cy.get('#demo_plugin').contains('Demo Plugin').should('be.visible'); cy.contains('Sign in').should('be.visible'); }); @@ -356,7 +380,10 @@ describe('Login', () => { cy.contains('h1', 'Sign in').should('be.visible'); // test that autologin fails after token validation + refresh fail - verifyResponse = failure; + cy.window().then(() => { + // use cy.window command just so that this line is async and executed at the right time + verifyResponse = failure; + }); cy.intercept('POST', '/refresh', { statusCode: 403 }); cy.window().then(($window) => $window.localStorage.setItem('scigateway:token', 'invalidtoken') @@ -374,6 +401,37 @@ describe('Login', () => { cy.get('#demo_plugin').contains('Demo Plugin').should('be.visible'); }); + it('can remove toasts with esc keydown when a plugin error occurs', () => { + cy.intercept('/settings.json', { + plugins: [ + { + name: 'demo_plugin', + src: '/plugins/main.js', + enable: true, + location: 'main', + }, + ], + 'ui-strings': 'res/default.json', + 'auth-provider': 'icat', + authUrl: 'http://localhost:8000', + autoLogin: true, + 'help-tour-steps': [], + }); + verifyResponse = verifySuccess; + loginResponse = loginSuccess; + cy.visit('/plugin1'); + + cy.contains( + 'Failed to load plugin demo_plugin from /plugins/main.js.' + ).should('exist'); + + cy.get('body').type('{esc}'); + + cy.contains( + 'Failed to load plugin demo_plugin from /plugins/main.js.' + ).should('not.exist'); + }); + it('should be able to switch authenticators and still be "auto logged in"', () => { verifyResponse = verifySuccess; loginResponse = loginSuccess; @@ -421,6 +479,8 @@ describe('Login', () => { cy.contains('Sign out').click(); cy.contains('Sign in').should('be.visible'); + cy.wait('@login'); + cy.contains('a', 'Demo Plugin').should('be.visible'); cy.contains('a', 'Demo Plugin').click(); diff --git a/cypress/support/commands.js b/cypress/support/commands.js index e4337c83..c8504af3 100644 --- a/cypress/support/commands.js +++ b/cypress/support/commands.js @@ -26,11 +26,11 @@ Cypress.Commands.add('login', (username, password) => { return cy.readFile('server/e2e-settings.json').then((settings) => { - cy.request('POST', `${settings.authUrl}/api/jwt/authenticate`, { + cy.request('POST', `${settings.authUrl}/login`, { username: username, password: password, }).then((response) => { - window.localStorage.setItem('scigateway:token', response.body.token); + window.localStorage.setItem('scigateway:token', response.body); }); }); }); diff --git a/micro-frontend-tools/.gitignore b/micro-frontend-tools/.gitignore index bc71dcdf..b2664113 100644 --- a/micro-frontend-tools/.gitignore +++ b/micro-frontend-tools/.gitignore @@ -1 +1,2 @@ -dev-plugin-settings.json \ No newline at end of file +/*settings*.json +!/*settings.example.json \ No newline at end of file diff --git a/package.json b/package.json index bd1d5f88..4b167c7a 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,10 @@ { "name": "scigateway", - "version": "2.0.0", + "version": "3.0.0", "private": true, "resolutions": { - "@types/react": "17.0.38", - "@types/react-dom": "17.0.11", + "@types/react": "18.0.33", + "@types/react-dom": "18.0.11", "@typescript-eslint/eslint-plugin": "7.0.2", "@typescript-eslint/parser": "7.0.2" }, @@ -13,22 +13,22 @@ "@emotion/styled": "11.11.0", "@mui/icons-material": "5.15.10", "@mui/material": "5.15.10", - "@types/history": "4.7.3", + "@types/history": "4.7.11", "@types/jest": "29.5.2", "@types/js-cookie": "3.0.1", - "@types/react-dom": "17.0.11", - "@types/react-redux-toastr": "7.6.0", - "@types/react-router-dom": "5.3.1", + "@types/react-dom": "18.0.11", + "@types/react-redux-toastr": "7.6.2", + "@types/react-router-dom": "5.3.3", "@types/redux-logger": "3.0.8", - "axios": "1.6.2", - "connected-react-router": "6.9.1", + "axios": "1.7.4", + "connected-react-router": "6.9.3", "cookie-parser": "1.4.5", "custom-event-polyfill": "1.0.7", "cypress-failed-log": "2.10.0", "eslint-config-prettier": "9.1.0", "eslint-plugin-cypress": "2.15.1", "eslint-plugin-prettier": "5.1.3", - "express": "4.19.2", + "express": "4.20.0", "husky": "9.0.6", "i18next": "23.8.2", "i18next-browser-languagedetector": "7.2.0", @@ -39,19 +39,19 @@ "prettier": "3.2.5", "prop-types": "15.8.1", "query-string": "7.1.1", - "react": "17.0.2", + "react": "18.2.0", "react-app-polyfill": "3.0.0", - "react-dom": "17.0.2", + "react-dom": "18.2.0", "react-i18next": "14.0.1", "react-joyride": "2.7.2", "react-redux": "8.1.2", "react-redux-toastr": "7.6.8", "react-router-dom": "5.3.0", "react-scripts": "5.0.0", - "redux": "4.2.0", + "redux": "4.2.1", "redux-logger": "3.0.6", "redux-thunk": "3.1.0", - "single-spa": "5.9.1", + "single-spa": "5.9.4", "typeface-roboto": "1.1.13", "typescript": "5.3.3" }, @@ -105,13 +105,13 @@ "devDependencies": { "@babel/eslint-parser": "7.23.3", "@testing-library/jest-dom": "6.4.1", - "@testing-library/react": "12.1.5", + "@testing-library/react": "14.0.0", "@testing-library/user-event": "14.5.2", "@types/jsonwebtoken": "9.0.1", - "@types/node": "20.14.0", - "@types/react": "17.0.38", + "@types/node": "20.16.5", + "@types/react": "18.0.33", "@types/react-redux": "7.1.20", - "@types/react-router": "5.1.12", + "@types/react-router": "5.1.20", "@types/redux-mock-store": "1.0.2", "@typescript-eslint/eslint-plugin": "7.0.2", "@typescript-eslint/parser": "7.0.2", diff --git a/public/index.html b/public/index.html index 6de9f64d..fdecfc10 100644 --- a/public/index.html +++ b/public/index.html @@ -1,19 +1,17 @@ -
- - - - - - - -