diff --git a/_locales/en/messages.json b/_locales/en/messages.json index cb1f2c7f6..4ebee76d9 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -1817,7 +1817,7 @@ "description": "Label text for menu bar visibility setting" }, "startConversation": { - "message": "Start new conversation…", + "message": "Start New Conversation", "description": "Label underneath number a user enters that is not an existing contact" }, @@ -2259,6 +2259,14 @@ "editProfileDialogTitle": { "message": "Editing Profile" }, + + + "editProfileModalTitle": { + "message": "Edit Profile", + "description": "Title for the Edit Profile modal" + }, + + "profileName": { "message": "Profile Name" }, diff --git a/js/modules/signal.js b/js/modules/signal.js index ecfee5e70..0d5617e19 100644 --- a/js/modules/signal.js +++ b/js/modules/signal.js @@ -50,6 +50,7 @@ const { } = require('../../ts/components/conversation/CreateGroupDialog'); const { EditProfileDialog } = require('../../ts/components/EditProfileDialog'); const { UserDetailsDialog } = require('../../ts/components/UserDetailsDialog'); +const { DevicePairingDialog } = require('../../ts/components/DevicePairingDialog'); const { SessionToast } = require('../../ts/components/session/SessionToast'); const { SessionToggle } = require('../../ts/components/session/SessionToggle'); const { SessionModal } = require('../../ts/components/session/SessionModal'); @@ -248,6 +249,7 @@ exports.setup = (options = {}) => { CreateGroupDialog, EditProfileDialog, UserDetailsDialog, + DevicePairingDialog, SessionRegistrationView, ConfirmDialog, UpdateGroupDialog, diff --git a/js/views/device_pairing_dialog_view.js b/js/views/device_pairing_dialog_view.js index 80d6b4f61..32d44eed2 100644 --- a/js/views/device_pairing_dialog_view.js +++ b/js/views/device_pairing_dialog_view.js @@ -27,183 +27,12 @@ }); this.qr.makeCode(textsecure.storage.user.getNumber()); }, - reset() { - this.pubKey = null; - this.accepted = false; - this.isListening = false; - this.pubKeyToUnpair = null; - this.success = false; - }, - events: { - 'click #startPairing': 'startReceivingRequests', - 'click #close': 'close', - 'click .waitingForRequestView .cancel': 'stopReceivingRequests', - 'click .requestReceivedView .skip': 'skipDevice', - 'click #allowPairing': 'allowDevice', - 'click .requestAcceptedView .ok': 'stopReceivingRequests', - 'click .confirmUnpairView .cancel': 'stopReceivingRequests', - 'click .confirmUnpairView .unpairDevice': 'confirmUnpairDevice', - }, - render_attributes() { - return { - defaultTitle: i18n('pairedDevices'), - waitingForRequestTitle: i18n('waitingForDeviceToRegister'), - requestReceivedTitle: i18n('devicePairingReceived'), - requestAcceptedTitle: i18n('devicePairingAccepted'), - startPairingText: i18n('pairNewDevice'), - cancelText: i18n('cancel'), - unpairDevice: i18n('unpairDevice'), - closeText: i18n('close'), - skipText: i18n('skip'), - okText: i18n('ok'), - allowPairingText: i18n('allowPairing'), - confirmUnpairViewTitle: i18n('confirmUnpairingTitle'), - }; - }, - startReceivingRequests() { - this.trigger('startReceivingRequests'); - this.isListening = true; - this.showView(); - }, - stopReceivingRequests() { - if (this.success) { - const deviceAlias = this.$('#deviceAlias')[0].value.trim(); - const conv = ConversationController.get(this.pubKey); - if (conv) { - conv.setNickname(deviceAlias); - } - } - this.trigger('stopReceivingRequests'); - this.reset(); - this.showView(); - }, - requestReceived(secondaryDevicePubKey) { - // FIFO: push at the front of the array with unshift() - this.pubKeyRequests.unshift(secondaryDevicePubKey); - if (!this.pubKey) { - this.nextPubKey(); - this.showView('requestReceived'); - } - }, - allowDevice() { - this.accepted = true; - this.trigger('devicePairingRequestAccepted', this.pubKey, errors => - this.transmisssionCB(errors) - ); - this.showView(); - }, - transmisssionCB(errors) { - if (!errors) { - this.$('.transmissionStatus').text(i18n('provideDeviceAlias')); - this.$('#deviceAliasView').show(); - this.$('#deviceAlias').on('input', e => { - if (e.target.value.trim()) { - this.$('.requestAcceptedView .ok').removeAttr('disabled'); - } else { - this.$('.requestAcceptedView .ok').attr('disabled', true); - } - }); - this.$('.requestAcceptedView .ok').show(); - this.$('.requestAcceptedView .ok').attr('disabled', true); - this.success = true; - } else { - this.$('.transmissionStatus').text(errors); - this.$('.requestAcceptedView .ok').show(); - } - }, - skipDevice() { - this.trigger('devicePairingRequestRejected', this.pubKey); - this.nextPubKey(); - this.showView(); - }, - nextPubKey() { - // FIFO: pop at the back of the array using pop() - this.pubKey = this.pubKeyRequests.pop(); - }, - async confirmUnpairDevice() { - this.trigger('deviceUnpairingRequested', this.pubKeyToUnpair); - this.reset(); - this.showView(); - }, - requestUnpairDevice(pubKey) { - this.pubKeyToUnpair = pubKey; - this.showView(); - }, - getPubkeyName(pubKey) { - const secretWords = window.mnemonic.pubkey_to_secret_words(pubKey); - const conv = ConversationController.get(pubKey); - const deviceAlias = conv ? conv.getNickname() : 'Unnamed Device'; - return `${deviceAlias} (pairing secret: ${secretWords})`; - }, - async showView() { - const defaultView = this.$('.defaultView'); - const waitingForRequestView = this.$('.waitingForRequestView'); - const requestReceivedView = this.$('.requestReceivedView'); - const requestAcceptedView = this.$('.requestAcceptedView'); - const confirmUnpairView = this.$('.confirmUnpairView'); - if (this.pubKeyToUnpair) { - defaultView.hide(); - requestReceivedView.hide(); - waitingForRequestView.hide(); - requestAcceptedView.hide(); - confirmUnpairView.show(); - const name = this.getPubkeyName(this.pubKeyToUnpair); - this.$('.confirmUnpairView #pubkey').html(name); - } else if (!this.isListening) { - requestReceivedView.hide(); - waitingForRequestView.hide(); - requestAcceptedView.hide(); - confirmUnpairView.hide(); - - const ourPubKey = textsecure.storage.user.getNumber(); - defaultView.show(); - const pubKeys = await libloki.storage.getSecondaryDevicesFor(ourPubKey); - this.$('#pairedPubKeys').empty(); - if (pubKeys && pubKeys.length > 0) { - this.$('#startPairing').attr('disabled', true); - pubKeys.forEach(x => { - const name = this.getPubkeyName(x); - const li = $('
  • ').html(name); - if (window.lokiFeatureFlags.multiDeviceUnpairing) { - const link = $('') - .text('Unpair') - .attr('href', '#'); - link.on('click', () => this.requestUnpairDevice(x)); - li.append(' - '); - li.append(link); - } - this.$('#pairedPubKeys').append(li); - }); - } else { - this.$('#startPairing').removeAttr('disabled'); - this.$('#pairedPubKeys').append('
  • No paired devices
  • '); - } - } else if (this.accepted) { - defaultView.hide(); - requestReceivedView.hide(); - waitingForRequestView.hide(); - requestAcceptedView.show(); - } else if (this.pubKey) { - const secretWords = window.mnemonic.pubkey_to_secret_words(this.pubKey); - this.$('.secretWords').text(secretWords); - requestReceivedView.show(); - waitingForRequestView.hide(); - requestAcceptedView.hide(); - defaultView.hide(); - } else { - waitingForRequestView.show(); - requestReceivedView.hide(); - requestAcceptedView.hide(); - defaultView.hide(); - } - }, - close() { - this.remove(); - this.qr.clear(); - if (this.pubKey && !this.accepted) { - this.trigger('devicePairingRequestRejected', this.pubKey); - } - this.trigger('close'); + + render() { + this.dialogView = new Whisper.ReactWrapperView({ + className: 'device-pairing-dialog', + Component: window.Signal.Components.DevicePairingDialog, + }); }, }); })(); diff --git a/js/views/device_pairing_dialog_view_old.js b/js/views/device_pairing_dialog_view_old.js new file mode 100644 index 000000000..80d6b4f61 --- /dev/null +++ b/js/views/device_pairing_dialog_view_old.js @@ -0,0 +1,209 @@ +/* global + Whisper, + i18n, + libloki, + textsecure, + ConversationController, + $, + QRCode, +*/ + +// eslint-disable-next-line func-names +(function() { + 'use strict'; + + window.Whisper = window.Whisper || {}; + + Whisper.DevicePairingDialogView = Whisper.View.extend({ + className: 'loki-dialog device-pairing-dialog modal', + templateName: 'device-pairing-dialog', + initialize() { + this.pubKeyRequests = []; + this.reset(); + this.render(); + this.showView(); + this.qr = new QRCode(this.$('#qr')[0], { + correctLevel: QRCode.CorrectLevel.L, + }); + this.qr.makeCode(textsecure.storage.user.getNumber()); + }, + reset() { + this.pubKey = null; + this.accepted = false; + this.isListening = false; + this.pubKeyToUnpair = null; + this.success = false; + }, + events: { + 'click #startPairing': 'startReceivingRequests', + 'click #close': 'close', + 'click .waitingForRequestView .cancel': 'stopReceivingRequests', + 'click .requestReceivedView .skip': 'skipDevice', + 'click #allowPairing': 'allowDevice', + 'click .requestAcceptedView .ok': 'stopReceivingRequests', + 'click .confirmUnpairView .cancel': 'stopReceivingRequests', + 'click .confirmUnpairView .unpairDevice': 'confirmUnpairDevice', + }, + render_attributes() { + return { + defaultTitle: i18n('pairedDevices'), + waitingForRequestTitle: i18n('waitingForDeviceToRegister'), + requestReceivedTitle: i18n('devicePairingReceived'), + requestAcceptedTitle: i18n('devicePairingAccepted'), + startPairingText: i18n('pairNewDevice'), + cancelText: i18n('cancel'), + unpairDevice: i18n('unpairDevice'), + closeText: i18n('close'), + skipText: i18n('skip'), + okText: i18n('ok'), + allowPairingText: i18n('allowPairing'), + confirmUnpairViewTitle: i18n('confirmUnpairingTitle'), + }; + }, + startReceivingRequests() { + this.trigger('startReceivingRequests'); + this.isListening = true; + this.showView(); + }, + stopReceivingRequests() { + if (this.success) { + const deviceAlias = this.$('#deviceAlias')[0].value.trim(); + const conv = ConversationController.get(this.pubKey); + if (conv) { + conv.setNickname(deviceAlias); + } + } + this.trigger('stopReceivingRequests'); + this.reset(); + this.showView(); + }, + requestReceived(secondaryDevicePubKey) { + // FIFO: push at the front of the array with unshift() + this.pubKeyRequests.unshift(secondaryDevicePubKey); + if (!this.pubKey) { + this.nextPubKey(); + this.showView('requestReceived'); + } + }, + allowDevice() { + this.accepted = true; + this.trigger('devicePairingRequestAccepted', this.pubKey, errors => + this.transmisssionCB(errors) + ); + this.showView(); + }, + transmisssionCB(errors) { + if (!errors) { + this.$('.transmissionStatus').text(i18n('provideDeviceAlias')); + this.$('#deviceAliasView').show(); + this.$('#deviceAlias').on('input', e => { + if (e.target.value.trim()) { + this.$('.requestAcceptedView .ok').removeAttr('disabled'); + } else { + this.$('.requestAcceptedView .ok').attr('disabled', true); + } + }); + this.$('.requestAcceptedView .ok').show(); + this.$('.requestAcceptedView .ok').attr('disabled', true); + this.success = true; + } else { + this.$('.transmissionStatus').text(errors); + this.$('.requestAcceptedView .ok').show(); + } + }, + skipDevice() { + this.trigger('devicePairingRequestRejected', this.pubKey); + this.nextPubKey(); + this.showView(); + }, + nextPubKey() { + // FIFO: pop at the back of the array using pop() + this.pubKey = this.pubKeyRequests.pop(); + }, + async confirmUnpairDevice() { + this.trigger('deviceUnpairingRequested', this.pubKeyToUnpair); + this.reset(); + this.showView(); + }, + requestUnpairDevice(pubKey) { + this.pubKeyToUnpair = pubKey; + this.showView(); + }, + getPubkeyName(pubKey) { + const secretWords = window.mnemonic.pubkey_to_secret_words(pubKey); + const conv = ConversationController.get(pubKey); + const deviceAlias = conv ? conv.getNickname() : 'Unnamed Device'; + return `${deviceAlias} (pairing secret: ${secretWords})`; + }, + async showView() { + const defaultView = this.$('.defaultView'); + const waitingForRequestView = this.$('.waitingForRequestView'); + const requestReceivedView = this.$('.requestReceivedView'); + const requestAcceptedView = this.$('.requestAcceptedView'); + const confirmUnpairView = this.$('.confirmUnpairView'); + if (this.pubKeyToUnpair) { + defaultView.hide(); + requestReceivedView.hide(); + waitingForRequestView.hide(); + requestAcceptedView.hide(); + confirmUnpairView.show(); + const name = this.getPubkeyName(this.pubKeyToUnpair); + this.$('.confirmUnpairView #pubkey').html(name); + } else if (!this.isListening) { + requestReceivedView.hide(); + waitingForRequestView.hide(); + requestAcceptedView.hide(); + confirmUnpairView.hide(); + + const ourPubKey = textsecure.storage.user.getNumber(); + defaultView.show(); + const pubKeys = await libloki.storage.getSecondaryDevicesFor(ourPubKey); + this.$('#pairedPubKeys').empty(); + if (pubKeys && pubKeys.length > 0) { + this.$('#startPairing').attr('disabled', true); + pubKeys.forEach(x => { + const name = this.getPubkeyName(x); + const li = $('
  • ').html(name); + if (window.lokiFeatureFlags.multiDeviceUnpairing) { + const link = $('') + .text('Unpair') + .attr('href', '#'); + link.on('click', () => this.requestUnpairDevice(x)); + li.append(' - '); + li.append(link); + } + this.$('#pairedPubKeys').append(li); + }); + } else { + this.$('#startPairing').removeAttr('disabled'); + this.$('#pairedPubKeys').append('
  • No paired devices
  • '); + } + } else if (this.accepted) { + defaultView.hide(); + requestReceivedView.hide(); + waitingForRequestView.hide(); + requestAcceptedView.show(); + } else if (this.pubKey) { + const secretWords = window.mnemonic.pubkey_to_secret_words(this.pubKey); + this.$('.secretWords').text(secretWords); + requestReceivedView.show(); + waitingForRequestView.hide(); + requestAcceptedView.hide(); + defaultView.hide(); + } else { + waitingForRequestView.show(); + requestReceivedView.hide(); + requestAcceptedView.hide(); + defaultView.hide(); + } + }, + close() { + this.remove(); + this.qr.clear(); + if (this.pubKey && !this.accepted) { + this.trigger('devicePairingRequestRejected', this.pubKey); + } + this.trigger('close'); + }, + }); +})(); diff --git a/stylesheets/_session.scss b/stylesheets/_session.scss index 1316b1f10..e317f4b41 100644 --- a/stylesheets/_session.scss +++ b/stylesheets/_session.scss @@ -78,6 +78,16 @@ $session-margin-sm: 10px; $session-margin-md: 15px; $session-margin-lg: 20px; +div.spacer-sm { + height: $session-margin-sm; +} +div.spacer-md { + height: $session-margin-md; +} +div.spacer-lg { + height: $session-margin-lg; +} + @mixin session-color-subtle($color) { color: rgba($color, 0.6); } @@ -173,6 +183,9 @@ $session_message-container-border-radius: 5px; &.secondary { background-color: $session-color-secondary; } + &.success { + background-color: $session-color-success; + } &.danger { background-color: $session-color-danger; } @@ -493,19 +506,21 @@ label { .session-modal { z-index: 150; position: fixed; - top: 50%; left: 50%; + top: 50%; + transform: translate(-50%, -50%); box-sizing: border-box; - height: 529px; - width: 345px; + max-height: 70vh; + max-width: 70vw; background-color: $session-shade-4; border: 1px solid $session-shade-8; - .header { + &__header { display: flex; flex-direction: row; justify-content: space-between; + padding: $session-margin-lg; font-family: 'Wasa'; @@ -514,17 +529,45 @@ label { font-size: 15px; font-weight: 700; - .close, - .icons { - width: 70px; + &__icons, &__close { + width: 60px; } - .close > div { + &__icons { + float: right; + } + &__close > div { float: left; } - .icons > div { + &__icons > div { float: right; + padding-left: 10px; + } + } + + &__body { + padding: $session-margin-lg; + + font-family: 'Wasa'; + line-height: 16px; + font-size: 13px; + + .message{ + text-align: center; } } + + &__button-group { + display: flex; + justify-content: flex-end; + + &__center{ + align-items: center; + } + .session-button { + margin-left: $session-margin-sm; + } + } + } .session-toggle { @@ -636,3 +679,11 @@ label { } } } + + + +.edit-profile-dialog .image-upload-section { + position: absolute; + margin-top: 50px; + margin-left: 75px; +} \ No newline at end of file diff --git a/ts/components/ConfirmDialog.tsx b/ts/components/ConfirmDialog.tsx index 0a1cb510e..ef02efaf0 100644 --- a/ts/components/ConfirmDialog.tsx +++ b/ts/components/ConfirmDialog.tsx @@ -1,5 +1,8 @@ import React from 'react'; +import { SessionModal } from './session/SessionModal'; +import { SessionButton } from './session/SessionButton'; + interface Props { titleText: string; messageText: string; @@ -16,18 +19,23 @@ export class ConfirmDialog extends React.Component { public render() { return ( -
    -

    {this.props.titleText}

    + null} onOk={() => null}> +

    {this.props.messageText}

    -
    - - +
    + +
    + + +
    -
    +
    ); } } diff --git a/ts/components/DevicePairingDialog.tsx b/ts/components/DevicePairingDialog.tsx new file mode 100644 index 000000000..e69de29bb diff --git a/ts/components/EditProfileDialog.tsx b/ts/components/EditProfileDialog.tsx index 4c103b56d..438d937a9 100644 --- a/ts/components/EditProfileDialog.tsx +++ b/ts/components/EditProfileDialog.tsx @@ -2,6 +2,11 @@ import React from 'react'; import classNames from 'classnames'; import { Avatar } from './Avatar'; +import { SessionModal } from './session/SessionModal'; +import { SessionButton, SessionButtonColor } from './session/SessionButton'; +import { SessionIconButton, SessionIconType, SessionIconSize } from './session/icon'; + + declare global { interface Window { displayNameRegex: any; @@ -63,11 +68,15 @@ export class EditProfileDialog extends React.Component { ); return ( -
    +
    {this.renderAvatar()} -
    +
    { name="name" onChange={this.onFileSelected} /> -
    { - const el = this.inputEl.current; - if (el) { - el.click(); - } - }} - /> + + { + const el = this.inputEl.current; + if (el) { + el.click(); + } + }} + />
    + +
    + { />
    {i18n('editProfileDisplayNameWarning')}
    {this.state.errorMessage} -
    - - + +
    + +
    + +
    -
    + ); } diff --git a/ts/components/UserDetailsDialog.tsx b/ts/components/UserDetailsDialog.tsx index f0d765b96..b1a9b6020 100644 --- a/ts/components/UserDetailsDialog.tsx +++ b/ts/components/UserDetailsDialog.tsx @@ -1,7 +1,8 @@ import React from 'react'; import { Avatar } from './Avatar'; -import { SessionDropdown } from './session/SessionDropdown'; +import { SessionModal } from './session/SessionModal'; +import { SessionButton, SessionButtonType, SessionButtonColor } from './session/SessionButton'; declare global { interface Window { @@ -31,64 +32,27 @@ export class UserDetailsDialog extends React.Component { public render() { const i18n = this.props.i18n; - - const cancelText = i18n('cancel'); - const startConversation = i18n('startConversation'); - - const items = [ - { - content: 'sdgsdfg', - display: true, //!isPublic && !isMe, - }, - { - content: i18n('changeNickname'), - display: true, //!isPublic && !isMe, - }, - { - content: i18n('clearNickname'), - display: true, //!isPublic && !isMe && hasNickname, - }, - { - content: i18n('copyPublicKey'), - display: false, //!isPublic, - }, - { - content: i18n('deleteMessages'), - }, - { - content: i18n('deleteContact'), - display: true, //!isMe && isClosable && !isPublic, - }, - { - content: i18n('deletePublicChannel'), - display: true, //!isMe && isClosable && !isPublic, - }, - ]; - + return ( -
    - - + null} + onClose={this.closeDialog} + >
    {this.renderAvatar()}
    -
    {this.props.profileName}
    {this.props.pubkey}
    -
    - - - +
    +
    -
    +
    ); } diff --git a/ts/components/session/SessionButton.tsx b/ts/components/session/SessionButton.tsx index 62b0aebd2..99f92f9c9 100644 --- a/ts/components/session/SessionButton.tsx +++ b/ts/components/session/SessionButton.tsx @@ -16,6 +16,7 @@ export enum SessionButtonColor { White = 'white', Primary = 'primary', Secondary = 'secondary', + Success = 'success', Danger = 'danger', Warning = 'warning', } diff --git a/ts/components/session/SessionModal.tsx b/ts/components/session/SessionModal.tsx index 325f772ec..9217568b3 100644 --- a/ts/components/session/SessionModal.tsx +++ b/ts/components/session/SessionModal.tsx @@ -5,39 +5,87 @@ import { SessionIconButton, SessionIconSize, SessionIconType } from './icon/'; interface Props { title: string; - body: any; + onClose: any; + onOk: any; + //Maximum of two icons in header + headerIconButtons?: Array<{ + type: SessionIconType; + onClick?: any; + }>; } -export class SessionModal extends React.PureComponent { +interface State { + isVisible: boolean; +} + +export class SessionModal extends React.PureComponent { + constructor(props: any) { super(props); + this.state = { + isVisible: true, + }; + + this.close = this.close.bind(this); + this.onKeyUp = this.onKeyUp.bind(this); + + window.addEventListener('keyup', this.onKeyUp); } public render() { - const { title } = this.props; - - return ( -
    -
    -
    - + const { title, headerIconButtons } = this.props; + const { isVisible } = this.state; + + return isVisible ? ( +
    +
    +
    + +
    +
    {title}
    +
    + { headerIconButtons ? headerIconButtons.map((iconItem: any) => { + return ( + + ) + }) : null + } +
    -
    {title}
    -
    - - + +
    + {this.props.children}
    -
    - ); + ) : null; + } + + public close() { + this.setState({ + isVisible: false, + }); + + window.removeEventListener('keyup', this.onKeyUp); + this.props.onClose(); + } + + public onKeyUp(event: any){ + switch (event.key) { + case 'Enter': + this.props.onOk(); + break; + case 'Esc': + case 'Escape': + this.close(); + break; + default: + } } } diff --git a/ts/components/session/icon/Icons.tsx b/ts/components/session/icon/Icons.tsx index 4b4544907..05d098e4f 100644 --- a/ts/components/session/icon/Icons.tsx +++ b/ts/components/session/icon/Icons.tsx @@ -26,6 +26,7 @@ export enum SessionIconType { Star = 'star', QR = 'qr', Users = 'users', + Upload = 'upload', Warning = 'warning', } @@ -171,6 +172,11 @@ export const icons = { 'M9.38,2.17c-1.73,0-3.12,1.4-3.12,3.12s1.4,3.12,3.12,3.12s3.12-1.4,3.12-3.12S11.1,2.17,9.38,2.17z M16.93,0.25c2.3,0.59,3.92,2.67,3.92,5.05s-1.61,4.46-3.92,5.05c-0.56,0.14-1.12-0.19-1.27-0.75c-0.14-0.56,0.19-1.12,0.75-1.27 c1.38-0.35,2.35-1.6,2.35-3.03s-0.97-2.67-2.35-3.03c-0.56-0.14-0.9-0.71-0.75-1.27C15.8,0.44,16.37,0.11,16.93,0.25z M9.38,0.08 c2.88,0,5.21,2.33,5.21,5.21s-2.33,5.21-5.21,5.21S4.17,8.17,4.17,5.29C4.17,2.42,6.5,0.08,9.38,0.08z M21.09,12.75 c2.22,0.57,3.8,2.53,3.9,4.81L25,17.79v2.08c0,0.58-0.47,1.04-1.04,1.04c-0.54,0-0.98-0.41-1.04-0.93l-0.01-0.11v-2.08 c0-1.42-0.96-2.67-2.34-3.02c-0.56-0.14-0.89-0.71-0.75-1.27C19.97,12.94,20.54,12.61,21.09,12.75z M13.54,12.58 c2.8,0,5.09,2.21,5.2,4.99v0.22v2.08c0,0.58-0.47,1.04-1.04,1.04c-0.54,0-0.98-0.41-1.04-0.93l-0.01-0.11v-2.08 c0-1.67-1.3-3.03-2.95-3.12h-0.18H5.21c-1.67,0-3.03,1.3-3.12,2.95v0.18v2.08c0,0.58-0.47,1.04-1.04,1.04 c-0.54,0-0.98-0.41-1.04-0.93L0,19.88V17.8c0-2.8,2.21-5.09,4.99-5.2h0.22h8.33V12.58z', viewBox: '0 0 25 21', }, + [SessionIconType.Upload]: { + path: + 'M380.032,133.472l-112-128C264.992,2.016,260.608,0,256,0c-4.608,0-8.992,2.016-12.032,5.472l-112,128 c-4.128,4.736-5.152,11.424-2.528,17.152C132.032,156.32,137.728,160,144,160h64v208c0,8.832,7.168,16,16,16h64 c8.832,0,16-7.168,16-16V160h64c6.272,0,11.968-3.648,14.56-9.376C385.152,144.896,384.192,138.176,380.032,133.472z M432,352v96H80v-96H16v128c0,17.696,14.336,32,32,32h416c17.696,0,32-14.304,32-32V352H432z', + viewBox: '0 0 512 512', + }, [SessionIconType.Warning]: { path: 'M243.225,333.382c-13.6,0-25,11.4-25,25s11.4,25,25,25c13.1,0,25-11.4,24.4-24.4 C268.225,344.682,256.925,333.382,243.225,333.382z M474.625,421.982c15.7-27.1,15.8-59.4,0.2-86.4l-156.6-271.2c-15.5-27.3-43.5-43.5-74.9-43.5s-59.4,16.3-74.9,43.4 l-156.8,271.5c-15.6,27.3-15.5,59.8,0.3,86.9c15.6,26.8,43.5,42.9,74.7,42.9h312.8 C430.725,465.582,458.825,449.282,474.625,421.982z M440.625,402.382c-8.7,15-24.1,23.9-41.3,23.9h-312.8 c-17,0-32.3-8.7-40.8-23.4c-8.6-14.9-8.7-32.7-0.1-47.7l156.8-271.4c8.5-14.9,23.7-23.7,40.9-23.7c17.1,0,32.4,8.9,40.9,23.8 l156.7,271.4C449.325,369.882,449.225,387.482,440.625,402.382z M237.025,157.882c-11.9,3.4-19.3,14.2-19.3,27.3c0.6,7.9,1.1,15.9,1.7,23.8c1.7,30.1,3.4,59.6,5.1,89.7 c0.6,10.2,8.5,17.6,18.7,17.6c10.2,0,18.2-7.9,18.7-18.2c0-6.2,0-11.9,0.6-18.2c1.1-19.3,2.3-38.6,3.4-57.9 c0.6-12.5,1.7-25,2.3-37.5c0-4.5-0.6-8.5-2.3-12.5C260.825,160.782,248.925,155.082,237.025,157.882z',