diff --git a/setupTests.js b/setupTests.js index 0ac548936c7..6ccea002da7 100644 --- a/setupTests.js +++ b/setupTests.js @@ -26,7 +26,6 @@ require('fake-indexeddb/auto'); require('src/script/util/test/mock/createObjectURLMock'); require('src/script/util/test/mock/cryptoMock'); -require('src/script/util/test/mock/iconsMock'); require('src/script/util/test/mock/matchMediaMock'); require('src/script/util/test/mock/mediaDevicesMock'); require('src/script/util/test/mock/navigatorPermissionsMock'); diff --git a/src/script/components/AppContainer/AppContainer.tsx b/src/script/components/AppContainer/AppContainer.tsx index 18a8b63c6c3..627d1d495c7 100644 --- a/src/script/components/AppContainer/AppContainer.tsx +++ b/src/script/components/AppContainer/AppContainer.tsx @@ -23,6 +23,7 @@ import {ClientType} from '@wireapp/api-client/lib/client/'; import {container} from 'tsyringe'; import {Configuration} from '../../Config'; +import {setAppLocale} from '../../localization/Localizer'; import {App} from '../../main/app'; import {AppMain} from '../../page/AppMain'; import {APIClient} from '../../service/APIClientSingleton'; @@ -36,6 +37,7 @@ interface AppProps { } export const AppContainer: FC = ({config, clientType}) => { + setAppLocale(); const app = new App(container.resolve(Core), container.resolve(APIClient), config); // Publishing application on the global scope for debug and testing purposes. window.wire.app = app; diff --git a/src/script/components/icons.ts b/src/script/components/icons.ts deleted file mode 100644 index 186ebc350b3..00000000000 --- a/src/script/components/icons.ts +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Wire - * Copyright (C) 2018 Wire Swiss GmbH - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see http://www.gnu.org/licenses/. - * - */ - -const fileList = require.context('Resource/image/icon', true, /.+\.svg$/); - -fileList.keys().forEach(iconFileName => { - const iconPath = iconFileName.replace(/^\.\//, ''); - const iconName = iconFileName.substring(iconFileName.lastIndexOf('/') + 1).replace(/\.svg$/i, ''); - ko.components.register(iconName, { - template: require(`Resource/image/icon/${iconPath}`), - }); -}); diff --git a/src/script/entity/Conversation.test.ts b/src/script/entity/Conversation.test.ts index e0112ba875a..d713f2afbab 100644 --- a/src/script/entity/Conversation.test.ts +++ b/src/script/entity/Conversation.test.ts @@ -508,7 +508,7 @@ describe('Conversation', () => { it('displays "Empty Conversation" if no other participants are in the conversation', () => { conversation_et.type(CONVERSATION_TYPE.REGULAR); - expect(conversation_et.display_name()).toBe(window.z.string.conversationsEmptyConversation); + expect(conversation_et.display_name()).toBe('Group conversation'); }); it('displays a fallback if no user name has been set for a group conversation', () => { diff --git a/src/script/localization/Localizer.ts b/src/script/localization/Localizer.ts index 2d821948b92..cb2a40a00aa 100644 --- a/src/script/localization/Localizer.ts +++ b/src/script/localization/Localizer.ts @@ -47,8 +47,6 @@ import {getParameter} from 'Util/UrlUtil'; import {URLParameter} from '../auth/URLParameter'; import {StorageKey} from '../storage/StorageKey'; -window.z = window.z || {}; - const strings = { cs, da, @@ -74,10 +72,9 @@ const strings = { uk, }; -window.z.string = strings; setStrings(strings); -(function setAppLocale() { +export function setAppLocale() { const queryParam = getParameter(URLParameter.LOCALE); const currentBrowserLocale = navigator.language.slice(0, 2) as LocaleType; @@ -91,8 +88,4 @@ setStrings(strings); setDateLocale(locale); document.getElementsByTagName('html')[0].setAttribute('lang', locale); - - if (window.z.string[locale]) { - window.z.string = {...window.z.string, ...window.z.string[DEFAULT_LOCALE], ...window.z.string[locale]}; - } -})(); +} diff --git a/src/script/main/app.ts b/src/script/main/app.ts index 748b9744658..825788ae2a2 100644 --- a/src/script/main/app.ts +++ b/src/script/main/app.ts @@ -25,7 +25,6 @@ import {Context} from '@wireapp/api-client/lib/auth'; import {ClientClassification, ClientType} from '@wireapp/api-client/lib/client/'; import {amplify} from 'amplify'; import Dexie from 'dexie'; -import ko from 'knockout'; import platform from 'platform'; import {container} from 'tsyringe'; @@ -41,7 +40,6 @@ import {TIME_IN_MILLIS} from 'Util/TimeUtil'; import {appendParameter} from 'Util/UrlUtil'; import {checkIndexedDb, createRandomUuid, supportsMLS} from 'Util/util'; -import './globals'; import {migrateToQualifiedSessionIds} from './sessionIdMigrator'; import {SingleInstanceHandler} from './SingleInstanceHandler'; @@ -103,7 +101,6 @@ import {AppInitTimingsStep} from '../telemetry/app_init/AppInitTimingsStep'; import {serverTimeHandler} from '../time/serverTimeHandler'; import {EventTrackingRepository} from '../tracking/EventTrackingRepository'; import {WindowHandler} from '../ui/WindowHandler'; -import * as UserPermission from '../user/UserPermission'; import {UserRepository} from '../user/UserRepository'; import {UserService} from '../user/UserService'; import {ViewModelRepositories} from '../view_model/MainViewModel'; @@ -191,8 +188,6 @@ export class App { }); } - this._publishGlobals(); - const onExtraInstanceStarted = () => this._redirectToLogin(SIGN_OUT_REASON.MULTIPLE_TABS); this.singleInstanceHandler = new SingleInstanceHandler(onExtraInstanceStarted); @@ -831,16 +826,4 @@ export class App { doRedirect(signOutReason); } - - //############################################################################## - // Debugging - //############################################################################## - - private _publishGlobals() { - window.z.userPermission = ko.observable({}); - ko.pureComputed(() => { - const selfUser = this.repository.user['userState'].self(); - return selfUser && selfUser.teamRole(); - }).subscribe(role => window.z.userPermission(UserPermission.generatePermissionHelpers(role))); - } } diff --git a/src/script/main/globals.ts b/src/script/main/globals.ts deleted file mode 100644 index c684a2527df..00000000000 --- a/src/script/main/globals.ts +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Wire - * Copyright (C) 2019 Wire Swiss GmbH - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see http://www.gnu.org/licenses/. - * - */ - -import {amplify} from 'amplify'; -import jQuery from 'jquery'; -import ko from 'knockout'; - -import 'Components/icons'; -import 'Util/LocalizerUtil'; - -import '../Config'; -import '../localization/Localizer'; -import '../page/AppMain'; -import '../view_model/MainViewModel'; - -window.amplify = amplify; -// we need to publish jQuery on the window so that knockout can use it -window.jQuery = jQuery; -window.ko = ko; diff --git a/src/script/util/LocalizerUtil.ts b/src/script/util/LocalizerUtil.ts index e402bbd384d..3d51d5bbb33 100644 --- a/src/script/util/LocalizerUtil.ts +++ b/src/script/util/LocalizerUtil.ts @@ -145,5 +145,3 @@ export const replaceLink = (href: string, className: string = '', uieName: strin '/link': '', link: ``, }); - -window.t = LocalizerUtil.translate; diff --git a/test/unit_tests/util/SanitizationUtilSpec.js b/src/script/util/SanitizationUtil.test.ts similarity index 85% rename from test/unit_tests/util/SanitizationUtilSpec.js rename to src/script/util/SanitizationUtil.test.ts index 25f67a01e4c..affcef8ea60 100644 --- a/test/unit_tests/util/SanitizationUtilSpec.js +++ b/src/script/util/SanitizationUtil.test.ts @@ -17,16 +17,13 @@ * */ -import {User} from 'src/script/entity/User'; -import 'src/script/localization/Localizer'; -import {escapeRegex, getSelfName, getUserName, safeWindowOpen} from 'src/script/util/SanitizationUtil'; -import {Declension, LocalizerUtil, setStrings} from 'Util/LocalizerUtil'; +import {Declension, LocalizerUtil, t} from 'Util/LocalizerUtil'; -describe('SanitizationUtil', () => { - beforeEach(() => { - setStrings({en: z.string}); - }); +import {escapeRegex, getSelfName, getUserName, safeWindowOpen} from './SanitizationUtil'; +import {User} from '../entity/User'; + +describe('SanitizationUtil', () => { describe('escapeRegex', () => { it('will return escaped regex strings', () => { const escapedRegex = escapeRegex(':)'); @@ -48,7 +45,7 @@ describe('SanitizationUtil', () => { userEntity.isMe = true; const escapedSelfName = getUserName(userEntity); - expect(escapedSelfName).toEqual('you'); + expect(escapedSelfName).toEqual(t('conversationYouNominative')); }); }); @@ -57,15 +54,15 @@ describe('SanitizationUtil', () => { // eslint-disable-line const escapedNominativeName = getSelfName(Declension.NOMINATIVE); - expect(escapedNominativeName).toEqual('you'); + expect(escapedNominativeName).toEqual(t('conversationYouNominative')); const unescapedNominativeName = getSelfName(Declension.NOMINATIVE, true); - expect(unescapedNominativeName).toEqual('you'); + expect(unescapedNominativeName).toEqual(t('conversationYouNominative')); const escapedDativeName = getSelfName(Declension.DATIVE); - expect(escapedDativeName).toEqual('you'); + expect(escapedDativeName).toEqual(t('conversationYouDative')); spyOn(LocalizerUtil, 'translate').and.returnValue(''); const escapedAccusativeName = getSelfName(Declension.DATIVE); @@ -84,7 +81,7 @@ describe('SanitizationUtil', () => { focus: jest.fn(), opener: 'remove me', }; - jest.spyOn(window, 'open').mockImplementation(() => mockedWindow); + jest.spyOn(window, 'open').mockImplementation(() => mockedWindow as any); const newWindow = safeWindowOpen('https://wire.com/'); expect(newWindow.opener).toBeNull(); diff --git a/src/script/util/SanitizationUtil.ts b/src/script/util/SanitizationUtil.ts index 3041730c88b..fa07987b6a3 100644 --- a/src/script/util/SanitizationUtil.ts +++ b/src/script/util/SanitizationUtil.ts @@ -37,7 +37,7 @@ export const getSelfName = (declension = Declension.NOMINATIVE, bypassSanitizati return bypassSanitization ? selfName : escape(selfName); }; -export const getUserName = (userEntity: User, declension: string, bypassSanitization: boolean = false): string => { +export const getUserName = (userEntity: User, declension?: string, bypassSanitization: boolean = false): string => { if (userEntity.isMe) { return getSelfName(declension, bypassSanitization); } diff --git a/src/script/util/test/mock/iconsMock.ts b/src/script/util/test/mock/iconsMock.ts deleted file mode 100644 index fe85029d60f..00000000000 --- a/src/script/util/test/mock/iconsMock.ts +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Wire - * Copyright (C) 2020 Wire Swiss GmbH - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see http://www.gnu.org/licenses/. - * - */ - -import ko from 'knockout'; - -jest.mock('Components/icons', () => ({Icon: {}})); - -ko.components.register('profile-icon', {template: ''}); -ko.components.register('leave-icon', {template: ''}); -ko.components.register('edit-icon', {template: ''}); -ko.components.register('message-icon', {template: ''}); -ko.components.register('copy-icon', {template: ''}); -ko.components.register('block-icon', {template: ''}); -ko.components.register('pickup-icon', {template: ''}); diff --git a/src/script/util/wrapper.ts b/src/script/util/wrapper.ts index 81669cacf94..f68a8380482 100644 --- a/src/script/util/wrapper.ts +++ b/src/script/util/wrapper.ts @@ -17,6 +17,8 @@ * */ +import {amplify} from 'amplify'; + import {Runtime} from '@wireapp/commons'; import {WebAppEvents} from '@wireapp/webapp-events'; @@ -26,6 +28,7 @@ import {ROLE} from '../user/UserPermission'; export function exposeWrapperGlobals(): void { if (Runtime.isDesktopApp()) { + window.amplify = amplify; window.z ||= {}; window.z.event ||= {}; diff --git a/test/unit_tests/notification/NotificationRepositorySpec.js b/test/unit_tests/notification/NotificationRepositorySpec.js index 789f778ca50..f5e37c2666d 100644 --- a/test/unit_tests/notification/NotificationRepositorySpec.js +++ b/test/unit_tests/notification/NotificationRepositorySpec.js @@ -153,9 +153,9 @@ describe('NotificationRepository', () => { expect(testFactory.notification_repository.showNotification).toHaveBeenCalledTimes(1); const trigger = testFactory.notification_repository.createTrigger(message_et, null, conversation_et); - notification_content.options.body = z.string.notificationObfuscated; + notification_content.options.body = t('notificationObfuscated'); notification_content.options.data.messageType = _message.type; - notification_content.title = z.string.notificationObfuscatedTitle; + notification_content.title = t('notificationObfuscatedTitle'); notification_content.trigger = trigger; const [firstResultArgs] = testFactory.notification_repository.showNotification.calls.first().args; @@ -176,11 +176,11 @@ describe('NotificationRepository', () => { const titleLength = NotificationRepository.CONFIG.TITLE_LENGTH; const titleText = `${message_et.user().name()} in ${conversation_et.display_name()}`; - notification_content.options.body = z.string.notificationObfuscated; + notification_content.options.body = t('notificationObfuscated'); notification_content.title = truncate(titleText, titleLength, false); } else { - notification_content.options.body = z.string.notificationObfuscated; - notification_content.title = z.string.notificationObfuscatedTitle; + notification_content.options.body = t('notificationObfuscated'); + notification_content.title = t('notificationObfuscatedTitle'); } notification_content.options.data.messageType = _message.type; @@ -372,7 +372,7 @@ describe('NotificationRepository', () => { describe('shows a well-formed call notification', () => { describe('for an incoming call', () => { - const expected_body = z.string.notificationVoiceChannelActivate; + const expected_body = t('notificationVoiceChannelActivate'); beforeEach(() => { message_et = new CallMessage(); @@ -391,7 +391,7 @@ describe('NotificationRepository', () => { }); describe('for a missed call', () => { - const expected_body = z.string.notificationVoiceChannelDeactivate; + const expected_body = t('notificationVoiceChannelDeactivate'); beforeEach(() => { message_et = new CallMessage(); @@ -451,7 +451,7 @@ describe('NotificationRepository', () => { describe('for a picture', () => { beforeEach(() => { message_et.assets.push(new MediumImage()); - expected_body = z.string.notificationAssetAdd; + expected_body = t('notificationAssetAdd'); }); it('in a 1:1 conversation', () => { @@ -479,7 +479,7 @@ describe('NotificationRepository', () => { describe('for a location', () => { beforeEach(() => { message_et.assets.push(new Location()); - expected_body = z.string.notificationSharedLocation; + expected_body = t('notificationSharedLocation'); }); it('in a 1:1 conversation', () => { @@ -685,7 +685,7 @@ describe('NotificationRepository', () => { connectionEntity.status = 'pending'; message_et.memberMessageType = SystemMessageType.CONNECTION_REQUEST; - const expected_body = z.string.notificationConnectionRequest; + const expected_body = t('notificationConnectionRequest'); expect(expected_body).toBeDefined(); return verifyNotificationSystem(conversation_et, message_et, expected_body, expected_title); }); @@ -693,7 +693,7 @@ describe('NotificationRepository', () => { it('if your connection request was accepted', () => { message_et.memberMessageType = SystemMessageType.CONNECTION_ACCEPTED; - const expected_body = z.string.notificationConnectionAccepted; + const expected_body = t('notificationConnectionAccepted'); expect(expected_body).toBeDefined(); return verifyNotificationSystem(conversation_et, message_et, expected_body, expected_title); }); @@ -701,14 +701,14 @@ describe('NotificationRepository', () => { it('if you are automatically connected', () => { message_et.memberMessageType = SystemMessageType.CONNECTION_CONNECTED; - const expected_body = z.string.notificationConnectionConnected; + const expected_body = t('notificationConnectionConnected'); expect(expected_body).toBeDefined(); return verifyNotificationSystem(conversation_et, message_et, expected_body, expected_title); }); }); describe('shows a well-formed ping notification', () => { - const expected_body = z.string.notificationPing; + const expected_body = t('notificationPing'); beforeAll(() => { user_et = testFactory.user_repository.userMapper.mapUserFromJson(payload.users.get.one[0]);