diff --git a/.gitea/tools/render-docker-compose-ci.sh b/.gitea/tools/render-docker-compose-ci.sh new file mode 100755 index 0000000..e0401a3 --- /dev/null +++ b/.gitea/tools/render-docker-compose-ci.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash +set -e +set +x +set -o pipefail + +cat >"./docker-compose-ci-${COMPOSE_PROJECT}.yaml" <> $GITHUB_OUTPUT - name: "Get build options" id: "get-build-options" run: | @@ -37,28 +36,6 @@ jobs: echo "SHORT_SHA=$SHORT_SHA" >> $GITHUB_OUTPUT echo "BUILD_ARCH=$BUILD_ARCH" >> $GITHUB_OUTPUT echo "BUILD_PLATFORM=$BUILD_PLATFORM" >> $GITHUB_OUTPUT - - name: "Get `backend` version" - id: "get-backend-version" - run: | - set -x - if [ "${GITHUB_REF_NAME}" = "development" ]; then - VERSION="${GITHUB_SHA::8}" - BUILD="${GITHUB_RUN_NUMBER}" - else - VERSION="v$(grep -Po '(?<=^version\s=\s")[^"]+' services/backend/pyproject.toml)" - BUILD="01" - fi - echo "HOTPOCKET_BACKEND_VERSION=$VERSION" >> $GITHUB_OUTPUT - echo "HOTPOCKET_BACKEND_BUILD=$BUILD" >> $GITHUB_OUTPUT - - run-checks: - name: "Checks" - runs-on: "ubuntu-latest" - needs: - - "setup" - steps: - - name: "Checkout the code" - uses: "actions/checkout@v2" - name: "Set up Docker Buildx" id: "setup-docker-buildx" uses: "docker/setup-buildx-action@v3" @@ -76,8 +53,10 @@ jobs: context: "services/" push: false load: true - tags: "docker-hosted.nexus.bthlabs.pl/hotpocket/postgres:15.13-local" - platforms: "${{ needs.setup.outputs.BUILD_PLATFORM }}" + tags: "docker-hosted.nexus.bthlabs.pl/hotpocket/postgres:15.13-${{ steps.get-run-info.outputs.COMPOSE_PROJECT }}" + platforms: "${{ steps.get-build-options.outputs.BUILD_PLATFORM }}" + cache-from: "type=registry,ref=nexus.bthlab.bthlabs.net:8001/hotpocket" + cache-to: "type=registry,ref=nexus.bthlab.bthlabs.net:8001/hotpocket,mode=max" - name: "Build `keycloak` image" uses: docker/build-push-action@v6 with: @@ -85,8 +64,10 @@ jobs: context: "services/" push: false load: true - tags: "docker-hosted.nexus.bthlabs.pl/hotpocket/keycloak:22.0.3-local" - platforms: "${{ needs.setup.outputs.BUILD_PLATFORM }}" + tags: "docker-hosted.nexus.bthlabs.pl/hotpocket/keycloak:22.0.3-${{ steps.get-run-info.outputs.COMPOSE_PROJECT }}" + platforms: "${{ steps.get-build-options.outputs.BUILD_PLATFORM }}" + cache-from: "type=registry,ref=nexus.bthlab.bthlabs.net:8001/hotpocket" + cache-to: "type=registry,ref=nexus.bthlab.bthlabs.net:8001/hotpocket,mode=max" - name: "Build `rabbitmq` image" uses: docker/build-push-action@v6 with: @@ -94,8 +75,10 @@ jobs: context: "services/" push: false load: true - tags: "docker-hosted.nexus.bthlabs.pl/hotpocket/rabbitmq:3.10.8-local" - platforms: "${{ needs.setup.outputs.BUILD_PLATFORM }}" + tags: "docker-hosted.nexus.bthlabs.pl/hotpocket/rabbitmq:3.10.8-${{ steps.get-run-info.outputs.COMPOSE_PROJECT }}" + platforms: "${{ steps.get-build-options.outputs.BUILD_PLATFORM }}" + cache-from: "type=registry,ref=nexus.bthlab.bthlabs.net:8001/hotpocket" + cache-to: "type=registry,ref=nexus.bthlab.bthlabs.net:8001/hotpocket,mode=max" - name: "Build `backend-ci` image" uses: docker/build-push-action@v6 with: @@ -104,8 +87,10 @@ jobs: target: "ci" push: false load: true - tags: "docker-hosted.nexus.bthlabs.pl/hotpocket/backend:ci-local" - platforms: "${{ needs.setup.outputs.BUILD_PLATFORM }}" + tags: "docker-hosted.nexus.bthlabs.pl/hotpocket/backend:ci-${{ steps.get-run-info.outputs.COMPOSE_PROJECT }}" + platforms: "${{ steps.get-build-options.outputs.BUILD_PLATFORM }}" + cache-from: "type=registry,ref=nexus.bthlab.bthlabs.net:8001/hotpocket" + cache-to: "type=registry,ref=nexus.bthlab.bthlabs.net:8001/hotpocket,mode=max" - name: "Build `packages-ci` image" uses: docker/build-push-action@v6 with: @@ -114,8 +99,10 @@ jobs: target: "ci" push: false load: true - tags: "docker-hosted.nexus.bthlabs.pl/hotpocket/packages:ci-local" - platforms: "${{ needs.setup.outputs.BUILD_PLATFORM }}" + tags: "docker-hosted.nexus.bthlabs.pl/hotpocket/packages:ci-${{ steps.get-run-info.outputs.COMPOSE_PROJECT }}" + platforms: "${{ steps.get-build-options.outputs.BUILD_PLATFORM }}" + cache-from: "type=registry,ref=nexus.bthlab.bthlabs.net:8001/hotpocket" + cache-to: "type=registry,ref=nexus.bthlab.bthlabs.net:8001/hotpocket,mode=max" - name: "Build `extension-ci` image" uses: docker/build-push-action@v6 with: @@ -124,8 +111,10 @@ jobs: target: "ci" push: false load: true - tags: "docker-hosted.nexus.bthlabs.pl/hotpocket/extension:ci-local" - platforms: "${{ needs.setup.outputs.BUILD_PLATFORM }}" + tags: "docker-hosted.nexus.bthlabs.pl/hotpocket/extension:ci-${{ steps.get-run-info.outputs.COMPOSE_PROJECT }}" + platforms: "${{ steps.get-build-options.outputs.BUILD_PLATFORM }}" + cache-from: "type=registry,ref=nexus.bthlab.bthlabs.net:8001/hotpocket" + cache-to: "type=registry,ref=nexus.bthlab.bthlabs.net:8001/hotpocket,mode=max" - name: "Build `apple-ci` image" uses: docker/build-push-action@v6 with: @@ -134,29 +123,79 @@ jobs: target: "ci" push: false load: true - tags: "docker-hosted.nexus.bthlabs.pl/hotpocket/apple:ci-local" - platforms: "${{ needs.setup.outputs.BUILD_PLATFORM }}" + tags: "docker-hosted.nexus.bthlabs.pl/hotpocket/apple:ci-${{ steps.get-run-info.outputs.COMPOSE_PROJECT }}" + platforms: "${{ steps.get-build-options.outputs.BUILD_PLATFORM }}" + cache-from: "type=registry,ref=nexus.bthlab.bthlabs.net:8001/hotpocket" + cache-to: "type=registry,ref=nexus.bthlab.bthlabs.net:8001/hotpocket,mode=max" + - name: "Prepare the build" + id: "prepare" + env: + COMPOSE_PROJECT: "${{ steps.get-run-info.outputs.COMPOSE_PROJECT }}" + run: | + set -x + ./.gitea/tools/render-docker-compose-ci.sh - name: "Run `backend` checks" + if: "steps.prepare.conclusion == 'success'" + env: + COMPOSE_PROJECT: "${{ steps.get-run-info.outputs.COMPOSE_PROJECT }}" run: | set -x - docker compose -f docker-compose.yaml -f docker-compose-ci.yaml run --rm backend-ci inv ci + docker compose \ + -p "${COMPOSE_PROJECT}" \ + -f "docker-compose.yaml" \ + -f "docker-compose-ci.yaml" \ + -f "docker-compose-ci-${COMPOSE_PROJECT}.yaml" \ + run --rm \ + backend-ci inv ci - name: "Run `packages` checks" - if: always() + if: "steps.prepare.conclusion == 'success'" + env: + COMPOSE_PROJECT: "${{ steps.get-run-info.outputs.COMPOSE_PROJECT }}" run: | set -x - docker compose -f docker-compose.yaml -f docker-compose-ci.yaml run --rm packages-ci inv ci + docker compose \ + -p "${COMPOSE_PROJECT}" \ + -f "docker-compose.yaml" \ + -f "docker-compose-ci.yaml" \ + -f "docker-compose-ci-${COMPOSE_PROJECT}.yaml" \ + run --rm \ + packages-ci inv ci - name: "Run `extension` checks" - if: always() + if: "steps.prepare.conclusion == 'success'" + env: + COMPOSE_PROJECT: "${{ steps.get-run-info.outputs.COMPOSE_PROJECT }}" run: | set -x - docker compose -f docker-compose.yaml -f docker-compose-ci.yaml run --rm extension-ci inv ci + docker compose \ + -p "${COMPOSE_PROJECT}" \ + -f "docker-compose.yaml" \ + -f "docker-compose-ci.yaml" \ + -f "docker-compose-ci-${COMPOSE_PROJECT}.yaml" \ + run --rm \ + extension-ci inv ci - name: "Run `apple` checks" - if: always() + if: "steps.prepare.conclusion == 'success'" + env: + COMPOSE_PROJECT: "${{ steps.get-run-info.outputs.COMPOSE_PROJECT }}" run: | set -x - docker compose -f docker-compose.yaml -f docker-compose-ci.yaml run --rm apple-ci inv ci + docker compose \ + -p "${COMPOSE_PROJECT}" \ + -f "docker-compose.yaml" \ + -f "docker-compose-ci.yaml" \ + -f "docker-compose-ci-${COMPOSE_PROJECT}.yaml" \ + run --rm \ + apple-ci inv ci - name: "Clean up" if: always() + env: + COMPOSE_PROJECT: "${{ steps.get-run-info.outputs.COMPOSE_PROJECT }}" run: | set -x - docker compose -f docker-compose.yaml -f docker-compose-ci.yaml down --volumes + docker compose \ + -p "${COMPOSE_PROJECT}" \ + -f "docker-compose.yaml" \ + -f "docker-compose-ci.yaml" \ + -f "docker-compose-ci-${COMPOSE_PROJECT}.yaml" \ + down --volumes --rmi all || true + rm -f "docker-compose-ci-${COMPOSE_PROJECT}.yaml" || true diff --git a/.gitignore b/.gitignore index e445853..94bc380 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .envrc* .ipythonhome/ +/docker-compose-ci-*.yaml diff --git a/NOTICE.txt b/NOTICE.txt index 0bd2b7b..3a30cac 100644 --- a/NOTICE.txt +++ b/NOTICE.txt @@ -86,3 +86,5 @@ Licensed under terms of the MIT License Pepper Hot Solid icon Copyright (c) Icons8 Licensed under terms of the MIT License + +Spinner Loader CSS from https://css-loaders.com/ diff --git a/docker-compose-ci.yaml b/docker-compose-ci.yaml index 9d9c19d..8b2f3e8 100644 --- a/docker-compose-ci.yaml +++ b/docker-compose-ci.yaml @@ -1,14 +1,14 @@ services: postgres: - ports: [] + ports: !override [] keycloak: command: "echo 'NOOP'" - ports: [] + ports: !override [] restart: "no" rabbitmq: - ports: [] + ports: !override [] include: - path: "./services/backend/docker-compose-ci.yaml" diff --git a/services/extension/src/background/main.js b/services/extension/src/background/main.js index 2820064..86fa370 100644 --- a/services/extension/src/background/main.js +++ b/services/extension/src/background/main.js @@ -164,7 +164,7 @@ const doHandleAuthFlow = (authTab) => { ); const expectedSessionTabQuery = `?authSessionToken=${authSessionToken}`; - if (tabId !== currentAuthTabId && changedURL.includes(expectedSessionTabQuery)) { + if (tabId !== currentAuthTabId && changedURL && changedURL.includes(expectedSessionTabQuery)) { // When redirecting from the preauth page to the HotPocket instance, // Safari "replaces" the auth tab with a new one. This nasty hack will // allow the extension to keep track of it. @@ -268,7 +268,7 @@ const doSetupRPC = async () => { }; const doSendTabMessage = (tab, message) => { - HotPocketExtension.api.tabs.sendMessage(tab.id, message). + return HotPocketExtension.api.tabs.sendMessage(tab.id, message). then((result) => { HotPocketExtension.LOGGER.debug( 'HotPocketExtension.background.doSendTabMessage(): message sent', @@ -327,6 +327,10 @@ const onBrowserActionClicked = async (tab) => { let result = false; let error = null; + await doSendTabMessage(tab, { + type: 'HotPocket:Extension:browserActionClicked', + }); + try { let accessToken = await doSetupRPC(); @@ -348,7 +352,7 @@ const onBrowserActionClicked = async (tab) => { error: error, }; - doSendTabMessage(tab, message); + return await doSendTabMessage(tab, message); }; const onMessage = (message, sender, sendResponse) => { diff --git a/services/extension/src/content/main.js b/services/extension/src/content/main.js index 7f40802..ae660e4 100644 --- a/services/extension/src/content/main.js +++ b/services/extension/src/content/main.js @@ -1,6 +1,7 @@ import HotPocketExtension from '../common'; import POPUP from './templates/popup.html'; +import POPUP_CONTENT_SAVING from './templates/popup_content_saving.html'; import POPUP_CONTENT_SUCCESS from './templates/popup_content_success.html'; import POPUP_CONTENT_ERROR from './templates/popup_content_error.html'; @@ -18,6 +19,19 @@ class Popup { this.timeout = null; } }; + setContent = (content) => { + const shadow = this.container.shadowRoot; + + const body = shadow.querySelector('.hotpocket-extension-popup-body'); + body.innerHTML = content; + + const i18nElements = shadow.querySelectorAll('[data-message]'); + for (let i18nElement of i18nElements) { + i18nElement.innerHTML = HotPocketExtension.api.i18n.getMessage( + i18nElement.dataset.message, + ); + } + }; close = () => { this.clearCloseTimeout(); @@ -36,15 +50,7 @@ class Popup { const shadow = this.container.attachShadow({mode: 'open'}); shadow.innerHTML = POPUP; - const body = shadow.querySelector('.hotpocket-extension-popup-body'); - body.innerHTML = content; - - const i18nElements = shadow.querySelectorAll('[data-message]'); - for (let i18nElement of i18nElements) { - i18nElement.innerHTML = HotPocketExtension.api.i18n.getMessage( - i18nElement.dataset.message, - ); - } + this.setContent(content); const closeElements = shadow.querySelectorAll('.hotpocket-extension-popup-close'); for (const closeElement of closeElements) { @@ -53,6 +59,9 @@ class Popup { document.body.appendChild(this.container); }; + update = (content) => { + this.setContent(content); + }; onCloseClick = (event) => { this.close(); }; @@ -60,15 +69,27 @@ class Popup { let currentPopup = null; -const doHandleSaveMessage = (message) => { +const doHandleBrowserActionClickedMessage = (message) => { if (currentPopup !== null) { currentPopup.close(); } currentPopup = new Popup(); - currentPopup.show( - (message.result === true) ? POPUP_CONTENT_SUCCESS : POPUP_CONTENT_ERROR, - ); + currentPopup.show(POPUP_CONTENT_SAVING); +}; + +const doHandleSaveMessage = (message) => { + let content = POPUP_CONTENT_ERROR; + if (message.result === true) { + content = POPUP_CONTENT_SUCCESS; + } + + if (currentPopup === null) { + currentPopup = new Popup(); + currentPopup.show(content); + } else { + currentPopup.update(content); + } }; const doSendMessage = (message) => { @@ -93,7 +114,9 @@ export default ({...configuration}) => { let response = {ok: true}; try { - if (message.type === 'HotPocket:Extension:save') { + if (message.type === 'HotPocket:Extension:browserActionClicked') { + doHandleBrowserActionClickedMessage(message); + } else if (message.type === 'HotPocket:Extension:save') { doHandleSaveMessage(message); } } catch (exception) { diff --git a/services/extension/src/content/templates/popup.html b/services/extension/src/content/templates/popup.html index 1b262ca..e96837a 100644 --- a/services/extension/src/content/templates/popup.html +++ b/services/extension/src/content/templates/popup.html @@ -58,6 +58,9 @@ .hotpocket-extension-popup .hotpocket-extension-popup-body > * { margin: 0px; } +.hotpocket-extension-popup .hotpocket-extension-popup-body > .hotpocket-extension-popup-loader { + margin: 0px auto; +} .hotpocket-extension-popup .hotpocket-extension-popup-body strong { font-weight: 600; } @@ -67,6 +70,33 @@ .hotpocket-extension-popup .hotpocket-extension-popup-message-error { color: #EE6476; } +.hotpocket-extension-popup-loader { + animation: hotpocket-extension-popup-loader-animation 1s infinite steps(12); + aspect-ratio: 1; + background: + linear-gradient(0deg ,rgb(240 240 240/50%) 30%,#0000 0 70%,rgb(240 240 240/100%) 0) 50%/8% 100%, + linear-gradient(90deg,rgb(240 240 240/25%) 30%,#0000 0 70%,rgb(240 240 240/75% ) 0) 50%/100% 8%; + background-repeat: no-repeat; + border-radius: 50%; + display: grid; + width: 32px; +} +.hotpocket-extension-popup-loader::before, +.hotpocket-extension-popup-loader::after { + background: inherit; + border-radius: 50%; + content: ""; + grid-area: 1/1; + opacity: 0.915; + transform: rotate(30deg); +} +.hotpocket-extension-popup-loader::after { + opacity: 0.83; + transform: rotate(60deg); +} +@keyframes hotpocket-extension-popup-loader-animation { + 100% {transform: rotate(1turn)} +}
diff --git a/services/extension/src/content/templates/popup_content_saving.html b/services/extension/src/content/templates/popup_content_saving.html new file mode 100644 index 0000000..b6a0590 --- /dev/null +++ b/services/extension/src/content/templates/popup_content_saving.html @@ -0,0 +1 @@ +