From 13e3be91d4d0cc5d452ef6d2c512ed799821e889 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?gr=C3=A9goire=20parant?= Date: Mon, 4 Sep 2023 09:13:19 +0200 Subject: [PATCH] New version MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --------- Co-authored-by: grp grp Co-authored-by: David Négrier --- .env.template | 10 + .github/workflows/build-test-and-deploy.yml | 50 +- back/package.json | 3 +- .../EnvironmentVariableValidator.test.ts | 2 +- chat/Dockerfile | 1 + chat/index.html | 4 + chat/package.json | 5 +- .../static/images/applications/appOff.png | Bin 0 -> 543 bytes .../static/images/applications/appOn.png | Bin 0 -> 373 bytes .../static/images/applications/eraser.svg | 1 + .../images/applications/google-docs.svg | 1 + .../images/applications/google-forms.svg | 1 + .../images/applications/google-keeps.svg | 1 + .../images/applications/google-sheets.svg | 1 + .../images/applications/google-slides.svg | 1 + .../static/images/applications/klaxoon.svg | 17 + .../static/images/applications/youtube.svg | 1 + chat/public/static/images/no-app.png | Bin 0 -> 2394 bytes chat/src/Components/ChatMessageForm.svelte | 313 +- chat/src/Components/ChatMessagesList.svelte | 2 +- .../Content/ApplicationPicker.svelte | 113 + chat/src/Components/Content/File.svelte | 50 +- .../src/Components/Content/HtmlMessage.svelte | 75 +- chat/src/Components/Content/Message.svelte | 111 +- .../Timeline/ChatActiveThreadTimeline.svelte | 425 +- chat/src/Connection/ChatConnectionManager.ts | 55 +- chat/src/Event/IframeEvent.ts | 32 + chat/src/IframeListener.ts | 16 +- chat/src/Services/WebLinkManager.ts | 125 +- chat/src/Xmpp/AbstractRoom.ts | 6 + chat/src/Xmpp/XmppClient.ts | 4 +- chat/src/i18n/de-DE/index.ts | 36 + chat/src/i18n/en-US/index.ts | 38 +- chat/src/i18n/fr-FR/index.ts | 36 + chat/src/i18n/hsb-DE/index.ts | 31 + contrib/docker/.env.prod.template | 20 +- contrib/docker/docker-compose.prod.yaml | 7 + deeployer.libsonnet | 8 + docker-compose.yaml | 12 +- docs/schema/1.0/wam.json | 25 +- libs/map-editor/package.json | 2 +- libs/map-editor/src/GameMap/GameMapAreas.ts | 1 + libs/map-editor/src/types.ts | 25 +- libs/messages/src/JsonMessages/ChatData.ts | 7 + .../src/JsonMessages/MapDetailsData.ts | 31 +- libs/shared-utils/package.json | 2 +- .../src/Application/EraserService.ts | 10 + .../Application/Exception/EraserException.ts | 1 + .../Exception/GoogleWorkSpaceException.ts | 7 + .../Application/Exception/KlaxoonException.ts | 1 + .../src/Application/GoogleWorkSpaceService.ts | 47 + .../src/Application/KlaxoonService.ts | 99 + .../src/Application/YoutubeService.ts | 31 + libs/shared-utils/src/index.ts | 8 + libs/shared-utils/src/types.ts | 20 + libs/tailwind/style/tailwind.scss | 2 +- map-storage/package.json | 5 +- package-lock.json | 5256 ++++++++--------- package.json | 1 + play/index.html | 2 +- .../help-popup-blocked/1-popupblocked.png | Bin 0 -> 65207 bytes .../help-popup-blocked/2-popupblocked.png | Bin 0 -> 34323 bytes .../help-popup-blocked/3-popupblocked.png | Bin 0 -> 79585 bytes .../icons/applications/icon_google_docs.svg | 1 + .../icons/applications/icon_google_forms.svg | 1 + .../icons/applications/icon_google_keeps.svg | 1 + .../icons/applications/icon_google_sheets.svg | 1 + .../icons/applications/icon_google_slides.svg | 1 + .../icons/applications/icon_klaxoon.svg | 17 + .../icons/applications/icon_youtube.svg | 1 + .../src/common/FrontConfigurationInterface.ts | 7 + play/src/front/Api/Desktop/index.ts | 2 +- play/src/front/Api/Events/IframeEvent.ts | 6 + play/src/front/Api/Iframe/players.ts | 2 +- play/src/front/Api/IframeListener.ts | 11 + .../Components/ActionBar/ActionBar.svelte | 14 +- .../Components/ActionBar/Applicatons.svelte | 184 + play/src/front/Components/Chat/Chat.svelte | 11 +- .../HelpSettings/HelpPopUpBlocked.svelte | 39 + play/src/front/Components/MainLayout.svelte | 6 + .../MapEditor/AreaPropertiesEditor.svelte | 174 +- .../MapEditor/EntityPropertiesEditor.svelte | 170 +- .../Components/MapEditor/ItemPicker.svelte | 14 +- .../Components/MapEditor/MapEditor.svelte | 4 + .../PropertyEditor/AddPropertyButton.svelte | 25 +- .../OpenWebsitePropertyEditor.svelte | 249 +- .../Components/images/applications/appOff.png | Bin 0 -> 543 bytes .../Components/images/applications/appOn.png | Bin 0 -> 373 bytes .../images/applications/icon_eraser.svg | 1 + .../images/applications/icon_google_docs.svg | 1 + .../images/applications/icon_google_forms.svg | 1 + .../images/applications/icon_google_keeps.svg | 1 + .../applications/icon_google_sheets.svg | 1 + .../applications/icon_google_slides.svg | 1 + .../images/applications/icon_klaxoon.svg | 17 + .../images/applications/icon_youtube.svg | 1 + .../front/Connection/AdminMessagesService.ts | 2 +- play/src/front/Connection/AxiosUtils.ts | 2 +- .../src/front/Connection/ConnectionManager.ts | 2 +- play/src/front/Connection/Room.ts | 51 +- play/src/front/Enum/EnvironmentVariable.ts | 8 + play/src/front/Network/ServiceWorker.ts | 4 +- play/src/front/Phaser/Companion/Companion.ts | 1 - .../src/front/Phaser/Components/SoundMeter.ts | 1 - play/src/front/Phaser/ECS/Entity.ts | 5 + play/src/front/Phaser/Game/GameManager.ts | 2 +- .../Game/GameMap/GameMapFrontWrapper.ts | 4 +- .../Phaser/Game/GameMapPropertiesListener.ts | 2 +- play/src/front/Phaser/Game/GameScene.ts | 5 +- .../Game/MapEditor/AreasPropertiesListener.ts | 8 +- .../Game/MapEditor/Tools/EntityEditorTool.ts | 1 - .../Tools/EntityRelatedEditorTool.ts | 2 +- .../Game/MapEditor/Tools/FloorEditorTool.ts | 14 +- .../MapEditor/Tools/WAMSettingsEditorTool.ts | 12 +- play/src/front/Phaser/Game/PlayerMovement.ts | 3 - .../Game/PlayersPositionInterpolator.ts | 2 - .../Phaser/Services/SuperLoaderPlugin.ts | 2 +- .../Stores/HelpSettingsPopupBlockedStore.ts | 3 + play/src/front/Stores/MenuStore.ts | 1 - .../Streaming/Jitsi/JitsiTrackWrapper.ts | 1 - play/src/front/Utils/PathfindingManager.ts | 2 +- play/src/front/WebRtc/ScreenSharingPeer.ts | 2 - play/src/front/WebRtc/SimplePeer.ts | 2 - play/src/i18n/ca-ES/warning.ts | 6 + play/src/i18n/de-DE/actionbar.ts | 1 + play/src/i18n/de-DE/mapEditor.ts | 1 + play/src/i18n/de-DE/warning.ts | 5 + play/src/i18n/en-US/actionbar.ts | 1 + play/src/i18n/en-US/mapEditor.ts | 38 + play/src/i18n/en-US/warning.ts | 5 + play/src/i18n/es-ES/warning.ts | 5 + play/src/i18n/fr-FR/actionbar.ts | 1 + play/src/i18n/fr-FR/mapEditor.ts | 14 +- play/src/i18n/fr-FR/warning.ts | 5 + play/src/i18n/hsb-DE/actionbar.ts | 5 + play/src/i18n/hsb-DE/warning.ts | 5 + play/src/i18n/pt-BR/warning.ts | 5 + play/src/i18n/zh-CN/warning.ts | 5 + play/src/iframe_api.ts | 1 - .../src/pusher/controllers/FrontController.ts | 13 +- .../pusher/controllers/IoSocketController.ts | 12 +- play/src/pusher/enums/EnvironmentVariable.ts | 16 + .../enums/EnvironmentVariableValidator.ts | 7 + play/src/pusher/services/AdminApi.ts | 4 +- .../pusher/services/AdminCompanionService.ts | 2 +- play/src/pusher/services/CpuTracker.ts | 7 +- play/src/pusher/services/LocalAdmin.ts | 14 + play/src/pusher/services/MetaTagsBuilder.ts | 2 +- play/src/pusher/services/OpenIDClient.ts | 3 +- play/src/pusher/services/SocketManager.ts | 10 +- play/src/server.ts | 4 +- tests/playwright.config.ts | 3 + tests/tests/api_players.spec.ts | 1 - tests/tests/chat.spec.ts | 63 + tests/tests/iframe_script.spec.ts | 4 +- tests/tests/map_editor.spec.ts | 166 + tests/tests/map_storage_upload.spec.ts | 145 +- tests/tests/utils/containers.ts | 33 +- tests/tests/utils/map-editor/entityEditor.ts | 27 + tests/tests/utils/mapeditor.ts | 6 +- 160 files changed, 5809 insertions(+), 3142 deletions(-) create mode 100644 chat/public/static/images/applications/appOff.png create mode 100644 chat/public/static/images/applications/appOn.png create mode 100644 chat/public/static/images/applications/eraser.svg create mode 100644 chat/public/static/images/applications/google-docs.svg create mode 100644 chat/public/static/images/applications/google-forms.svg create mode 100644 chat/public/static/images/applications/google-keeps.svg create mode 100644 chat/public/static/images/applications/google-sheets.svg create mode 100644 chat/public/static/images/applications/google-slides.svg create mode 100644 chat/public/static/images/applications/klaxoon.svg create mode 100644 chat/public/static/images/applications/youtube.svg create mode 100644 chat/public/static/images/no-app.png create mode 100644 chat/src/Components/Content/ApplicationPicker.svelte create mode 100644 libs/shared-utils/src/Application/EraserService.ts create mode 100644 libs/shared-utils/src/Application/Exception/EraserException.ts create mode 100644 libs/shared-utils/src/Application/Exception/GoogleWorkSpaceException.ts create mode 100644 libs/shared-utils/src/Application/Exception/KlaxoonException.ts create mode 100644 libs/shared-utils/src/Application/GoogleWorkSpaceService.ts create mode 100644 libs/shared-utils/src/Application/KlaxoonService.ts create mode 100644 libs/shared-utils/src/Application/YoutubeService.ts create mode 100644 libs/shared-utils/src/types.ts create mode 100644 play/public/resources/help-popup-blocked/1-popupblocked.png create mode 100644 play/public/resources/help-popup-blocked/2-popupblocked.png create mode 100644 play/public/resources/help-popup-blocked/3-popupblocked.png create mode 100644 play/public/resources/icons/applications/icon_google_docs.svg create mode 100644 play/public/resources/icons/applications/icon_google_forms.svg create mode 100644 play/public/resources/icons/applications/icon_google_keeps.svg create mode 100644 play/public/resources/icons/applications/icon_google_sheets.svg create mode 100644 play/public/resources/icons/applications/icon_google_slides.svg create mode 100644 play/public/resources/icons/applications/icon_klaxoon.svg create mode 100644 play/public/resources/icons/applications/icon_youtube.svg create mode 100644 play/src/front/Components/ActionBar/Applicatons.svelte create mode 100644 play/src/front/Components/HelpSettings/HelpPopUpBlocked.svelte create mode 100644 play/src/front/Components/images/applications/appOff.png create mode 100644 play/src/front/Components/images/applications/appOn.png create mode 100644 play/src/front/Components/images/applications/icon_eraser.svg create mode 100644 play/src/front/Components/images/applications/icon_google_docs.svg create mode 100644 play/src/front/Components/images/applications/icon_google_forms.svg create mode 100644 play/src/front/Components/images/applications/icon_google_keeps.svg create mode 100644 play/src/front/Components/images/applications/icon_google_sheets.svg create mode 100644 play/src/front/Components/images/applications/icon_google_slides.svg create mode 100644 play/src/front/Components/images/applications/icon_klaxoon.svg create mode 100644 play/src/front/Components/images/applications/icon_youtube.svg create mode 100644 play/src/front/Stores/HelpSettingsPopupBlockedStore.ts create mode 100644 tests/tests/utils/map-editor/entityEditor.ts diff --git a/.env.template b/.env.template index b8ddd7076d..9ca87d0877 100644 --- a/.env.template +++ b/.env.template @@ -168,3 +168,13 @@ SENTRY_PROJECT= # RoomAPI ROOM_API_SECRET_KEY= + +# Integration tools +KLAXOON_ENABLED=false +KLAXOON_CLIENT_ID= +YOUTUBE_ENABLED=true +GOOGLE_DOCS_ENABLED=true +GOOGLE_SHEETS_ENABLED=true +GOOGLE_SLIDES_ENABLED=true +GOOGLE_DRIVE_ENABLED=true +ERASER_ENABLED=true diff --git a/.github/workflows/build-test-and-deploy.yml b/.github/workflows/build-test-and-deploy.yml index 18ecf5a581..af578acb4e 100644 --- a/.github/workflows/build-test-and-deploy.yml +++ b/.github/workflows/build-test-and-deploy.yml @@ -15,7 +15,6 @@ concurrency: jobs: build-play: runs-on: ubuntu-latest - steps: - name: Checkout uses: actions/checkout@v2 @@ -118,7 +117,6 @@ jobs: build-chat: runs-on: ubuntu-latest - steps: - name: Checkout uses: actions/checkout@v2 @@ -194,7 +192,6 @@ jobs: build-back: runs-on: ubuntu-latest - steps: - name: Checkout uses: actions/checkout@v2 @@ -295,7 +292,6 @@ jobs: build-uploader: runs-on: ubuntu-latest - steps: - name: Set up QEMU uses: docker/setup-qemu-action@v1 @@ -356,7 +352,6 @@ jobs: build-maps: runs-on: ubuntu-latest - steps: - name: Checkout uses: actions/checkout@v2 @@ -422,7 +417,6 @@ jobs: build-map-storage: runs-on: ubuntu-latest - steps: - name: Checkout uses: actions/checkout@v2 @@ -516,7 +510,6 @@ jobs: build-ejabberd: runs-on: ubuntu-latest - steps: - name: Checkout uses: actions/checkout@v2 @@ -651,51 +644,45 @@ jobs: sed -i "s/JITSI_DOMAIN=/JITSI_DOMAIN=coremeet.workadventu.re/g" .env sed -i "s/JITSI_MUC_DOMAIN=/JITSI_MUC_DOMAIN=muc.prosody.workadventu.re/g" .env sed -i "s/JITSI_XMPP_DOMAIN=/JITSI_XMPP_DOMAIN=prosody.workadventu.re/g" .env + sed -i "s/KLAXOON_ENABLED=false/KLAXOON_ENABLED=true/g" .env + sed -i "s/KLAXOON_CLIENT_ID=/KLAXOON_CLIENT_ID=${{ env.KLAXOON_CLIENT_ID }}/g" .env - - - name: Download artifact + - name: Download artifact uses: actions/download-artifact@v3 with: name: play path: /tmp - - - name: Download artifact + - name: Download artifact uses: actions/download-artifact@v3 with: name: chat path: /tmp - - - name: Download artifact + - name: Download artifact uses: actions/download-artifact@v3 with: name: back path: /tmp - - - name: Download artifact + - name: Download artifact uses: actions/download-artifact@v3 with: name: maps path: /tmp - - - name: Download artifact + - name: Download artifact uses: actions/download-artifact@v3 with: name: map-storage path: /tmp - - - name: Download artifact + - name: Download artifact uses: actions/download-artifact@v3 with: name: uploader path: /tmp - - - name: Download artifact + - name: Download artifact uses: actions/download-artifact@v3 with: name: ejabberd path: /tmp - - - name: Load image + - name: Load image run: | docker load --input /tmp/play.tar.gz docker load --input /tmp/chat.tar.gz @@ -706,11 +693,13 @@ jobs: docker load --input /tmp/ejabberd.tar.gz docker image ls -a - name: Start WorkAdventure - run: docker-compose -f docker-compose.yaml -f docker-compose-oidc.yaml -f docker-compose.e2e.yml up -d + run: | + docker-compose -f docker-compose.yaml -f docker-compose-oidc.yaml -f docker-compose.e2e.yml pull + docker-compose -f docker-compose.yaml -f docker-compose-oidc.yaml -f docker-compose.e2e.yml up -d env: DOCKER_TAG: ${{ github.event_name == 'pull_request' && env.GITHUB_HEAD_REF_SLUG || env.GITHUB_REF_SLUG }} - name: Upload test-map - run: sleep 10 && npm run upload-test-map + run: sleep 30 && npm run upload-test-map working-directory: map-storage - name: Run Playwright tests run: npm run test-prod-like -- --project=${{ matrix.browser }} --shard=${{ matrix.shard }}/${{ matrix.nbShards }} @@ -797,6 +786,8 @@ jobs: sed -i "s/JITSI_MUC_DOMAIN=/JITSI_MUC_DOMAIN=muc.prosody.workadventu.re/g" .env sed -i "s/JITSI_XMPP_DOMAIN=/JITSI_XMPP_DOMAIN=prosody.workadventu.re/g" .env sed -i "s/FEATURE_FLAG_BROADCAST_AREAS=/FEATURE_FLAG_BROADCAST_AREAS=true/g" .env + sed -i "s/KLAXOON_ENABLED=false/KLAXOON_ENABLED=true/g" .env + sed -i "s/KLAXOON_CLIENT_ID=/KLAXOON_CLIENT_ID=${{ env.KLAXOON_CLIENT_ID }}/g" .env echo "WOKA_SPEED=3" >> .env env: DOCKER_TAG: ${{ github.event_name == 'pull_request' && env.GITHUB_HEAD_REF_SLUG || env.GITHUB_REF_SLUG }} @@ -807,7 +798,10 @@ jobs: DOCKER_TAG: ${{ github.event_name == 'pull_request' && env.GITHUB_HEAD_REF_SLUG || env.GITHUB_REF_SLUG }} working-directory: contrib/docker - name: Upload test-map - run: sleep 10 && npm run upload-test-map-single-domain + run: | + sed -i "s/http:/https:/g" tests/assets/maps/empty.wam + sleep 10 + npm run upload-test-map-single-domain working-directory: map-storage - name: Run Playwright tests # Run all tests, except the ones needing to restart Docker and the ones relying on an OIDC server @@ -840,7 +834,6 @@ jobs: path: tests/playwright-report/ retention-days: 30 - deeploy: needs: - build-play @@ -912,6 +905,7 @@ jobs: ENABLE_REPORT_ISSUES_MENU: ${{ secrets.ENABLE_REPORT_ISSUES_MENU }} REPORT_ISSUES_URL: ${{ secrets.REPORT_ISSUES_URL }} LOGROCKET_ID: ${{ secrets.LOGROCKET_ID }} + KLAXOON_CLIENT_ID: ${{ secrets.KLAXOON_CLIENT_ID }} with: namespace: workadventure-${{ github.event_name == 'pull_request' && env.GITHUB_HEAD_REF_SLUG || env.GITHUB_REF_SLUG }} @@ -942,4 +936,4 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: msg: "Environment deployed at https://play-${{ env.GITHUB_HEAD_REF_SLUG }}.test.workadventu.re \nTests available at https://maps-${{ env.GITHUB_HEAD_REF_SLUG }}.test.workadventu.re/tests" - + check_for_duplicate_msg: true diff --git a/back/package.json b/back/package.json index 8b195a5dfc..5715a0a65e 100644 --- a/back/package.json +++ b/back/package.json @@ -44,13 +44,14 @@ "dependencies": { "@anatine/zod-openapi": "^1.3.0", "@grpc/grpc-js": "^1.7.1", + "@grpc/proto-loader": "0.7.8", "@sentry/node": "^7.48.0", "@workadventure/messages": "1.0.0", "@workadventure/shared-utils": "1.0.0", "@workadventure/tiled-map-type-guard": "^2.1.0", "axios": "^1.3.2", "bigbluebutton-js": "^0.1.1", - "busboy": "^0.3.1", + "busboy": "^1.6.0", "circular-json": "^0.5.9", "debug": "^4.3.1", "google-protobuf": "^3.21.0", diff --git a/back/tests/EnvironmentVariableValidator.test.ts b/back/tests/EnvironmentVariableValidator.test.ts index d386d48d35..14124a0ad1 100644 --- a/back/tests/EnvironmentVariableValidator.test.ts +++ b/back/tests/EnvironmentVariableValidator.test.ts @@ -6,7 +6,7 @@ import { EnvironmentVariables } from "../src/Enum/EnvironmentVariableValidator"; describe("EnvironmentVariable", () => { it("should validate properly URLs", () => { let result = EnvironmentVariables.safeParse({ - PLAY_URL: "https://exemple.com", + PLAY_URL: "https://example.com", }); expect(result.success).toBe(true); diff --git a/chat/Dockerfile b/chat/Dockerfile index 834e6130ea..6cc5b81d54 100644 --- a/chat/Dockerfile +++ b/chat/Dockerfile @@ -22,6 +22,7 @@ COPY libs/map-editor/package.json libs/map-editor/package.json COPY libs/math-utils/package.json libs/math-utils/package.json COPY libs/tailwind/package.json libs/tailwind/package.json COPY libs/store-utils/package.json libs/store-utils/package.json +COPY libs/shared-utils/package.json libs/shared-utils/package.json RUN npm ci --workspace=workadventurechat COPY libs ./libs COPY --from=proto-builder /usr/libs/messages/src ./libs/messages/src diff --git a/chat/index.html b/chat/index.html index 967e7abc86..921f20b5cc 100644 --- a/chat/index.html +++ b/chat/index.html @@ -37,5 +37,9 @@ + + + + diff --git a/chat/package.json b/chat/package.json index 25cae881e5..1eccbf3e31 100644 --- a/chat/package.json +++ b/chat/package.json @@ -51,6 +51,7 @@ "@sentry/browser": "^7.48.0", "@tailwindcss/forms": "^0.5.3", "@workadventure/messages": "1.0.0", + "@workadventure/shared-utils": "^1.0.0", "@workadventure/store-utils": "1.0.0", "@workadventure/tailwind": "1.0.0", "axios": "^1.3.2", @@ -78,8 +79,8 @@ "lint": "eslint src/ tests/ --ext .ts,.svelte", "fix": "eslint --fix src/ tests/ --ext .ts,.svelte", "precommit": "lint-staged", - "svelte-check-watch": "svelte-check --fail-on-warnings --threshold error --compiler-warnings \"a11y-no-onchange:ignore,a11y-autofocus:ignore,a11y-media-has-caption:ignore,a11y-click-events-have-key-events:ignore,security-anchor-rel-noreferrer:ignore\" --watch", - "svelte-check": "svelte-check --fail-on-warnings --fail-on-hints --compiler-warnings \"a11y-no-onchange:ignore,a11y-autofocus:ignore,a11y-media-has-caption:ignore,a11y-click-events-have-key-events:ignore,security-anchor-rel-noreferrer:ignore\"", + "svelte-check-watch": "svelte-check --fail-on-errors --threshold error --compiler-warnings \"a11y-no-onchange:ignore,a11y-autofocus:ignore,a11y-media-has-caption:ignore,a11y-click-events-have-key-events:ignore,security-anchor-rel-noreferrer:ignore\" --watch", + "svelte-check": "svelte-check --fail-on-errors --fail-on-hints --compiler-warnings \"a11y-no-onchange:ignore,a11y-autofocus:ignore,a11y-media-has-caption:ignore,a11y-click-events-have-key-events:ignore,security-anchor-rel-noreferrer:ignore\"", "pretty": "prettier --write 'src/**/*.{ts,svelte}'", "pretty-check": "prettier --check 'src/**/*.{ts,svelte}'", "typecheck": "tsc --noEmit", diff --git a/chat/public/static/images/applications/appOff.png b/chat/public/static/images/applications/appOff.png new file mode 100644 index 0000000000000000000000000000000000000000..cdd156e17082959c56f243fce1359374b76a1e35 GIT binary patch literal 543 zcmV+)0^t3LP)R9J=Wm(fw=Fc3r^6#qDb-3)LBYz8bD_#%K1Oa>+cGC)Ld zCIgXyFM}n5=0hV8TZ?Q_qPUOks;RQaBdJFowIn1pl17zbki?!1g?)^Ynlr!wm%zO} z=gFzM*@*R^9y5#F--|wfr2%re5n$8^ECziI7vE@G!S(8nPqC$5tQ$m4+Y%< zkH9~|UNDCZasM$ky=AZjUefkJMqB%~w2xjACz2Nbw4cC#vkH2^16p97@XvGD5Ncse z+Bib}d_t`vjA-~c;Jn(vBhVVDbKu4L@IbX?82zybdmUbqour*vE9srUp{mYVZ|(L^ zNwPt5ZCfKSNoryZ%$?!pu(4^sV_pYh4XuFNTC1QV{PSU9{D{>;EdpyoW+gM}fK@F5 zmy{n$J=7DT7s662L0gl+L@2~k03{$L literal 0 HcmV?d00001 diff --git a/chat/public/static/images/applications/appOn.png b/chat/public/static/images/applications/appOn.png new file mode 100644 index 0000000000000000000000000000000000000000..24cda9d421090e46913f19b50f488743c34b6280 GIT binary patch literal 373 zcmV-*0gC>KP)R9J=Wm(fkbFcd{kqy7^%V1s&uY*02J-5?_{LfHT|2pcd$ z*nkaiC%AmnMXoUrKUvC8u4E;aeBV2flPd>FPLkJrc}cw_lF=LLxQ!$a+)$ zZ-Ea>oyK4ycw97h);f*BR8=d$3a|pK0M;l5xaB&EKMgfb4KQ%d_7WYU=7jr0X>(xM zNP_bdxWCtbYf75ODz0+@SWJt*gxhefwFRl-x_O`BB%@zWMCs{h%J?Qp_wiZ`%`a** zjay0M4DWLcU{#j^nA7|UqUKB31N(yY4?tHFV6b><0kpu*;M>;%nEMI;(BeT<3t(Cr zzyt3F-)qe+cr \ No newline at end of file diff --git a/chat/public/static/images/applications/google-docs.svg b/chat/public/static/images/applications/google-docs.svg new file mode 100644 index 0000000000..375414dcd8 --- /dev/null +++ b/chat/public/static/images/applications/google-docs.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/chat/public/static/images/applications/google-forms.svg b/chat/public/static/images/applications/google-forms.svg new file mode 100644 index 0000000000..2fd12219b6 --- /dev/null +++ b/chat/public/static/images/applications/google-forms.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/chat/public/static/images/applications/google-keeps.svg b/chat/public/static/images/applications/google-keeps.svg new file mode 100644 index 0000000000..81bc2ee404 --- /dev/null +++ b/chat/public/static/images/applications/google-keeps.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/chat/public/static/images/applications/google-sheets.svg b/chat/public/static/images/applications/google-sheets.svg new file mode 100644 index 0000000000..d2ca1f9d24 --- /dev/null +++ b/chat/public/static/images/applications/google-sheets.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/chat/public/static/images/applications/google-slides.svg b/chat/public/static/images/applications/google-slides.svg new file mode 100644 index 0000000000..6d014028c9 --- /dev/null +++ b/chat/public/static/images/applications/google-slides.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/chat/public/static/images/applications/klaxoon.svg b/chat/public/static/images/applications/klaxoon.svg new file mode 100644 index 0000000000..363f848404 --- /dev/null +++ b/chat/public/static/images/applications/klaxoon.svg @@ -0,0 +1,17 @@ + + + + + + + + \ No newline at end of file diff --git a/chat/public/static/images/applications/youtube.svg b/chat/public/static/images/applications/youtube.svg new file mode 100644 index 0000000000..5e7bc500a7 --- /dev/null +++ b/chat/public/static/images/applications/youtube.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/chat/public/static/images/no-app.png b/chat/public/static/images/no-app.png new file mode 100644 index 0000000000000000000000000000000000000000..e4631fa56bab8e2b3028e682450915057455fb0a GIT binary patch literal 2394 zcmV-g38nUlP)^}ethLc8j({SeHJ-#L@f2F) zDSR}N(9@=+m$>XoiNh`xIc!)G@Z$7H8c&?*wq73^HUT`Ewya+hk#^Mr7-L}v=X=ZD z_To*Yh0d@|#)HQ@tmiu~u#h6RF~*J$=|)@1vQ7f%kU5X~CB7nQTGwSPayLbS+UoqU z{p?U051l<{oz7@&1BP+KgxMgXF$+M2%6ZRErsbyl7S+(kk^*uGq4^}y3}E(n`~?0* zZi)Y1V$Ar#lpuXtS3!+AIph+206@iM_;Jo*mGhp*X675`8)~S;sis1*{2_qaFC(5n zNUd9l&+9x+?c=%%x+k1BDk3i%$Fpm0=X~!SQ-bcsa6m8s#SS|qEQxfZx=5o$;=P)f822>G?iax@%!ItqA#( z4$eOW;Qp#v7+oGAHkCW=T1!P4RXH7|%K5`%N&p}tGnP6yH%50(4Ow1EYVk^9?|h#t z-Mz4yzMbn&I5T~%V+aH?}SDA>|_Pjr52x7$zYhT)sD_lHz2U(W&VUK|#?atGu^o&Jr4q$PfO*VY8z@FYg#UQ#j>wM@# zhPmuaD)ZNbX?3nGoa$MU8`!xv8lJ7|x;qw&;gfgvq4nMUNGB5@vT&yD2#&n92g#uU zcmuf%K*?ylgke3?+&|0w ztYD6AS5++@k5hAVGp$&06WLUi{DC0lM+@m!>mQ*Fo3~TN{6z#{Lv}2u;JsUB6w)1m z0J(+O#vPnj)p=avvt(KuFw8^QzY=3C=5~8`$gG6^^J1UhNy| z*S~13qvTG;*hk4!g4eHDiK5DyOF_!!EI?6ZE#7=-8&<7ah4%J#)Ya8NQEgz1U9mq5 z7{}Hge&zh7elb%r6G|q6TK9Y^I{w__AlsfI{wnTb5fH%f_ z$g+&4rX~b~LEO9cKHUHCBV+cnZ&Xdw@bbTQVas2hG5h;^69D#SV>u8NV73c}0Vn4p zlEnG>uCx|u@OvD)dj=W+Y@YO!Cb8$YZNqy94xqcQAKzRs-vV%YcxZ4PfR~6!&&GOX zQCjA(^IpS%jq_fvS#-E%I8OC`x2kY{!&fB-fRM}e_7XilyvQNrZ$){1pI1%)77=Y9 zPYwVKti0asLR&hGv}v{Qq-p+r=lT9riPH`MKE~KJ7qJ8Y&CSh|5)TayqOJ84B!N@w zqmi18(<7Y=e4daH;>`kwx{)#F8bi+5>=DB(E0t8d6(2DNO!GzHi&mUIG_Qhg4Ejbm zaOtMvoUe8`96ix!H2(C{Pt%SaJE*j*oc_7zHTvFdO=MG5GZ+l+2M{A7_$6uAO(B0` zaB(dy5BZZ0AzA>qM&mhz*n4BZYiyrBoot-z0Bj&4xP{o-6b@(y=f+4drUR(S>Vg75 zqs!&`NRlK&k|a`9Rrh+mn*kJ!>zE#g5Fgwa^d);5YG`TDcS!_*TA49p&#alW-0P*F zEN>rk9V?ur56+EIQ#hb2j2#1@PSBF)0r)8Z?-eE?r&Eac7Ug(S-3`^W&^6j@Oy)X{ezi zwJ}bxt8#@>L~ybY3Oh6V4;A z5F-G>V{j8VRyYOkyK7pmac*HXtqcbeoIzJPe-yy1_0|%c4V6ShAo|F&?I^Tz*_)L0GI|KU*){mA$V-a zFt1%2^y$BdM$}}=#Qi5frw&~|bwStbiKzQBu89O(6rtKVUvGl$z9lz@uZd2PW;j)} zCsH^t7}xd>3?+_?q!5&)Or_glkGbrgBD>1UU3PRPHT?EuC%ry2Y&kgpQ@>%XC8G3% zJd+8?5)$#rVnfojZjC4k-4f1GYu!$af1I96W$;da9Ix~Z80U2Zeu?ku(u`F^)OE%9 zUnU?+hz-DEpDeyFGk$HxvO;Og@&jNl&PSX=3>kz&U7EH9U*UQFe{{E##xt*Ds{jB1 M07*qoM6N<$f~X^aMF0Q* literal 0 HcmV?d00001 diff --git a/chat/src/Components/ChatMessageForm.svelte b/chat/src/Components/ChatMessageForm.svelte index 69498726c6..4cfd004ec6 100644 --- a/chat/src/Components/ChatMessageForm.svelte +++ b/chat/src/Components/ChatMessageForm.svelte @@ -14,7 +14,17 @@ import { EmojiButton } from "@joeattardi/emoji-button"; import { UserData } from "@workadventure/messages"; import { ChatState } from "stanza/Constants"; - import { get } from "svelte/store"; + import { get, writable } from "svelte/store"; + import { + EraserException, + EraserService, + GoogleWorkSpaceException, + GoogleWorkSpaceService, + KlaxoonEvent, + KlaxoonException, + KlaxoonService, + YoutubeService, + } from "@workadventure/shared-utils"; import { MucRoom } from "../Xmpp/MucRoom"; import { defaultWoka, User } from "../Xmpp/AbstractRoom"; import { LL, locale } from "../i18n/i18n-svelte"; @@ -31,7 +41,9 @@ import { FileExt, fileMessageManager, UploadedFile, uploadingState } from "../Services/FileMessageManager"; import crown from "../../public/static/svg/icone-premium-crown.svg"; import { iframeListener } from "../IframeListener"; + import { chatConnectionManager } from "../Connection/ChatConnectionManager"; import File from "./Content/File.svelte"; + import ApplicationPicker from "./Content/ApplicationPicker.svelte"; export let mucRoom: MucRoom; @@ -46,6 +58,17 @@ let newMessageText = ""; let htmlMessageText = ""; let usersSearching: User[] = []; + let applicationMenuIsOpenned = false; + + interface Application { + name: string; + icon: string; + example: string; + link?: string; + error?: string; + } + const applicationsSelected = writable>(new Set()); + const applications = writable>(new Set()); const maxCharMessage = 10_000; $: isMessageTooLong = newMessageText.length > maxCharMessage; @@ -92,7 +115,8 @@ } if ( fileMessageManager.files.length === 0 && - (!htmlMessageText || htmlMessageText.replace(/\s/g, "").length === 0) + (!htmlMessageText || htmlMessageText.replace(/\s/g, "").length === 0) && + $applicationsSelected.size === 0 ) { return false; } @@ -114,6 +138,19 @@ textarea.innerHTML = ""; dispatch("formHeight", messageForm.clientHeight); }, 0); + + if ($applicationsSelected.size > 0) { + for (const app of $applicationsSelected) { + if (app.link != undefined) { + mucRoom.sendMessage(app.link); + } + applicationsSelected.update((apps) => { + apps.delete(app); + return apps; + }); + } + } + return false; } @@ -226,6 +263,138 @@ textarea.focus(); } + function toggleApplicationMenu() { + applicationMenuIsOpenned = !applicationMenuIsOpenned; + } + + function addNewApp(app: Application) { + applicationsSelected.update((apps) => { + apps.add(app); + return apps; + }); + if (app.name === "Klaxoon") { + if (!chatConnectionManager.klaxoonToolClientId) return; + KlaxoonService.openKlaxoonActivityPicker( + chatConnectionManager.klaxoonToolClientId, + (event: KlaxoonEvent) => { + // Remove previous app + applicationsSelected.update((apps) => { + apps.delete(app); + return apps; + }); + // Update app with Klaxoon's Activity Picker + app.link = KlaxoonService.getKlaxoonEmbedUrl(new URL(event.url)); + if (event.imageUrl) app.icon = event.imageUrl; + if (event.title) app.name = event.title; + // Add new app + applicationsSelected.update((apps) => { + apps.add(app); + return apps; + }); + } + ); + } + applicationMenuIsOpenned = false; + } + + function deleteApplication(app: Application) { + applicationsSelected.update((apps) => { + apps.delete(app); + return apps; + }); + } + + async function checkWebsiteProperty(app: Application): Promise { + app.error = undefined; + if (app.link == undefined) return; + switch (app.name) { + case "Klaxoon": + try { + app.link = KlaxoonService.getKlaxoonEmbedUrl(new URL(app.link)); + } catch (err) { + if (err instanceof KlaxoonException.KlaxoonException) { + app.error = $LL.form.application.klaxoon.error(); + } else { + app.error = $LL.form.application.weblink.error(); + } + app.link = undefined; + } + break; + case "Youtube": + try { + app.link = await YoutubeService.getYoutubeEmbedUrl(new URL(app.link)); + } catch (e) { + console.info($LL.form.application.youtube.error(), e); + app.error = $LL.form.application.youtube.error(); + app.link = undefined; + } + break; + case "Google Docs": + try { + app.link = GoogleWorkSpaceService.getGoogleDocsEmbedUrl(new URL(app.link)); + } catch (err) { + if (err instanceof GoogleWorkSpaceException.GoogleDocsException) { + app.error = $LL.form.application.googleDocs.error(); + } else { + app.error = $LL.form.application.weblink.error(); + } + app.link = undefined; + } + break; + case "Google Sheets": + try { + app.link = GoogleWorkSpaceService.getGoogleSheetsEmbedUrl(new URL(app.link)); + } catch (err) { + console.error(err); + if (err instanceof GoogleWorkSpaceException.GoogleSheetsException) { + app.error = $LL.form.application.googleSheets.error(); + } else { + app.error = $LL.form.application.weblink.error(); + } + app.link = undefined; + } + break; + case "Google Slides": + try { + app.link = GoogleWorkSpaceService.getGoogleSlidesEmbedUrl(new URL(app.link)); + } catch (err) { + if (err instanceof GoogleWorkSpaceException.GoogleSlidesException) { + app.error = $LL.form.application.googleSlides.error(); + } else { + app.error = $LL.form.application.weblink.error(); + } + app.link = undefined; + } + break; + case "Eraser": + try { + EraserService.validateEraserLink(new URL(app.link)); + } catch (err) { + if (err instanceof EraserException.EraserLinkException) { + app.error = $LL.form.application.eraser.error(); + } else { + app.error = $LL.form.application.weblink.error(); + } + app.link = undefined; + } + break; + default: + throw new Error("Application not found"); + } + applicationsSelected.update((apps) => { + apps.add(app); + return apps; + }); + } + + function handlerKeyDownAppInput(keyPressEvent: KeyboardEvent) { + if (keyPressEvent.key === "Enter" && !keyPressEvent.shiftKey) { + // blur element from keyPressEvent + (keyPressEvent.target as HTMLInputElement).blur(); + keyPressEvent.preventDefault(); + } + } + onMount(() => { dispatch("formHeight", messageForm.clientHeight); picker = new EmojiButton({ @@ -266,6 +435,67 @@ picker.on("hidden", () => { emojiOpened = false; }); + + if (chatConnectionManager.klaxoonToolIsActivated) { + applications.update((apps) => { + apps.add({ + name: "Klaxoon", + icon: "./static/images/applications/klaxoon.svg", + example: "https://klaxoon.com/fr", + }); + return apps; + }); + } + if (chatConnectionManager.youtubeToolIsActivated) { + applications.update((apps) => { + apps.add({ + name: "Youtube", + icon: "./static/images/applications/youtube.svg", + example: "https://www.youtube.com/watch?v=Y9ubBWf5w20", + }); + return apps; + }); + } + if (chatConnectionManager.googleDocsToolIsActivated) { + applications.update((apps) => { + apps.add({ + name: "Google Docs", + icon: "./static/images/applications/google-docs.svg", + example: "https://docs.google.com/document/d/1iFHmKL4HJ6WzvQI-6FlyeuCy1gzX8bWQ83dNlcTzigk/edit", + }); + return apps; + }); + } + if (chatConnectionManager.googleSheetsToolIsActivated) { + applications.update((apps) => { + apps.add({ + name: "Google Sheets", + icon: "./static/images/applications/google-sheets.svg", + example: "https://docs.google.com/spreadsheets/d/1SBIn3IBG30eeq944OhT4VI_tSg-b1CbB0TV0ejK70RA/edit", + }); + return apps; + }); + } + if (chatConnectionManager.googleSlidesToolIsActivated) { + applications.update((apps) => { + apps.add({ + name: "Google Slides", + icon: "./static/images/applications/google-slides.svg", + example: "https://docs.google.com/presentation/d/1fU4fOnRiDIvOoVXbksrF2Eb0L8BYavs7YSsBmR_We3g/edit", + }); + return apps; + }); + } + if (chatConnectionManager.eraserToolIsActivated) { + applications.update((apps) => { + apps.add({ + name: "Eraser", + icon: "./static/images/applications/eraser.svg", + example: "https://app.eraser.io/workspace/ExSd8Z4wPsaqMMgTN4VU", + }); + return apps; + }); + } }); @@ -324,6 +554,60 @@ {/if} + {#each [...$applicationsSelected] as app} +
+
+ + +
+ checkWebsiteProperty(app)} + /> + {#if app.error} +

{app.error}

+ {/if} +
+ {/each} + + {#if applicationMenuIsOpenned} + addNewApp(event.detail)} /> + {/if} +
{#each [...$filesUploadStore.values()] as fileUploaded} @@ -412,7 +696,24 @@

{/if} -
+ +
+
+
+ +
+
-
+
{/each} {#if $unreads > 0} -
+
+ import { createEventDispatcher } from "svelte"; + + interface Application { + name: string; + icon: string; + example: string; + link?: string; + error?: string; + } + + const dispatch = createEventDispatcher(); + export let applications: Set; + export let _class: string = ""; + export let _style: string = ""; + + function addNewApp(app: Application) { + dispatch("addNewApp", app); + } + + +
+ {#each [...applications] as app} + + {/each} +
+ + diff --git a/chat/src/Components/Content/File.svelte b/chat/src/Components/Content/File.svelte index 43aaba7d25..758ef4b693 100644 --- a/chat/src/Components/Content/File.svelte +++ b/chat/src/Components/Content/File.svelte @@ -1,40 +1,15 @@ @@ -68,19 +43,4 @@
{/if} - -
- - -
diff --git a/chat/src/Components/Content/HtmlMessage.svelte b/chat/src/Components/Content/HtmlMessage.svelte index 830d950bac..c3f851953b 100644 --- a/chat/src/Components/Content/HtmlMessage.svelte +++ b/chat/src/Components/Content/HtmlMessage.svelte @@ -1,81 +1,13 @@ diff --git a/chat/src/Components/Content/Message.svelte b/chat/src/Components/Content/Message.svelte index a86554de5f..20ef165923 100644 --- a/chat/src/Components/Content/Message.svelte +++ b/chat/src/Components/Content/Message.svelte @@ -5,19 +5,25 @@ CopyIcon, CornerDownLeftIcon, CornerLeftUpIcon, + EyeIcon, RefreshCwIcon, SmileIcon, Trash2Icon, + DownloadCloudIcon, + LoaderIcon, } from "svelte-feather-icons"; import { Writable } from "svelte/store"; import { EmojiButton } from "@joeattardi/emoji-button"; import { JID } from "stanza"; + import { onMount } from "svelte"; import { MucRoom } from "../../Xmpp/MucRoom"; import { Message } from "../../Model/Message"; import { LL, locale } from "../../i18n/i18n-svelte"; import { selectedMessageToReact, selectedMessageToReply } from "../../Stores/ChatStore"; import { HtmlUtils } from "../../Utils/HtmlUtils"; import { User } from "../../Xmpp/AbstractRoom"; + import { iframeListener } from "../../IframeListener"; + import { FileMessageManager } from "../../Services/FileMessageManager"; import HtmlMessage from "./HtmlMessage.svelte"; import File from "./File.svelte"; import Reactions from "./Reactions.svelte"; @@ -31,6 +37,10 @@ export let woka: string; export let needHideHeader: boolean; export let me: Writable | undefined; + let html: string; + let urlifyError: string; + let embedLink: string | undefined; + let loadingDownload = false; const deletedMessagesStore = mucRoom.getDeletedMessagesStore(); @@ -66,6 +76,69 @@ console.error("error copy message => ", err); }); } + + function scrollToMessage(messageId?: string) { + if (!messageId) return; + const messageElement = document.getElementById(`message_${messageId}`); + if (!messageElement) return; + messageElement.scrollIntoView({ behavior: "smooth", block: "center", inline: "nearest" }); + } + + function openCowebsite() { + if (embedLink) iframeListener.openCoWebsite(embedLink, true, "allowfullscreen"); + if (message.links) + message.links.forEach((link) => iframeListener.openCoWebsite(link.url, true, "allowfullscreen")); + } + + function downloadAllFile() { + if (message.links == undefined) return; + message.links.forEach((link) => { + download(link.url, link.description); + }); + } + + function download(url: string, name?: string) { + loadingDownload = true; + fetch(url, { method: "GET" }) + .then((res) => { + return res.blob(); + }) + .then((blob) => { + var url = URL.createObjectURL(blob); + var a = document.createElement("a"); + a.href = url; + a.download = name ?? FileMessageManager.getName(url); + document.body.appendChild(a); + a.click(); + setTimeout((_) => { + URL.revokeObjectURL(url); + }, 60000); + a.remove(); + loadingDownload = false; + }) + .catch((err) => { + loadingDownload = false; + console.error("err: ", err); + }); + } + + onMount(() => { + HtmlUtils.urlify(message.body) + .then((htmlFromBody) => { + html = htmlFromBody; + + // check if the message html body contains attribute embed-link + // if yes, capture the embed-link value and store it in embedLink variable + const embedLinkMatching = html.match(/embed-link="(.*)"/); + if (embedLinkMatching) { + // if embed link add a new action in actions element to open the embed link into WorkAdventure + embedLink = embedLinkMatching[1]; + } + }) + .catch((err) => { + urlifyError = err.message; + }); + });
+ {#if message.links != undefined && message.links.length > 0} +
downloadAllFile()}> + {#if loadingDownload} + + {:else} + + {/if} +
{$LL.file.download()}
+
+ {/if} + {#if (message.links && message.links.length > 0) || embedLink != undefined} +
openCowebsite()}> + +
{$LL.open()}
+
+ {/if}
selectMessage(message)}>
{$LL.reply()}
@@ -186,17 +275,26 @@ @@ -210,6 +308,9 @@ {#if message.targetMessageReply}
{ + scrollToMessage(message.targetMessageReply?.id); + }} >
diff --git a/chat/src/Components/Timeline/ChatActiveThreadTimeline.svelte b/chat/src/Components/Timeline/ChatActiveThreadTimeline.svelte index 5b1ee16b7b..89a606d06c 100644 --- a/chat/src/Components/Timeline/ChatActiveThreadTimeline.svelte +++ b/chat/src/Components/Timeline/ChatActiveThreadTimeline.svelte @@ -1,9 +1,19 @@ +
(applicationMenuIsOpenned = false)} >