diff --git a/.github/workflows/continuous_integration.yml b/.github/workflows/continuous_integration.yml index a90d9397..fcde792a 100644 --- a/.github/workflows/continuous_integration.yml +++ b/.github/workflows/continuous_integration.yml @@ -62,18 +62,13 @@ jobs: working-directory: "front" - name: "Pretty" - run: yarn run pretty + run: yarn run pretty-check working-directory: "front" - name: "Jasmine" run: yarn test working-directory: "front" - # We will enable prettier checks on front in a few month, when most PRs without prettier have been merged - # - name: "Prettier" - # run: yarn run pretty-check - # working-directory: "front" - continuous-integration-pusher: name: "Continuous Integration Pusher" diff --git a/front/src/Api/Events/CloseCoWebsiteEvent.ts b/front/src/Api/Events/CloseCoWebsiteEvent.ts index 94167d5e..4dc1e51d 100644 --- a/front/src/Api/Events/CloseCoWebsiteEvent.ts +++ b/front/src/Api/Events/CloseCoWebsiteEvent.ts @@ -2,7 +2,7 @@ import * as tg from "generic-type-guard"; export const isCloseCoWebsite = new tg.IsInterface() .withProperties({ - id: tg.isOptional(tg.isString) + id: tg.isOptional(tg.isString), }) .get(); diff --git a/front/src/Api/Events/IframeEvent.ts b/front/src/Api/Events/IframeEvent.ts index 64a3891e..89230302 100644 --- a/front/src/Api/Events/IframeEvent.ts +++ b/front/src/Api/Events/IframeEvent.ts @@ -24,9 +24,7 @@ import type { EmbeddedWebsite } from "../iframe/Room/EmbeddedWebsite"; import { isCreateEmbeddedWebsiteEvent } from "./EmbeddedWebsiteEvent"; import type { LoadTilesetEvent } from "./LoadTilesetEvent"; import { isLoadTilesetEvent } from "./LoadTilesetEvent"; -import type { - MessageReferenceEvent, -} from "./ui/TriggerActionMessageEvent"; +import type { MessageReferenceEvent } from "./ui/TriggerActionMessageEvent"; import { isMessageReferenceEvent, isTriggerActionMessageEvent } from "./ui/TriggerActionMessageEvent"; import type { MenuRegisterEvent, UnregisterMenuEvent } from "./ui/MenuRegisterEvent"; import type { ChangeLayerEvent } from "./ChangeLayerEvent"; @@ -122,19 +120,19 @@ export const iframeQueryMapTypeGuards = { }, openCoWebsite: { query: isOpenCoWebsiteEvent, - answer: isCoWebsite + answer: isCoWebsite, }, getCoWebsites: { query: tg.isUndefined, - answer: tg.isArray(isCoWebsite) + answer: tg.isArray(isCoWebsite), }, closeCoWebsite: { query: tg.isString, - answer: tg.isUndefined + answer: tg.isUndefined, }, closeCoWebsites: { query: tg.isUndefined, - answer: tg.isUndefined + answer: tg.isUndefined, }, triggerActionMessage: { query: isTriggerActionMessageEvent, diff --git a/front/src/Api/Events/OpenCoWebsiteEvent.ts b/front/src/Api/Events/OpenCoWebsiteEvent.ts index 9c02b7a3..514fd110 100644 --- a/front/src/Api/Events/OpenCoWebsiteEvent.ts +++ b/front/src/Api/Events/OpenCoWebsiteEvent.ts @@ -5,7 +5,7 @@ export const isOpenCoWebsiteEvent = new tg.IsInterface() url: tg.isString, allowApi: tg.isOptional(tg.isBoolean), allowPolicy: tg.isOptional(tg.isString), - position: tg.isOptional(tg.isNumber) + position: tg.isOptional(tg.isNumber), }) .get(); diff --git a/front/src/Api/iframe/nav.ts b/front/src/Api/iframe/nav.ts index 5acfa2a5..206961bf 100644 --- a/front/src/Api/iframe/nav.ts +++ b/front/src/Api/iframe/nav.ts @@ -57,7 +57,7 @@ export class WorkadventureNavigationCommands extends IframeApiContribution { const result = await queryWorkadventure({ type: "getCoWebsites", - data: undefined + data: undefined, }); return result.map((cowebsiteEvent) => new CoWebsite(cowebsiteEvent.id, cowebsiteEvent.position)); } diff --git a/front/src/Phaser/Entity/Character.ts b/front/src/Phaser/Entity/Character.ts index 7df18fcd..1211a52d 100644 --- a/front/src/Phaser/Entity/Character.ts +++ b/front/src/Phaser/Entity/Character.ts @@ -128,6 +128,10 @@ export abstract class Character extends Container { } public addTextures(textures: string[], frame?: string | number): void { + if (textures.length < 1) { + throw new TextureError("no texture given"); + } + for (const texture of textures) { if (this.scene && !this.scene.textures.exists(texture)) { throw new TextureError("texture not found"); diff --git a/front/src/Phaser/Entity/PlayerTexturesLoadingManager.ts b/front/src/Phaser/Entity/PlayerTexturesLoadingManager.ts index 92954bfb..edaeb5b8 100644 --- a/front/src/Phaser/Entity/PlayerTexturesLoadingManager.ts +++ b/front/src/Phaser/Entity/PlayerTexturesLoadingManager.ts @@ -69,13 +69,11 @@ export const lazyLoadPlayerCharacterTextures = ( } //If the loading fail, we render the default model instead. - return returnPromise - .then((keys) => - keys.map((key) => { - return typeof key !== "string" ? key.name : key; - }) - ) - .catch(() => lazyLoadPlayerCharacterTextures(loadPlugin, ["color_22", "eyes_23"])); + return returnPromise.then((keys) => + keys.map((key) => { + return typeof key !== "string" ? key.name : key; + }) + ); }; export const getRessourceDescriptor = ( diff --git a/front/src/Phaser/Game/GameMap.ts b/front/src/Phaser/Game/GameMap.ts index 5f1b1704..2cd34b4c 100644 --- a/front/src/Phaser/Game/GameMap.ts +++ b/front/src/Phaser/Game/GameMap.ts @@ -12,8 +12,7 @@ export type PropertyChangeCallback = ( export type layerChangeCallback = ( layersChangedByAction: Array, - allLayersOnNewPosition: Array, - + allLayersOnNewPosition: Array ) => void; /** @@ -81,7 +80,7 @@ export class GameMap { } private getLayersByKey(key: number): Array { - return this.flatLayers.filter(flatLayer => flatLayer.type === 'tilelayer' && flatLayer.data[key] !== 0); + return this.flatLayers.filter((flatLayer) => flatLayer.type === "tilelayer" && flatLayer.data[key] !== 0); } /** @@ -134,14 +133,13 @@ export class GameMap { const enterLayers = new Set(layersByNewKey); const leaveLayers = new Set(layersByOldKey); - enterLayers.forEach(layer => { + enterLayers.forEach((layer) => { if (leaveLayers.has(layer)) { leaveLayers.delete(layer); enterLayers.delete(layer); } }); - if (enterLayers.size > 0) { const layerArray = Array.from(enterLayers); for (const callback of this.enterLayerCallbacks) { diff --git a/front/src/Phaser/Game/GameMapProperties.ts b/front/src/Phaser/Game/GameMapProperties.ts index d13f828a..65ce6ab8 100644 --- a/front/src/Phaser/Game/GameMapProperties.ts +++ b/front/src/Phaser/Game/GameMapProperties.ts @@ -1,37 +1,37 @@ export enum GameMapProperties { - ALLOW_API = 'allowApi', - AUDIO_LOOP = 'audioLoop', - AUDIO_VOLUME = 'audioVolume', - COLLIDES = 'collides', - DEFAULT = 'default', - EXIT_URL = 'exitUrl', - EXIT_SCENE_URL = 'exitSceneUrl', - FONT_FAMILY = 'font-family', - JITSI_ADMIN_ROOM_TAG = 'jitsiRoomAdminTag', - JITSI_CONFIG = 'jitsiConfig', - JITSI_INTERFACE_CONFIG = 'jitsiInterfaceConfig', - JITSI_ROOM = 'jitsiRoom', - JITSI_TRIGGER = 'jitsiTrigger', - JITSI_TRIGGER_MESSAGE = 'jitsiTriggerMessage', - JITSI_URL = 'jitsiUrl', - JITSI_WIDTH = 'jitsiWidth', - NAME = 'name', - OPEN_TAB = 'openTab', - OPEN_WEBSITE = 'openWebsite', - OPEN_WEBSITE_ALLOW_API = 'openWebsiteAllowApi', - OPEN_WEBSITE_POLICY = 'openWebsitePolicy', - OPEN_WEBSITE_WIDTH = 'openWebsiteWidth', - OPEN_WEBSITE_POSITION = 'openWebsitePosition', - OPEN_WEBSITE_TRIGGER = 'openWebsiteTrigger', - OPEN_WEBSITE_TRIGGER_MESSAGE = 'openWebsiteTriggerMessage', - PLAY_AUDIO = 'playAudio', - PLAY_AUDIO_LOOP = 'playAudioLoop', - READABLE_BY = 'readableBy', - SCRIPT = 'script', - SILENT = 'silent', - START = 'start', - START_LAYER = 'startLayer', - URL = 'url', - WRITABLE_BY = 'writableBy', - ZONE = 'zone', + ALLOW_API = "allowApi", + AUDIO_LOOP = "audioLoop", + AUDIO_VOLUME = "audioVolume", + COLLIDES = "collides", + DEFAULT = "default", + EXIT_URL = "exitUrl", + EXIT_SCENE_URL = "exitSceneUrl", + FONT_FAMILY = "font-family", + JITSI_ADMIN_ROOM_TAG = "jitsiRoomAdminTag", + JITSI_CONFIG = "jitsiConfig", + JITSI_INTERFACE_CONFIG = "jitsiInterfaceConfig", + JITSI_ROOM = "jitsiRoom", + JITSI_TRIGGER = "jitsiTrigger", + JITSI_TRIGGER_MESSAGE = "jitsiTriggerMessage", + JITSI_URL = "jitsiUrl", + JITSI_WIDTH = "jitsiWidth", + NAME = "name", + OPEN_TAB = "openTab", + OPEN_WEBSITE = "openWebsite", + OPEN_WEBSITE_ALLOW_API = "openWebsiteAllowApi", + OPEN_WEBSITE_POLICY = "openWebsitePolicy", + OPEN_WEBSITE_WIDTH = "openWebsiteWidth", + OPEN_WEBSITE_POSITION = "openWebsitePosition", + OPEN_WEBSITE_TRIGGER = "openWebsiteTrigger", + OPEN_WEBSITE_TRIGGER_MESSAGE = "openWebsiteTriggerMessage", + PLAY_AUDIO = "playAudio", + PLAY_AUDIO_LOOP = "playAudioLoop", + READABLE_BY = "readableBy", + SCRIPT = "script", + SILENT = "silent", + START = "start", + START_LAYER = "startLayer", + URL = "url", + WRITABLE_BY = "writableBy", + ZONE = "zone", } diff --git a/front/src/Phaser/Game/GameMapPropertiesListener.ts b/front/src/Phaser/Game/GameMapPropertiesListener.ts index 2f0f457e..c40990db 100644 --- a/front/src/Phaser/Game/GameMapPropertiesListener.ts +++ b/front/src/Phaser/Game/GameMapPropertiesListener.ts @@ -4,10 +4,8 @@ import { scriptUtils } from "../../Api/ScriptUtils"; import type { CoWebsite } from "../../WebRtc/CoWebsiteManager"; import { coWebsiteManager, CoWebsiteState } from "../../WebRtc/CoWebsiteManager"; import { layoutManagerActionStore } from "../../Stores/LayoutManagerStore"; -import { get } from 'svelte/store'; -import { - ON_ACTION_TRIGGER_BUTTON, ON_ACTION_TRIGGER_DISABLE, -} from "../../WebRtc/LayoutManager"; +import { get } from "svelte/store"; +import { ON_ACTION_TRIGGER_BUTTON, ON_ACTION_TRIGGER_DISABLE } from "../../WebRtc/LayoutManager"; import type { ITiledMapLayer } from "../Map/ITiledMap"; import { GameMapProperties } from "./GameMapProperties"; import { iframeListener } from "../../Api/IframeListener"; @@ -21,8 +19,8 @@ enum OpenCoWebsiteState { } interface OpenCoWebsite { - coWebsite: CoWebsite | undefined, - state: OpenCoWebsiteState + coWebsite: CoWebsite | undefined; + state: OpenCoWebsiteState; } export class GameMapPropertiesListener { @@ -33,7 +31,7 @@ export class GameMapPropertiesListener { constructor(private scene: GameScene, private gameMap: GameMap) {} register() { - this.gameMap.onPropertyChange(GameMapProperties.OPEN_TAB, (newValue, oldvalue, allProps) => { + this.gameMap.onPropertyChange(GameMapProperties.OPEN_TAB, (newValue, oldValue, allProps) => { if (newValue === undefined) { layoutManagerActionStore.removeAction("openTab"); } @@ -57,10 +55,10 @@ export class GameMapPropertiesListener { } }); - // Open a new co-website by the property. + // Open a new co-website by the property. this.gameMap.onEnterLayer((newLayers) => { const handler = () => { - newLayers.forEach(layer => { + newLayers.forEach((layer) => { if (!layer.properties) { return; } @@ -73,8 +71,8 @@ export class GameMapPropertiesListener { let websiteTriggerProperty: string | undefined; let websiteTriggerMessageProperty: string | undefined; - layer.properties.forEach(property => { - switch(property.name) { + layer.properties.forEach((property) => { + switch (property.name) { case GameMapProperties.OPEN_WEBSITE: openWebsiteProperty = property.value as string | undefined; break; @@ -115,26 +113,28 @@ export class GameMapPropertiesListener { }); const openWebsiteFunction = () => { - coWebsiteManager.loadCoWebsite( - openWebsiteProperty as string, - this.scene.MapUrlFile, - allowApiProperty, - websitePolicyProperty, - websiteWidthProperty, - websitePositionProperty, - ).then(coWebsite => { - const coWebsiteOpen = this.coWebsitesOpenByLayer.get(layer); - if (coWebsiteOpen && coWebsiteOpen.state === OpenCoWebsiteState.MUST_BE_CLOSE) { - coWebsiteManager.closeCoWebsite(coWebsite); - this.coWebsitesOpenByLayer.delete(layer); - this.coWebsitesActionTriggerByLayer.delete(layer); - } else { - this.coWebsitesOpenByLayer.set(layer, { - coWebsite, - state: OpenCoWebsiteState.OPENED - }); - } - }); + coWebsiteManager + .loadCoWebsite( + openWebsiteProperty as string, + this.scene.MapUrlFile, + allowApiProperty, + websitePolicyProperty, + websiteWidthProperty, + websitePositionProperty + ) + .then((coWebsite) => { + const coWebsiteOpen = this.coWebsitesOpenByLayer.get(layer); + if (coWebsiteOpen && coWebsiteOpen.state === OpenCoWebsiteState.MUST_BE_CLOSE) { + coWebsiteManager.closeCoWebsite(coWebsite); + this.coWebsitesOpenByLayer.delete(layer); + this.coWebsitesActionTriggerByLayer.delete(layer); + } else { + this.coWebsitesOpenByLayer.set(layer, { + coWebsite, + state: OpenCoWebsiteState.OPENED, + }); + } + }); layoutManagerActionStore.removeAction(actionUuid); }; @@ -186,7 +186,7 @@ export class GameMapPropertiesListener { // Close opened co-websites on leave the layer who contain the property. this.gameMap.onLeaveLayer((oldLayers) => { const handler = () => { - oldLayers.forEach(layer => { + oldLayers.forEach((layer) => { if (!layer.properties) { return; } @@ -194,8 +194,8 @@ export class GameMapPropertiesListener { let openWebsiteProperty: string | undefined; let websiteTriggerProperty: string | undefined; - layer.properties.forEach(property => { - switch(property.name) { + layer.properties.forEach((property) => { + switch (property.name) { case GameMapProperties.OPEN_WEBSITE: openWebsiteProperty = property.value as string | undefined; break; @@ -245,9 +245,10 @@ export class GameMapPropertiesListener { return; } - const action = actionStore && actionStore.length > 0 ? - actionStore.find(action => action.uuid === actionTriggerUuid) : undefined; - + const action = + actionStore && actionStore.length > 0 + ? actionStore.find((action) => action.uuid === actionTriggerUuid) + : undefined; if (action) { layoutManagerActionStore.removeAction(actionTriggerUuid); diff --git a/front/src/Stores/LayoutManagerStore.ts b/front/src/Stores/LayoutManagerStore.ts index 063d45a7..e92cd3c4 100644 --- a/front/src/Stores/LayoutManagerStore.ts +++ b/front/src/Stores/LayoutManagerStore.ts @@ -9,9 +9,7 @@ export interface LayoutManagerAction { userInputManager: UserInputManager | undefined; } - function createLayoutManagerAction() { - const { subscribe, set, update } = writable([]); return { diff --git a/front/src/WebRtc/JitsiFactory.ts b/front/src/WebRtc/JitsiFactory.ts index c72f53c1..32e8da24 100644 --- a/front/src/WebRtc/JitsiFactory.ts +++ b/front/src/WebRtc/JitsiFactory.ts @@ -144,51 +144,55 @@ class JitsiFactory { jitsiUrl?: string, jitsiWidth?: number ): void { - coWebsiteManager.addCoWebsite(async (cowebsiteDiv) => { - // Jitsi meet external API maintains some data in local storage - // which is sent via the appData URL parameter when joining a - // conference. Problem is that this data grows indefinitely. Thus - // after some time the URLs get so huge that loading the iframe - // becomes slow and eventually breaks completely. Thus lets just - // clear jitsi local storage before starting a new conference. - window.localStorage.removeItem("jitsiLocalStorage"); + coWebsiteManager.addCoWebsite( + async (cowebsiteDiv) => { + // Jitsi meet external API maintains some data in local storage + // which is sent via the appData URL parameter when joining a + // conference. Problem is that this data grows indefinitely. Thus + // after some time the URLs get so huge that loading the iframe + // becomes slow and eventually breaks completely. Thus lets just + // clear jitsi local storage before starting a new conference. + window.localStorage.removeItem("jitsiLocalStorage"); - const domain = jitsiUrl || JITSI_URL; - if (domain === undefined) { - throw new Error("Missing JITSI_URL environment variable or jitsiUrl parameter in the map."); - } - await this.loadJitsiScript(domain); - - const options: JitsiOptions = { - roomName: roomName, - jwt: jwt, - width: "100%", - height: "100%", - parentNode: cowebsiteDiv, - configOverwrite: mergeConfig(config), - interfaceConfigOverwrite: { ...defaultInterfaceConfig, ...interfaceConfig }, - }; - if (!options.jwt) { - delete options.jwt; - } - - return new Promise((resolve, reject) => { - const doResolve = (): void => { - const iframe = cowebsiteDiv.querySelector('[id*="jitsi" i]'); - if (iframe === null) { - throw new Error("Could not find Jitsi Iframe"); - } - resolve(iframe); + const domain = jitsiUrl || JITSI_URL; + if (domain === undefined) { + throw new Error("Missing JITSI_URL environment variable or jitsiUrl parameter in the map."); } - options.onload = () => doResolve(); //we want for the iframe to be loaded before triggering animations. - setTimeout(() => doResolve(), 2000); //failsafe in case the iframe is deleted before loading or too long to load - this.jitsiApi = new window.JitsiMeetExternalAPI(domain, options); - this.jitsiApi.executeCommand("displayName", playerName); + await this.loadJitsiScript(domain); - this.jitsiApi.addListener("audioMuteStatusChanged", this.audioCallback); - this.jitsiApi.addListener("videoMuteStatusChanged", this.videoCallback); - }); - }, jitsiWidth, 0); + const options: JitsiOptions = { + roomName: roomName, + jwt: jwt, + width: "100%", + height: "100%", + parentNode: cowebsiteDiv, + configOverwrite: mergeConfig(config), + interfaceConfigOverwrite: { ...defaultInterfaceConfig, ...interfaceConfig }, + }; + if (!options.jwt) { + delete options.jwt; + } + + return new Promise((resolve, reject) => { + const doResolve = (): void => { + const iframe = cowebsiteDiv.querySelector('[id*="jitsi" i]'); + if (iframe === null) { + throw new Error("Could not find Jitsi Iframe"); + } + resolve(iframe); + }; + options.onload = () => doResolve(); //we want for the iframe to be loaded before triggering animations. + setTimeout(() => doResolve(), 2000); //failsafe in case the iframe is deleted before loading or too long to load + this.jitsiApi = new window.JitsiMeetExternalAPI(domain, options); + this.jitsiApi.executeCommand("displayName", playerName); + + this.jitsiApi.addListener("audioMuteStatusChanged", this.audioCallback); + this.jitsiApi.addListener("videoMuteStatusChanged", this.videoCallback); + }); + }, + jitsiWidth, + 0 + ); } public stop() {