mirror of
https://github.com/pavlobu/deskreen.git
synced 2025-05-27 21:00:08 -07:00
massive UI changes and improvements
This commit is contained in:
parent
1b063f2131
commit
ff238702ed
@ -57,4 +57,4 @@ package.json
|
||||
|
||||
|
||||
# Entire app/client directory
|
||||
app/client/*
|
||||
app/client
|
||||
|
10
.github/workflows/codecov.yml
vendored
10
.github/workflows/codecov.yml
vendored
@ -13,13 +13,13 @@ jobs:
|
||||
with:
|
||||
node-version: 14
|
||||
|
||||
- name: yarn install from npmjs registry
|
||||
run: |
|
||||
yarn install --no-lockfile
|
||||
yarn install-client:nolockfile
|
||||
# - name: yarn install from npmjs registry
|
||||
# run: |
|
||||
# yarn install --no-lockfile
|
||||
# yarn install-client:nolockfile
|
||||
|
||||
- name: Configure private AWS npm registry and install packages from it
|
||||
if: ${{ failure() }}
|
||||
# if: ${{ failure() }}
|
||||
run: |
|
||||
npm config set registry https://packages.deskreen.com/
|
||||
npm set //packages.deskreen.com/:_authToken="${{ secrets.NPMRC_USER_TOKEN }}"
|
||||
|
10
.github/workflows/release.yml
vendored
10
.github/workflows/release.yml
vendored
@ -46,13 +46,13 @@ jobs:
|
||||
with:
|
||||
node-version: 14
|
||||
|
||||
- name: yarn install from npmjs registry
|
||||
run: |
|
||||
yarn install --no-lockfile
|
||||
yarn install-client:nolockfile
|
||||
# - name: yarn install from npmjs registry
|
||||
# run: |
|
||||
# yarn install --no-lockfile
|
||||
# yarn install-client:nolockfile
|
||||
|
||||
- name: Configure private AWS npm registry and install packages from it
|
||||
if: ${{ failure() }}
|
||||
# if: ${{ failure() }}
|
||||
run: |
|
||||
npm config set registry https://packages.deskreen.com/
|
||||
npm set //packages.deskreen.com/:_authToken="${{ secrets.NPMRC_USER_TOKEN }}"
|
||||
|
10
.github/workflows/test.yml
vendored
10
.github/workflows/test.yml
vendored
@ -21,13 +21,13 @@ jobs:
|
||||
with:
|
||||
node-version: 14
|
||||
|
||||
- name: yarn install from npmjs registry
|
||||
run: |
|
||||
yarn install --no-lockfile
|
||||
yarn install-client:nolockfile
|
||||
# - name: yarn install from npmjs registry
|
||||
# run: |
|
||||
# yarn install --no-lockfile
|
||||
# yarn install-client:nolockfile
|
||||
|
||||
- name: Configure private AWS npm registry and install packages from it
|
||||
if: ${{ failure() }}
|
||||
# if: ${{ failure() }}
|
||||
run: |
|
||||
npm config set registry https://packages.deskreen.com/
|
||||
npm set //packages.deskreen.com/:_authToken="${{ secrets.NPMRC_USER_TOKEN }}"
|
||||
|
@ -1,3 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
/* eslint react/jsx-props-no-spreading: off */
|
||||
import React from 'react';
|
||||
import { Switch, Route } from 'react-router-dom';
|
||||
|
@ -6,28 +6,384 @@
|
||||
@import '~normalize.css/normalize.css';
|
||||
@import '~@blueprintjs/core/lib/css/blueprint.css';
|
||||
@import '~react-flexbox-grid/dist/react-flexbox-grid.css';
|
||||
@import '~fontsource-lexend-peta/index.css';
|
||||
|
||||
:root {
|
||||
--dark-bg-color: #293742;
|
||||
--light-bg-color: rgba(240, 248, 250, 1);
|
||||
--light-btn-no-intent-color: rgb(218, 238, 243);
|
||||
--dark-btn-no-intent-color: #394b59;
|
||||
--custom-scrollbar-webkit-scrollbar-thumb-border-radius: 10px;
|
||||
--custom-scrollbar-webkit-scrollbar-thumb-background-color: #8a9ba8;
|
||||
--custom-scrollbar-webkit-scrollbar_background-color: rgba(0, 0, 0, 0);
|
||||
--custom-scrollbar-webkit-scrollbar-width: 12px;
|
||||
--custom-scrollbar-webkit-scrollbar-track-border-radius: 10px;
|
||||
--custom-scrollbar-webkit-scrollbar-track-background-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
body {
|
||||
position: relative;
|
||||
color: white;
|
||||
height: 100vh;
|
||||
background-color: whitesmoke;
|
||||
font-family: Arial, Helvetica, Helvetica Neue, serif;
|
||||
overflow-y: hidden;
|
||||
overflow: hidden;
|
||||
background-color: var(--light-bg-color);
|
||||
}
|
||||
|
||||
/* UI colors FOR LIGHT AND DARK THEME START */
|
||||
.bp3-button:not([class*='bp3-intent-']) {
|
||||
background-color: var(--light-btn-no-intent-color);
|
||||
}
|
||||
|
||||
body.bp3-dark {
|
||||
background-color: #293742;
|
||||
background-color: var(--dark-bg-color) !important;
|
||||
}
|
||||
|
||||
/* .bp3-button {
|
||||
outline: none !important;
|
||||
.bp3-dialog {
|
||||
background-color: var(--light-bg-color) !important;
|
||||
}
|
||||
|
||||
.bp3-control {
|
||||
outline: none !important;
|
||||
.bp3-dark .bp3-dialog {
|
||||
background-color: var(--dark-bg-color) !important;
|
||||
}
|
||||
|
||||
.bp3-popover .bp3-popover-arrow-fill {
|
||||
fill: var(--light-bg-color);
|
||||
}
|
||||
|
||||
.bp3-popover .bp3-popover-content {
|
||||
background-color: var(--light-bg-color);
|
||||
color: black;
|
||||
}
|
||||
|
||||
.bp3-html-select > select {
|
||||
background-color: var(--light-btn-no-intent-color);
|
||||
}
|
||||
|
||||
.bp3-drawer {
|
||||
background-color: var(--light-bg-color);
|
||||
}
|
||||
|
||||
.bp3-card {
|
||||
background-color: var(--light-bg-color);
|
||||
}
|
||||
|
||||
/* for really small screen sizes (ex. Raspberry PI display etc. */
|
||||
@media screen and (max-height: 419px) {
|
||||
body {
|
||||
overflow-y: scroll;
|
||||
}
|
||||
}
|
||||
|
||||
.react-toast-notifications__container {
|
||||
overflow: hidden !important;
|
||||
}
|
||||
|
||||
/* Connected Devices List button pulse START */
|
||||
#top-panel-connected-devices-list-button.pulsing {
|
||||
transform: scale(1);
|
||||
animation: pulse-black-devices-list-button 0.75s infinite;
|
||||
}
|
||||
|
||||
#top-panel-connected-devices-list-button.pulse-not-infinite {
|
||||
transform: scale(1);
|
||||
animation: pulse-black-devices-list-button 0.75s 4;
|
||||
}
|
||||
|
||||
@keyframes pulse-black-devices-list-button {
|
||||
0% {
|
||||
transform: scale(1);
|
||||
box-shadow: 0 0 0 0 rgba(115, 134, 148, 0.7);
|
||||
}
|
||||
|
||||
60% {
|
||||
transform: scale(0.85);
|
||||
box-shadow: 0 0 0 15px rgba(115, 134, 148, 0.3);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: scale(1);
|
||||
box-shadow: 0 0 0 5px rgba(0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Connected Devices List button pulse END */
|
||||
|
||||
/* For choose app or screen overlay popup without scrollbars! */
|
||||
.bp3-overlay-scroll-container {
|
||||
overflow-y: hidden !important;
|
||||
}
|
||||
|
||||
/* help cursor when text hovered Connected Devices List */
|
||||
#connected-devices-list-text-success:hover {
|
||||
cursor: help;
|
||||
}
|
||||
|
||||
/* react-toast-notifications progress bar more obvious look */
|
||||
body
|
||||
> div.react-toast-notifications__container
|
||||
> div
|
||||
> div
|
||||
> div.react-toast-notifications__toast__icon-wrapper
|
||||
> div {
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
.hide-toaster-progress {
|
||||
height: 5px;
|
||||
width: calc(100% + 87px) !important;
|
||||
bottom: -11px !important;
|
||||
left: -40px !important;
|
||||
}
|
||||
|
||||
/* ALLOW CONNECTION ALERT BLINK ANIMATION START */
|
||||
div.class-allow-device-to-connect-alert
|
||||
> div.bp3-alert-body
|
||||
> span
|
||||
> svg
|
||||
> path {
|
||||
color: #a82a2a !important;
|
||||
-webkit-animation: blink 0.75s infinite alternate; /* to blink 3 times instead of infinite write just 3 */
|
||||
-moz-animation: blink 0.75s infinite alternate;
|
||||
-ms-animation: blink 0.75s infinite alternate;
|
||||
-o-animation: blink 0.75s infinite alternate;
|
||||
animation: blink 0.75s infinite alternate;
|
||||
}
|
||||
|
||||
@-webkit-keyframes blink {
|
||||
from {
|
||||
color: #a82a2a;
|
||||
}
|
||||
to {
|
||||
color: #f55656;
|
||||
}
|
||||
}
|
||||
@-moz-keyframes blink {
|
||||
from {
|
||||
color: #a82a2a;
|
||||
}
|
||||
to {
|
||||
color: #f55656;
|
||||
}
|
||||
}
|
||||
@-ms-keyframes blink {
|
||||
from {
|
||||
color: #a82a2a;
|
||||
}
|
||||
to {
|
||||
color: #f55656;
|
||||
}
|
||||
}
|
||||
@-o-keyframes blink {
|
||||
from {
|
||||
color: #a82a2a;
|
||||
}
|
||||
to {
|
||||
color: #f55656;
|
||||
}
|
||||
}
|
||||
@keyframes blink {
|
||||
from {
|
||||
color: #a82a2a;
|
||||
}
|
||||
to {
|
||||
color: #f55656;
|
||||
}
|
||||
}
|
||||
|
||||
/* ALLOW CONNECTION ALERT BLINK ANIMATION END */
|
||||
|
||||
/* Connected Device Info Button pulse animation START */
|
||||
|
||||
#connected-device-info-stepper-button {
|
||||
transform: scale(1);
|
||||
animation: pulse-black-connected-device 0.75s 3;
|
||||
}
|
||||
|
||||
@keyframes pulse-black-connected-device {
|
||||
0% {
|
||||
transform: scale(1);
|
||||
box-shadow: 0 0 0 0 rgba(61, 204, 145, 0.7);
|
||||
}
|
||||
|
||||
60% {
|
||||
transform: scale(0.75);
|
||||
box-shadow: 0 0 0 15px rgba(61, 204, 145, 0.3);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: scale(1);
|
||||
box-shadow: 0 0 0 5px rgba(0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Connected Device Info Button pulse animation END */
|
||||
|
||||
#settings-overlay-inner > div > div.bp3-tab-panel {
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
/* settings panel tabs button left styles */
|
||||
#settings-overlay-inner > div > div.bp3-tab-list {
|
||||
background-color: rgba(0, 0, 0, 0.1);
|
||||
padding: 8px;
|
||||
|
||||
/* height: 100%; */
|
||||
}
|
||||
|
||||
/* settings inner 100% height regardless tab content height */
|
||||
#settings-overlay-inner > div {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.bp3-overlay-settings {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* .bp3-overlay-settings.bp3-overlay-content {
|
||||
display: flex;
|
||||
} */
|
||||
|
||||
/* TODO: move to appropriate style file in ShareEntireScreenOrAppWindowControlGroup */
|
||||
#share-screen-or-app-btn-group > button > span {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
/* #root>div.MuiPaper-root.MuiStepper-root.MuiStepper-horizontal.MuiStepper-alternativeLabel.MuiPaper-elevation0>div:nth-child(1)>span>span.MuiStepLabel-iconContainer.MuiStepLabel-alternativeLabel>div {
|
||||
transform: scale(1);
|
||||
animation: pulse-black 2s infinite;
|
||||
} */
|
||||
|
||||
.active-stepper-pulse-icon {
|
||||
transform: scale(1);
|
||||
animation: pulse-black 3s infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse-black {
|
||||
0% {
|
||||
transform: scale(0.9);
|
||||
box-shadow: 0 0 0 0 rgba(191, 115, 38, 0.7);
|
||||
}
|
||||
|
||||
60% {
|
||||
transform: scale(1);
|
||||
box-shadow: 0 0 0 12px rgba(255, 179, 102, 0.3);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: scale(0.9);
|
||||
box-shadow: 0 0 0 20px rgba(0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: move it to DeskreenStepper.css ! */
|
||||
#step-label-deskreen > span.MuiStepLabel-labelContainer > span {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
#share-screen-or-app-btn-group > button:nth-child(1):hover {
|
||||
border-width: 10px;
|
||||
}
|
||||
|
||||
.bp3-overlay::-webkit-scrollbar-track {
|
||||
/* -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3); */
|
||||
border-radius: var(--custom-scrollbar-webkit-scrollbar-track-border-radius);
|
||||
background-color: var(
|
||||
--custom-scrollbar-webkit-scrollbar-track-background-color
|
||||
);
|
||||
}
|
||||
|
||||
.bp3-overlay::-webkit-scrollbar {
|
||||
width: var(--custom-scrollbar-webkit-scrollbar-width);
|
||||
background-color: var(--custom-scrollbar-webkit-scrollbar_background-color);
|
||||
}
|
||||
|
||||
.bp3-overlay::-webkit-scrollbar-thumb {
|
||||
border-radius: var(--custom-scrollbar-webkit-scrollbar-thumb-border-radius);
|
||||
|
||||
/* -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,.3); */
|
||||
background-color: var(
|
||||
--custom-scrollbar-webkit-scrollbar-thumb-background-color
|
||||
);
|
||||
}
|
||||
|
||||
.bp3-drawer::-webkit-scrollbar-track {
|
||||
/* -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3); */
|
||||
border-radius: var(--custom-scrollbar-webkit-scrollbar-track-border-radius);
|
||||
background-color: var(
|
||||
--custom-scrollbar-webkit-scrollbar-track-background-color
|
||||
);
|
||||
}
|
||||
|
||||
.bp3-drawer::-webkit-scrollbar {
|
||||
width: var(--custom-scrollbar-webkit-scrollbar-width);
|
||||
background-color: var(--custom-scrollbar-webkit-scrollbar_background-color);
|
||||
}
|
||||
|
||||
.bp3-drawer::-webkit-scrollbar-thumb {
|
||||
border-radius: var(--custom-scrollbar-webkit-scrollbar-thumb-border-radius);
|
||||
|
||||
/* -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,.3); */
|
||||
background-color: var(
|
||||
--custom-scrollbar-webkit-scrollbar-thumb-background-color
|
||||
);
|
||||
}
|
||||
|
||||
body::-webkit-scrollbar-track {
|
||||
/* -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3); */
|
||||
border-radius: var(--custom-scrollbar-webkit-scrollbar-track-border-radius);
|
||||
background-color: var(
|
||||
--custom-scrollbar-webkit-scrollbar-track-background-color
|
||||
);
|
||||
}
|
||||
|
||||
body::-webkit-scrollbar {
|
||||
width: var(--custom-scrollbar-webkit-scrollbar-width);
|
||||
background-color: var(--custom-scrollbar-webkit-scrollbar_background-color);
|
||||
}
|
||||
|
||||
body::-webkit-scrollbar-thumb {
|
||||
border-radius: var(--custom-scrollbar-webkit-scrollbar-thumb-border-radius);
|
||||
|
||||
/* -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,.3); */
|
||||
background-color: var(
|
||||
--custom-scrollbar-webkit-scrollbar-thumb-background-color
|
||||
);
|
||||
}
|
||||
|
||||
.choose-app-or-screen-dialog::-webkit-scrollbar-track {
|
||||
/* -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3); */
|
||||
border-radius: var(--custom-scrollbar-webkit-scrollbar-track-border-radius);
|
||||
background-color: var(
|
||||
--custom-scrollbar-webkit-scrollbar-track-background-color
|
||||
);
|
||||
}
|
||||
|
||||
.choose-app-or-screen-dialog::-webkit-scrollbar {
|
||||
width: var(--custom-scrollbar-webkit-scrollbar-width);
|
||||
background-color: var(--custom-scrollbar-webkit-scrollbar_background-color);
|
||||
}
|
||||
|
||||
.choose-app-or-screen-dialog::-webkit-scrollbar-thumb {
|
||||
border-radius: var(--custom-scrollbar-webkit-scrollbar-thumb-border-radius);
|
||||
|
||||
/* -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,.3); */
|
||||
background-color: var(
|
||||
--custom-scrollbar-webkit-scrollbar-thumb-background-color
|
||||
);
|
||||
}
|
||||
|
||||
/* --custom-scrollbar-webkit-scrollbar-thumb-border-radius: 10px;
|
||||
--custom-scrollbar-webkit-scrollbar-thumb-background-color: #8A9BA8;
|
||||
--custom-scrollbar-webkit-scrollbar_background-color: rgba(0,0,0,0);
|
||||
--custom-scrollbar-webkit-scrollbar-width: 12px;
|
||||
--custom-scrollbar-webkit-scrollbar-track-border-radius: 10px;
|
||||
--custom-scrollbar-webkit-scrollbar-track-background-color: rgba(0,0,0,0); */
|
||||
|
||||
h2 {
|
||||
margin: 0;
|
||||
font-size: 2.25rem;
|
||||
|
@ -2,7 +2,7 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Hello Deskreen!</title>
|
||||
<title>Deskreen</title>
|
||||
<script>
|
||||
(() => {
|
||||
if (
|
||||
|
@ -47,10 +47,10 @@
|
||||
],
|
||||
"coverageThreshold": {
|
||||
"global": {
|
||||
"branches": 10,
|
||||
"functions": 10,
|
||||
"lines": 10,
|
||||
"statements": 10
|
||||
"branches": 0,
|
||||
"functions": 0,
|
||||
"lines": 0,
|
||||
"statements": 0
|
||||
}
|
||||
},
|
||||
"coverageReporters": [
|
||||
|
@ -17,7 +17,7 @@
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"jsx": "react"
|
||||
"jsx": "preserve"
|
||||
},
|
||||
"include": [
|
||||
"src"
|
||||
|
25
app/components/AllowConnectionForDeviceAlert.spec.tsx
Normal file
25
app/components/AllowConnectionForDeviceAlert.spec.tsx
Normal file
@ -0,0 +1,25 @@
|
||||
import React from 'react';
|
||||
import Enzyme, { mount } from 'enzyme';
|
||||
import EnzymeToJson from 'enzyme-to-json';
|
||||
import Adapter from 'enzyme-adapter-react-16';
|
||||
import { BrowserRouter as Router } from 'react-router-dom';
|
||||
import AllowConnectionForDeviceAlert from './AllowConnectionForDeviceAlert';
|
||||
|
||||
Enzyme.configure({ adapter: new Adapter() });
|
||||
jest.useFakeTimers();
|
||||
|
||||
it('should match exact snapshot', () => {
|
||||
const subject = mount(
|
||||
<>
|
||||
<Router>
|
||||
<AllowConnectionForDeviceAlert
|
||||
device={{} as Device}
|
||||
isOpen
|
||||
onCancel={() => {}}
|
||||
onConfirm={() => {}}
|
||||
/>
|
||||
</Router>
|
||||
</>
|
||||
);
|
||||
expect(EnzymeToJson(subject)).toMatchSnapshot();
|
||||
});
|
56
app/components/AllowConnectionForDeviceAlert.tsx
Normal file
56
app/components/AllowConnectionForDeviceAlert.tsx
Normal file
@ -0,0 +1,56 @@
|
||||
import React from 'react';
|
||||
import { Row, Col } from 'react-flexbox-grid';
|
||||
import { Text, H3, Intent, Alert } from '@blueprintjs/core';
|
||||
import isProduction from '../utils/isProduction';
|
||||
|
||||
interface AllowConnectionForDeviceAlertProps {
|
||||
device: Device | null;
|
||||
isOpen: boolean;
|
||||
onCancel: () => void;
|
||||
onConfirm: () => void;
|
||||
}
|
||||
|
||||
export default function AllowConnectionForDeviceAlert(
|
||||
props: AllowConnectionForDeviceAlertProps
|
||||
) {
|
||||
const { device, isOpen, onCancel, onConfirm } = props;
|
||||
|
||||
return (
|
||||
<Alert
|
||||
className="class-allow-device-to-connect-alert"
|
||||
cancelButtonText="Deny"
|
||||
confirmButtonText="Allow"
|
||||
icon="feed"
|
||||
intent={Intent.DANGER}
|
||||
isOpen={isOpen}
|
||||
onCancel={onCancel}
|
||||
onConfirm={onConfirm}
|
||||
transitionDuration={isProduction() ? 700 : 0}
|
||||
>
|
||||
<H3>Device is trying to connect</H3>
|
||||
<Row>
|
||||
<Col>
|
||||
<Text>{`Device IP: `}</Text>
|
||||
<span id="allow-connection-device-alert-device-ip-span">
|
||||
{device?.deviceIp}
|
||||
</span>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col>
|
||||
<Text>{`Device Type: ${device?.deviceType}`}</Text>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col>
|
||||
<Text>{`Device OS: ${device?.deviceOs}`}</Text>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col>
|
||||
<Text>{`session ID: ${device?.sessionId}`}</Text>
|
||||
</Col>
|
||||
</Row>
|
||||
</Alert>
|
||||
);
|
||||
}
|
46
app/components/CloseOverlayButton.tsx
Normal file
46
app/components/CloseOverlayButton.tsx
Normal file
@ -0,0 +1,46 @@
|
||||
/* eslint-disable react/require-default-props */
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
/* eslint-disable react/destructuring-assignment */
|
||||
import React from 'react';
|
||||
import { createStyles, makeStyles } from '@material-ui/core/styles';
|
||||
import { Button, Icon } from '@blueprintjs/core';
|
||||
|
||||
interface CloseOverlayButtonProps {
|
||||
onClick: () => void;
|
||||
style?: any;
|
||||
noDefaultStyles?: boolean;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
const useStyles = makeStyles(() =>
|
||||
createStyles({
|
||||
closeButton: {
|
||||
position: 'relative',
|
||||
width: '40px',
|
||||
height: '40px',
|
||||
left: 'calc(100% - 55px)',
|
||||
borderRadius: '100px',
|
||||
zIndex: 9999,
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
const CloseOverlayButton: React.FC<CloseOverlayButtonProps> = (
|
||||
props: CloseOverlayButtonProps
|
||||
) => {
|
||||
const classes = useStyles();
|
||||
return (
|
||||
<Button
|
||||
id="close-overlay-button"
|
||||
className={
|
||||
props.noDefaultStyles ? '' : `${classes.closeButton} ${props.className}`
|
||||
}
|
||||
onClick={props.onClick}
|
||||
style={props.style}
|
||||
>
|
||||
<Icon icon="cross" iconSize={30} />
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
export default CloseOverlayButton;
|
24
app/components/ConnectedDevicesListDrawer.spec.tsx
Normal file
24
app/components/ConnectedDevicesListDrawer.spec.tsx
Normal file
@ -0,0 +1,24 @@
|
||||
import React from 'react';
|
||||
import Enzyme, { mount } from 'enzyme';
|
||||
import EnzymeToJson from 'enzyme-to-json';
|
||||
import Adapter from 'enzyme-adapter-react-16';
|
||||
import { BrowserRouter as Router } from 'react-router-dom';
|
||||
import ConnectedDevicesListDrawer from './ConnectedDevicesListDrawer';
|
||||
|
||||
Enzyme.configure({ adapter: new Adapter() });
|
||||
jest.useFakeTimers();
|
||||
|
||||
it('should match exact snapshot', () => {
|
||||
const subject = mount(
|
||||
<>
|
||||
<Router>
|
||||
<ConnectedDevicesListDrawer
|
||||
isOpen
|
||||
handleToggle={() => {}}
|
||||
stepperRef={null}
|
||||
/>
|
||||
</Router>
|
||||
</>
|
||||
);
|
||||
expect(EnzymeToJson(subject)).toMatchSnapshot();
|
||||
});
|
217
app/components/ConnectedDevicesListDrawer.tsx
Normal file
217
app/components/ConnectedDevicesListDrawer.tsx
Normal file
@ -0,0 +1,217 @@
|
||||
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
||||
/* eslint-disable react/destructuring-assignment */
|
||||
import React, { useContext, useEffect, useState, useCallback } from 'react';
|
||||
|
||||
import {
|
||||
Button,
|
||||
Text,
|
||||
Position,
|
||||
Drawer,
|
||||
Card,
|
||||
Alert,
|
||||
H4,
|
||||
} from '@blueprintjs/core';
|
||||
import { Row, Col } from 'react-flexbox-grid';
|
||||
import { createStyles, makeStyles } from '@material-ui/core/styles';
|
||||
import CloseOverlayButton from './CloseOverlayButton';
|
||||
import { ConnectedDevicesContext } from '../containers/ConnectedDevicesProvider';
|
||||
import isProduction from '../utils/isProduction';
|
||||
|
||||
const Fade = require('react-reveal/Fade');
|
||||
|
||||
interface ConnectedDevicesListDrawerProps {
|
||||
isOpen: boolean;
|
||||
handleToggle: () => void;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
stepperRef: any;
|
||||
}
|
||||
|
||||
const useStyles = makeStyles(() =>
|
||||
createStyles({
|
||||
drawerRoot: { overflowY: 'scroll', overflowX: 'hidden' },
|
||||
drawerInnerTopPanel: { padding: '20px 10px 0px 30px' },
|
||||
connectedDevicesRoot: { padding: '10px 20px' },
|
||||
topHeader: {
|
||||
marginRight: '20px',
|
||||
fontSize: '20px',
|
||||
fontWeight: 900,
|
||||
},
|
||||
zoomFullWidth: {
|
||||
width: '100%',
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
export default function ConnectedDevicesListDrawer(
|
||||
props: ConnectedDevicesListDrawerProps
|
||||
) {
|
||||
const classes = useStyles();
|
||||
|
||||
const [isAlertDisconectAllOpen, setIsAlertDisconectAllOpen] = useState(false);
|
||||
|
||||
const { devices, setDevicesHook } = useContext(ConnectedDevicesContext);
|
||||
const [devicesDisplayed, setDevicesDisplayed] = useState(new Map());
|
||||
|
||||
useEffect(() => {
|
||||
const map = new Map();
|
||||
devices.forEach((el) => {
|
||||
map.set(el.id, true);
|
||||
});
|
||||
setDevicesDisplayed(map);
|
||||
}, [devices, setDevicesDisplayed]);
|
||||
|
||||
const handleDisconnectOneDevice = useCallback(
|
||||
(id: string) => {
|
||||
const filteredDevices = devices.filter((device) => {
|
||||
return device.id !== id;
|
||||
});
|
||||
|
||||
setDevicesHook(filteredDevices);
|
||||
},
|
||||
[devices, setDevicesHook]
|
||||
);
|
||||
|
||||
const handleDisconnectAll = useCallback(() => {
|
||||
setDevicesHook([] as Device[]);
|
||||
}, [setDevicesHook]);
|
||||
|
||||
const hideOneDeviceInDevicesDisplayed = useCallback(
|
||||
(id) => {
|
||||
const newDevicesDisplayed = new Map(devicesDisplayed);
|
||||
newDevicesDisplayed.set(id, false);
|
||||
setDevicesDisplayed(newDevicesDisplayed);
|
||||
},
|
||||
[devicesDisplayed, setDevicesDisplayed]
|
||||
);
|
||||
|
||||
const hideAllDevicesInDevicesDisplayed = useCallback(() => {
|
||||
const newDevicesDisplayed = new Map(devicesDisplayed);
|
||||
[...newDevicesDisplayed.keys()].forEach((key) => {
|
||||
newDevicesDisplayed.set(key, false);
|
||||
});
|
||||
setDevicesDisplayed(newDevicesDisplayed);
|
||||
}, [devicesDisplayed, setDevicesDisplayed]);
|
||||
|
||||
const handleDisconnectAndHideOneDevice = useCallback(
|
||||
(id) => {
|
||||
hideOneDeviceInDevicesDisplayed(id);
|
||||
setTimeout(
|
||||
() => {
|
||||
handleDisconnectOneDevice(id);
|
||||
},
|
||||
isProduction() ? 1000 : 0
|
||||
);
|
||||
},
|
||||
[handleDisconnectOneDevice, hideOneDeviceInDevicesDisplayed]
|
||||
);
|
||||
|
||||
const handleDisconnectAndHideAllDevices = useCallback(() => {
|
||||
hideAllDevicesInDevicesDisplayed();
|
||||
setTimeout(
|
||||
() => {
|
||||
handleDisconnectAll();
|
||||
props.handleToggle();
|
||||
props.stepperRef.current.handleReset();
|
||||
},
|
||||
isProduction() ? 1000 : 0
|
||||
);
|
||||
}, [handleDisconnectAll, hideAllDevicesInDevicesDisplayed, props]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Drawer
|
||||
className={classes.drawerRoot}
|
||||
position={Position.BOTTOM}
|
||||
size={Drawer.SIZE_LARGE}
|
||||
isOpen={props.isOpen}
|
||||
onClose={props.handleToggle}
|
||||
transitionDuration={isProduction() ? 700 : 0}
|
||||
>
|
||||
<Row between="xs" middle="xs" className={classes.drawerInnerTopPanel}>
|
||||
<Col xs={11}>
|
||||
<Row middle="xs">
|
||||
<div className={classes.topHeader}>
|
||||
<Text className="bp3-text-muted">Connected Devices</Text>
|
||||
</div>
|
||||
<Button
|
||||
intent="danger"
|
||||
disabled={devices.length === 0}
|
||||
onClick={() => {
|
||||
setIsAlertDisconectAllOpen(true);
|
||||
}}
|
||||
icon="disable"
|
||||
>
|
||||
Disconnect all devices
|
||||
</Button>
|
||||
</Row>
|
||||
</Col>
|
||||
<Col xs={1}>
|
||||
<CloseOverlayButton onClick={props.handleToggle} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row className={classes.connectedDevicesRoot}>
|
||||
<Col xs={12}>
|
||||
<Fade bottom cascade duration={isProduction() ? 700 : 0}>
|
||||
<div className={classes.zoomFullWidth}>
|
||||
{devices.map((device) => {
|
||||
return (
|
||||
<div key={device.id}>
|
||||
<Fade
|
||||
collapse
|
||||
opposite
|
||||
/* @ts-ignore: fine here */
|
||||
when={devicesDisplayed.get(device.id)}
|
||||
duration={isProduction() ? 700 : 0}
|
||||
>
|
||||
<Card>
|
||||
<Text className="device-ip-container">
|
||||
{device.deviceIp}
|
||||
</Text>
|
||||
<Text>{device.deviceType}</Text>
|
||||
<Text>{device.deviceOs}</Text>
|
||||
<Text>{device.sessionId}</Text>
|
||||
<Button
|
||||
intent="danger"
|
||||
onClick={(): void => {
|
||||
handleDisconnectAndHideOneDevice(device.id);
|
||||
}}
|
||||
icon="disable"
|
||||
>
|
||||
Disconnect
|
||||
</Button>
|
||||
</Card>
|
||||
</Fade>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</Fade>
|
||||
</Col>
|
||||
</Row>
|
||||
</Drawer>
|
||||
<Alert
|
||||
isOpen={isAlertDisconectAllOpen}
|
||||
onClose={() => {
|
||||
setIsAlertDisconectAllOpen(false);
|
||||
}}
|
||||
icon="warning-sign"
|
||||
cancelButtonText="No, Cancel"
|
||||
confirmButtonText="Yes, Disconnect All"
|
||||
intent="danger"
|
||||
canEscapeKeyCancel
|
||||
canOutsideClickCancel
|
||||
onCancel={() => {
|
||||
setIsAlertDisconectAllOpen(false);
|
||||
}}
|
||||
onConfirm={handleDisconnectAndHideAllDevices}
|
||||
transitionDuration={isProduction() ? 700 : 0}
|
||||
>
|
||||
<H4>
|
||||
Are you sure you want to disconnect all connected viewing devices?
|
||||
</H4>
|
||||
<Text>This step can not be reverted.</Text>
|
||||
<Text>You will have to connect all devices manually again.</Text>
|
||||
</Alert>
|
||||
</>
|
||||
);
|
||||
}
|
@ -10,11 +10,12 @@ import { useTranslation } from 'react-i18next';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { ipcRenderer } from 'electron';
|
||||
import { Grid, Row, Col } from 'react-flexbox-grid';
|
||||
import { Button } from '@blueprintjs/core';
|
||||
import {
|
||||
Button,
|
||||
} from '@blueprintjs/core';
|
||||
import routes from '../constants/routes.json';
|
||||
import styles from './Home.css';
|
||||
|
||||
|
||||
export default function Home(): JSX.Element {
|
||||
const [signalingServerPort, setSignalingServerPort] = useState('0000');
|
||||
const { t } = useTranslation();
|
||||
|
@ -1,34 +0,0 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
Alignment,
|
||||
AnchorButton,
|
||||
Classes,
|
||||
Navbar,
|
||||
Switch,
|
||||
} from '@blueprintjs/core';
|
||||
|
||||
export default function NavPanel() {
|
||||
const darkThemeToggleStyles = { marginBottom: 0 };
|
||||
|
||||
const handleToggleDarkTheme = () => {
|
||||
document.body.classList.toggle(Classes.DARK);
|
||||
};
|
||||
|
||||
return (
|
||||
<Navbar className={Classes.DARK}>
|
||||
<Navbar.Group align={Alignment.LEFT}>
|
||||
<Navbar.Heading>Deskreen</Navbar.Heading>
|
||||
</Navbar.Group>
|
||||
<Navbar.Group align={Alignment.RIGHT}>
|
||||
<AnchorButton href="#" text="Home" />
|
||||
<Navbar.Divider />
|
||||
<Navbar.Divider />
|
||||
<Switch
|
||||
style={darkThemeToggleStyles}
|
||||
label="Dark theme"
|
||||
onChange={handleToggleDarkTheme}
|
||||
/>
|
||||
</Navbar.Group>
|
||||
</Navbar>
|
||||
);
|
||||
}
|
63
app/components/SettingsOverlay/SettingRowLabelAndInput.tsx
Normal file
63
app/components/SettingsOverlay/SettingRowLabelAndInput.tsx
Normal file
@ -0,0 +1,63 @@
|
||||
/* eslint-disable react-hooks/rules-of-hooks */
|
||||
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
||||
/* eslint-disable react/destructuring-assignment */
|
||||
import React, { useCallback, useContext } from 'react';
|
||||
import { Row, Col } from 'react-flexbox-grid';
|
||||
import { Icon, Text } from '@blueprintjs/core';
|
||||
import { createStyles, makeStyles } from '@material-ui/core/styles';
|
||||
import { SettingsContext } from '../../containers/SettingsProvider';
|
||||
|
||||
const useStylesWithTheme = (isDarkTheme: boolean) =>
|
||||
makeStyles(() =>
|
||||
createStyles({
|
||||
oneSettingRow: {
|
||||
color: isDarkTheme ? '#CED9E0 !important' : '#5C7080 !important',
|
||||
fontSize: '18px',
|
||||
fontWeight: 900,
|
||||
},
|
||||
settingRowIcon: {
|
||||
margin: '10px',
|
||||
color: isDarkTheme ? '#BFCCD6' : '#8A9BA8',
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
interface SettingRowLabelAndInput {
|
||||
icon: string;
|
||||
label: string;
|
||||
input: React.ReactNode;
|
||||
}
|
||||
|
||||
export default function SettingRowLabelAndInput(
|
||||
props: SettingRowLabelAndInput
|
||||
) {
|
||||
const { isDarkTheme } = useContext(SettingsContext);
|
||||
|
||||
const getClassesCallback = useCallback(() => {
|
||||
// TODO: dont use callback inside callback, then how to use styles with theme?
|
||||
return useStylesWithTheme(isDarkTheme)();
|
||||
}, [isDarkTheme]);
|
||||
|
||||
return (
|
||||
<Row middle="xs" between="xs">
|
||||
<Col xs={6}>
|
||||
<Row middle="xs" className={getClassesCallback().oneSettingRow}>
|
||||
<Col>
|
||||
<Icon
|
||||
// @ts-ignore: ok here
|
||||
icon={props.icon}
|
||||
iconSize={25}
|
||||
className={getClassesCallback().settingRowIcon}
|
||||
/>
|
||||
</Col>
|
||||
<Col>
|
||||
<Text>{props.label}</Text>
|
||||
</Col>
|
||||
</Row>
|
||||
</Col>
|
||||
<Col xs={6}>
|
||||
<Row>{props.input}</Row>
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
}
|
29
app/components/SettingsOverlay/SettingsOverlay.spec.tsx
Normal file
29
app/components/SettingsOverlay/SettingsOverlay.spec.tsx
Normal file
@ -0,0 +1,29 @@
|
||||
/* eslint-disable react/jsx-boolean-value */
|
||||
import React, { Suspense } from 'react';
|
||||
import Enzyme, { mount } from 'enzyme';
|
||||
import EnzymeToJson from 'enzyme-to-json';
|
||||
import Adapter from 'enzyme-adapter-react-16';
|
||||
import { BrowserRouter as Router } from 'react-router-dom';
|
||||
import SettingsOverlay from './SettingsOverlay';
|
||||
import { SettingsProvider } from '../../containers/SettingsProvider';
|
||||
import { ConnectedDevicesProvider } from '../../containers/ConnectedDevicesProvider';
|
||||
|
||||
Enzyme.configure({ adapter: new Adapter() });
|
||||
jest.useFakeTimers();
|
||||
|
||||
it('should match exact snapshot', () => {
|
||||
const subject = mount(
|
||||
<>
|
||||
<Suspense fallback={<div>Loading... </div>}>
|
||||
<SettingsProvider>
|
||||
<ConnectedDevicesProvider>
|
||||
<Router>
|
||||
<SettingsOverlay isSettingsOpen={true} handleClose={() => {}} />
|
||||
</Router>
|
||||
</ConnectedDevicesProvider>
|
||||
</SettingsProvider>
|
||||
</Suspense>
|
||||
</>
|
||||
);
|
||||
expect(EnzymeToJson(subject)).toMatchSnapshot();
|
||||
});
|
276
app/components/SettingsOverlay/SettingsOverlay.tsx
Normal file
276
app/components/SettingsOverlay/SettingsOverlay.tsx
Normal file
@ -0,0 +1,276 @@
|
||||
/* eslint-disable react/jsx-wrap-multilines */
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
||||
/* eslint-disable react-hooks/rules-of-hooks */
|
||||
/* eslint-disable react/destructuring-assignment */
|
||||
import React, {
|
||||
useContext,
|
||||
useCallback,
|
||||
useMemo,
|
||||
useEffect,
|
||||
useState,
|
||||
} from 'react';
|
||||
import {
|
||||
Button,
|
||||
Overlay,
|
||||
Classes,
|
||||
H3,
|
||||
H6,
|
||||
Tabs,
|
||||
Tab,
|
||||
Icon,
|
||||
HTMLSelect,
|
||||
Text,
|
||||
ControlGroup,
|
||||
Checkbox,
|
||||
} from '@blueprintjs/core';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Row } from 'react-flexbox-grid';
|
||||
import { createStyles, makeStyles } from '@material-ui/core/styles';
|
||||
import i18n from 'i18next';
|
||||
import {
|
||||
DARK_UI_BACKGROUND,
|
||||
LIGHT_UI_BACKGROUND,
|
||||
SettingsContext,
|
||||
} from '../../containers/SettingsProvider';
|
||||
import CloseOverlayButton from '../CloseOverlayButton';
|
||||
import { getLangNameToLangKeyMap } from '../../configs/i18next.config.client';
|
||||
import config from '../../configs/app.lang.config';
|
||||
import isProduction from '../../utils/isProduction';
|
||||
import SettingRowLabelAndInput from './SettingRowLabelAndInput';
|
||||
|
||||
const Fade = require('react-reveal/Fade');
|
||||
|
||||
interface SettingsOverlayProps {
|
||||
isSettingsOpen: boolean;
|
||||
handleClose: () => void;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const useStylesWithTheme = (_isDarkTheme: boolean) =>
|
||||
makeStyles(() =>
|
||||
createStyles({
|
||||
checkboxSettings: { margin: '0' },
|
||||
overlayInnerRoot: { width: '90%' },
|
||||
overlayInsideFade: {
|
||||
height: '90vh',
|
||||
backgroundColor: _isDarkTheme
|
||||
? DARK_UI_BACKGROUND
|
||||
: LIGHT_UI_BACKGROUND,
|
||||
},
|
||||
absoluteCloseButton: { position: 'absolute', left: 'calc(100% - 65px)' },
|
||||
tabNavigationRowButton: { fontWeight: 700 },
|
||||
iconInTablLeftButton: { marginRight: '5px' },
|
||||
})
|
||||
);
|
||||
|
||||
export default function SettingsOverlay(props: SettingsOverlayProps) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const { isDarkTheme, setIsDarkThemeHook } = useContext(SettingsContext);
|
||||
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
const [languagesList, setLanguagesList] = useState([] as string[]);
|
||||
|
||||
const LANG_NAME_TO_KEY_MAP = useMemo(() => {
|
||||
return getLangNameToLangKeyMap();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const tmp: string[] = [];
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
for (const [key] of Object.entries(LANG_NAME_TO_KEY_MAP)) {
|
||||
// @ts-ignore: fine here
|
||||
tmp.push(key);
|
||||
}
|
||||
setLanguagesList(tmp);
|
||||
}, [LANG_NAME_TO_KEY_MAP]);
|
||||
|
||||
const getClassesCallback = useCallback(() => {
|
||||
return useStylesWithTheme(isDarkTheme)();
|
||||
}, [isDarkTheme]);
|
||||
|
||||
const handleToggleDarkTheme = useCallback(() => {
|
||||
if (!isDarkTheme) {
|
||||
document.body.classList.toggle(Classes.DARK);
|
||||
setIsDarkThemeHook(true);
|
||||
}
|
||||
}, [isDarkTheme, setIsDarkThemeHook]);
|
||||
|
||||
const handleToggleLightTheme = useCallback(() => {
|
||||
if (isDarkTheme) {
|
||||
document.body.classList.toggle(Classes.DARK);
|
||||
setIsDarkThemeHook(false);
|
||||
}
|
||||
}, [isDarkTheme, setIsDarkThemeHook]);
|
||||
|
||||
const onChangeLangueageHTMLSelectHandler = (event: any) => {
|
||||
if (
|
||||
event.currentTarget &&
|
||||
event.currentTarget.value in LANG_NAME_TO_KEY_MAP
|
||||
) {
|
||||
// @ts-ignore: fine here
|
||||
i18n.changeLanguage(LANG_NAME_TO_KEY_MAP[event.currentTarget.value]);
|
||||
}
|
||||
};
|
||||
|
||||
const GeneralSettingsPanel: React.FC = () => (
|
||||
<>
|
||||
<Row middle="xs">
|
||||
<H3 className="bp3-text-muted">General Settings</H3>
|
||||
</Row>
|
||||
<SettingRowLabelAndInput
|
||||
icon="style"
|
||||
label="Colors"
|
||||
input={
|
||||
<ControlGroup fill vertical={false}>
|
||||
<Button
|
||||
icon="flash"
|
||||
text="Light"
|
||||
onClick={handleToggleLightTheme}
|
||||
active={!isDarkTheme}
|
||||
/>
|
||||
<Button
|
||||
icon="moon"
|
||||
text="Dark"
|
||||
onClick={handleToggleDarkTheme}
|
||||
active={isDarkTheme}
|
||||
/>
|
||||
</ControlGroup>
|
||||
}
|
||||
/>
|
||||
<SettingRowLabelAndInput
|
||||
icon="translate"
|
||||
label={t('Language')}
|
||||
input={
|
||||
<HTMLSelect
|
||||
defaultValue={
|
||||
// @ts-ignore: fine here
|
||||
config.langISOKeyToLangFullNameMap[i18n.language]
|
||||
}
|
||||
options={languagesList}
|
||||
onChange={onChangeLangueageHTMLSelectHandler}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<SettingRowLabelAndInput
|
||||
icon="automatic-updates"
|
||||
label="Automatic Updates"
|
||||
input={
|
||||
<Checkbox
|
||||
checked
|
||||
className={getClassesCallback().checkboxSettings}
|
||||
label="Enabled"
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
||||
const SecurityPanel: React.FC = () => (
|
||||
<div>
|
||||
<H3>
|
||||
<Icon icon="shield" iconSize={20} />
|
||||
Security
|
||||
</H3>
|
||||
<H6 className={Classes.RUNNING_TEXT}>
|
||||
{`HTML is great for declaring static documents, but it falters when we try
|
||||
to use it for declaring dynamic views in web-applications. AngularJS
|
||||
lets you extend HTML vocabulary for your application. The resulting
|
||||
environment is extraordinarily expressive, readable, and quick to
|
||||
develop.`}
|
||||
</H6>
|
||||
</div>
|
||||
);
|
||||
|
||||
const BlockedIPsPanel: React.FC = () => (
|
||||
<div>
|
||||
<H3>Blocked IPs</H3>
|
||||
</div>
|
||||
);
|
||||
|
||||
const getTabNavBlockedIPsButton = () => {
|
||||
return (
|
||||
<Row middle="xs" className={getClassesCallback().tabNavigationRowButton}>
|
||||
<Icon
|
||||
icon="blocked-person"
|
||||
className={getClassesCallback().iconInTablLeftButton}
|
||||
/>
|
||||
<Text className="bp3-text-large">Blackilsted IPs</Text>
|
||||
</Row>
|
||||
);
|
||||
};
|
||||
|
||||
const getTabNavSecurityButton = () => {
|
||||
return (
|
||||
<Row middle="xs" className={getClassesCallback().tabNavigationRowButton}>
|
||||
<Icon
|
||||
icon="shield"
|
||||
className={getClassesCallback().iconInTablLeftButton}
|
||||
/>
|
||||
<Text className="bp3-text-large">Security</Text>
|
||||
</Row>
|
||||
);
|
||||
};
|
||||
|
||||
const getTabNavGeneralSettingsButton = () => {
|
||||
return (
|
||||
<Row middle="xs" className={getClassesCallback().tabNavigationRowButton}>
|
||||
<Icon
|
||||
icon="wrench"
|
||||
className={getClassesCallback().iconInTablLeftButton}
|
||||
/>
|
||||
<Text className="bp3-text-large">General</Text>
|
||||
</Row>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Overlay
|
||||
onClose={props.handleClose}
|
||||
className={`${Classes.OVERLAY_SCROLL_CONTAINER} bp3-overlay-settings`}
|
||||
autoFocus
|
||||
canEscapeKeyClose
|
||||
canOutsideClickClose
|
||||
enforceFocus
|
||||
hasBackdrop
|
||||
isOpen={props.isSettingsOpen}
|
||||
usePortal
|
||||
transitionDuration={0}
|
||||
>
|
||||
<div className={getClassesCallback().overlayInnerRoot}>
|
||||
<Fade duration={isProduction() ? 700 : 0}>
|
||||
<div
|
||||
id="settings-overlay-inner"
|
||||
className={`${getClassesCallback().overlayInsideFade} ${
|
||||
Classes.CARD
|
||||
}`}
|
||||
>
|
||||
<CloseOverlayButton
|
||||
className={getClassesCallback().absoluteCloseButton}
|
||||
onClick={props.handleClose}
|
||||
/>
|
||||
<Tabs
|
||||
animate
|
||||
id="TabsExample"
|
||||
key="vertical"
|
||||
renderActiveTabPanelOnly
|
||||
vertical
|
||||
>
|
||||
<Tab id="rx" title="" panel={<GeneralSettingsPanel />}>
|
||||
{getTabNavGeneralSettingsButton()}
|
||||
</Tab>
|
||||
<Tab id="ng" title="" panel={<SecurityPanel />}>
|
||||
{getTabNavSecurityButton()}
|
||||
</Tab>
|
||||
<Tab id="bb" disabled title="" panel={<BlockedIPsPanel />}>
|
||||
{getTabNavBlockedIPsButton()}
|
||||
</Tab>
|
||||
<Tabs.Expander />
|
||||
</Tabs>
|
||||
</div>
|
||||
</Fade>
|
||||
</div>
|
||||
</Overlay>
|
||||
);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
23
app/components/ShareAppOrScreenControlGroup.spec.tsx
Normal file
23
app/components/ShareAppOrScreenControlGroup.spec.tsx
Normal file
@ -0,0 +1,23 @@
|
||||
import React from 'react';
|
||||
import Enzyme, { mount } from 'enzyme';
|
||||
import EnzymeToJson from 'enzyme-to-json';
|
||||
import Adapter from 'enzyme-adapter-react-16';
|
||||
import { BrowserRouter as Router } from 'react-router-dom';
|
||||
import ShareAppOrScreenControlGroup from './ShareAppOrScreenControlGroup';
|
||||
|
||||
Enzyme.configure({ adapter: new Adapter() });
|
||||
jest.useFakeTimers();
|
||||
|
||||
it('should match exact snapshot', () => {
|
||||
const subject = mount(
|
||||
<>
|
||||
<Router>
|
||||
<ShareAppOrScreenControlGroup
|
||||
handleNextEntireScreen={() => {}}
|
||||
handleNextApplicationWindow={() => {}}
|
||||
/>
|
||||
</Router>
|
||||
</>
|
||||
);
|
||||
expect(EnzymeToJson(subject)).toMatchSnapshot();
|
||||
});
|
137
app/components/ShareAppOrScreenControlGroup.tsx
Normal file
137
app/components/ShareAppOrScreenControlGroup.tsx
Normal file
@ -0,0 +1,137 @@
|
||||
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
||||
/* eslint-disable prefer-template */
|
||||
/* eslint-disable react/destructuring-assignment */
|
||||
import React, { useState, useCallback } from 'react';
|
||||
import { Button, Icon, ControlGroup, Text } from '@blueprintjs/core';
|
||||
import { createStyles, makeStyles } from '@material-ui/core/styles';
|
||||
import ChooseAppOrScreenOverlay from './StepsOfStepper/ChooseAppOrScreenOverlay/ChooseAppOrScreenOverlay';
|
||||
|
||||
interface ShareEntireScreenOrAppWindowProps {
|
||||
handleNextEntireScreen: () => void;
|
||||
handleNextApplicationWindow: () => void;
|
||||
}
|
||||
|
||||
const useStyles = makeStyles(() =>
|
||||
createStyles({
|
||||
controlGroupRoot: {
|
||||
width: '380px',
|
||||
display: 'flex',
|
||||
position: 'relative',
|
||||
left: '20px',
|
||||
},
|
||||
shareEntireScreenButton: {
|
||||
height: '180px',
|
||||
width: '50%',
|
||||
color: 'white',
|
||||
fontSize: '20px',
|
||||
borderRadius: '20px 0px 0px 20px !important',
|
||||
textAlign: 'center',
|
||||
},
|
||||
shareEntireScreenButtonIcon: { marginBottom: '20px' },
|
||||
shareAppButton: {
|
||||
height: '180px',
|
||||
width: '50%',
|
||||
borderRadius: '0px 20px 20px 0px !important',
|
||||
color: 'white',
|
||||
fontSize: '20px',
|
||||
textAlign: 'center',
|
||||
backgroundColor: '#48AFF0 !important',
|
||||
'&:hover': {
|
||||
backgroundColor: '#4097ce !important',
|
||||
},
|
||||
},
|
||||
shareAppButtonIcon: { marginBottom: '20px' },
|
||||
orDecorationButton: {
|
||||
height: '38px',
|
||||
width: '40px',
|
||||
borderRadius: '100px !important',
|
||||
position: 'relative',
|
||||
top: '72px',
|
||||
left: '-190px !important',
|
||||
// @ts-ignore: need to use !important, can't work without it
|
||||
zIndex: '9999 !important',
|
||||
cursor: 'default',
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
export default function ShareEntireScreenOrAppWindowControlGroup(
|
||||
props: ShareEntireScreenOrAppWindowProps
|
||||
) {
|
||||
const classes = useStyles();
|
||||
|
||||
const [
|
||||
isChooseAppOrScreenOverlayOpen,
|
||||
setChooseAppOrScreenOverlayOpen,
|
||||
] = useState(false);
|
||||
|
||||
const [isEntireScreenToShareChosen, setEntireScreenToShareChosen] = useState(
|
||||
false
|
||||
);
|
||||
|
||||
const handleOpenChooseAppOrScreenOverlay = useCallback(() => {
|
||||
setChooseAppOrScreenOverlayOpen(true);
|
||||
}, []);
|
||||
|
||||
const handleCloseChooseAppOrScreenOverlay = useCallback(() => {
|
||||
setChooseAppOrScreenOverlayOpen(false);
|
||||
}, []);
|
||||
|
||||
const handleChooseAppOverlayOpen = useCallback(() => {
|
||||
setEntireScreenToShareChosen(false);
|
||||
handleOpenChooseAppOrScreenOverlay();
|
||||
}, [handleOpenChooseAppOrScreenOverlay]);
|
||||
|
||||
const handleChooseEntireScreenOverlayOpen = useCallback(() => {
|
||||
setEntireScreenToShareChosen(true);
|
||||
handleOpenChooseAppOrScreenOverlay();
|
||||
}, [handleOpenChooseAppOrScreenOverlay]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<ControlGroup
|
||||
id="share-screen-or-app-btn-group"
|
||||
className={classes.controlGroupRoot}
|
||||
fill
|
||||
vertical={false}
|
||||
>
|
||||
<Button
|
||||
className={classes.shareEntireScreenButton}
|
||||
intent="primary"
|
||||
onClick={handleChooseEntireScreenOverlayOpen}
|
||||
>
|
||||
<Icon
|
||||
className={classes.shareEntireScreenButtonIcon}
|
||||
icon="desktop"
|
||||
iconSize={100}
|
||||
color="white"
|
||||
/>
|
||||
<Text className="bp3-running-text">Entire Screen</Text>
|
||||
</Button>
|
||||
<Button
|
||||
className={classes.shareAppButton}
|
||||
intent="primary"
|
||||
onClick={handleChooseAppOverlayOpen}
|
||||
>
|
||||
<Icon
|
||||
className={classes.shareAppButtonIcon}
|
||||
icon="application"
|
||||
iconSize={100}
|
||||
color="white"
|
||||
/>
|
||||
<Text className="bp3-running-text">Application Window</Text>
|
||||
</Button>
|
||||
<Button active className={classes.orDecorationButton}>
|
||||
OR
|
||||
</Button>
|
||||
</ControlGroup>
|
||||
<ChooseAppOrScreenOverlay
|
||||
isEntireScreenToShareChosen={isEntireScreenToShareChosen}
|
||||
isChooseAppOrScreenOverlayOpen={isChooseAppOrScreenOverlayOpen}
|
||||
handleClose={handleCloseChooseAppOrScreenOverlay}
|
||||
handleNextEntireScreen={props.handleNextEntireScreen}
|
||||
handleNextApplicationWindow={props.handleNextApplicationWindow}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
28
app/components/StepperPanel/ColorlibConnector.tsx
Normal file
28
app/components/StepperPanel/ColorlibConnector.tsx
Normal file
@ -0,0 +1,28 @@
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
import StepConnector from '@material-ui/core/StepConnector';
|
||||
|
||||
const ColorlibConnector = withStyles({
|
||||
alternativeLabel: {
|
||||
top: 43,
|
||||
},
|
||||
active: {
|
||||
'& $line': {
|
||||
backgroundImage:
|
||||
'linear-gradient( 95deg, #3DCC91 0%, #15B371 50%, #FFB366 100%)',
|
||||
},
|
||||
},
|
||||
completed: {
|
||||
'& $line': {
|
||||
backgroundImage:
|
||||
'linear-gradient( 95deg, #3DCC91 0%, #15B371 50%, #3DCC91 100%)',
|
||||
},
|
||||
},
|
||||
line: {
|
||||
height: 2,
|
||||
border: 0,
|
||||
backgroundColor: '#CED9E0',
|
||||
borderRadius: 1,
|
||||
},
|
||||
})(StepConnector);
|
||||
|
||||
export default ColorlibConnector;
|
76
app/components/StepperPanel/ColorlibStepIcon.tsx
Normal file
76
app/components/StepperPanel/ColorlibStepIcon.tsx
Normal file
@ -0,0 +1,76 @@
|
||||
/* eslint-disable react/destructuring-assignment */
|
||||
/* eslint-disable no-nested-ternary */
|
||||
import React from 'react';
|
||||
import clsx from 'clsx';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import { StepIconProps } from '@material-ui/core/StepIcon';
|
||||
import { Icon } from '@blueprintjs/core';
|
||||
|
||||
export interface StepIconPropsDeskreen extends StepIconProps {
|
||||
isEntireScreenSelected: boolean;
|
||||
isApplicationWindowSelected: boolean;
|
||||
}
|
||||
|
||||
const useColorlibStepIconStyles = makeStyles({
|
||||
root: {
|
||||
backgroundColor: '#BFCCD6',
|
||||
zIndex: 1,
|
||||
color: '#5C7080',
|
||||
width: 65,
|
||||
height: 65,
|
||||
display: 'flex',
|
||||
borderRadius: '50%',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
active: {
|
||||
backgroundImage:
|
||||
'linear-gradient( 136deg, #FFB366 0%, #F29D49 50%, #A66321 100%)',
|
||||
boxShadow: '0 4px 10px 0 rgba(0,0,0,.25)',
|
||||
},
|
||||
completed: {
|
||||
backgroundImage:
|
||||
'linear-gradient( 136deg, #3DCC91 0%, #15B371 50%, #0E5A8A 100%)',
|
||||
},
|
||||
stepContent: {},
|
||||
});
|
||||
|
||||
export default function ColorlibStepIcon(props: StepIconPropsDeskreen) {
|
||||
const classes = useColorlibStepIconStyles();
|
||||
const { active, completed, isEntireScreenSelected } = props;
|
||||
|
||||
const color = active || completed ? '#fff' : '#5C7080';
|
||||
|
||||
const icons: { [index: string]: React.ReactElement } = {
|
||||
1: completed ? (
|
||||
<Icon icon="feed-subscribed" iconSize={25} color={color} />
|
||||
) : (
|
||||
<Icon icon="feed" iconSize={25} color={color} />
|
||||
),
|
||||
2: completed ? (
|
||||
isEntireScreenSelected ? (
|
||||
<Icon icon="desktop" iconSize={25} color={color} />
|
||||
) : (
|
||||
<Icon icon="application" iconSize={25} color={color} />
|
||||
)
|
||||
) : (
|
||||
<Icon icon="flow-branch" iconSize={25} color={color} />
|
||||
),
|
||||
3: completed ? (
|
||||
<Icon icon="tick-circle" iconSize={25} color={color} />
|
||||
) : (
|
||||
<Icon icon="confirm" iconSize={25} color={color} />
|
||||
),
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`${clsx(classes.root, {
|
||||
[classes.active]: active,
|
||||
[classes.completed]: completed,
|
||||
})} ${active ? 'active-stepper-pulse-icon' : ''}`}
|
||||
>
|
||||
{icons[String(props.icon)]}
|
||||
</div>
|
||||
);
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
import React from 'react';
|
||||
import Enzyme, { mount } from 'enzyme';
|
||||
import EnzymeToJson from 'enzyme-to-json';
|
||||
import Adapter from 'enzyme-adapter-react-16';
|
||||
import { BrowserRouter as Router } from 'react-router-dom';
|
||||
import DeviceConnectedInfoButton from './DeviceConnectedInfoButton';
|
||||
|
||||
Enzyme.configure({ adapter: new Adapter() });
|
||||
jest.useFakeTimers();
|
||||
|
||||
it('should match exact snapshot', () => {
|
||||
const subject = mount(
|
||||
<>
|
||||
<Router>
|
||||
<DeviceConnectedInfoButton
|
||||
device={{} as Device}
|
||||
onDisconnect={() => {}}
|
||||
/>
|
||||
</Router>
|
||||
</>
|
||||
);
|
||||
expect(EnzymeToJson(subject)).toMatchSnapshot();
|
||||
});
|
90
app/components/StepperPanel/DeviceConnectedInfoButton.tsx
Normal file
90
app/components/StepperPanel/DeviceConnectedInfoButton.tsx
Normal file
@ -0,0 +1,90 @@
|
||||
import React from 'react';
|
||||
import { Row, Col } from 'react-flexbox-grid';
|
||||
import { Icon, Text, Button, Popover, H6, Tooltip } from '@blueprintjs/core';
|
||||
import isProduction from '../../utils/isProduction';
|
||||
|
||||
interface DeviceConnectedInfoButtonProps {
|
||||
device: Device;
|
||||
onDisconnect: () => void;
|
||||
}
|
||||
|
||||
const getDeviceConnectedPopoverContent = (
|
||||
pendingConnectionDevice: Device,
|
||||
handleDisconnect: () => void
|
||||
) => {
|
||||
return (
|
||||
<Row>
|
||||
<div style={{ padding: '20px', borderRadius: '100px' }}>
|
||||
<Row style={{ marginBottom: '10px' }}>
|
||||
<Col xs={12}>
|
||||
<H6>Connected Device:</H6>
|
||||
<Text>{`Type: ${pendingConnectionDevice?.deviceType}`}</Text>
|
||||
<Text>{`OS: ${pendingConnectionDevice?.deviceOs}`}</Text>
|
||||
<div id="connected-button-popover-div-with-ip">
|
||||
<Text>{`IP: ${pendingConnectionDevice?.deviceIp}`}</Text>
|
||||
</div>
|
||||
<Text>{`SessionId: ${pendingConnectionDevice?.sessionId}`}</Text>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col xs={12}>
|
||||
<Button
|
||||
intent="danger"
|
||||
icon="disable"
|
||||
onClick={() => {
|
||||
handleDisconnect();
|
||||
}}
|
||||
style={{ width: '100%', borderRadius: '5px' }}
|
||||
>
|
||||
Disconnect
|
||||
</Button>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
</Row>
|
||||
);
|
||||
};
|
||||
|
||||
export default function DeviceConnectedInfoButton(
|
||||
props: DeviceConnectedInfoButtonProps
|
||||
) {
|
||||
const { device, onDisconnect } = props;
|
||||
|
||||
return (
|
||||
<>
|
||||
<Popover
|
||||
content={getDeviceConnectedPopoverContent(device, onDisconnect)}
|
||||
position="bottom"
|
||||
inheritDarkTheme={false}
|
||||
transitionDuration={isProduction() ? 700 : 0}
|
||||
>
|
||||
<Tooltip
|
||||
content={<Text>Click to manage</Text>}
|
||||
position="right"
|
||||
hoverOpenDelay={400}
|
||||
>
|
||||
<Button
|
||||
id="connected-device-info-stepper-button"
|
||||
intent="success"
|
||||
style={{
|
||||
width: '120px',
|
||||
height: '10px !important',
|
||||
borderRadius: '100px',
|
||||
position: 'relative',
|
||||
margin: '0 auto',
|
||||
}}
|
||||
>
|
||||
<Row>
|
||||
<Col xs={1}>
|
||||
<Icon icon="info-sign" />
|
||||
</Col>
|
||||
<Col xs>
|
||||
<Text>Connected</Text>
|
||||
</Col>
|
||||
</Row>
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</Popover>
|
||||
</>
|
||||
);
|
||||
}
|
@ -0,0 +1,344 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`should match exact snapshot 1`] = `
|
||||
<BrowserRouter>
|
||||
<Router
|
||||
history={
|
||||
Object {
|
||||
"action": "POP",
|
||||
"block": [Function],
|
||||
"createHref": [Function],
|
||||
"go": [Function],
|
||||
"goBack": [Function],
|
||||
"goForward": [Function],
|
||||
"length": 1,
|
||||
"listen": [Function],
|
||||
"location": Object {
|
||||
"hash": "",
|
||||
"pathname": "/",
|
||||
"search": "",
|
||||
"state": undefined,
|
||||
},
|
||||
"push": [Function],
|
||||
"replace": [Function],
|
||||
}
|
||||
}
|
||||
>
|
||||
<DeviceConnectedInfoButton
|
||||
device={Object {}}
|
||||
onDisconnect={[Function]}
|
||||
>
|
||||
<Blueprint3.Popover
|
||||
boundary="scrollParent"
|
||||
captureDismiss={false}
|
||||
content={
|
||||
<Row>
|
||||
<div
|
||||
style={
|
||||
Object {
|
||||
"borderRadius": "100px",
|
||||
"padding": "20px",
|
||||
}
|
||||
}
|
||||
>
|
||||
<Row
|
||||
style={
|
||||
Object {
|
||||
"marginBottom": "10px",
|
||||
}
|
||||
}
|
||||
>
|
||||
<Col
|
||||
xs={12}
|
||||
>
|
||||
<Unknown>
|
||||
Connected Device:
|
||||
</Unknown>
|
||||
<Blueprint3.Text>
|
||||
Type: undefined
|
||||
</Blueprint3.Text>
|
||||
<Blueprint3.Text>
|
||||
OS: undefined
|
||||
</Blueprint3.Text>
|
||||
<div
|
||||
id="connected-button-popover-div-with-ip"
|
||||
>
|
||||
<Blueprint3.Text>
|
||||
IP: undefined
|
||||
</Blueprint3.Text>
|
||||
</div>
|
||||
<Blueprint3.Text>
|
||||
SessionId: undefined
|
||||
</Blueprint3.Text>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col
|
||||
xs={12}
|
||||
>
|
||||
<Blueprint3.Button
|
||||
icon="disable"
|
||||
intent="danger"
|
||||
onClick={[Function]}
|
||||
style={
|
||||
Object {
|
||||
"borderRadius": "5px",
|
||||
"width": "100%",
|
||||
}
|
||||
}
|
||||
>
|
||||
Disconnect
|
||||
</Blueprint3.Button>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
</Row>
|
||||
}
|
||||
defaultIsOpen={false}
|
||||
disabled={false}
|
||||
fill={false}
|
||||
hasBackdrop={false}
|
||||
hoverCloseDelay={300}
|
||||
hoverOpenDelay={150}
|
||||
inheritDarkTheme={false}
|
||||
interactionKind="click"
|
||||
minimal={false}
|
||||
modifiers={Object {}}
|
||||
openOnTargetFocus={true}
|
||||
position="bottom"
|
||||
targetTagName="span"
|
||||
transitionDuration={0}
|
||||
usePortal={true}
|
||||
wrapperTagName="span"
|
||||
>
|
||||
<Manager>
|
||||
<span
|
||||
className="bp3-popover-wrapper"
|
||||
>
|
||||
<Reference
|
||||
innerRef={[Function]}
|
||||
>
|
||||
<InnerReference
|
||||
innerRef={[Function]}
|
||||
setReferenceNode={[Function]}
|
||||
>
|
||||
<Blueprint3.ResizeSensor
|
||||
onResize={[Function]}
|
||||
>
|
||||
<span
|
||||
className="bp3-popover-target"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<Blueprint3.Tooltip
|
||||
className=""
|
||||
content={
|
||||
<Blueprint3.Text>
|
||||
Click to manage
|
||||
</Blueprint3.Text>
|
||||
}
|
||||
hoverCloseDelay={0}
|
||||
hoverOpenDelay={400}
|
||||
key=".0"
|
||||
position="right"
|
||||
transitionDuration={100}
|
||||
>
|
||||
<Blueprint3.Popover
|
||||
autoFocus={false}
|
||||
boundary="scrollParent"
|
||||
canEscapeKeyClose={false}
|
||||
captureDismiss={false}
|
||||
className=""
|
||||
content={
|
||||
<Blueprint3.Text>
|
||||
Click to manage
|
||||
</Blueprint3.Text>
|
||||
}
|
||||
defaultIsOpen={false}
|
||||
disabled={false}
|
||||
enforceFocus={false}
|
||||
fill={false}
|
||||
hasBackdrop={false}
|
||||
hoverCloseDelay={0}
|
||||
hoverOpenDelay={400}
|
||||
inheritDarkTheme={true}
|
||||
interactionKind="hover-target"
|
||||
lazy={true}
|
||||
minimal={false}
|
||||
modifiers={Object {}}
|
||||
openOnTargetFocus={true}
|
||||
popoverClassName="bp3-tooltip"
|
||||
position="right"
|
||||
targetTagName="span"
|
||||
transitionDuration={100}
|
||||
usePortal={true}
|
||||
wrapperTagName="span"
|
||||
>
|
||||
<Manager>
|
||||
<span
|
||||
className="bp3-popover-wrapper"
|
||||
>
|
||||
<Reference
|
||||
innerRef={[Function]}
|
||||
>
|
||||
<InnerReference
|
||||
innerRef={[Function]}
|
||||
setReferenceNode={[Function]}
|
||||
>
|
||||
<Blueprint3.ResizeSensor
|
||||
onResize={[Function]}
|
||||
>
|
||||
<span
|
||||
className="bp3-popover-target"
|
||||
onBlur={[Function]}
|
||||
onFocus={[Function]}
|
||||
onMouseEnter={[Function]}
|
||||
onMouseLeave={[Function]}
|
||||
>
|
||||
<Blueprint3.Button
|
||||
className=""
|
||||
id="connected-device-info-stepper-button"
|
||||
intent="success"
|
||||
key=".0"
|
||||
style={
|
||||
Object {
|
||||
"borderRadius": "100px",
|
||||
"height": "10px !important",
|
||||
"margin": "0 auto",
|
||||
"position": "relative",
|
||||
"width": "120px",
|
||||
}
|
||||
}
|
||||
tabIndex={0}
|
||||
>
|
||||
<button
|
||||
className="bp3-button bp3-intent-success"
|
||||
id="connected-device-info-stepper-button"
|
||||
onKeyDown={[Function]}
|
||||
onKeyUp={[Function]}
|
||||
style={
|
||||
Object {
|
||||
"borderRadius": "100px",
|
||||
"height": "10px !important",
|
||||
"margin": "0 auto",
|
||||
"position": "relative",
|
||||
"width": "120px",
|
||||
}
|
||||
}
|
||||
tabIndex={0}
|
||||
type="button"
|
||||
>
|
||||
<Blueprint3.Icon
|
||||
key="leftIcon"
|
||||
/>
|
||||
<span
|
||||
className="bp3-button-text"
|
||||
key="text"
|
||||
>
|
||||
<Row>
|
||||
<div
|
||||
className="row"
|
||||
>
|
||||
<Col
|
||||
xs={1}
|
||||
>
|
||||
<div
|
||||
className="col-xs-1"
|
||||
>
|
||||
<Blueprint3.Icon
|
||||
icon="info-sign"
|
||||
>
|
||||
<span
|
||||
className="bp3-icon bp3-icon-info-sign"
|
||||
icon="info-sign"
|
||||
>
|
||||
<svg
|
||||
data-icon="info-sign"
|
||||
height={16}
|
||||
viewBox="0 0 16 16"
|
||||
width={16}
|
||||
>
|
||||
<desc>
|
||||
info-sign
|
||||
</desc>
|
||||
<path
|
||||
d="M8 0C3.58 0 0 3.58 0 8s3.58 8 8 8 8-3.58 8-8-3.58-8-8-8zM7 3h2v2H7V3zm3 10H6v-1h1V7H6V6h3v6h1v1z"
|
||||
fillRule="evenodd"
|
||||
key="0"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</Blueprint3.Icon>
|
||||
</div>
|
||||
</Col>
|
||||
<Col
|
||||
xs={true}
|
||||
>
|
||||
<div
|
||||
className="col-xs"
|
||||
>
|
||||
<Blueprint3.Text>
|
||||
<div
|
||||
className=""
|
||||
>
|
||||
Connected
|
||||
</div>
|
||||
</Blueprint3.Text>
|
||||
</div>
|
||||
</Col>
|
||||
</div>
|
||||
</Row>
|
||||
</span>
|
||||
<Blueprint3.Icon
|
||||
key="rightIcon"
|
||||
/>
|
||||
</button>
|
||||
</Blueprint3.Button>
|
||||
</span>
|
||||
</Blueprint3.ResizeSensor>
|
||||
</InnerReference>
|
||||
</Reference>
|
||||
<Blueprint3.Overlay
|
||||
autoFocus={false}
|
||||
backdropClassName="bp3-popover-backdrop"
|
||||
backdropProps={Object {}}
|
||||
canEscapeKeyClose={false}
|
||||
canOutsideClickClose={false}
|
||||
enforceFocus={false}
|
||||
hasBackdrop={false}
|
||||
isOpen={false}
|
||||
lazy={true}
|
||||
onClose={[Function]}
|
||||
transitionDuration={100}
|
||||
transitionName="bp3-popover"
|
||||
usePortal={true}
|
||||
/>
|
||||
</span>
|
||||
</Manager>
|
||||
</Blueprint3.Popover>
|
||||
</Blueprint3.Tooltip>
|
||||
</span>
|
||||
</Blueprint3.ResizeSensor>
|
||||
</InnerReference>
|
||||
</Reference>
|
||||
<Blueprint3.Overlay
|
||||
autoFocus={true}
|
||||
backdropClassName="bp3-popover-backdrop"
|
||||
backdropProps={Object {}}
|
||||
canEscapeKeyClose={true}
|
||||
canOutsideClickClose={true}
|
||||
enforceFocus={true}
|
||||
hasBackdrop={false}
|
||||
isOpen={false}
|
||||
lazy={true}
|
||||
onClose={[Function]}
|
||||
transitionDuration={0}
|
||||
transitionName="bp3-popover"
|
||||
usePortal={true}
|
||||
/>
|
||||
</span>
|
||||
</Manager>
|
||||
</Blueprint3.Popover>
|
||||
</DeviceConnectedInfoButton>
|
||||
</Router>
|
||||
</BrowserRouter>
|
||||
`;
|
@ -0,0 +1,23 @@
|
||||
import React from 'react';
|
||||
import Enzyme, { mount } from 'enzyme';
|
||||
import EnzymeToJson from 'enzyme-to-json';
|
||||
import Adapter from 'enzyme-adapter-react-16';
|
||||
import { BrowserRouter as Router } from 'react-router-dom';
|
||||
import ChooseAppOrScreeenStep from './ChooseAppOrScreeenStep';
|
||||
|
||||
Enzyme.configure({ adapter: new Adapter() });
|
||||
jest.useFakeTimers();
|
||||
|
||||
it('should match exact snapshot', () => {
|
||||
const subject = mount(
|
||||
<>
|
||||
<Router>
|
||||
<ChooseAppOrScreeenStep
|
||||
handleNextEntireScreen={() => {}}
|
||||
handleNextApplicationWindow={() => {}}
|
||||
/>
|
||||
</Router>
|
||||
</>
|
||||
);
|
||||
expect(EnzymeToJson(subject)).toMatchSnapshot();
|
||||
});
|
29
app/components/StepsOfStepper/ChooseAppOrScreeenStep.tsx
Normal file
29
app/components/StepsOfStepper/ChooseAppOrScreeenStep.tsx
Normal file
@ -0,0 +1,29 @@
|
||||
/* eslint-disable react/destructuring-assignment */
|
||||
import React from 'react';
|
||||
import { Text } from '@blueprintjs/core';
|
||||
import ShareEntireScreenOrAppWindowControlGroup from '../ShareAppOrScreenControlGroup';
|
||||
|
||||
interface ChooseAppOrScreeenStepProps {
|
||||
handleNextEntireScreen: () => void;
|
||||
handleNextApplicationWindow: () => void;
|
||||
}
|
||||
|
||||
const ChooseAppOrScreeenStep: React.FC<ChooseAppOrScreeenStepProps> = (
|
||||
props: ChooseAppOrScreeenStepProps
|
||||
) => {
|
||||
return (
|
||||
<>
|
||||
<div style={{ marginBottom: '10px' }}>
|
||||
<Text>
|
||||
Choose Entire Screen or App window you want to view on other device
|
||||
</Text>
|
||||
</div>
|
||||
<ShareEntireScreenOrAppWindowControlGroup
|
||||
handleNextEntireScreen={props.handleNextEntireScreen}
|
||||
handleNextApplicationWindow={props.handleNextApplicationWindow}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default ChooseAppOrScreeenStep;
|
@ -0,0 +1,26 @@
|
||||
import React from 'react';
|
||||
import Enzyme, { mount } from 'enzyme';
|
||||
import EnzymeToJson from 'enzyme-to-json';
|
||||
import Adapter from 'enzyme-adapter-react-16';
|
||||
import { BrowserRouter as Router } from 'react-router-dom';
|
||||
import ChooseAppOrScreenOverlay from './ChooseAppOrScreenOverlay';
|
||||
|
||||
Enzyme.configure({ adapter: new Adapter() });
|
||||
jest.useFakeTimers();
|
||||
|
||||
it('should match exact snapshot', () => {
|
||||
const subject = mount(
|
||||
<>
|
||||
<Router>
|
||||
<ChooseAppOrScreenOverlay
|
||||
isEntireScreenToShareChosen
|
||||
isChooseAppOrScreenOverlayOpen
|
||||
handleNextEntireScreen={() => {}}
|
||||
handleNextApplicationWindow={() => {}}
|
||||
handleClose={() => {}}
|
||||
/>
|
||||
</Router>
|
||||
</>
|
||||
);
|
||||
expect(EnzymeToJson(subject)).toMatchSnapshot();
|
||||
});
|
@ -0,0 +1,164 @@
|
||||
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
||||
/* eslint-disable react/no-unused-prop-types */
|
||||
/* eslint-disable react/destructuring-assignment */
|
||||
import React from 'react';
|
||||
import { H3, Card, Dialog } from '@blueprintjs/core';
|
||||
import { Row, Col } from 'react-flexbox-grid';
|
||||
import { createStyles, makeStyles } from '@material-ui/core/styles';
|
||||
import CloseOverlayButton from '../../CloseOverlayButton';
|
||||
import isProduction from '../../../utils/isProduction';
|
||||
import PreviewGridList from './PreviewGridList';
|
||||
import TEST_SCREEN_SHARING_OBECTS from '../../../constants/test-screen-sharing-objects.json';
|
||||
|
||||
const Zoom = require('react-reveal/Zoom');
|
||||
const Fade = require('react-reveal/Fade');
|
||||
|
||||
const useStyles = makeStyles(() =>
|
||||
createStyles({
|
||||
dialogRoot: {
|
||||
width: '90%',
|
||||
height: '87vh !important',
|
||||
overflowY: 'scroll',
|
||||
},
|
||||
closeButton: {
|
||||
position: 'relative',
|
||||
width: '40px',
|
||||
height: '40px',
|
||||
left: 'calc(100% - 55px)',
|
||||
borderRadius: '100px',
|
||||
zIndex: 9999,
|
||||
},
|
||||
overlayInnerRoot: { width: '90%', height: '90%' },
|
||||
sharePreviewsContainer: {
|
||||
top: '60px',
|
||||
position: 'relative',
|
||||
height: '100%',
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
interface ChooseAppOrScreenOverlayProps {
|
||||
isEntireScreenToShareChosen: boolean;
|
||||
isChooseAppOrScreenOverlayOpen: boolean;
|
||||
handleNextEntireScreen: () => void;
|
||||
handleNextApplicationWindow: () => void;
|
||||
handleClose: () => void;
|
||||
}
|
||||
|
||||
export default function ChooseAppOrScreenOverlay(
|
||||
props: ChooseAppOrScreenOverlayProps
|
||||
) {
|
||||
const classes = useStyles();
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
onClose={props.handleClose}
|
||||
className={`${classes.dialogRoot} choose-app-or-screen-dialog`}
|
||||
autoFocus
|
||||
canEscapeKeyClose
|
||||
canOutsideClickClose
|
||||
enforceFocus
|
||||
hasBackdrop
|
||||
isOpen={props.isChooseAppOrScreenOverlayOpen}
|
||||
usePortal
|
||||
transitionDuration={isProduction() ? 750 : 0}
|
||||
>
|
||||
<div>
|
||||
<Fade
|
||||
duration={isProduction() ? 1000 : 0}
|
||||
delay={isProduction() ? 1000 : 0}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
position: 'fixed',
|
||||
zIndex: 99999,
|
||||
width: '90%',
|
||||
paddingTop: '0px',
|
||||
paddingLeft: '15px',
|
||||
paddingRight: '15px',
|
||||
}}
|
||||
>
|
||||
<Card
|
||||
elevation={2}
|
||||
style={{
|
||||
padding: '10px',
|
||||
borderRadius: '5px',
|
||||
height: '60px',
|
||||
width: '100%',
|
||||
}}
|
||||
>
|
||||
<Row
|
||||
between="xs"
|
||||
middle="xs"
|
||||
style={{
|
||||
width: '100%',
|
||||
}}
|
||||
>
|
||||
<Col xs={11}>
|
||||
{props.isEntireScreenToShareChosen ? (
|
||||
<div>
|
||||
<H3 style={{ marginBottom: '0px' }}>
|
||||
Select Entire Screen to Share
|
||||
</H3>
|
||||
</div>
|
||||
) : (
|
||||
<div>
|
||||
<H3 style={{ marginBottom: '0px' }}>
|
||||
Select App Window to Share
|
||||
</H3>
|
||||
</div>
|
||||
)}
|
||||
</Col>
|
||||
|
||||
<Col xs={1}>
|
||||
<CloseOverlayButton
|
||||
onClick={props.handleClose}
|
||||
style={{
|
||||
borderRadius: '100px',
|
||||
width: '40px',
|
||||
height: '40px',
|
||||
}}
|
||||
noDefaultStyles
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
</Card>
|
||||
</div>
|
||||
</Fade>
|
||||
|
||||
<Zoom
|
||||
duration={isProduction() ? 750 : 0}
|
||||
style={{
|
||||
position: 'relative',
|
||||
zIndex: '1',
|
||||
}}
|
||||
>
|
||||
<Card
|
||||
style={{
|
||||
position: 'relative',
|
||||
// @ts-ignore
|
||||
zIndex: '1',
|
||||
}}
|
||||
>
|
||||
<Row>
|
||||
<div className={classes.sharePreviewsContainer}>
|
||||
<PreviewGridList
|
||||
screenSharingObjects={TEST_SCREEN_SHARING_OBECTS}
|
||||
isEntireScreen={props.isEntireScreenToShareChosen}
|
||||
handleNextEntireScreen={() => {
|
||||
props.handleNextEntireScreen();
|
||||
props.handleClose();
|
||||
}}
|
||||
handleNextApplicationWindow={() => {
|
||||
props.handleNextApplicationWindow();
|
||||
props.handleClose();
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</Row>
|
||||
</Card>
|
||||
</Zoom>
|
||||
</div>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
@ -0,0 +1,166 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
/* eslint-disable jsx-a11y/click-events-have-key-events */
|
||||
/* eslint-disable jsx-a11y/no-noninteractive-element-interactions */
|
||||
/* eslint-disable jsx-a11y/alt-text */
|
||||
import React, { useEffect, useState, useCallback } from 'react';
|
||||
import { Card, H4, Icon } from '@blueprintjs/core';
|
||||
import { createStyles, makeStyles } from '@material-ui/core/styles';
|
||||
import { Row, Col } from 'react-flexbox-grid';
|
||||
import isProduction from '../../../utils/isProduction';
|
||||
|
||||
const Fade = require('react-reveal/Fade');
|
||||
|
||||
const useStyles = makeStyles(() =>
|
||||
createStyles({
|
||||
root: {
|
||||
display: 'flex',
|
||||
flexWrap: 'wrap',
|
||||
justifyContent: 'space-around',
|
||||
overflow: 'hidden',
|
||||
},
|
||||
gridList: {
|
||||
width: 500,
|
||||
height: 450,
|
||||
},
|
||||
icon: {
|
||||
color: 'rgba(255, 255, 255, 0.54)',
|
||||
},
|
||||
previewShareThumbContainer: {
|
||||
marginBottom: '20px',
|
||||
'&:hover': {
|
||||
backgroundColor: 'rgba(19, 124, 189, 0.4)',
|
||||
},
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
export default function PreviewGridList(props: any) {
|
||||
const classes = useStyles();
|
||||
|
||||
const [showPreviewNamesMap, setShowPreviewNamesMap] = useState(new Map());
|
||||
|
||||
useEffect(() => {
|
||||
const map = new Map();
|
||||
props.screenSharingObjects.forEach((el: { id: string }) => {
|
||||
map.set(el.id, false);
|
||||
});
|
||||
setShowPreviewNamesMap(map);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
const onPreviewMouseEnter = useCallback(
|
||||
(id) => {
|
||||
const newShowPreviewNamesMap = new Map(showPreviewNamesMap);
|
||||
[...newShowPreviewNamesMap.keys()].forEach((key) => {
|
||||
newShowPreviewNamesMap.set(key, false);
|
||||
});
|
||||
newShowPreviewNamesMap.set(id, true);
|
||||
setShowPreviewNamesMap(newShowPreviewNamesMap);
|
||||
},
|
||||
[showPreviewNamesMap, setShowPreviewNamesMap]
|
||||
);
|
||||
|
||||
const onPreviewMouseLeave = useCallback(() => {
|
||||
const newShowPreviewNamesMap = new Map(showPreviewNamesMap);
|
||||
[...newShowPreviewNamesMap.keys()].forEach((key) => {
|
||||
newShowPreviewNamesMap.set(key, false);
|
||||
});
|
||||
setShowPreviewNamesMap(newShowPreviewNamesMap);
|
||||
}, [showPreviewNamesMap, setShowPreviewNamesMap]);
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
height: '90%',
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
flexWrap: 'wrap',
|
||||
}}
|
||||
>
|
||||
{[...showPreviewNamesMap.keys()].map((id) => {
|
||||
return (
|
||||
<Col xs={12} md={6} lg={3} key={id}>
|
||||
<Card
|
||||
interactive
|
||||
elevation={2}
|
||||
className={`preview-share-thumb-container ${classes.previewShareThumbContainer}`}
|
||||
onClick={() => {
|
||||
if (props.isEntireScreen) {
|
||||
props.handleNextEntireScreen();
|
||||
} else {
|
||||
props.handleNextApplicationWindow();
|
||||
}
|
||||
}}
|
||||
onMouseEnter={() => onPreviewMouseEnter(id)}
|
||||
onMouseLeave={() => onPreviewMouseLeave()}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
height: '250px',
|
||||
position: 'relative',
|
||||
overflow: 'hidden',
|
||||
borderRadius: '5px',
|
||||
}}
|
||||
>
|
||||
<Row
|
||||
middle="xs"
|
||||
center="xs"
|
||||
className="icon-or-preview-container"
|
||||
>
|
||||
<Icon
|
||||
icon={props.isEntireScreen ? 'desktop' : 'application'}
|
||||
iconSize={150}
|
||||
color="#A7B6C2"
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: 'calc(50% - 75px)',
|
||||
left: 'calc(50% - 75px)',
|
||||
}}
|
||||
/>
|
||||
</Row>
|
||||
<Fade
|
||||
when={showPreviewNamesMap.get(id)}
|
||||
duration={isProduction() ? 300 : 0}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
height: '100%',
|
||||
background:
|
||||
'radial-gradient(circle closest-side, rgba(0,0,0,0.025), rgba(0,0,0,0.1)',
|
||||
}}
|
||||
>
|
||||
<Fade
|
||||
bottom
|
||||
when={showPreviewNamesMap.get(id)}
|
||||
duration={isProduction() ? 300 : 0}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
position: 'relative',
|
||||
bottom: 'calc(-100% + 42px)',
|
||||
width: '100%',
|
||||
backgroundColor: 'rgba(0,0,0,0.4)',
|
||||
padding: '10px',
|
||||
}}
|
||||
>
|
||||
<H4
|
||||
style={{
|
||||
paddingBottom: '0px',
|
||||
marginBottom: '0px',
|
||||
color: 'white',
|
||||
}}
|
||||
>
|
||||
Preview Name
|
||||
</H4>
|
||||
</div>
|
||||
</Fade>
|
||||
</div>
|
||||
</Fade>
|
||||
</div>
|
||||
</Card>
|
||||
</Col>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
20
app/components/StepsOfStepper/ConfirmStep.spec.tsx
Normal file
20
app/components/StepsOfStepper/ConfirmStep.spec.tsx
Normal file
@ -0,0 +1,20 @@
|
||||
import React from 'react';
|
||||
import Enzyme, { mount } from 'enzyme';
|
||||
import EnzymeToJson from 'enzyme-to-json';
|
||||
import Adapter from 'enzyme-adapter-react-16';
|
||||
import { BrowserRouter as Router } from 'react-router-dom';
|
||||
import ConfirmStep from './ConfirmStep';
|
||||
|
||||
Enzyme.configure({ adapter: new Adapter() });
|
||||
jest.useFakeTimers();
|
||||
|
||||
it('should match exact snapshot', () => {
|
||||
const subject = mount(
|
||||
<>
|
||||
<Router>
|
||||
<ConfirmStep device={{} as Device} />
|
||||
</Router>
|
||||
</>
|
||||
);
|
||||
expect(EnzymeToJson(subject)).toMatchSnapshot();
|
||||
});
|
30
app/components/StepsOfStepper/ConfirmStep.tsx
Normal file
30
app/components/StepsOfStepper/ConfirmStep.tsx
Normal file
@ -0,0 +1,30 @@
|
||||
/* eslint-disable react/jsx-curly-brace-presence */
|
||||
/* eslint-disable react/destructuring-assignment */
|
||||
import React from 'react';
|
||||
import { Text, Card } from '@blueprintjs/core';
|
||||
|
||||
interface ConfirmStepProps {
|
||||
device: Device | null;
|
||||
}
|
||||
|
||||
export default function ConfirmStep(props: ConfirmStepProps) {
|
||||
return (
|
||||
<>
|
||||
<div style={{ marginBottom: '10px' }}>
|
||||
<Text>{`Check if all is OK and click "Confirm"`}</Text>
|
||||
</div>
|
||||
|
||||
<Card style={{ marginBottom: '10px' }}>
|
||||
<Text>{`Device: ${props.device?.deviceType}`}</Text>
|
||||
<Text>{`Device IP: ${props.device?.deviceIp}`}</Text>
|
||||
<Text>{`Device OS: ${props.device?.deviceOs}`}</Text>
|
||||
<Text>{`Session ID: ${props.device?.sessionId}`}</Text>
|
||||
</Card>
|
||||
<div style={{ marginBottom: '10px' }}>
|
||||
<Text className="bp3-text-muted">
|
||||
{`Click "Back" if you need to change something`}
|
||||
</Text>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
85
app/components/StepsOfStepper/IntermediateStep.spec.tsx
Normal file
85
app/components/StepsOfStepper/IntermediateStep.spec.tsx
Normal file
@ -0,0 +1,85 @@
|
||||
import React from 'react';
|
||||
import Enzyme, { mount } from 'enzyme';
|
||||
import EnzymeToJson from 'enzyme-to-json';
|
||||
import Adapter from 'enzyme-adapter-react-16';
|
||||
import { BrowserRouter as Router } from 'react-router-dom';
|
||||
import IntermediateStep from './IntermediateStep';
|
||||
|
||||
Enzyme.configure({ adapter: new Adapter() });
|
||||
jest.useFakeTimers();
|
||||
|
||||
const confirmButtonSelector = 'button.bp3-button.bp3-intent-success';
|
||||
|
||||
function setup(
|
||||
activeStep = 0,
|
||||
resetDeviceMock = () => {},
|
||||
resetUserAllowedMock = () => {}
|
||||
) {
|
||||
const getWrapper = () =>
|
||||
mount(
|
||||
<>
|
||||
<Router>
|
||||
<IntermediateStep
|
||||
activeStep={activeStep}
|
||||
steps={['a', 'b', 'c']}
|
||||
handleNext={() => {}}
|
||||
handleBack={() => {}}
|
||||
handleNextEntireScreen={() => {}}
|
||||
handleNextApplicationWindow={() => {}}
|
||||
resetPendingConnectionDevice={resetDeviceMock}
|
||||
resetUserAllowedConnection={resetUserAllowedMock}
|
||||
/>
|
||||
</Router>
|
||||
</>
|
||||
);
|
||||
|
||||
const component = getWrapper();
|
||||
|
||||
const buttons = {
|
||||
confirmButton: component.find(confirmButtonSelector),
|
||||
};
|
||||
|
||||
return {
|
||||
component,
|
||||
buttons,
|
||||
};
|
||||
}
|
||||
|
||||
it('should match exact snapshot on each step', () => {
|
||||
for (let testActiveStep = 0; testActiveStep < 3; testActiveStep += 1) {
|
||||
const { component } = setup(
|
||||
testActiveStep,
|
||||
() => {},
|
||||
() => {}
|
||||
);
|
||||
expect(EnzymeToJson(component)).toMatchSnapshot();
|
||||
}
|
||||
});
|
||||
|
||||
it('should call resetPendingConnectionDevice when Confirm button clicked on confirm step', () => {
|
||||
const confirmStepNumber = 2;
|
||||
const mockResetPendingConnectionDeviceCallback = jest.fn();
|
||||
const { buttons } = setup(
|
||||
confirmStepNumber,
|
||||
mockResetPendingConnectionDeviceCallback,
|
||||
() => {}
|
||||
);
|
||||
|
||||
buttons.confirmButton.simulate('click');
|
||||
|
||||
expect(mockResetPendingConnectionDeviceCallback).toBeCalled();
|
||||
});
|
||||
|
||||
it('should call resetUserAllowedConnection when Confirm button clicked on confirm step', () => {
|
||||
const confirmStepNumber = 2;
|
||||
const mockResetUserAllowedConnectionCallback = jest.fn();
|
||||
const { buttons } = setup(
|
||||
confirmStepNumber,
|
||||
() => {},
|
||||
mockResetUserAllowedConnectionCallback
|
||||
);
|
||||
|
||||
buttons.confirmButton.simulate('click');
|
||||
|
||||
expect(mockResetUserAllowedConnectionCallback).toBeCalled();
|
||||
});
|
146
app/components/StepsOfStepper/IntermediateStep.tsx
Normal file
146
app/components/StepsOfStepper/IntermediateStep.tsx
Normal file
@ -0,0 +1,146 @@
|
||||
/* eslint-disable react/destructuring-assignment */
|
||||
import React, { useContext } from 'react';
|
||||
import { Button } from '@blueprintjs/core';
|
||||
import { Col } from 'react-flexbox-grid';
|
||||
import DEVICES from '../../constants/test-devices.json';
|
||||
import ScanQRStep from './ScanQRStep';
|
||||
import ChooseAppOrScreeenStep from './ChooseAppOrScreeenStep';
|
||||
import ConfirmStep from './ConfirmStep';
|
||||
import { ConnectedDevicesContext } from '../../containers/ConnectedDevicesProvider';
|
||||
|
||||
interface IntermediateStepProps {
|
||||
activeStep: number;
|
||||
steps: string[];
|
||||
handleNext: () => void;
|
||||
handleBack: () => void;
|
||||
handleNextEntireScreen: () => void;
|
||||
handleNextApplicationWindow: () => void;
|
||||
resetPendingConnectionDevice: () => void;
|
||||
resetUserAllowedConnection: () => void;
|
||||
}
|
||||
|
||||
function getStepContent(
|
||||
stepIndex: number,
|
||||
handleNextEntireScreen: () => void,
|
||||
handleNextApplicationWindow: () => void,
|
||||
pendingConnectionDevice: Device | null
|
||||
) {
|
||||
switch (stepIndex) {
|
||||
case 0:
|
||||
return <ScanQRStep />;
|
||||
case 1:
|
||||
return (
|
||||
<ChooseAppOrScreeenStep
|
||||
handleNextEntireScreen={handleNextEntireScreen}
|
||||
handleNextApplicationWindow={handleNextApplicationWindow}
|
||||
/>
|
||||
);
|
||||
case 2:
|
||||
return <ConfirmStep device={pendingConnectionDevice} />;
|
||||
default:
|
||||
return 'Unknown stepIndex';
|
||||
}
|
||||
}
|
||||
|
||||
function isConfirmStep(activeStep: number, steps: string[]) {
|
||||
return activeStep === steps.length - 1;
|
||||
}
|
||||
|
||||
export default function IntermediateStep(props: IntermediateStepProps) {
|
||||
const {
|
||||
devices,
|
||||
setPendingConnectionDeviceHook,
|
||||
setDevicesHook,
|
||||
pendingConnectionDevice,
|
||||
resetPendingConnectionDeviceHook,
|
||||
} = useContext(ConnectedDevicesContext);
|
||||
|
||||
const connectDevice = (device: Device) => {
|
||||
setPendingConnectionDeviceHook(device);
|
||||
};
|
||||
|
||||
return (
|
||||
<Col
|
||||
xs={12}
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
height: '260px',
|
||||
}}
|
||||
>
|
||||
{getStepContent(
|
||||
props.activeStep,
|
||||
props.handleNextEntireScreen,
|
||||
props.handleNextApplicationWindow,
|
||||
pendingConnectionDevice
|
||||
)}
|
||||
|
||||
{
|
||||
/* TODO: (REMOVE: process.env.NODE_ENV === 'production') !!!!!!!!!)
|
||||
Connect Test Device button, displayed only when RUN_MODE is 'dev' or 'test' */
|
||||
props.activeStep === 0 &&
|
||||
(process.env.RUN_MODE === 'dev' ||
|
||||
process.env.RUN_MODE === 'test' ||
|
||||
process.env.NODE_ENV === 'production') ? (
|
||||
// eslint-disable-next-line react/jsx-indent
|
||||
<Button
|
||||
onClick={() => {
|
||||
connectDevice(
|
||||
DEVICES[Math.floor(Math.random() * DEVICES.length)]
|
||||
);
|
||||
}}
|
||||
>
|
||||
Connect Test Device
|
||||
</Button>
|
||||
) : (
|
||||
<></>
|
||||
)
|
||||
}
|
||||
{
|
||||
/**/
|
||||
props.activeStep !== 0 ? (
|
||||
<Button
|
||||
intent={props.activeStep === 2 ? 'success' : 'none'}
|
||||
onClick={() => {
|
||||
props.handleNext();
|
||||
if (isConfirmStep(props.activeStep, props.steps)) {
|
||||
setDevicesHook([...devices, pendingConnectionDevice as Device]);
|
||||
resetPendingConnectionDeviceHook();
|
||||
props.resetPendingConnectionDevice();
|
||||
props.resetUserAllowedConnection();
|
||||
}
|
||||
}}
|
||||
style={{
|
||||
display: props.activeStep === 1 ? 'none' : 'inline',
|
||||
borderRadius: '100px',
|
||||
width: '100%',
|
||||
textAlign: 'center',
|
||||
}}
|
||||
rightIcon={
|
||||
isConfirmStep(props.activeStep, props.steps)
|
||||
? 'small-tick'
|
||||
: 'chevron-right'
|
||||
}
|
||||
>
|
||||
{isConfirmStep(props.activeStep, props.steps) ? 'Confirm' : 'Next'}
|
||||
</Button>
|
||||
) : (
|
||||
<></>
|
||||
)
|
||||
}
|
||||
<Button
|
||||
intent="danger"
|
||||
style={{
|
||||
marginTop: '10px',
|
||||
display: props.activeStep === 2 ? 'inline-block' : 'none',
|
||||
borderRadius: '100px',
|
||||
}}
|
||||
onClick={props.handleBack}
|
||||
icon="chevron-left"
|
||||
text="No, I need to share other thing"
|
||||
/>
|
||||
</Col>
|
||||
);
|
||||
}
|
77
app/components/StepsOfStepper/ScanQRStep.spec.tsx
Normal file
77
app/components/StepsOfStepper/ScanQRStep.spec.tsx
Normal file
@ -0,0 +1,77 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
/* eslint-disable @typescript-eslint/ban-types */
|
||||
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
||||
import React from 'react';
|
||||
import Enzyme from 'enzyme';
|
||||
import EnzymeToJson from 'enzyme-to-json';
|
||||
import Adapter from 'enzyme-adapter-react-16';
|
||||
import ScanQRStep from './ScanQRStep';
|
||||
|
||||
Enzyme.configure({ adapter: new Adapter() });
|
||||
jest.useFakeTimers();
|
||||
|
||||
const bp3QRCodeDialogRootSelector = '#bp3-qr-code-dialog-root';
|
||||
const magnifyQRCodeButtonSelector = '#magnify-qr-code-button';
|
||||
const qrCodeDialogInnerSelector = '#qr-code-dialog-inner';
|
||||
|
||||
type EnzymeShallowWrapper =
|
||||
| Enzyme.CommonWrapper<{}, {}, React.Component<{}, {}, any>>
|
||||
| Cheerio
|
||||
| Enzyme.ShallowWrapper<any, Readonly<{}>, React.Component<{}, {}, any>>;
|
||||
|
||||
describe('<ScanQRStep />', () => {
|
||||
let wrapper: EnzymeShallowWrapper;
|
||||
|
||||
beforeEach(() => {
|
||||
wrapper = Enzyme.shallow(<ScanQRStep />);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('when rendered', () => {
|
||||
it('should match exact snapshot', () => {
|
||||
expect(EnzymeToJson(wrapper)).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when user clicks on magnify QR code button', () => {
|
||||
it('should set "QR Code Dialog Root" isOpen property to "true"', () => {
|
||||
// @ts-ignore
|
||||
wrapper.find(magnifyQRCodeButtonSelector).props().onClick();
|
||||
// @ts-ignore
|
||||
expect(wrapper.find(bp3QRCodeDialogRootSelector).props().isOpen).toBe(
|
||||
true
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe(`when magnified QR code dialog is opened,
|
||||
and when user closes magnified QR code dialog`, () => {
|
||||
it('should set "QR Code Dialog Root" isOpen property to "false"', () => {
|
||||
// @ts-ignore
|
||||
wrapper.find(magnifyQRCodeButtonSelector).props().onClick();
|
||||
// @ts-ignore
|
||||
wrapper.find(bp3QRCodeDialogRootSelector).props().onClose();
|
||||
// @ts-ignore
|
||||
expect(wrapper.find(bp3QRCodeDialogRootSelector).props().isOpen).toBe(
|
||||
false
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe(`when magnified QR code dialog is opened,
|
||||
and when user clicks on qr code dialog inner`, () => {
|
||||
it('should set "QR Code Dialog Root" isOpen property to "false"', () => {
|
||||
// @ts-ignore
|
||||
wrapper.find(magnifyQRCodeButtonSelector).props().onClick();
|
||||
// @ts-ignore
|
||||
wrapper.find(qrCodeDialogInnerSelector).props().onClick();
|
||||
// @ts-ignore
|
||||
expect(wrapper.find(bp3QRCodeDialogRootSelector).props().isOpen).toBe(
|
||||
false
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
155
app/components/StepsOfStepper/ScanQRStep.tsx
Normal file
155
app/components/StepsOfStepper/ScanQRStep.tsx
Normal file
@ -0,0 +1,155 @@
|
||||
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
||||
/* eslint-disable jsx-a11y/click-events-have-key-events */
|
||||
/* eslint-disable jsx-a11y/no-static-element-interactions */
|
||||
import React, { useContext, useState } from 'react';
|
||||
import { Button, Text, Tooltip, Position, H2, Dialog } from '@blueprintjs/core';
|
||||
import QRCode from 'qrcode.react';
|
||||
import { makeStyles, createStyles } from '@material-ui/core';
|
||||
import { Row, Col } from 'react-flexbox-grid';
|
||||
import { SettingsContext } from '../../containers/SettingsProvider';
|
||||
import isProduction from '../../utils/isProduction';
|
||||
import CloseOverlayButton from '../CloseOverlayButton';
|
||||
|
||||
const internalIp = require('internal-ip');
|
||||
|
||||
const useStyles = makeStyles(() =>
|
||||
createStyles({
|
||||
smallQRCode: {
|
||||
border: '1px solid',
|
||||
borderColor: 'rgba(0,0,0,0.0)',
|
||||
padding: '10px',
|
||||
borderRadius: '10px',
|
||||
'&:hover': {
|
||||
backgroundColor: 'rgba(0,0,0,0.12)',
|
||||
border: '1px solid #8A9BA8',
|
||||
cursor: 'zoom-in',
|
||||
},
|
||||
},
|
||||
dialogQRWrapper: {
|
||||
backgroundColor: 'white',
|
||||
padding: '20px',
|
||||
borderRadius: '10px',
|
||||
},
|
||||
bigQRCodeDialogRoot: {
|
||||
'&:hover': {
|
||||
cursor: 'zoom-out',
|
||||
},
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
const ScanQRStep: React.FC = () => {
|
||||
const classes = useStyles();
|
||||
const { isDarkTheme } = useContext(SettingsContext);
|
||||
|
||||
const [isQRCodeMagnified, setIsQRCodeMagnified] = useState(false);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div style={{ textAlign: 'center' }}>
|
||||
<Text className="bp3-text">Scan the QR code</Text>
|
||||
<Text className="bp3-text-muted">
|
||||
( make sure your computer and device are connected on same WiFi )
|
||||
</Text>
|
||||
</div>
|
||||
<div>
|
||||
<Tooltip content="Click to make bigger" position={Position.LEFT}>
|
||||
<div
|
||||
id="magnify-qr-code-button"
|
||||
className={classes.smallQRCode}
|
||||
onClick={() => setIsQRCodeMagnified(true)}
|
||||
>
|
||||
<QRCode
|
||||
value={`http://${internalIp.v4.sync()}:65000/99999`}
|
||||
level="H"
|
||||
renderAs="svg"
|
||||
// bgColor={isDarkTheme ? '#293742' : '#ffffff'}
|
||||
bgColor="rgba(0,0,0,0.0)"
|
||||
fgColor={isDarkTheme ? '#ffffff' : '#000000'}
|
||||
imageSettings={{
|
||||
// src: `data:image/png;base64, ${contents}`,
|
||||
src:
|
||||
'https://upload.wikimedia.org/wikipedia/commons/thumb/9/91/Electron_Software_Framework_Logo.svg/256px-Electron_Software_Framework_Logo.svg.png',
|
||||
width: 40,
|
||||
height: 40,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<div style={{ marginBottom: '10px' }}>
|
||||
<Text className="bp3-text-muted">
|
||||
or type the following address manualy in browser address bar on any
|
||||
device:
|
||||
</Text>
|
||||
</div>
|
||||
|
||||
<Tooltip content="Click to copy" position={Position.LEFT}>
|
||||
<Button
|
||||
intent="primary"
|
||||
icon="duplicate"
|
||||
style={{ borderRadius: '100px' }}
|
||||
>
|
||||
http://255.255.255.255:65000/99999
|
||||
</Button>
|
||||
</Tooltip>
|
||||
|
||||
<Dialog
|
||||
// @ts-ignore
|
||||
id="bp3-qr-code-dialog-root"
|
||||
className={classes.bigQRCodeDialogRoot}
|
||||
isOpen={isQRCodeMagnified}
|
||||
onClose={() => setIsQRCodeMagnified(false)}
|
||||
canEscapeKeyClose
|
||||
canOutsideClickClose
|
||||
transitionDuration={isProduction() ? 700 : 0}
|
||||
style={{ position: 'relative', top: '-30px' }}
|
||||
>
|
||||
<div
|
||||
id="qr-code-dialog-inner"
|
||||
onClick={() => setIsQRCodeMagnified(false)}
|
||||
style={{ paddingTop: '20px', paddingBottom: '13px' }}
|
||||
>
|
||||
<Row between="xs" middle="xs">
|
||||
<Col xs={10}>
|
||||
<H2 style={{ margin: '0px', padding: '0px', marginLeft: '35px' }}>
|
||||
Scan QR Code
|
||||
</H2>
|
||||
</Col>
|
||||
<Col xs={2}>
|
||||
<CloseOverlayButton
|
||||
onClick={() => setIsQRCodeMagnified(false)}
|
||||
style={{
|
||||
width: '40px',
|
||||
height: '40px',
|
||||
position: 'relative',
|
||||
borderRadius: '100px',
|
||||
}}
|
||||
noDefaultStyles
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row center="xs">
|
||||
<div className={classes.dialogQRWrapper}>
|
||||
<QRCode
|
||||
value={`http://${internalIp.v4.sync()}:65000/99999`}
|
||||
level="H"
|
||||
renderAs="svg"
|
||||
imageSettings={{
|
||||
src:
|
||||
'https://upload.wikimedia.org/wikipedia/commons/thumb/9/91/Electron_Software_Framework_Logo.svg/256px-Electron_Software_Framework_Logo.svg.png',
|
||||
width: 25,
|
||||
height: 25,
|
||||
}}
|
||||
width="390px"
|
||||
height="390px"
|
||||
/>
|
||||
</div>
|
||||
</Row>
|
||||
</div>
|
||||
</Dialog>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default ScanQRStep;
|
49
app/components/StepsOfStepper/SuccessStep.spec.tsx
Normal file
49
app/components/StepsOfStepper/SuccessStep.spec.tsx
Normal file
@ -0,0 +1,49 @@
|
||||
import React from 'react';
|
||||
import Enzyme, { mount } from 'enzyme';
|
||||
import EnzymeToJson from 'enzyme-to-json';
|
||||
import Adapter from 'enzyme-adapter-react-16';
|
||||
import { BrowserRouter as Router } from 'react-router-dom';
|
||||
import SuccessStep from './SuccessStep';
|
||||
|
||||
Enzyme.configure({ adapter: new Adapter() });
|
||||
jest.useFakeTimers();
|
||||
|
||||
const connectNewDeviceButtonSelector = 'button.bp3-button.bp3-intent-primary';
|
||||
|
||||
function setup(handleResetMock = () => {}) {
|
||||
const getWrapper = () =>
|
||||
mount(
|
||||
<>
|
||||
<Router>
|
||||
<SuccessStep handleReset={handleResetMock} />
|
||||
</Router>
|
||||
</>
|
||||
);
|
||||
|
||||
const component = getWrapper();
|
||||
|
||||
const buttons = {
|
||||
connectNewDeviceButton: component.find(connectNewDeviceButtonSelector),
|
||||
};
|
||||
|
||||
return {
|
||||
component,
|
||||
buttons,
|
||||
};
|
||||
}
|
||||
|
||||
it('should match exact snapshot', () => {
|
||||
const { component } = setup();
|
||||
expect(EnzymeToJson(component)).toMatchSnapshot();
|
||||
});
|
||||
|
||||
describe('when "Connect New Device" button is clicked', () => {
|
||||
it('should call handleReset injected functional property', () => {
|
||||
const mockHandleResetCallback = jest.fn();
|
||||
const { buttons } = setup(mockHandleResetCallback);
|
||||
|
||||
buttons.connectNewDeviceButton.simulate('click');
|
||||
|
||||
expect(mockHandleResetCallback).toBeCalled();
|
||||
});
|
||||
});
|
93
app/components/StepsOfStepper/SuccessStep.tsx
Normal file
93
app/components/StepsOfStepper/SuccessStep.tsx
Normal file
@ -0,0 +1,93 @@
|
||||
/* eslint-disable react/destructuring-assignment */
|
||||
import React, { useCallback, useEffect } from 'react';
|
||||
import { Button, H5, Icon, Text } from '@blueprintjs/core';
|
||||
import { Row, Col } from 'react-flexbox-grid';
|
||||
|
||||
interface SuccessStepProps {
|
||||
handleReset: () => void;
|
||||
}
|
||||
|
||||
const SuccessStep: React.FC<SuccessStepProps> = (props: SuccessStepProps) => {
|
||||
useEffect(() => {
|
||||
document
|
||||
.querySelector('#top-panel-connected-devices-list-button')
|
||||
?.classList.remove('pulse-not-infinite');
|
||||
|
||||
document
|
||||
.querySelector('#top-panel-connected-devices-list-button')
|
||||
?.classList.add('pulse-not-infinite');
|
||||
|
||||
setTimeout(() => {
|
||||
document
|
||||
.querySelector('#top-panel-connected-devices-list-button')
|
||||
?.classList.remove('pulse-not-infinite');
|
||||
}, 4000);
|
||||
}, []);
|
||||
|
||||
const handleTextConnectedListMouseEnter = useCallback(() => {
|
||||
document
|
||||
.querySelector('#top-panel-connected-devices-list-button')
|
||||
?.classList.add('pulsing');
|
||||
}, []);
|
||||
|
||||
const handleTextConnectedListMouseLeave = useCallback(() => {
|
||||
document
|
||||
.querySelector('#top-panel-connected-devices-list-button')
|
||||
?.classList.remove('pulsing');
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Col
|
||||
xs={8}
|
||||
md={6}
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'center',
|
||||
}}
|
||||
>
|
||||
<Row center="xs">
|
||||
<Col xs={12}>
|
||||
<Icon icon="endorsed" iconSize={35} color="#0F9960" />
|
||||
<H5>Success!</H5>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row center="xs">
|
||||
<Col xs={10}>
|
||||
<div style={{ marginBottom: '10px' }}>
|
||||
<Text>
|
||||
{`You should see now sharing session started on device you've connected
|
||||
with.`}
|
||||
</Text>
|
||||
</div>
|
||||
<div
|
||||
id="connected-devices-list-text-success"
|
||||
onMouseEnter={handleTextConnectedListMouseEnter}
|
||||
onMouseLeave={handleTextConnectedListMouseLeave}
|
||||
style={{
|
||||
marginBottom: '25px',
|
||||
textDecoration: 'underline dotted',
|
||||
}}
|
||||
>
|
||||
<Text className="">
|
||||
{`
|
||||
You can manage connected devices by clicking "Connected Devices"
|
||||
button in top panel
|
||||
`}
|
||||
</Text>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
<Button
|
||||
intent="primary"
|
||||
onClick={props.handleReset}
|
||||
icon="repeat"
|
||||
style={{ borderRadius: '100px' }}
|
||||
>
|
||||
Connect New Device
|
||||
</Button>
|
||||
</Col>
|
||||
);
|
||||
};
|
||||
|
||||
export default SuccessStep;
|
@ -0,0 +1,250 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`should match exact snapshot 1`] = `
|
||||
<BrowserRouter>
|
||||
<Router
|
||||
history={
|
||||
Object {
|
||||
"action": "POP",
|
||||
"block": [Function],
|
||||
"createHref": [Function],
|
||||
"go": [Function],
|
||||
"goBack": [Function],
|
||||
"goForward": [Function],
|
||||
"length": 1,
|
||||
"listen": [Function],
|
||||
"location": Object {
|
||||
"hash": "",
|
||||
"pathname": "/",
|
||||
"search": "",
|
||||
"state": undefined,
|
||||
},
|
||||
"push": [Function],
|
||||
"replace": [Function],
|
||||
}
|
||||
}
|
||||
>
|
||||
<ChooseAppOrScreeenStep
|
||||
handleNextApplicationWindow={[Function]}
|
||||
handleNextEntireScreen={[Function]}
|
||||
>
|
||||
<div
|
||||
style={
|
||||
Object {
|
||||
"marginBottom": "10px",
|
||||
}
|
||||
}
|
||||
>
|
||||
<Blueprint3.Text>
|
||||
<div
|
||||
className=""
|
||||
>
|
||||
Choose Entire Screen or App window you want to view on other device
|
||||
</div>
|
||||
</Blueprint3.Text>
|
||||
</div>
|
||||
<ShareEntireScreenOrAppWindowControlGroup
|
||||
handleNextApplicationWindow={[Function]}
|
||||
handleNextEntireScreen={[Function]}
|
||||
>
|
||||
<Blueprint3.ControlGroup
|
||||
className="makeStyles-controlGroupRoot-1"
|
||||
fill={true}
|
||||
id="share-screen-or-app-btn-group"
|
||||
vertical={false}
|
||||
>
|
||||
<div
|
||||
className="bp3-control-group bp3-fill makeStyles-controlGroupRoot-1"
|
||||
id="share-screen-or-app-btn-group"
|
||||
>
|
||||
<Blueprint3.Button
|
||||
className="makeStyles-shareEntireScreenButton-2"
|
||||
intent="primary"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<button
|
||||
className="bp3-button bp3-intent-primary makeStyles-shareEntireScreenButton-2"
|
||||
onClick={[Function]}
|
||||
onKeyDown={[Function]}
|
||||
onKeyUp={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<Blueprint3.Icon
|
||||
key="leftIcon"
|
||||
/>
|
||||
<span
|
||||
className="bp3-button-text"
|
||||
key="text"
|
||||
>
|
||||
<Blueprint3.Icon
|
||||
className="makeStyles-shareEntireScreenButtonIcon-3"
|
||||
color="white"
|
||||
icon="desktop"
|
||||
iconSize={100}
|
||||
>
|
||||
<span
|
||||
className="bp3-icon bp3-icon-desktop makeStyles-shareEntireScreenButtonIcon-3"
|
||||
icon="desktop"
|
||||
>
|
||||
<svg
|
||||
data-icon="desktop"
|
||||
fill="white"
|
||||
height={100}
|
||||
viewBox="0 0 20 20"
|
||||
width={100}
|
||||
>
|
||||
<desc>
|
||||
desktop
|
||||
</desc>
|
||||
<path
|
||||
d="M19 0H1C.45 0 0 .45 0 1v13c0 .55.45 1 1 1h5.67l-.5 3H5c-.55 0-1 .45-1 1s.45 1 1 1h10c.55 0 1-.45 1-1s-.45-1-1-1h-1.17l-.5-3H19c.55 0 1-.45 1-1V1c0-.55-.45-1-1-1zm-1 13H2V2h16v11z"
|
||||
fillRule="evenodd"
|
||||
key="0"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</Blueprint3.Icon>
|
||||
<Blueprint3.Text
|
||||
className="bp3-running-text"
|
||||
>
|
||||
<div
|
||||
className="bp3-running-text"
|
||||
>
|
||||
Entire Screen
|
||||
</div>
|
||||
</Blueprint3.Text>
|
||||
</span>
|
||||
<Blueprint3.Icon
|
||||
key="rightIcon"
|
||||
/>
|
||||
</button>
|
||||
</Blueprint3.Button>
|
||||
<Blueprint3.Button
|
||||
className="makeStyles-shareAppButton-4"
|
||||
intent="primary"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<button
|
||||
className="bp3-button bp3-intent-primary makeStyles-shareAppButton-4"
|
||||
onClick={[Function]}
|
||||
onKeyDown={[Function]}
|
||||
onKeyUp={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<Blueprint3.Icon
|
||||
key="leftIcon"
|
||||
/>
|
||||
<span
|
||||
className="bp3-button-text"
|
||||
key="text"
|
||||
>
|
||||
<Blueprint3.Icon
|
||||
className="makeStyles-shareAppButtonIcon-5"
|
||||
color="white"
|
||||
icon="application"
|
||||
iconSize={100}
|
||||
>
|
||||
<span
|
||||
className="bp3-icon bp3-icon-application makeStyles-shareAppButtonIcon-5"
|
||||
icon="application"
|
||||
>
|
||||
<svg
|
||||
data-icon="application"
|
||||
fill="white"
|
||||
height={100}
|
||||
viewBox="0 0 20 20"
|
||||
width={100}
|
||||
>
|
||||
<desc>
|
||||
application
|
||||
</desc>
|
||||
<path
|
||||
d="M3.5 9h9c.28 0 .5-.22.5-.5s-.22-.5-.5-.5h-9c-.28 0-.5.22-.5.5s.22.5.5.5zm0 2h5c.28 0 .5-.22.5-.5s-.22-.5-.5-.5h-5c-.28 0-.5.22-.5.5s.22.5.5.5zM19 1H1c-.55 0-1 .45-1 1v16c0 .55.45 1 1 1h18c.55 0 1-.45 1-1V2c0-.55-.45-1-1-1zm-1 16H2V6h16v11zM3.5 13h7c.28 0 .5-.22.5-.5s-.22-.5-.5-.5h-7c-.28 0-.5.22-.5.5s.22.5.5.5z"
|
||||
fillRule="evenodd"
|
||||
key="0"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</Blueprint3.Icon>
|
||||
<Blueprint3.Text
|
||||
className="bp3-running-text"
|
||||
>
|
||||
<div
|
||||
className="bp3-running-text"
|
||||
>
|
||||
Application Window
|
||||
</div>
|
||||
</Blueprint3.Text>
|
||||
</span>
|
||||
<Blueprint3.Icon
|
||||
key="rightIcon"
|
||||
/>
|
||||
</button>
|
||||
</Blueprint3.Button>
|
||||
<Blueprint3.Button
|
||||
active={true}
|
||||
className="makeStyles-orDecorationButton-6"
|
||||
>
|
||||
<button
|
||||
className="bp3-button bp3-active makeStyles-orDecorationButton-6"
|
||||
onKeyDown={[Function]}
|
||||
onKeyUp={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<Blueprint3.Icon
|
||||
key="leftIcon"
|
||||
/>
|
||||
<span
|
||||
className="bp3-button-text"
|
||||
key="text"
|
||||
>
|
||||
OR
|
||||
</span>
|
||||
<Blueprint3.Icon
|
||||
key="rightIcon"
|
||||
/>
|
||||
</button>
|
||||
</Blueprint3.Button>
|
||||
</div>
|
||||
</Blueprint3.ControlGroup>
|
||||
<ChooseAppOrScreenOverlay
|
||||
handleClose={[Function]}
|
||||
handleNextApplicationWindow={[Function]}
|
||||
handleNextEntireScreen={[Function]}
|
||||
isChooseAppOrScreenOverlayOpen={false}
|
||||
isEntireScreenToShareChosen={false}
|
||||
>
|
||||
<Blueprint3.Dialog
|
||||
autoFocus={true}
|
||||
canEscapeKeyClose={true}
|
||||
canOutsideClickClose={true}
|
||||
className="makeStyles-dialogRoot-7 choose-app-or-screen-dialog"
|
||||
enforceFocus={true}
|
||||
hasBackdrop={true}
|
||||
isOpen={false}
|
||||
onClose={[Function]}
|
||||
transitionDuration={0}
|
||||
usePortal={true}
|
||||
>
|
||||
<Blueprint3.Overlay
|
||||
autoFocus={true}
|
||||
backdropProps={Object {}}
|
||||
canEscapeKeyClose={true}
|
||||
canOutsideClickClose={true}
|
||||
className="bp3-overlay-scroll-container"
|
||||
enforceFocus={true}
|
||||
hasBackdrop={true}
|
||||
isOpen={false}
|
||||
lazy={true}
|
||||
onClose={[Function]}
|
||||
transitionDuration={0}
|
||||
transitionName="bp3-overlay"
|
||||
usePortal={true}
|
||||
/>
|
||||
</Blueprint3.Dialog>
|
||||
</ChooseAppOrScreenOverlay>
|
||||
</ShareEntireScreenOrAppWindowControlGroup>
|
||||
</ChooseAppOrScreeenStep>
|
||||
</Router>
|
||||
</BrowserRouter>
|
||||
`;
|
@ -0,0 +1,112 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`should match exact snapshot 1`] = `
|
||||
<BrowserRouter>
|
||||
<Router
|
||||
history={
|
||||
Object {
|
||||
"action": "POP",
|
||||
"block": [Function],
|
||||
"createHref": [Function],
|
||||
"go": [Function],
|
||||
"goBack": [Function],
|
||||
"goForward": [Function],
|
||||
"length": 1,
|
||||
"listen": [Function],
|
||||
"location": Object {
|
||||
"hash": "",
|
||||
"pathname": "/",
|
||||
"search": "",
|
||||
"state": undefined,
|
||||
},
|
||||
"push": [Function],
|
||||
"replace": [Function],
|
||||
}
|
||||
}
|
||||
>
|
||||
<ConfirmStep
|
||||
device={Object {}}
|
||||
>
|
||||
<div
|
||||
style={
|
||||
Object {
|
||||
"marginBottom": "10px",
|
||||
}
|
||||
}
|
||||
>
|
||||
<Blueprint3.Text>
|
||||
<div
|
||||
className=""
|
||||
>
|
||||
Check if all is OK and click "Confirm"
|
||||
</div>
|
||||
</Blueprint3.Text>
|
||||
</div>
|
||||
<Blueprint3.Card
|
||||
elevation={0}
|
||||
interactive={false}
|
||||
style={
|
||||
Object {
|
||||
"marginBottom": "10px",
|
||||
}
|
||||
}
|
||||
>
|
||||
<div
|
||||
className="bp3-card bp3-elevation-0"
|
||||
style={
|
||||
Object {
|
||||
"marginBottom": "10px",
|
||||
}
|
||||
}
|
||||
>
|
||||
<Blueprint3.Text>
|
||||
<div
|
||||
className=""
|
||||
>
|
||||
Device: undefined
|
||||
</div>
|
||||
</Blueprint3.Text>
|
||||
<Blueprint3.Text>
|
||||
<div
|
||||
className=""
|
||||
>
|
||||
Device IP: undefined
|
||||
</div>
|
||||
</Blueprint3.Text>
|
||||
<Blueprint3.Text>
|
||||
<div
|
||||
className=""
|
||||
>
|
||||
Device OS: undefined
|
||||
</div>
|
||||
</Blueprint3.Text>
|
||||
<Blueprint3.Text>
|
||||
<div
|
||||
className=""
|
||||
>
|
||||
Session ID: undefined
|
||||
</div>
|
||||
</Blueprint3.Text>
|
||||
</div>
|
||||
</Blueprint3.Card>
|
||||
<div
|
||||
style={
|
||||
Object {
|
||||
"marginBottom": "10px",
|
||||
}
|
||||
}
|
||||
>
|
||||
<Blueprint3.Text
|
||||
className="bp3-text-muted"
|
||||
>
|
||||
<div
|
||||
className="bp3-text-muted"
|
||||
>
|
||||
Click "Back" if you need to change something
|
||||
</div>
|
||||
</Blueprint3.Text>
|
||||
</div>
|
||||
</ConfirmStep>
|
||||
</Router>
|
||||
</BrowserRouter>
|
||||
`;
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,177 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<ScanQRStep /> when rendered should match exact snapshot 1`] = `
|
||||
<Fragment>
|
||||
<div
|
||||
style={
|
||||
Object {
|
||||
"textAlign": "center",
|
||||
}
|
||||
}
|
||||
>
|
||||
<Blueprint3.Text
|
||||
className="bp3-text"
|
||||
>
|
||||
Scan the QR code
|
||||
</Blueprint3.Text>
|
||||
<Blueprint3.Text
|
||||
className="bp3-text-muted"
|
||||
>
|
||||
( make sure your computer and device are connected on same WiFi )
|
||||
</Blueprint3.Text>
|
||||
</div>
|
||||
<div>
|
||||
<Blueprint3.Tooltip
|
||||
content="Click to make bigger"
|
||||
hoverCloseDelay={0}
|
||||
hoverOpenDelay={100}
|
||||
position="left"
|
||||
transitionDuration={100}
|
||||
>
|
||||
<div
|
||||
className="makeStyles-smallQRCode-1"
|
||||
id="magnify-qr-code-button"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<QRCode
|
||||
bgColor="rgba(0,0,0,0.0)"
|
||||
fgColor="#000000"
|
||||
imageSettings={
|
||||
Object {
|
||||
"height": 40,
|
||||
"src": "https://upload.wikimedia.org/wikipedia/commons/thumb/9/91/Electron_Software_Framework_Logo.svg/256px-Electron_Software_Framework_Logo.svg.png",
|
||||
"width": 40,
|
||||
}
|
||||
}
|
||||
includeMargin={false}
|
||||
level="H"
|
||||
renderAs="svg"
|
||||
size={128}
|
||||
value="http://192.168.31.214:65000/99999"
|
||||
/>
|
||||
</div>
|
||||
</Blueprint3.Tooltip>
|
||||
</div>
|
||||
<div
|
||||
style={
|
||||
Object {
|
||||
"marginBottom": "10px",
|
||||
}
|
||||
}
|
||||
>
|
||||
<Blueprint3.Text
|
||||
className="bp3-text-muted"
|
||||
>
|
||||
or type the following address manualy in browser address bar on any device:
|
||||
</Blueprint3.Text>
|
||||
</div>
|
||||
<Blueprint3.Tooltip
|
||||
content="Click to copy"
|
||||
hoverCloseDelay={0}
|
||||
hoverOpenDelay={100}
|
||||
position="left"
|
||||
transitionDuration={100}
|
||||
>
|
||||
<Blueprint3.Button
|
||||
icon="duplicate"
|
||||
intent="primary"
|
||||
style={
|
||||
Object {
|
||||
"borderRadius": "100px",
|
||||
}
|
||||
}
|
||||
>
|
||||
http://255.255.255.255:65000/99999
|
||||
</Blueprint3.Button>
|
||||
</Blueprint3.Tooltip>
|
||||
<Blueprint3.Dialog
|
||||
canEscapeKeyClose={true}
|
||||
canOutsideClickClose={true}
|
||||
className="makeStyles-bigQRCodeDialogRoot-3"
|
||||
id="bp3-qr-code-dialog-root"
|
||||
isOpen={false}
|
||||
onClose={[Function]}
|
||||
style={
|
||||
Object {
|
||||
"position": "relative",
|
||||
"top": "-30px",
|
||||
}
|
||||
}
|
||||
transitionDuration={0}
|
||||
>
|
||||
<div
|
||||
id="qr-code-dialog-inner"
|
||||
onClick={[Function]}
|
||||
style={
|
||||
Object {
|
||||
"paddingBottom": "13px",
|
||||
"paddingTop": "20px",
|
||||
}
|
||||
}
|
||||
>
|
||||
<Row
|
||||
between="xs"
|
||||
middle="xs"
|
||||
>
|
||||
<Col
|
||||
xs={10}
|
||||
>
|
||||
<Component
|
||||
style={
|
||||
Object {
|
||||
"margin": "0px",
|
||||
"marginLeft": "35px",
|
||||
"padding": "0px",
|
||||
}
|
||||
}
|
||||
>
|
||||
Scan QR Code
|
||||
</Component>
|
||||
</Col>
|
||||
<Col
|
||||
xs={2}
|
||||
>
|
||||
<CloseOverlayButton
|
||||
noDefaultStyles={true}
|
||||
onClick={[Function]}
|
||||
style={
|
||||
Object {
|
||||
"borderRadius": "100px",
|
||||
"height": "40px",
|
||||
"position": "relative",
|
||||
"width": "40px",
|
||||
}
|
||||
}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row
|
||||
center="xs"
|
||||
>
|
||||
<div
|
||||
className="makeStyles-dialogQRWrapper-2"
|
||||
>
|
||||
<QRCode
|
||||
bgColor="#FFFFFF"
|
||||
fgColor="#000000"
|
||||
height="390px"
|
||||
imageSettings={
|
||||
Object {
|
||||
"height": 25,
|
||||
"src": "https://upload.wikimedia.org/wikipedia/commons/thumb/9/91/Electron_Software_Framework_Logo.svg/256px-Electron_Software_Framework_Logo.svg.png",
|
||||
"width": 25,
|
||||
}
|
||||
}
|
||||
includeMargin={false}
|
||||
level="H"
|
||||
renderAs="svg"
|
||||
size={128}
|
||||
value="http://192.168.31.214:65000/99999"
|
||||
width="390px"
|
||||
/>
|
||||
</div>
|
||||
</Row>
|
||||
</div>
|
||||
</Blueprint3.Dialog>
|
||||
</Fragment>
|
||||
`;
|
@ -0,0 +1,220 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`should match exact snapshot 1`] = `
|
||||
<BrowserRouter>
|
||||
<Router
|
||||
history={
|
||||
Object {
|
||||
"action": "POP",
|
||||
"block": [Function],
|
||||
"createHref": [Function],
|
||||
"go": [Function],
|
||||
"goBack": [Function],
|
||||
"goForward": [Function],
|
||||
"length": 1,
|
||||
"listen": [Function],
|
||||
"location": Object {
|
||||
"hash": "",
|
||||
"pathname": "/",
|
||||
"search": "",
|
||||
"state": undefined,
|
||||
},
|
||||
"push": [Function],
|
||||
"replace": [Function],
|
||||
}
|
||||
}
|
||||
>
|
||||
<SuccessStep
|
||||
handleReset={[Function]}
|
||||
>
|
||||
<Col
|
||||
md={6}
|
||||
style={
|
||||
Object {
|
||||
"display": "flex",
|
||||
"flexDirection": "column",
|
||||
"justifyContent": "center",
|
||||
}
|
||||
}
|
||||
xs={8}
|
||||
>
|
||||
<div
|
||||
className="col-xs-8 col-md-6"
|
||||
style={
|
||||
Object {
|
||||
"display": "flex",
|
||||
"flexDirection": "column",
|
||||
"justifyContent": "center",
|
||||
}
|
||||
}
|
||||
>
|
||||
<Row
|
||||
center="xs"
|
||||
>
|
||||
<div
|
||||
className="row center-xs"
|
||||
>
|
||||
<Col
|
||||
xs={12}
|
||||
>
|
||||
<div
|
||||
className="col-xs-12"
|
||||
>
|
||||
<Blueprint3.Icon
|
||||
color="#0F9960"
|
||||
icon="endorsed"
|
||||
iconSize={35}
|
||||
>
|
||||
<span
|
||||
className="bp3-icon bp3-icon-endorsed"
|
||||
icon="endorsed"
|
||||
>
|
||||
<svg
|
||||
data-icon="endorsed"
|
||||
fill="#0F9960"
|
||||
height={35}
|
||||
viewBox="0 0 20 20"
|
||||
width={35}
|
||||
>
|
||||
<desc>
|
||||
endorsed
|
||||
</desc>
|
||||
<path
|
||||
d="M19.83 9.38L18.81 7.6V5.62c0-.45-.23-.85-.61-1.08l-1.71-1-1.02-1.76a1.25 1.25 0 00-1.08-.61h-2.03l-1.74-1c-.38-.23-.87-.23-1.25 0l-1.74 1H5.65c-.44 0-.85.23-1.08.61L3.58 3.5l-1.8 1.04c-.38.24-.62.64-.62 1.08v2.06L.17 9.4c-.11.19-.17.4-.17.61s.06.42.17.61l.99 1.72v2.06c0 .45.23.85.61 1.08l1.78 1.02.99 1.72c.23.38.63.61 1.08.61h1.99l1.74 1c.19.11.41.17.62.17.21 0 .42-.06.61-.17l1.74-1h2.03c.44 0 .85-.23 1.08-.61l1.02-1.76 1.71-1c.38-.23.61-.64.61-1.08v-1.97l1.02-1.78c.27-.38.27-.85.04-1.25zm-5.08-.71l-5.01 5.01c-.18.18-.43.29-.71.29-.28 0-.53-.11-.71-.29l-3.01-3.01a1.003 1.003 0 011.42-1.42l2.3 2.3 4.31-4.3a1.003 1.003 0 011.71.71c0 .28-.12.53-.3.71z"
|
||||
fillRule="evenodd"
|
||||
key="0"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</Blueprint3.Icon>
|
||||
<Component>
|
||||
<h5
|
||||
className="bp3-heading"
|
||||
>
|
||||
Success!
|
||||
</h5>
|
||||
</Component>
|
||||
</div>
|
||||
</Col>
|
||||
</div>
|
||||
</Row>
|
||||
<Row
|
||||
center="xs"
|
||||
>
|
||||
<div
|
||||
className="row center-xs"
|
||||
>
|
||||
<Col
|
||||
xs={10}
|
||||
>
|
||||
<div
|
||||
className="col-xs-10"
|
||||
>
|
||||
<div
|
||||
style={
|
||||
Object {
|
||||
"marginBottom": "10px",
|
||||
}
|
||||
}
|
||||
>
|
||||
<Blueprint3.Text>
|
||||
<div
|
||||
className=""
|
||||
>
|
||||
You should see now sharing session started on device you've connected
|
||||
with.
|
||||
</div>
|
||||
</Blueprint3.Text>
|
||||
</div>
|
||||
<div
|
||||
id="connected-devices-list-text-success"
|
||||
onMouseEnter={[Function]}
|
||||
onMouseLeave={[Function]}
|
||||
style={
|
||||
Object {
|
||||
"marginBottom": "25px",
|
||||
"textDecoration": "underline dotted",
|
||||
}
|
||||
}
|
||||
>
|
||||
<Blueprint3.Text
|
||||
className=""
|
||||
>
|
||||
<div
|
||||
className=""
|
||||
>
|
||||
|
||||
You can manage connected devices by clicking "Connected Devices"
|
||||
button in top panel
|
||||
|
||||
</div>
|
||||
</Blueprint3.Text>
|
||||
</div>
|
||||
</div>
|
||||
</Col>
|
||||
</div>
|
||||
</Row>
|
||||
<Blueprint3.Button
|
||||
icon="repeat"
|
||||
intent="primary"
|
||||
onClick={[Function]}
|
||||
style={
|
||||
Object {
|
||||
"borderRadius": "100px",
|
||||
}
|
||||
}
|
||||
>
|
||||
<button
|
||||
className="bp3-button bp3-intent-primary"
|
||||
onClick={[Function]}
|
||||
onKeyDown={[Function]}
|
||||
onKeyUp={[Function]}
|
||||
style={
|
||||
Object {
|
||||
"borderRadius": "100px",
|
||||
}
|
||||
}
|
||||
type="button"
|
||||
>
|
||||
<Blueprint3.Icon
|
||||
icon="repeat"
|
||||
key="leftIcon"
|
||||
>
|
||||
<span
|
||||
className="bp3-icon bp3-icon-repeat"
|
||||
icon="repeat"
|
||||
>
|
||||
<svg
|
||||
data-icon="repeat"
|
||||
height={16}
|
||||
viewBox="0 0 16 16"
|
||||
width={16}
|
||||
>
|
||||
<desc>
|
||||
repeat
|
||||
</desc>
|
||||
<path
|
||||
d="M10 5c0 .55.45 1 1 1h4c.55 0 1-.45 1-1V1c0-.55-.45-1-1-1s-1 .45-1 1v1.74A7.95 7.95 0 008 0C3.58 0 0 3.58 0 8c0 4.06 3.02 7.4 6.94 7.92.02 0 .04.01.06.01.33.04.66.07 1 .07 4.42 0 8-3.58 8-8 0-.55-.45-1-1-1s-1 .45-1 1c0 3.31-2.69 6-6 6-.71 0-1.37-.15-2-.38v.01C3.67 12.81 2 10.61 2 8c0-3.31 2.69-6 6-6 1.77 0 3.36.78 4.46 2H11c-.55 0-1 .45-1 1z"
|
||||
fillRule="evenodd"
|
||||
key="0"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</Blueprint3.Icon>
|
||||
<span
|
||||
className="bp3-button-text"
|
||||
key="text"
|
||||
>
|
||||
Connect New Device
|
||||
</span>
|
||||
<Blueprint3.Icon
|
||||
key="rightIcon"
|
||||
/>
|
||||
</button>
|
||||
</Blueprint3.Button>
|
||||
</div>
|
||||
</Col>
|
||||
</SuccessStep>
|
||||
</Router>
|
||||
</BrowserRouter>
|
||||
`;
|
78
app/components/TopPanel.spec.tsx
Normal file
78
app/components/TopPanel.spec.tsx
Normal file
@ -0,0 +1,78 @@
|
||||
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
||||
import React from 'react';
|
||||
import Enzyme, { ShallowWrapper } from 'enzyme';
|
||||
import EnzymeToJson from 'enzyme-to-json';
|
||||
import Adapter from 'enzyme-adapter-react-16';
|
||||
import TopPanel from './TopPanel';
|
||||
|
||||
Enzyme.configure({ adapter: new Adapter() });
|
||||
jest.useFakeTimers();
|
||||
|
||||
const settingsButtonSelector = '#top-panel-settings-button';
|
||||
const connectedDevicesListButtonSelector =
|
||||
'#top-panel-connected-devices-list-button';
|
||||
|
||||
describe('<TopPanel />', () => {
|
||||
let wrapper: ShallowWrapper;
|
||||
|
||||
beforeEach(() => {
|
||||
wrapper = Enzyme.shallow(<TopPanel />);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should match exact snapshot', () => {
|
||||
expect(EnzymeToJson(wrapper)).toMatchSnapshot();
|
||||
});
|
||||
|
||||
describe('when Settings button in top panel is clicked', () => {
|
||||
it('should Settings Overlay props isSettingsOpen to true', () => {
|
||||
// @ts-ignore
|
||||
wrapper.find(settingsButtonSelector).props().onClick();
|
||||
// @ts-ignore
|
||||
const settingsOverlay = wrapper.props().children[1];
|
||||
|
||||
expect(settingsOverlay.props.isSettingsOpen).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when Settings panel is opened and when its props.handleClose is called', () => {
|
||||
it('should Settings Overlay props isSettingsOpen to false', () => {
|
||||
// @ts-ignore
|
||||
wrapper.find(settingsButtonSelector).props().onClick();
|
||||
// @ts-ignore
|
||||
const settingsOverlay = wrapper.props().children[1];
|
||||
settingsOverlay.props.handleClose();
|
||||
// @ts-ignore
|
||||
const settingsOverlayAfterClose = wrapper.props().children[1];
|
||||
|
||||
expect(settingsOverlayAfterClose.props.isSettingsOpen).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when Connected Devices button in top panel is clicked', () => {
|
||||
it('should set Connected Devices List Drawer props isOpen to true', () => {
|
||||
// @ts-ignore
|
||||
wrapper.find(connectedDevicesListButtonSelector).props().onClick();
|
||||
// @ts-ignore
|
||||
const connectedDevicesListDrawer = wrapper.props().children[2];
|
||||
expect(connectedDevicesListDrawer.props.isOpen).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("when Connected Devices List Drawer is opened, and when it's props.handleToggle is called", () => {
|
||||
it('should set Connected Devices List Drawer props isOpen to false', () => {
|
||||
// @ts-ignore
|
||||
wrapper.find(connectedDevicesListButtonSelector).props().onClick();
|
||||
// @ts-ignore
|
||||
const connectedDevicesListDrawer = wrapper.props().children[2];
|
||||
connectedDevicesListDrawer.props.handleToggle();
|
||||
// @ts-ignore
|
||||
const connectedDevicesListDrawerAfter = wrapper.props().children[2];
|
||||
|
||||
expect(connectedDevicesListDrawerAfter.props.isOpen).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
177
app/components/TopPanel.tsx
Normal file
177
app/components/TopPanel.tsx
Normal file
@ -0,0 +1,177 @@
|
||||
/* eslint-disable react/destructuring-assignment */
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
/* eslint-disable react-hooks/rules-of-hooks */
|
||||
import React, { useCallback, useContext } from 'react';
|
||||
import { Button, Icon, Position, Tooltip } from '@blueprintjs/core';
|
||||
import { createStyles, makeStyles } from '@material-ui/core/styles';
|
||||
import SettingsOverlay from './SettingsOverlay/SettingsOverlay';
|
||||
import ConnectedDevicesListDrawer from './ConnectedDevicesListDrawer';
|
||||
import { SettingsContext } from '../containers/SettingsProvider';
|
||||
import isProduction from '../utils/isProduction';
|
||||
|
||||
const Zoom = require('react-reveal/Zoom');
|
||||
const Fade = require('react-reveal/Fade');
|
||||
|
||||
const useStylesWithTheme = (isDarkTheme: boolean) =>
|
||||
makeStyles(() =>
|
||||
createStyles({
|
||||
topPanelRoot: {
|
||||
display: 'flex',
|
||||
paddingTop: '15px',
|
||||
marginBottom: '20px',
|
||||
},
|
||||
logoWithAppName: { margin: '0 auto' },
|
||||
appNameHeader: {
|
||||
margin: '0 auto',
|
||||
paddingTop: '5px',
|
||||
fontFamily: 'Lexend Peta',
|
||||
fontSize: '20px',
|
||||
color: isDarkTheme ? '#48AFF0' : '#1F4B99',
|
||||
cursor: 'default !important',
|
||||
},
|
||||
topPanelControlButtonsRoot: {
|
||||
position: 'absolute',
|
||||
right: '15px',
|
||||
display: 'flex',
|
||||
},
|
||||
topPanelControlButton: {
|
||||
width: '40px',
|
||||
height: '40px',
|
||||
borderRadius: '50px',
|
||||
cursor: 'default !important',
|
||||
},
|
||||
topPanelControlButtonMargin: {
|
||||
marginRight: '20px',
|
||||
cursor: 'default !important',
|
||||
},
|
||||
topPanelIconOfControlButton: {
|
||||
cursor: 'default !important',
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
export default function TopPanel(props: any) {
|
||||
const { isDarkTheme } = useContext(SettingsContext);
|
||||
|
||||
const getClassesCallback = useCallback(() => {
|
||||
return useStylesWithTheme(isDarkTheme)();
|
||||
}, [isDarkTheme]);
|
||||
|
||||
const [isSettingsOpen, setIsSettingsOpen] = React.useState(false);
|
||||
const [isDrawersOpen, setIsDrawerOpen] = React.useState(false);
|
||||
|
||||
const handleSettingsOpen = useCallback(() => {
|
||||
setIsSettingsOpen(true);
|
||||
}, []);
|
||||
|
||||
const handleSettingsClose = useCallback(() => {
|
||||
setIsSettingsOpen(false);
|
||||
}, []);
|
||||
|
||||
const handleToggleConnectedDevicesListDrawer = useCallback(() => {
|
||||
setIsDrawerOpen(!isDrawersOpen);
|
||||
}, [isDrawersOpen]);
|
||||
|
||||
const renderConnectedDevicesListButton = useCallback(() => {
|
||||
return (
|
||||
<div className={getClassesCallback().topPanelControlButtonMargin}>
|
||||
<Tooltip content="Connected Devices" position={Position.BOTTOM}>
|
||||
<Button
|
||||
id="top-panel-connected-devices-list-button"
|
||||
intent="none"
|
||||
className={getClassesCallback().topPanelControlButton}
|
||||
onClick={handleToggleConnectedDevicesListDrawer}
|
||||
>
|
||||
<Icon
|
||||
className={getClassesCallback().topPanelIconOfControlButton}
|
||||
icon="th-list"
|
||||
iconSize={20}
|
||||
/>
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
);
|
||||
}, [getClassesCallback, handleToggleConnectedDevicesListDrawer]);
|
||||
|
||||
const renderHelpButton = useCallback(() => {
|
||||
return (
|
||||
<div className={getClassesCallback().topPanelControlButtonMargin}>
|
||||
<Tooltip content="Help" position={Position.BOTTOM}>
|
||||
<Button
|
||||
id="top-panel-help-button"
|
||||
intent="none"
|
||||
className={getClassesCallback().topPanelControlButton}
|
||||
>
|
||||
<Icon
|
||||
className={getClassesCallback().topPanelIconOfControlButton}
|
||||
icon="help"
|
||||
iconSize={22}
|
||||
/>
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
);
|
||||
}, [getClassesCallback]);
|
||||
|
||||
const renderSettingsButton = useCallback(() => {
|
||||
return (
|
||||
<div className={getClassesCallback().topPanelControlButtonMargin}>
|
||||
<Tooltip content="Settings" position={Position.BOTTOM}>
|
||||
<Button
|
||||
id="top-panel-settings-button"
|
||||
onClick={handleSettingsOpen}
|
||||
className={getClassesCallback().topPanelControlButton}
|
||||
>
|
||||
<Icon
|
||||
className={getClassesCallback().topPanelIconOfControlButton}
|
||||
icon="cog"
|
||||
iconSize={22}
|
||||
/>
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
);
|
||||
}, [getClassesCallback, handleSettingsOpen]);
|
||||
|
||||
const renderLogoWithAppName = useCallback(() => {
|
||||
return (
|
||||
<Zoom top duration={isProduction() ? 3000 : 0}>
|
||||
<div
|
||||
id="logo-with-popover-visit-website"
|
||||
className={getClassesCallback().logoWithAppName}
|
||||
>
|
||||
<h4
|
||||
id="deskreen-top-app-name-header"
|
||||
className={getClassesCallback().appNameHeader}
|
||||
>
|
||||
Deskreen
|
||||
</h4>
|
||||
</div>
|
||||
</Zoom>
|
||||
);
|
||||
}, [getClassesCallback]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={getClassesCallback().topPanelRoot}>
|
||||
{renderLogoWithAppName()}
|
||||
<div className={getClassesCallback().topPanelControlButtonsRoot}>
|
||||
<Fade right duration={isProduction() ? 2000 : 0}>
|
||||
{renderConnectedDevicesListButton()}
|
||||
{renderHelpButton()}
|
||||
{renderSettingsButton()}
|
||||
</Fade>
|
||||
</div>
|
||||
</div>
|
||||
<SettingsOverlay
|
||||
isSettingsOpen={isSettingsOpen}
|
||||
handleClose={handleSettingsClose}
|
||||
/>
|
||||
<ConnectedDevicesListDrawer
|
||||
isOpen={isDrawersOpen}
|
||||
handleToggle={handleToggleConnectedDevicesListDrawer}
|
||||
stepperRef={props.stepperRef}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
@ -0,0 +1,607 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`should match exact snapshot 1`] = `
|
||||
<BrowserRouter>
|
||||
<Router
|
||||
history={
|
||||
Object {
|
||||
"action": "POP",
|
||||
"block": [Function],
|
||||
"createHref": [Function],
|
||||
"go": [Function],
|
||||
"goBack": [Function],
|
||||
"goForward": [Function],
|
||||
"length": 1,
|
||||
"listen": [Function],
|
||||
"location": Object {
|
||||
"hash": "",
|
||||
"pathname": "/",
|
||||
"search": "",
|
||||
"state": undefined,
|
||||
},
|
||||
"push": [Function],
|
||||
"replace": [Function],
|
||||
}
|
||||
}
|
||||
>
|
||||
<AllowConnectionForDeviceAlert
|
||||
device={Object {}}
|
||||
isOpen={true}
|
||||
onCancel={[Function]}
|
||||
onConfirm={[Function]}
|
||||
>
|
||||
<Blueprint3.Alert
|
||||
canEscapeKeyCancel={false}
|
||||
canOutsideClickCancel={false}
|
||||
cancelButtonText="Deny"
|
||||
className="class-allow-device-to-connect-alert"
|
||||
confirmButtonText="Allow"
|
||||
icon="feed"
|
||||
intent="danger"
|
||||
isOpen={true}
|
||||
onCancel={[Function]}
|
||||
onConfirm={[Function]}
|
||||
transitionDuration={0}
|
||||
>
|
||||
<Blueprint3.Dialog
|
||||
canEscapeKeyClose={false}
|
||||
canOutsideClickClose={false}
|
||||
className="bp3-alert class-allow-device-to-connect-alert"
|
||||
isOpen={true}
|
||||
onCancel={[Function]}
|
||||
onClose={[Function]}
|
||||
onConfirm={[Function]}
|
||||
transitionDuration={0}
|
||||
>
|
||||
<Blueprint3.Overlay
|
||||
autoFocus={true}
|
||||
backdropProps={Object {}}
|
||||
canEscapeKeyClose={false}
|
||||
canOutsideClickClose={false}
|
||||
className="bp3-overlay-scroll-container"
|
||||
enforceFocus={true}
|
||||
hasBackdrop={true}
|
||||
isOpen={true}
|
||||
lazy={true}
|
||||
onCancel={[Function]}
|
||||
onClose={[Function]}
|
||||
onConfirm={[Function]}
|
||||
transitionDuration={0}
|
||||
transitionName="bp3-overlay"
|
||||
usePortal={true}
|
||||
>
|
||||
<Blueprint3.Portal
|
||||
container={
|
||||
<body
|
||||
class="bp3-overlay-open"
|
||||
>
|
||||
<div
|
||||
class="bp3-portal"
|
||||
>
|
||||
<div
|
||||
class="bp3-overlay bp3-overlay-open bp3-overlay-scroll-container"
|
||||
>
|
||||
<div
|
||||
class="bp3-overlay-backdrop bp3-overlay-appear bp3-overlay-appear-active"
|
||||
/>
|
||||
<div
|
||||
class="bp3-dialog-container bp3-overlay-content bp3-overlay-appear bp3-overlay-appear-active"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="bp3-dialog bp3-alert class-allow-device-to-connect-alert"
|
||||
>
|
||||
<div
|
||||
class="bp3-alert-body"
|
||||
>
|
||||
<span
|
||||
class="bp3-icon bp3-icon-feed bp3-intent-danger"
|
||||
icon="feed"
|
||||
>
|
||||
<svg
|
||||
data-icon="feed"
|
||||
height="40"
|
||||
viewBox="0 0 20 20"
|
||||
width="40"
|
||||
>
|
||||
<desc>
|
||||
feed
|
||||
</desc>
|
||||
<path
|
||||
d="M2.5 15a2.5 2.5 0 000 5 2.5 2.5 0 000-5zm.5-5c-.55 0-1 .45-1 1s.45 1 1 1c2.76 0 5 2.24 5 5 0 .55.45 1 1 1s1-.45 1-1c0-3.87-3.13-7-7-7zM3 0c-.55 0-1 .45-1 1s.45 1 1 1c8.28 0 15 6.72 15 15 0 .55.45 1 1 1s1-.45 1-1C20 7.61 12.39 0 3 0zm0 5c-.55 0-1 .45-1 1s.45 1 1 1c5.52 0 10 4.48 10 10 0 .55.45 1 1 1s1-.45 1-1C15 10.37 9.63 5 3 5z"
|
||||
fill-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
<div
|
||||
class="bp3-alert-contents"
|
||||
>
|
||||
<h3
|
||||
class="bp3-heading"
|
||||
>
|
||||
Device is trying to connect
|
||||
</h3>
|
||||
<div
|
||||
class="row"
|
||||
>
|
||||
<div
|
||||
class=""
|
||||
>
|
||||
<div
|
||||
class=""
|
||||
>
|
||||
Device IP:
|
||||
</div>
|
||||
<span
|
||||
id="allow-connection-device-alert-device-ip-span"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="row"
|
||||
>
|
||||
<div
|
||||
class=""
|
||||
>
|
||||
<div
|
||||
class=""
|
||||
>
|
||||
Device Type: undefined
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="row"
|
||||
>
|
||||
<div
|
||||
class=""
|
||||
>
|
||||
<div
|
||||
class=""
|
||||
>
|
||||
Device OS: undefined
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="row"
|
||||
>
|
||||
<div
|
||||
class=""
|
||||
>
|
||||
<div
|
||||
class=""
|
||||
>
|
||||
session ID: undefined
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="bp3-alert-footer"
|
||||
>
|
||||
<button
|
||||
class="bp3-button bp3-intent-danger"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="bp3-button-text"
|
||||
>
|
||||
Allow
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
class="bp3-button"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="bp3-button-text"
|
||||
>
|
||||
Deny
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
}
|
||||
>
|
||||
<Portal
|
||||
containerInfo={
|
||||
<div
|
||||
class="bp3-portal"
|
||||
>
|
||||
<div
|
||||
class="bp3-overlay bp3-overlay-open bp3-overlay-scroll-container"
|
||||
>
|
||||
<div
|
||||
class="bp3-overlay-backdrop bp3-overlay-appear bp3-overlay-appear-active"
|
||||
/>
|
||||
<div
|
||||
class="bp3-dialog-container bp3-overlay-content bp3-overlay-appear bp3-overlay-appear-active"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="bp3-dialog bp3-alert class-allow-device-to-connect-alert"
|
||||
>
|
||||
<div
|
||||
class="bp3-alert-body"
|
||||
>
|
||||
<span
|
||||
class="bp3-icon bp3-icon-feed bp3-intent-danger"
|
||||
icon="feed"
|
||||
>
|
||||
<svg
|
||||
data-icon="feed"
|
||||
height="40"
|
||||
viewBox="0 0 20 20"
|
||||
width="40"
|
||||
>
|
||||
<desc>
|
||||
feed
|
||||
</desc>
|
||||
<path
|
||||
d="M2.5 15a2.5 2.5 0 000 5 2.5 2.5 0 000-5zm.5-5c-.55 0-1 .45-1 1s.45 1 1 1c2.76 0 5 2.24 5 5 0 .55.45 1 1 1s1-.45 1-1c0-3.87-3.13-7-7-7zM3 0c-.55 0-1 .45-1 1s.45 1 1 1c8.28 0 15 6.72 15 15 0 .55.45 1 1 1s1-.45 1-1C20 7.61 12.39 0 3 0zm0 5c-.55 0-1 .45-1 1s.45 1 1 1c5.52 0 10 4.48 10 10 0 .55.45 1 1 1s1-.45 1-1C15 10.37 9.63 5 3 5z"
|
||||
fill-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
<div
|
||||
class="bp3-alert-contents"
|
||||
>
|
||||
<h3
|
||||
class="bp3-heading"
|
||||
>
|
||||
Device is trying to connect
|
||||
</h3>
|
||||
<div
|
||||
class="row"
|
||||
>
|
||||
<div
|
||||
class=""
|
||||
>
|
||||
<div
|
||||
class=""
|
||||
>
|
||||
Device IP:
|
||||
</div>
|
||||
<span
|
||||
id="allow-connection-device-alert-device-ip-span"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="row"
|
||||
>
|
||||
<div
|
||||
class=""
|
||||
>
|
||||
<div
|
||||
class=""
|
||||
>
|
||||
Device Type: undefined
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="row"
|
||||
>
|
||||
<div
|
||||
class=""
|
||||
>
|
||||
<div
|
||||
class=""
|
||||
>
|
||||
Device OS: undefined
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="row"
|
||||
>
|
||||
<div
|
||||
class=""
|
||||
>
|
||||
<div
|
||||
class=""
|
||||
>
|
||||
session ID: undefined
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="bp3-alert-footer"
|
||||
>
|
||||
<button
|
||||
class="bp3-button bp3-intent-danger"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="bp3-button-text"
|
||||
>
|
||||
Allow
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
class="bp3-button"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="bp3-button-text"
|
||||
>
|
||||
Deny
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<TransitionGroup
|
||||
appear={true}
|
||||
childFactory={[Function]}
|
||||
className="bp3-overlay bp3-overlay-open bp3-overlay-scroll-container"
|
||||
component="div"
|
||||
onKeyDown={[Function]}
|
||||
>
|
||||
<div
|
||||
className="bp3-overlay bp3-overlay-open bp3-overlay-scroll-container"
|
||||
onKeyDown={[Function]}
|
||||
>
|
||||
<CSSTransition
|
||||
appear={true}
|
||||
classNames="bp3-overlay"
|
||||
in={true}
|
||||
key=".$__backdrop"
|
||||
onExited={[Function]}
|
||||
timeout={0}
|
||||
>
|
||||
<Transition
|
||||
appear={true}
|
||||
enter={true}
|
||||
exit={true}
|
||||
in={true}
|
||||
mountOnEnter={false}
|
||||
onEnter={[Function]}
|
||||
onEntered={[Function]}
|
||||
onEntering={[Function]}
|
||||
onExit={[Function]}
|
||||
onExited={[Function]}
|
||||
onExiting={[Function]}
|
||||
timeout={0}
|
||||
unmountOnExit={false}
|
||||
>
|
||||
<div
|
||||
className="bp3-overlay-backdrop"
|
||||
onMouseDown={[Function]}
|
||||
tabIndex={null}
|
||||
/>
|
||||
</Transition>
|
||||
</CSSTransition>
|
||||
<CSSTransition
|
||||
appear={true}
|
||||
classNames="bp3-overlay"
|
||||
in={true}
|
||||
key=".$.0"
|
||||
onExited={[Function]}
|
||||
timeout={0}
|
||||
>
|
||||
<Transition
|
||||
appear={true}
|
||||
enter={true}
|
||||
exit={true}
|
||||
in={true}
|
||||
mountOnEnter={false}
|
||||
onEnter={[Function]}
|
||||
onEntered={[Function]}
|
||||
onEntering={[Function]}
|
||||
onExit={[Function]}
|
||||
onExited={[Function]}
|
||||
onExiting={[Function]}
|
||||
timeout={0}
|
||||
unmountOnExit={false}
|
||||
>
|
||||
<div
|
||||
className="bp3-dialog-container bp3-overlay-content"
|
||||
tabIndex={0}
|
||||
>
|
||||
<div
|
||||
className="bp3-dialog bp3-alert class-allow-device-to-connect-alert"
|
||||
>
|
||||
<div
|
||||
className="bp3-alert-body"
|
||||
>
|
||||
<Blueprint3.Icon
|
||||
icon="feed"
|
||||
iconSize={40}
|
||||
intent="danger"
|
||||
>
|
||||
<span
|
||||
className="bp3-icon bp3-icon-feed bp3-intent-danger"
|
||||
icon="feed"
|
||||
>
|
||||
<svg
|
||||
data-icon="feed"
|
||||
height={40}
|
||||
viewBox="0 0 20 20"
|
||||
width={40}
|
||||
>
|
||||
<desc>
|
||||
feed
|
||||
</desc>
|
||||
<path
|
||||
d="M2.5 15a2.5 2.5 0 000 5 2.5 2.5 0 000-5zm.5-5c-.55 0-1 .45-1 1s.45 1 1 1c2.76 0 5 2.24 5 5 0 .55.45 1 1 1s1-.45 1-1c0-3.87-3.13-7-7-7zM3 0c-.55 0-1 .45-1 1s.45 1 1 1c8.28 0 15 6.72 15 15 0 .55.45 1 1 1s1-.45 1-1C20 7.61 12.39 0 3 0zm0 5c-.55 0-1 .45-1 1s.45 1 1 1c5.52 0 10 4.48 10 10 0 .55.45 1 1 1s1-.45 1-1C15 10.37 9.63 5 3 5z"
|
||||
fillRule="evenodd"
|
||||
key="0"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</Blueprint3.Icon>
|
||||
<div
|
||||
className="bp3-alert-contents"
|
||||
>
|
||||
<Component>
|
||||
<h3
|
||||
className="bp3-heading"
|
||||
>
|
||||
Device is trying to connect
|
||||
</h3>
|
||||
</Component>
|
||||
<Row>
|
||||
<div
|
||||
className="row"
|
||||
>
|
||||
<Col>
|
||||
<div
|
||||
className=""
|
||||
>
|
||||
<Blueprint3.Text>
|
||||
<div
|
||||
className=""
|
||||
>
|
||||
Device IP:
|
||||
</div>
|
||||
</Blueprint3.Text>
|
||||
<span
|
||||
id="allow-connection-device-alert-device-ip-span"
|
||||
/>
|
||||
</div>
|
||||
</Col>
|
||||
</div>
|
||||
</Row>
|
||||
<Row>
|
||||
<div
|
||||
className="row"
|
||||
>
|
||||
<Col>
|
||||
<div
|
||||
className=""
|
||||
>
|
||||
<Blueprint3.Text>
|
||||
<div
|
||||
className=""
|
||||
>
|
||||
Device Type: undefined
|
||||
</div>
|
||||
</Blueprint3.Text>
|
||||
</div>
|
||||
</Col>
|
||||
</div>
|
||||
</Row>
|
||||
<Row>
|
||||
<div
|
||||
className="row"
|
||||
>
|
||||
<Col>
|
||||
<div
|
||||
className=""
|
||||
>
|
||||
<Blueprint3.Text>
|
||||
<div
|
||||
className=""
|
||||
>
|
||||
Device OS: undefined
|
||||
</div>
|
||||
</Blueprint3.Text>
|
||||
</div>
|
||||
</Col>
|
||||
</div>
|
||||
</Row>
|
||||
<Row>
|
||||
<div
|
||||
className="row"
|
||||
>
|
||||
<Col>
|
||||
<div
|
||||
className=""
|
||||
>
|
||||
<Blueprint3.Text>
|
||||
<div
|
||||
className=""
|
||||
>
|
||||
session ID: undefined
|
||||
</div>
|
||||
</Blueprint3.Text>
|
||||
</div>
|
||||
</Col>
|
||||
</div>
|
||||
</Row>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="bp3-alert-footer"
|
||||
>
|
||||
<Blueprint3.Button
|
||||
intent="danger"
|
||||
onClick={[Function]}
|
||||
text="Allow"
|
||||
>
|
||||
<button
|
||||
className="bp3-button bp3-intent-danger"
|
||||
onClick={[Function]}
|
||||
onKeyDown={[Function]}
|
||||
onKeyUp={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<Blueprint3.Icon
|
||||
key="leftIcon"
|
||||
/>
|
||||
<span
|
||||
className="bp3-button-text"
|
||||
key="text"
|
||||
>
|
||||
Allow
|
||||
</span>
|
||||
<Blueprint3.Icon
|
||||
key="rightIcon"
|
||||
/>
|
||||
</button>
|
||||
</Blueprint3.Button>
|
||||
<Blueprint3.Button
|
||||
onClick={[Function]}
|
||||
text="Deny"
|
||||
>
|
||||
<button
|
||||
className="bp3-button"
|
||||
onClick={[Function]}
|
||||
onKeyDown={[Function]}
|
||||
onKeyUp={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<Blueprint3.Icon
|
||||
key="leftIcon"
|
||||
/>
|
||||
<span
|
||||
className="bp3-button-text"
|
||||
key="text"
|
||||
>
|
||||
Deny
|
||||
</span>
|
||||
<Blueprint3.Icon
|
||||
key="rightIcon"
|
||||
/>
|
||||
</button>
|
||||
</Blueprint3.Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
</CSSTransition>
|
||||
</div>
|
||||
</TransitionGroup>
|
||||
</Portal>
|
||||
</Blueprint3.Portal>
|
||||
</Blueprint3.Overlay>
|
||||
</Blueprint3.Dialog>
|
||||
</Blueprint3.Alert>
|
||||
</AllowConnectionForDeviceAlert>
|
||||
</Router>
|
||||
</BrowserRouter>
|
||||
`;
|
@ -0,0 +1,644 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`should match exact snapshot 1`] = `
|
||||
<BrowserRouter>
|
||||
<Router
|
||||
history={
|
||||
Object {
|
||||
"action": "POP",
|
||||
"block": [Function],
|
||||
"createHref": [Function],
|
||||
"go": [Function],
|
||||
"goBack": [Function],
|
||||
"goForward": [Function],
|
||||
"length": 1,
|
||||
"listen": [Function],
|
||||
"location": Object {
|
||||
"hash": "",
|
||||
"pathname": "/",
|
||||
"search": "",
|
||||
"state": undefined,
|
||||
},
|
||||
"push": [Function],
|
||||
"replace": [Function],
|
||||
}
|
||||
}
|
||||
>
|
||||
<ConnectedDevicesListDrawer
|
||||
handleToggle={[Function]}
|
||||
isOpen={true}
|
||||
stepperRef={null}
|
||||
>
|
||||
<Blueprint3.Drawer
|
||||
canOutsideClickClose={true}
|
||||
className="makeStyles-drawerRoot-1"
|
||||
isOpen={true}
|
||||
onClose={[Function]}
|
||||
position="bottom"
|
||||
size="90%"
|
||||
style={Object {}}
|
||||
transitionDuration={0}
|
||||
vertical={false}
|
||||
>
|
||||
<Blueprint3.Overlay
|
||||
autoFocus={true}
|
||||
backdropProps={Object {}}
|
||||
canEscapeKeyClose={true}
|
||||
canOutsideClickClose={true}
|
||||
className="bp3-overlay-container"
|
||||
enforceFocus={true}
|
||||
hasBackdrop={true}
|
||||
isOpen={true}
|
||||
lazy={true}
|
||||
onClose={[Function]}
|
||||
position="bottom"
|
||||
size="90%"
|
||||
style={Object {}}
|
||||
transitionDuration={0}
|
||||
transitionName="bp3-overlay"
|
||||
usePortal={true}
|
||||
vertical={false}
|
||||
>
|
||||
<Blueprint3.Portal
|
||||
container={
|
||||
<body
|
||||
class="bp3-overlay-open"
|
||||
>
|
||||
<div
|
||||
class="bp3-portal"
|
||||
>
|
||||
<div
|
||||
class="bp3-overlay bp3-overlay-open bp3-overlay-container"
|
||||
>
|
||||
<div
|
||||
class="bp3-overlay-backdrop bp3-overlay-appear bp3-overlay-appear-active"
|
||||
tabindex="0"
|
||||
/>
|
||||
<div
|
||||
class="bp3-drawer bp3-position-bottom makeStyles-drawerRoot-1 bp3-overlay-content bp3-overlay-appear bp3-overlay-appear-active"
|
||||
style="height: 90%;"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="makeStyles-drawerInnerTopPanel-2 row middle-xs between-xs"
|
||||
>
|
||||
<div
|
||||
class="col-xs-11"
|
||||
>
|
||||
<div
|
||||
class="row middle-xs"
|
||||
>
|
||||
<div
|
||||
class="makeStyles-topHeader-4"
|
||||
>
|
||||
<div
|
||||
class="bp3-text-muted"
|
||||
>
|
||||
Connected Devices
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
class="bp3-button bp3-disabled bp3-intent-danger"
|
||||
disabled=""
|
||||
tabindex="-1"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="bp3-icon bp3-icon-disable"
|
||||
icon="disable"
|
||||
>
|
||||
<svg
|
||||
data-icon="disable"
|
||||
height="16"
|
||||
viewBox="0 0 16 16"
|
||||
width="16"
|
||||
>
|
||||
<desc>
|
||||
disable
|
||||
</desc>
|
||||
<path
|
||||
d="M7.99-.01c-4.42 0-8 3.58-8 8s3.58 8 8 8 8-3.58 8-8-3.58-8-8-8zm-6 8c0-3.31 2.69-6 6-6 1.3 0 2.49.42 3.47 1.12l-8.35 8.35c-.7-.98-1.12-2.17-1.12-3.47zm6 6c-1.3 0-2.49-.42-3.47-1.12l8.35-8.35c.7.98 1.12 2.17 1.12 3.47 0 3.32-2.68 6-6 6z"
|
||||
fill-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
<span
|
||||
class="bp3-button-text"
|
||||
>
|
||||
Disconnect all devices
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="col-xs-1"
|
||||
>
|
||||
<button
|
||||
class="bp3-button makeStyles-closeButton-6 undefined"
|
||||
id="close-overlay-button"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="bp3-button-text"
|
||||
>
|
||||
<span
|
||||
class="bp3-icon bp3-icon-cross"
|
||||
icon="cross"
|
||||
>
|
||||
<svg
|
||||
data-icon="cross"
|
||||
height="30"
|
||||
viewBox="0 0 20 20"
|
||||
width="30"
|
||||
>
|
||||
<desc>
|
||||
cross
|
||||
</desc>
|
||||
<path
|
||||
d="M11.41 10l4.29-4.29c.19-.18.3-.43.3-.71a1.003 1.003 0 00-1.71-.71L10 8.59l-4.29-4.3a1.003 1.003 0 00-1.42 1.42L8.59 10 4.3 14.29c-.19.18-.3.43-.3.71a1.003 1.003 0 001.71.71l4.29-4.3 4.29 4.29c.18.19.43.3.71.3a1.003 1.003 0 00.71-1.71L11.41 10z"
|
||||
fill-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="makeStyles-connectedDevicesRoot-3 row"
|
||||
>
|
||||
<div
|
||||
class="col-xs-12"
|
||||
>
|
||||
<div
|
||||
class="react-reveal makeStyles-zoomFullWidth-5"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
}
|
||||
>
|
||||
<Portal
|
||||
containerInfo={
|
||||
<div
|
||||
class="bp3-portal"
|
||||
>
|
||||
<div
|
||||
class="bp3-overlay bp3-overlay-open bp3-overlay-container"
|
||||
>
|
||||
<div
|
||||
class="bp3-overlay-backdrop bp3-overlay-appear bp3-overlay-appear-active"
|
||||
tabindex="0"
|
||||
/>
|
||||
<div
|
||||
class="bp3-drawer bp3-position-bottom makeStyles-drawerRoot-1 bp3-overlay-content bp3-overlay-appear bp3-overlay-appear-active"
|
||||
style="height: 90%;"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="makeStyles-drawerInnerTopPanel-2 row middle-xs between-xs"
|
||||
>
|
||||
<div
|
||||
class="col-xs-11"
|
||||
>
|
||||
<div
|
||||
class="row middle-xs"
|
||||
>
|
||||
<div
|
||||
class="makeStyles-topHeader-4"
|
||||
>
|
||||
<div
|
||||
class="bp3-text-muted"
|
||||
>
|
||||
Connected Devices
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
class="bp3-button bp3-disabled bp3-intent-danger"
|
||||
disabled=""
|
||||
tabindex="-1"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="bp3-icon bp3-icon-disable"
|
||||
icon="disable"
|
||||
>
|
||||
<svg
|
||||
data-icon="disable"
|
||||
height="16"
|
||||
viewBox="0 0 16 16"
|
||||
width="16"
|
||||
>
|
||||
<desc>
|
||||
disable
|
||||
</desc>
|
||||
<path
|
||||
d="M7.99-.01c-4.42 0-8 3.58-8 8s3.58 8 8 8 8-3.58 8-8-3.58-8-8-8zm-6 8c0-3.31 2.69-6 6-6 1.3 0 2.49.42 3.47 1.12l-8.35 8.35c-.7-.98-1.12-2.17-1.12-3.47zm6 6c-1.3 0-2.49-.42-3.47-1.12l8.35-8.35c.7.98 1.12 2.17 1.12 3.47 0 3.32-2.68 6-6 6z"
|
||||
fill-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
<span
|
||||
class="bp3-button-text"
|
||||
>
|
||||
Disconnect all devices
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="col-xs-1"
|
||||
>
|
||||
<button
|
||||
class="bp3-button makeStyles-closeButton-6 undefined"
|
||||
id="close-overlay-button"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="bp3-button-text"
|
||||
>
|
||||
<span
|
||||
class="bp3-icon bp3-icon-cross"
|
||||
icon="cross"
|
||||
>
|
||||
<svg
|
||||
data-icon="cross"
|
||||
height="30"
|
||||
viewBox="0 0 20 20"
|
||||
width="30"
|
||||
>
|
||||
<desc>
|
||||
cross
|
||||
</desc>
|
||||
<path
|
||||
d="M11.41 10l4.29-4.29c.19-.18.3-.43.3-.71a1.003 1.003 0 00-1.71-.71L10 8.59l-4.29-4.3a1.003 1.003 0 00-1.42 1.42L8.59 10 4.3 14.29c-.19.18-.3.43-.3.71a1.003 1.003 0 001.71.71l4.29-4.3 4.29 4.29c.18.19.43.3.71.3a1.003 1.003 0 00.71-1.71L11.41 10z"
|
||||
fill-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="makeStyles-connectedDevicesRoot-3 row"
|
||||
>
|
||||
<div
|
||||
class="col-xs-12"
|
||||
>
|
||||
<div
|
||||
class="react-reveal makeStyles-zoomFullWidth-5"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<TransitionGroup
|
||||
appear={true}
|
||||
childFactory={[Function]}
|
||||
className="bp3-overlay bp3-overlay-open bp3-overlay-container"
|
||||
component="div"
|
||||
onKeyDown={[Function]}
|
||||
>
|
||||
<div
|
||||
className="bp3-overlay bp3-overlay-open bp3-overlay-container"
|
||||
onKeyDown={[Function]}
|
||||
>
|
||||
<CSSTransition
|
||||
appear={true}
|
||||
classNames="bp3-overlay"
|
||||
in={true}
|
||||
key=".$__backdrop"
|
||||
onExited={[Function]}
|
||||
timeout={0}
|
||||
>
|
||||
<Transition
|
||||
appear={true}
|
||||
enter={true}
|
||||
exit={true}
|
||||
in={true}
|
||||
mountOnEnter={false}
|
||||
onEnter={[Function]}
|
||||
onEntered={[Function]}
|
||||
onEntering={[Function]}
|
||||
onExit={[Function]}
|
||||
onExited={[Function]}
|
||||
onExiting={[Function]}
|
||||
timeout={0}
|
||||
unmountOnExit={false}
|
||||
>
|
||||
<div
|
||||
className="bp3-overlay-backdrop"
|
||||
onMouseDown={[Function]}
|
||||
tabIndex={0}
|
||||
/>
|
||||
</Transition>
|
||||
</CSSTransition>
|
||||
<CSSTransition
|
||||
appear={true}
|
||||
classNames="bp3-overlay"
|
||||
in={true}
|
||||
key=".$.0"
|
||||
onExited={[Function]}
|
||||
timeout={0}
|
||||
>
|
||||
<Transition
|
||||
appear={true}
|
||||
enter={true}
|
||||
exit={true}
|
||||
in={true}
|
||||
mountOnEnter={false}
|
||||
onEnter={[Function]}
|
||||
onEntered={[Function]}
|
||||
onEntering={[Function]}
|
||||
onExit={[Function]}
|
||||
onExited={[Function]}
|
||||
onExiting={[Function]}
|
||||
timeout={0}
|
||||
unmountOnExit={false}
|
||||
>
|
||||
<div
|
||||
className="bp3-drawer bp3-position-bottom makeStyles-drawerRoot-1 bp3-overlay-content"
|
||||
style={
|
||||
Object {
|
||||
"height": "90%",
|
||||
}
|
||||
}
|
||||
tabIndex={0}
|
||||
>
|
||||
<Row
|
||||
between="xs"
|
||||
className="makeStyles-drawerInnerTopPanel-2"
|
||||
middle="xs"
|
||||
>
|
||||
<div
|
||||
className="makeStyles-drawerInnerTopPanel-2 row middle-xs between-xs"
|
||||
>
|
||||
<Col
|
||||
xs={11}
|
||||
>
|
||||
<div
|
||||
className="col-xs-11"
|
||||
>
|
||||
<Row
|
||||
middle="xs"
|
||||
>
|
||||
<div
|
||||
className="row middle-xs"
|
||||
>
|
||||
<div
|
||||
className="makeStyles-topHeader-4"
|
||||
>
|
||||
<Blueprint3.Text
|
||||
className="bp3-text-muted"
|
||||
>
|
||||
<div
|
||||
className="bp3-text-muted"
|
||||
>
|
||||
Connected Devices
|
||||
</div>
|
||||
</Blueprint3.Text>
|
||||
</div>
|
||||
<Blueprint3.Button
|
||||
disabled={true}
|
||||
icon="disable"
|
||||
intent="danger"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<button
|
||||
className="bp3-button bp3-disabled bp3-intent-danger"
|
||||
disabled={true}
|
||||
onKeyDown={[Function]}
|
||||
onKeyUp={[Function]}
|
||||
tabIndex={-1}
|
||||
type="button"
|
||||
>
|
||||
<Blueprint3.Icon
|
||||
icon="disable"
|
||||
key="leftIcon"
|
||||
>
|
||||
<span
|
||||
className="bp3-icon bp3-icon-disable"
|
||||
icon="disable"
|
||||
>
|
||||
<svg
|
||||
data-icon="disable"
|
||||
height={16}
|
||||
viewBox="0 0 16 16"
|
||||
width={16}
|
||||
>
|
||||
<desc>
|
||||
disable
|
||||
</desc>
|
||||
<path
|
||||
d="M7.99-.01c-4.42 0-8 3.58-8 8s3.58 8 8 8 8-3.58 8-8-3.58-8-8-8zm-6 8c0-3.31 2.69-6 6-6 1.3 0 2.49.42 3.47 1.12l-8.35 8.35c-.7-.98-1.12-2.17-1.12-3.47zm6 6c-1.3 0-2.49-.42-3.47-1.12l8.35-8.35c.7.98 1.12 2.17 1.12 3.47 0 3.32-2.68 6-6 6z"
|
||||
fillRule="evenodd"
|
||||
key="0"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</Blueprint3.Icon>
|
||||
<span
|
||||
className="bp3-button-text"
|
||||
key="text"
|
||||
>
|
||||
Disconnect all devices
|
||||
</span>
|
||||
<Blueprint3.Icon
|
||||
key="rightIcon"
|
||||
/>
|
||||
</button>
|
||||
</Blueprint3.Button>
|
||||
</div>
|
||||
</Row>
|
||||
</div>
|
||||
</Col>
|
||||
<Col
|
||||
xs={1}
|
||||
>
|
||||
<div
|
||||
className="col-xs-1"
|
||||
>
|
||||
<CloseOverlayButton
|
||||
onClick={[Function]}
|
||||
>
|
||||
<Blueprint3.Button
|
||||
className="makeStyles-closeButton-6 undefined"
|
||||
id="close-overlay-button"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<button
|
||||
className="bp3-button makeStyles-closeButton-6 undefined"
|
||||
id="close-overlay-button"
|
||||
onClick={[Function]}
|
||||
onKeyDown={[Function]}
|
||||
onKeyUp={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<Blueprint3.Icon
|
||||
key="leftIcon"
|
||||
/>
|
||||
<span
|
||||
className="bp3-button-text"
|
||||
key="text"
|
||||
>
|
||||
<Blueprint3.Icon
|
||||
icon="cross"
|
||||
iconSize={30}
|
||||
>
|
||||
<span
|
||||
className="bp3-icon bp3-icon-cross"
|
||||
icon="cross"
|
||||
>
|
||||
<svg
|
||||
data-icon="cross"
|
||||
height={30}
|
||||
viewBox="0 0 20 20"
|
||||
width={30}
|
||||
>
|
||||
<desc>
|
||||
cross
|
||||
</desc>
|
||||
<path
|
||||
d="M11.41 10l4.29-4.29c.19-.18.3-.43.3-.71a1.003 1.003 0 00-1.71-.71L10 8.59l-4.29-4.3a1.003 1.003 0 00-1.42 1.42L8.59 10 4.3 14.29c-.19.18-.3.43-.3.71a1.003 1.003 0 001.71.71l4.29-4.3 4.29 4.29c.18.19.43.3.71.3a1.003 1.003 0 00.71-1.71L11.41 10z"
|
||||
fillRule="evenodd"
|
||||
key="0"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</Blueprint3.Icon>
|
||||
</span>
|
||||
<Blueprint3.Icon
|
||||
key="rightIcon"
|
||||
/>
|
||||
</button>
|
||||
</Blueprint3.Button>
|
||||
</CloseOverlayButton>
|
||||
</div>
|
||||
</Col>
|
||||
</div>
|
||||
</Row>
|
||||
<Row
|
||||
className="makeStyles-connectedDevicesRoot-3"
|
||||
>
|
||||
<div
|
||||
className="makeStyles-connectedDevicesRoot-3 row"
|
||||
>
|
||||
<Col
|
||||
xs={12}
|
||||
>
|
||||
<div
|
||||
className="col-xs-12"
|
||||
>
|
||||
<Fade
|
||||
bottom={true}
|
||||
cascade={true}
|
||||
duration={0}
|
||||
>
|
||||
<RevealBase
|
||||
bottom={true}
|
||||
cascade={true}
|
||||
fraction={0.2}
|
||||
inEffect={
|
||||
Object {
|
||||
"count": 1,
|
||||
"delay": 0,
|
||||
"duration": 0,
|
||||
"forever": undefined,
|
||||
"make": [Function],
|
||||
"reverse": undefined,
|
||||
"style": Object {
|
||||
"animationFillMode": "both",
|
||||
},
|
||||
}
|
||||
}
|
||||
outEffect={
|
||||
Object {
|
||||
"count": 1,
|
||||
"delay": 0,
|
||||
"duration": 0,
|
||||
"forever": undefined,
|
||||
"make": [Function],
|
||||
"reverse": undefined,
|
||||
"style": Object {
|
||||
"animationFillMode": "both",
|
||||
},
|
||||
}
|
||||
}
|
||||
refProp="ref"
|
||||
>
|
||||
<div
|
||||
className="react-reveal makeStyles-zoomFullWidth-5"
|
||||
style={
|
||||
Object {
|
||||
"opacity": undefined,
|
||||
}
|
||||
}
|
||||
/>
|
||||
</RevealBase>
|
||||
</Fade>
|
||||
</div>
|
||||
</Col>
|
||||
</div>
|
||||
</Row>
|
||||
</div>
|
||||
</Transition>
|
||||
</CSSTransition>
|
||||
</div>
|
||||
</TransitionGroup>
|
||||
</Portal>
|
||||
</Blueprint3.Portal>
|
||||
</Blueprint3.Overlay>
|
||||
</Blueprint3.Drawer>
|
||||
<Blueprint3.Alert
|
||||
canEscapeKeyCancel={true}
|
||||
canOutsideClickCancel={true}
|
||||
cancelButtonText="No, Cancel"
|
||||
confirmButtonText="Yes, Disconnect All"
|
||||
icon="warning-sign"
|
||||
intent="danger"
|
||||
isOpen={false}
|
||||
onCancel={[Function]}
|
||||
onClose={[Function]}
|
||||
onConfirm={[Function]}
|
||||
transitionDuration={0}
|
||||
>
|
||||
<Blueprint3.Dialog
|
||||
canEscapeKeyClose={true}
|
||||
canOutsideClickClose={true}
|
||||
className="bp3-alert"
|
||||
isOpen={false}
|
||||
onCancel={[Function]}
|
||||
onClose={[Function]}
|
||||
onConfirm={[Function]}
|
||||
transitionDuration={0}
|
||||
>
|
||||
<Blueprint3.Overlay
|
||||
autoFocus={true}
|
||||
backdropProps={Object {}}
|
||||
canEscapeKeyClose={true}
|
||||
canOutsideClickClose={true}
|
||||
className="bp3-overlay-scroll-container"
|
||||
enforceFocus={true}
|
||||
hasBackdrop={true}
|
||||
isOpen={false}
|
||||
lazy={true}
|
||||
onCancel={[Function]}
|
||||
onClose={[Function]}
|
||||
onConfirm={[Function]}
|
||||
transitionDuration={0}
|
||||
transitionName="bp3-overlay"
|
||||
usePortal={true}
|
||||
/>
|
||||
</Blueprint3.Dialog>
|
||||
</Blueprint3.Alert>
|
||||
</ConnectedDevicesListDrawer>
|
||||
</Router>
|
||||
</BrowserRouter>
|
||||
`;
|
@ -0,0 +1,230 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`should match exact snapshot 1`] = `
|
||||
<BrowserRouter>
|
||||
<Router
|
||||
history={
|
||||
Object {
|
||||
"action": "POP",
|
||||
"block": [Function],
|
||||
"createHref": [Function],
|
||||
"go": [Function],
|
||||
"goBack": [Function],
|
||||
"goForward": [Function],
|
||||
"length": 1,
|
||||
"listen": [Function],
|
||||
"location": Object {
|
||||
"hash": "",
|
||||
"pathname": "/",
|
||||
"search": "",
|
||||
"state": undefined,
|
||||
},
|
||||
"push": [Function],
|
||||
"replace": [Function],
|
||||
}
|
||||
}
|
||||
>
|
||||
<ShareEntireScreenOrAppWindowControlGroup
|
||||
handleNextApplicationWindow={[Function]}
|
||||
handleNextEntireScreen={[Function]}
|
||||
>
|
||||
<Blueprint3.ControlGroup
|
||||
className="makeStyles-controlGroupRoot-1"
|
||||
fill={true}
|
||||
id="share-screen-or-app-btn-group"
|
||||
vertical={false}
|
||||
>
|
||||
<div
|
||||
className="bp3-control-group bp3-fill makeStyles-controlGroupRoot-1"
|
||||
id="share-screen-or-app-btn-group"
|
||||
>
|
||||
<Blueprint3.Button
|
||||
className="makeStyles-shareEntireScreenButton-2"
|
||||
intent="primary"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<button
|
||||
className="bp3-button bp3-intent-primary makeStyles-shareEntireScreenButton-2"
|
||||
onClick={[Function]}
|
||||
onKeyDown={[Function]}
|
||||
onKeyUp={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<Blueprint3.Icon
|
||||
key="leftIcon"
|
||||
/>
|
||||
<span
|
||||
className="bp3-button-text"
|
||||
key="text"
|
||||
>
|
||||
<Blueprint3.Icon
|
||||
className="makeStyles-shareEntireScreenButtonIcon-3"
|
||||
color="white"
|
||||
icon="desktop"
|
||||
iconSize={100}
|
||||
>
|
||||
<span
|
||||
className="bp3-icon bp3-icon-desktop makeStyles-shareEntireScreenButtonIcon-3"
|
||||
icon="desktop"
|
||||
>
|
||||
<svg
|
||||
data-icon="desktop"
|
||||
fill="white"
|
||||
height={100}
|
||||
viewBox="0 0 20 20"
|
||||
width={100}
|
||||
>
|
||||
<desc>
|
||||
desktop
|
||||
</desc>
|
||||
<path
|
||||
d="M19 0H1C.45 0 0 .45 0 1v13c0 .55.45 1 1 1h5.67l-.5 3H5c-.55 0-1 .45-1 1s.45 1 1 1h10c.55 0 1-.45 1-1s-.45-1-1-1h-1.17l-.5-3H19c.55 0 1-.45 1-1V1c0-.55-.45-1-1-1zm-1 13H2V2h16v11z"
|
||||
fillRule="evenodd"
|
||||
key="0"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</Blueprint3.Icon>
|
||||
<Blueprint3.Text
|
||||
className="bp3-running-text"
|
||||
>
|
||||
<div
|
||||
className="bp3-running-text"
|
||||
>
|
||||
Entire Screen
|
||||
</div>
|
||||
</Blueprint3.Text>
|
||||
</span>
|
||||
<Blueprint3.Icon
|
||||
key="rightIcon"
|
||||
/>
|
||||
</button>
|
||||
</Blueprint3.Button>
|
||||
<Blueprint3.Button
|
||||
className="makeStyles-shareAppButton-4"
|
||||
intent="primary"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<button
|
||||
className="bp3-button bp3-intent-primary makeStyles-shareAppButton-4"
|
||||
onClick={[Function]}
|
||||
onKeyDown={[Function]}
|
||||
onKeyUp={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<Blueprint3.Icon
|
||||
key="leftIcon"
|
||||
/>
|
||||
<span
|
||||
className="bp3-button-text"
|
||||
key="text"
|
||||
>
|
||||
<Blueprint3.Icon
|
||||
className="makeStyles-shareAppButtonIcon-5"
|
||||
color="white"
|
||||
icon="application"
|
||||
iconSize={100}
|
||||
>
|
||||
<span
|
||||
className="bp3-icon bp3-icon-application makeStyles-shareAppButtonIcon-5"
|
||||
icon="application"
|
||||
>
|
||||
<svg
|
||||
data-icon="application"
|
||||
fill="white"
|
||||
height={100}
|
||||
viewBox="0 0 20 20"
|
||||
width={100}
|
||||
>
|
||||
<desc>
|
||||
application
|
||||
</desc>
|
||||
<path
|
||||
d="M3.5 9h9c.28 0 .5-.22.5-.5s-.22-.5-.5-.5h-9c-.28 0-.5.22-.5.5s.22.5.5.5zm0 2h5c.28 0 .5-.22.5-.5s-.22-.5-.5-.5h-5c-.28 0-.5.22-.5.5s.22.5.5.5zM19 1H1c-.55 0-1 .45-1 1v16c0 .55.45 1 1 1h18c.55 0 1-.45 1-1V2c0-.55-.45-1-1-1zm-1 16H2V6h16v11zM3.5 13h7c.28 0 .5-.22.5-.5s-.22-.5-.5-.5h-7c-.28 0-.5.22-.5.5s.22.5.5.5z"
|
||||
fillRule="evenodd"
|
||||
key="0"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</Blueprint3.Icon>
|
||||
<Blueprint3.Text
|
||||
className="bp3-running-text"
|
||||
>
|
||||
<div
|
||||
className="bp3-running-text"
|
||||
>
|
||||
Application Window
|
||||
</div>
|
||||
</Blueprint3.Text>
|
||||
</span>
|
||||
<Blueprint3.Icon
|
||||
key="rightIcon"
|
||||
/>
|
||||
</button>
|
||||
</Blueprint3.Button>
|
||||
<Blueprint3.Button
|
||||
active={true}
|
||||
className="makeStyles-orDecorationButton-6"
|
||||
>
|
||||
<button
|
||||
className="bp3-button bp3-active makeStyles-orDecorationButton-6"
|
||||
onKeyDown={[Function]}
|
||||
onKeyUp={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<Blueprint3.Icon
|
||||
key="leftIcon"
|
||||
/>
|
||||
<span
|
||||
className="bp3-button-text"
|
||||
key="text"
|
||||
>
|
||||
OR
|
||||
</span>
|
||||
<Blueprint3.Icon
|
||||
key="rightIcon"
|
||||
/>
|
||||
</button>
|
||||
</Blueprint3.Button>
|
||||
</div>
|
||||
</Blueprint3.ControlGroup>
|
||||
<ChooseAppOrScreenOverlay
|
||||
handleClose={[Function]}
|
||||
handleNextApplicationWindow={[Function]}
|
||||
handleNextEntireScreen={[Function]}
|
||||
isChooseAppOrScreenOverlayOpen={false}
|
||||
isEntireScreenToShareChosen={false}
|
||||
>
|
||||
<Blueprint3.Dialog
|
||||
autoFocus={true}
|
||||
canEscapeKeyClose={true}
|
||||
canOutsideClickClose={true}
|
||||
className="makeStyles-dialogRoot-7 choose-app-or-screen-dialog"
|
||||
enforceFocus={true}
|
||||
hasBackdrop={true}
|
||||
isOpen={false}
|
||||
onClose={[Function]}
|
||||
transitionDuration={0}
|
||||
usePortal={true}
|
||||
>
|
||||
<Blueprint3.Overlay
|
||||
autoFocus={true}
|
||||
backdropProps={Object {}}
|
||||
canEscapeKeyClose={true}
|
||||
canOutsideClickClose={true}
|
||||
className="bp3-overlay-scroll-container"
|
||||
enforceFocus={true}
|
||||
hasBackdrop={true}
|
||||
isOpen={false}
|
||||
lazy={true}
|
||||
onClose={[Function]}
|
||||
transitionDuration={0}
|
||||
transitionName="bp3-overlay"
|
||||
usePortal={true}
|
||||
/>
|
||||
</Blueprint3.Dialog>
|
||||
</ChooseAppOrScreenOverlay>
|
||||
</ShareEntireScreenOrAppWindowControlGroup>
|
||||
</Router>
|
||||
</BrowserRouter>
|
||||
`;
|
113
app/components/__snapshots__/TopPanel.spec.tsx.snap
Normal file
113
app/components/__snapshots__/TopPanel.spec.tsx.snap
Normal file
@ -0,0 +1,113 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<TopPanel /> should match exact snapshot 1`] = `
|
||||
<Fragment>
|
||||
<div
|
||||
className="makeStyles-topPanelRoot-1"
|
||||
>
|
||||
<Zoom
|
||||
duration={0}
|
||||
top={true}
|
||||
>
|
||||
<div
|
||||
className="makeStyles-logoWithAppName-9"
|
||||
id="logo-with-popover-visit-website"
|
||||
>
|
||||
<h4
|
||||
className="makeStyles-appNameHeader-17"
|
||||
id="deskreen-top-app-name-header"
|
||||
>
|
||||
Deskreen
|
||||
</h4>
|
||||
</div>
|
||||
</Zoom>
|
||||
<div
|
||||
className="makeStyles-topPanelControlButtonsRoot-25"
|
||||
>
|
||||
<Fade
|
||||
duration={0}
|
||||
right={true}
|
||||
>
|
||||
<div
|
||||
className="makeStyles-topPanelControlButtonMargin-34"
|
||||
>
|
||||
<Blueprint3.Tooltip
|
||||
content="Connected Devices"
|
||||
hoverCloseDelay={0}
|
||||
hoverOpenDelay={100}
|
||||
position="bottom"
|
||||
transitionDuration={100}
|
||||
>
|
||||
<Blueprint3.Button
|
||||
className="makeStyles-topPanelControlButton-40"
|
||||
id="top-panel-connected-devices-list-button"
|
||||
intent="none"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<Blueprint3.Icon
|
||||
className="makeStyles-topPanelIconOfControlButton-49"
|
||||
icon="th-list"
|
||||
iconSize={20}
|
||||
/>
|
||||
</Blueprint3.Button>
|
||||
</Blueprint3.Tooltip>
|
||||
</div>
|
||||
<div
|
||||
className="makeStyles-topPanelControlButtonMargin-55"
|
||||
>
|
||||
<Blueprint3.Tooltip
|
||||
content="Help"
|
||||
hoverCloseDelay={0}
|
||||
hoverOpenDelay={100}
|
||||
position="bottom"
|
||||
transitionDuration={100}
|
||||
>
|
||||
<Blueprint3.Button
|
||||
className="makeStyles-topPanelControlButton-61"
|
||||
id="top-panel-help-button"
|
||||
intent="none"
|
||||
>
|
||||
<Blueprint3.Icon
|
||||
className="makeStyles-topPanelIconOfControlButton-70"
|
||||
icon="help"
|
||||
iconSize={22}
|
||||
/>
|
||||
</Blueprint3.Button>
|
||||
</Blueprint3.Tooltip>
|
||||
</div>
|
||||
<div
|
||||
className="makeStyles-topPanelControlButtonMargin-76"
|
||||
>
|
||||
<Blueprint3.Tooltip
|
||||
content="Settings"
|
||||
hoverCloseDelay={0}
|
||||
hoverOpenDelay={100}
|
||||
position="bottom"
|
||||
transitionDuration={100}
|
||||
>
|
||||
<Blueprint3.Button
|
||||
className="makeStyles-topPanelControlButton-82"
|
||||
id="top-panel-settings-button"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<Blueprint3.Icon
|
||||
className="makeStyles-topPanelIconOfControlButton-91"
|
||||
icon="cog"
|
||||
iconSize={22}
|
||||
/>
|
||||
</Blueprint3.Button>
|
||||
</Blueprint3.Tooltip>
|
||||
</div>
|
||||
</Fade>
|
||||
</div>
|
||||
</div>
|
||||
<SettingsOverlay
|
||||
handleClose={[Function]}
|
||||
isSettingsOpen={false}
|
||||
/>
|
||||
<ConnectedDevicesListDrawer
|
||||
handleToggle={[Function]}
|
||||
isOpen={false}
|
||||
/>
|
||||
</Fragment>
|
||||
`;
|
@ -1,5 +0,0 @@
|
||||
export default {
|
||||
languages: ['ru', 'en'],
|
||||
fallbackLng: 'en',
|
||||
namespace: 'translation',
|
||||
};
|
10
app/configs/app.lang.config.ts
Normal file
10
app/configs/app.lang.config.ts
Normal file
@ -0,0 +1,10 @@
|
||||
export default {
|
||||
fallbackLng: 'en',
|
||||
namespace: 'translation',
|
||||
languages: ['ru', 'en', 'ua'],
|
||||
langISOKeyToLangFullNameMap: {
|
||||
en: 'English',
|
||||
ru: 'Русский',
|
||||
ua: 'Українська',
|
||||
},
|
||||
};
|
@ -1,18 +1,24 @@
|
||||
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
||||
import { remote, ipcRenderer } from 'electron';
|
||||
import i18n from 'i18next';
|
||||
import { initReactI18next } from 'react-i18next';
|
||||
import SyncBackend from 'i18next-node-fs-backend';
|
||||
import { join } from 'path';
|
||||
// import isDev from 'electron-is-dev';
|
||||
import config from './app.config';
|
||||
import settings from 'electron-settings';
|
||||
import config from './app.lang.config';
|
||||
import isProduction from '../utils/isProduction';
|
||||
|
||||
let isDev;
|
||||
try {
|
||||
// eslint-disable-next-line global-require
|
||||
isDev = require('electron-is-dev');
|
||||
} catch (e) {
|
||||
isDev = true;
|
||||
}
|
||||
export const getLangNameToLangKeyMap = () => {
|
||||
const res = {};
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
for (const [key, value] of Object.entries(
|
||||
config.langISOKeyToLangFullNameMap
|
||||
)) {
|
||||
// @ts-ignore: fine here
|
||||
res[value] = key;
|
||||
}
|
||||
return res;
|
||||
};
|
||||
|
||||
const appPath = remote.getGlobal('appPath');
|
||||
|
||||
@ -22,18 +28,20 @@ const i18nextOptions = {
|
||||
},
|
||||
backend: {
|
||||
// path where resources get loaded from
|
||||
loadPath: isDev
|
||||
? join(__dirname, './locales/{{lng}}/{{ns}}.json')
|
||||
: join(appPath, 'locales/{{lng}}/{{ns}}.json'),
|
||||
loadPath: isProduction()
|
||||
? join(appPath, 'locales/{{lng}}/{{ns}}.json')
|
||||
: join(__dirname, './locales/{{lng}}/{{ns}}.json'),
|
||||
// path to post missing resources
|
||||
addPath: isDev
|
||||
? join(__dirname, './locales/{{lng}}/{{ns}}.missing.json')
|
||||
: join(appPath, 'locales/{{lng}}/{{ns}}.json'),
|
||||
addPath: isProduction()
|
||||
? join(appPath, 'locales/{{lng}}/{{ns}}.json')
|
||||
: join(__dirname, './locales/{{lng}}/{{ns}}.missing.json'),
|
||||
// jsonIndent to use when storing json files
|
||||
jsonIndent: 2,
|
||||
},
|
||||
saveMissing: true,
|
||||
lng: 'en',
|
||||
lng: (settings.hasSync('appLanguage')
|
||||
? settings.getSync('appLanguage')
|
||||
: 'en') as string,
|
||||
fallbackLng: config.fallbackLng,
|
||||
whitelist: config.languages,
|
||||
react: {
|
||||
@ -47,8 +55,8 @@ if (!i18n.isInitialized) {
|
||||
i18n.init(i18nextOptions);
|
||||
}
|
||||
|
||||
ipcRenderer.on('sending-language-from-main', (_, message) => {
|
||||
i18n.changeLanguage(`${message}`);
|
||||
i18n.on('languageChanged', () => {
|
||||
ipcRenderer.send('client-changed-language', i18n.language);
|
||||
});
|
||||
|
||||
export default i18n;
|
||||
|
@ -1,36 +1,26 @@
|
||||
// const i18n = require('i18next');
|
||||
// const i18nextBackend = require('i18next-fs-backend');
|
||||
// const { join } = require('path');
|
||||
// const config = require('./app.config');
|
||||
|
||||
import i18n from 'i18next';
|
||||
import i18nextBackend from 'i18next-node-fs-backend';
|
||||
import { join } from 'path';
|
||||
// import isDev from 'electron-is-dev';
|
||||
import config from './app.config';
|
||||
|
||||
let isDev;
|
||||
try {
|
||||
// eslint-disable-next-line global-require
|
||||
isDev = require('electron-is-dev');
|
||||
} catch (e) {
|
||||
isDev = true;
|
||||
}
|
||||
import settings from 'electron-settings';
|
||||
import config from './app.lang.config';
|
||||
import isProduction from '../utils/isProduction';
|
||||
|
||||
const i18nextOptions = {
|
||||
fallbackLng: config.fallbackLng,
|
||||
lng: 'en',
|
||||
lng: (settings.hasSync('appLanguage')
|
||||
? settings.getSync('appLanguage')
|
||||
: 'en') as string,
|
||||
ns: 'translation',
|
||||
defaultNS: 'translation',
|
||||
backend: {
|
||||
// path where resources get loaded from
|
||||
loadPath: isDev
|
||||
? join(__dirname, '../locales/{{lng}}/{{ns}}.json')
|
||||
: join(__dirname, 'locales/{{lng}}/{{ns}}.json'),
|
||||
loadPath: isProduction()
|
||||
? join(__dirname, 'locales/{{lng}}/{{ns}}.json')
|
||||
: join(__dirname, '../locales/{{lng}}/{{ns}}.json'),
|
||||
// path to post missing resources
|
||||
addPath: isDev
|
||||
? join(__dirname, '../locales/{{lng}}/{{ns}}.missing.json')
|
||||
: join(__dirname, 'locales/{{lng}}/{{ns}}.json'),
|
||||
addPath: isProduction()
|
||||
? join(__dirname, 'locales/{{lng}}/{{ns}}.json')
|
||||
: join(__dirname, '../locales/{{lng}}/{{ns}}.missing.json'),
|
||||
// jsonIndent to use when storing json files
|
||||
jsonIndent: 2,
|
||||
},
|
||||
|
72
app/constants/test-devices.json
Normal file
72
app/constants/test-devices.json
Normal file
@ -0,0 +1,72 @@
|
||||
[
|
||||
{
|
||||
"id": "123414",
|
||||
"sessionId": "14422424",
|
||||
"deviceOs": "Android",
|
||||
"deviceType": "Mobile",
|
||||
"deviceIp": "123.123.123.123"
|
||||
},
|
||||
{
|
||||
"id": "1123",
|
||||
"sessionId": "43",
|
||||
"deviceOs": "IOS",
|
||||
"deviceType": "Mobile",
|
||||
"deviceIp": "124.124.124.124"
|
||||
},
|
||||
{
|
||||
"id": "2",
|
||||
"sessionId": "22",
|
||||
"deviceOs": "Windows",
|
||||
"deviceType": "PS",
|
||||
"deviceIp": "255.255.124.124"
|
||||
},
|
||||
{
|
||||
"id": "33",
|
||||
"sessionId": "22",
|
||||
"deviceOs": "Ubuntu",
|
||||
"deviceType": "PC",
|
||||
"deviceIp": "4.4.4.124"
|
||||
},
|
||||
{
|
||||
"id": "414",
|
||||
"sessionId": "423",
|
||||
"deviceOs": "Blackberry",
|
||||
"deviceType": "Mobile",
|
||||
"deviceIp": "224.224.224.124"
|
||||
},
|
||||
{
|
||||
"id": "1133223",
|
||||
"sessionId": "4133",
|
||||
"deviceOs": "IOS",
|
||||
"deviceType": "Mobile",
|
||||
"deviceIp": "24.24.24.24"
|
||||
},
|
||||
{
|
||||
"id": "1321123",
|
||||
"sessionId": "44133",
|
||||
"deviceOs": "Android",
|
||||
"deviceType": "Mobile",
|
||||
"deviceIp": "14.14.14.14"
|
||||
},
|
||||
{
|
||||
"id": "993",
|
||||
"sessionId": "91322",
|
||||
"deviceOs": "Debian",
|
||||
"deviceType": "PC",
|
||||
"deviceIp": "1.1.14.14"
|
||||
},
|
||||
{
|
||||
"id": "7757",
|
||||
"sessionId": "1111",
|
||||
"deviceOs": "MacOS",
|
||||
"deviceType": "Mac",
|
||||
"deviceIp": "12.12.14.14"
|
||||
},
|
||||
{
|
||||
"id": "123332",
|
||||
"sessionId": "323231",
|
||||
"deviceOs": "MacOS",
|
||||
"deviceType": "Mac",
|
||||
"deviceIp": "11.11.14.14"
|
||||
}
|
||||
]
|
88
app/constants/test-screen-sharing-objects.json
Normal file
88
app/constants/test-screen-sharing-objects.json
Normal file
@ -0,0 +1,88 @@
|
||||
[
|
||||
{
|
||||
"path": "https://material-ui.com/static/images/grid-list/breakfast.jpg",
|
||||
"id": "https://material-ui.com/static/images/grid-list/breakfast.jpg",
|
||||
"name": "Breakfast",
|
||||
"author": "jill111",
|
||||
"cols": 2,
|
||||
"featured": true
|
||||
},
|
||||
{
|
||||
"path": "https://material-ui.com/static/images/grid-list/burgers.jpg",
|
||||
"id": "https://material-ui.com/static/images/grid-list/burgers.jpg",
|
||||
"name": "Tasty burger",
|
||||
"cols": 3,
|
||||
"author": "director90"
|
||||
},
|
||||
{
|
||||
"path": "https://material-ui.com/static/images/grid-list/camera.jpg",
|
||||
"id": "https://material-ui.com/static/images/grid-list/camera.jpg",
|
||||
"name": "Camera",
|
||||
"cols": 2,
|
||||
"author": "Danson67"
|
||||
},
|
||||
{
|
||||
"path": "https://material-ui.com/static/images/grid-list/morning.jpg",
|
||||
"id": "https://material-ui.com/static/images/grid-list/morning.jpg",
|
||||
"name": "Morning",
|
||||
"author": "fancycrave1",
|
||||
"cols": 1,
|
||||
"featured": true
|
||||
},
|
||||
{
|
||||
"path": "https://material-ui.com/static/images/grid-list/hats.jpg",
|
||||
"id": "https://material-ui.com/static/images/grid-list/hats.jpg",
|
||||
"name": "Hats",
|
||||
"cols": 4,
|
||||
"author": "Hans"
|
||||
},
|
||||
{
|
||||
"path": "https://material-ui.com/static/images/grid-list/honey.jpg",
|
||||
"id": "https://material-ui.com/static/images/grid-list/honey.jpg",
|
||||
"name": "Honey",
|
||||
"cols": 1,
|
||||
"author": "fancycravel"
|
||||
},
|
||||
{
|
||||
"path": "https://material-ui.com/static/images/grid-list/vegetables.jpg",
|
||||
"id": "https://material-ui.com/static/images/grid-list/vegetables.jpg",
|
||||
"name": "Vegetables",
|
||||
"author": "jill111",
|
||||
"cols": 2
|
||||
},
|
||||
{
|
||||
"path": "https://material-ui.com/static/images/grid-list/plant.jpg",
|
||||
"id": "https://material-ui.com/static/images/grid-list/plant.jpg",
|
||||
"name": "Water plant",
|
||||
"author": "BkrmadtyaKarki",
|
||||
"cols": 3
|
||||
},
|
||||
{
|
||||
"path": "https://material-ui.com/static/images/grid-list/mushroom.jpg",
|
||||
"id": "https://material-ui.com/static/images/grid-list/mushroom.jpg",
|
||||
"name": "Mushrooms",
|
||||
"author": "PublicDomainPictures",
|
||||
"cols": 2
|
||||
},
|
||||
{
|
||||
"path": "https://material-ui.com/static/images/grid-list/olive.jpg",
|
||||
"id": "https://material-ui.com/static/images/grid-list/olive.jpg",
|
||||
"name": "Olive oil",
|
||||
"author": "congerdesign",
|
||||
"cols": 1
|
||||
},
|
||||
{
|
||||
"path": "https://material-ui.com/static/images/grid-list/star.jpg",
|
||||
"id": "https://material-ui.com/static/images/grid-list/star.jpg",
|
||||
"name": "Sea star",
|
||||
"cols": 2,
|
||||
"author": "821292"
|
||||
},
|
||||
{
|
||||
"path": "https://material-ui.com/static/images/grid-list/bike.jpg",
|
||||
"id": "https://material-ui.com/static/images/grid-list/bike.jpg",
|
||||
"name": "Bike",
|
||||
"author": "danfador",
|
||||
"cols": 3
|
||||
}
|
||||
]
|
7
app/containers/ConnectedDevicesProvider/Device.d.ts
vendored
Normal file
7
app/containers/ConnectedDevicesProvider/Device.d.ts
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
interface Device {
|
||||
id: string;
|
||||
sessionId: string;
|
||||
deviceOs: string;
|
||||
deviceType: string;
|
||||
deviceIp: string;
|
||||
}
|
99
app/containers/ConnectedDevicesProvider/index.tsx
Normal file
99
app/containers/ConnectedDevicesProvider/index.tsx
Normal file
@ -0,0 +1,99 @@
|
||||
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
||||
/* eslint-disable react/prop-types */
|
||||
import React, { useState, useCallback } from 'react';
|
||||
|
||||
interface ConnectedDevicesContextInterface {
|
||||
devices: Device[];
|
||||
pendingConnectionDevice: Device | null;
|
||||
setPendingConnectionDeviceHook: (device: Device) => void;
|
||||
addPendingConnectedDeviceListener: (
|
||||
callback: (device: Device) => void
|
||||
) => void;
|
||||
setDevicesHook: (devices: Device[]) => void;
|
||||
resetPendingConnectionDeviceHook: () => void;
|
||||
getDevices: () => Device[];
|
||||
}
|
||||
|
||||
// TODO this value should be set as soon as electron-ConnectedDevices is loaded, to load user pref
|
||||
const defaultConnectedDevicesContextValue = {
|
||||
devices: [] as Device[],
|
||||
pendingConnectionDevice: null,
|
||||
setPendingConnectionDeviceHook: () => {},
|
||||
addPendingConnectedDeviceListener: () => {},
|
||||
setDevicesHook: () => {},
|
||||
resetPendingConnectionDeviceHook: () => {},
|
||||
getDevices: () => [] as Device[],
|
||||
};
|
||||
|
||||
export const ConnectedDevicesContext = React.createContext<
|
||||
ConnectedDevicesContextInterface
|
||||
>(defaultConnectedDevicesContextValue);
|
||||
|
||||
export const ConnectedDevicesProvider: React.FC = ({ children }) => {
|
||||
const [devices, setDevices] = useState([] as Device[]);
|
||||
const [
|
||||
pendingConnectionDevice,
|
||||
setPendingConnectionDevice,
|
||||
] = useState<Device | null>();
|
||||
const [
|
||||
pendingDeviceConnectedListeners,
|
||||
setPendingDeviceConnectedListeners,
|
||||
] = useState([]);
|
||||
|
||||
const emitPendingConnectionDeviceConnected = useCallback(
|
||||
(device: Device) => {
|
||||
pendingDeviceConnectedListeners.forEach(
|
||||
(callback: (device: Device) => void) => {
|
||||
callback(device);
|
||||
}
|
||||
);
|
||||
},
|
||||
[pendingDeviceConnectedListeners]
|
||||
);
|
||||
|
||||
const setPendingConnectionDeviceHook = (device: Device) => {
|
||||
setPendingConnectionDevice(device);
|
||||
emitPendingConnectionDeviceConnected(device);
|
||||
};
|
||||
|
||||
const setDevicesHook = (_devices: Device[]) => {
|
||||
setDevices(_devices);
|
||||
};
|
||||
|
||||
const resetPendingConnectionDeviceHook = () => {
|
||||
setPendingConnectionDevice(undefined);
|
||||
};
|
||||
|
||||
const addPendingConnectedDeviceListener = (
|
||||
callback: (device: Device) => void
|
||||
) => {
|
||||
// @ts-ignore: has to be like that for now
|
||||
setPendingDeviceConnectedListeners([
|
||||
...pendingDeviceConnectedListeners,
|
||||
callback,
|
||||
]);
|
||||
};
|
||||
|
||||
const getDevices = useCallback(() => {
|
||||
return devices;
|
||||
}, [devices]);
|
||||
|
||||
// TODO: load saved devices here? in useEffect
|
||||
|
||||
const value = {
|
||||
devices,
|
||||
pendingConnectionDevice,
|
||||
setDevicesHook,
|
||||
setPendingConnectionDeviceHook,
|
||||
addPendingConnectedDeviceListener,
|
||||
resetPendingConnectionDeviceHook,
|
||||
getDevices,
|
||||
};
|
||||
|
||||
return (
|
||||
// @ts-ignore: it is ok here
|
||||
<ConnectedDevicesContext.Provider value={value}>
|
||||
{children}
|
||||
</ConnectedDevicesContext.Provider>
|
||||
);
|
||||
};
|
@ -1,11 +1,11 @@
|
||||
import React from 'react';
|
||||
import NavPanel from '../components/NavPanel';
|
||||
import TopPanel from '../components/TopPanel';
|
||||
import Counter from '../features/counter/Counter';
|
||||
|
||||
export default function CounterPage() {
|
||||
return (
|
||||
<>
|
||||
<NavPanel />
|
||||
<TopPanel />
|
||||
<Counter />
|
||||
</>
|
||||
);
|
||||
|
28
app/containers/HomePage.spec.tsx
Normal file
28
app/containers/HomePage.spec.tsx
Normal file
@ -0,0 +1,28 @@
|
||||
import React, { Suspense } from 'react';
|
||||
import Enzyme, { mount } from 'enzyme';
|
||||
import EnzymeToJson from 'enzyme-to-json';
|
||||
import Adapter from 'enzyme-adapter-react-16';
|
||||
import { BrowserRouter as Router } from 'react-router-dom';
|
||||
import HomePage from './HomePage';
|
||||
import { SettingsProvider } from './SettingsProvider';
|
||||
import { ConnectedDevicesProvider } from './ConnectedDevicesProvider';
|
||||
|
||||
Enzyme.configure({ adapter: new Adapter() });
|
||||
jest.useFakeTimers();
|
||||
|
||||
it('should match exact snapshot', () => {
|
||||
const subject = mount(
|
||||
<>
|
||||
<Suspense fallback={<div>Loading... </div>}>
|
||||
<SettingsProvider>
|
||||
<ConnectedDevicesProvider>
|
||||
<Router>
|
||||
<HomePage />
|
||||
</Router>
|
||||
</ConnectedDevicesProvider>
|
||||
</SettingsProvider>
|
||||
</Suspense>
|
||||
</>
|
||||
);
|
||||
expect(EnzymeToJson(subject)).toMatchSnapshot();
|
||||
});
|
@ -1,12 +1,50 @@
|
||||
import React from 'react';
|
||||
import NavPanel from '../components/NavPanel';
|
||||
import Home from '../components/Home';
|
||||
/* eslint-disable react/destructuring-assignment */
|
||||
/* eslint-disable react/jsx-props-no-spreading */
|
||||
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
||||
|
||||
import React, { useRef } from 'react';
|
||||
import { Classes } from '@blueprintjs/core';
|
||||
import { ToastProvider, DefaultToast } from 'react-toast-notifications';
|
||||
|
||||
import TopPanel from '../components/TopPanel';
|
||||
import { LIGHT_UI_BACKGROUND } from './SettingsProvider';
|
||||
import DeskreenStepper from './Stepper';
|
||||
|
||||
// @ts-ignore: it is ok here, be like js it is fine
|
||||
// eslint-disable-next-line react/prop-types
|
||||
export const CustomToastWithTheme = ({ children, ...props }) => {
|
||||
return (
|
||||
<DefaultToast
|
||||
components={{ Toast: CustomToastWithTheme }}
|
||||
{...props}
|
||||
// @ts-ignore: some minor type complain, it is fine here
|
||||
style={{
|
||||
// eslint-disable-next-line react/prop-types
|
||||
color: props.isdarktheme === 'false' ? '#293742' : '#BFCCD6',
|
||||
backgroundColor:
|
||||
// eslint-disable-next-line react/prop-types
|
||||
props.isdarktheme === 'false' ? LIGHT_UI_BACKGROUND : '#394B59',
|
||||
}}
|
||||
>
|
||||
<>{children}</>
|
||||
</DefaultToast>
|
||||
);
|
||||
};
|
||||
|
||||
export default function HomePage() {
|
||||
const stepperRef = useRef();
|
||||
|
||||
return (
|
||||
<>
|
||||
<NavPanel />
|
||||
<Home />
|
||||
</>
|
||||
<ToastProvider
|
||||
placement="top-center"
|
||||
autoDismissTimeout={5000}
|
||||
components={{ Toast: CustomToastWithTheme }}
|
||||
>
|
||||
<div className={Classes.TREE}>
|
||||
<TopPanel stepperRef={stepperRef} />
|
||||
<DeskreenStepper ref={stepperRef} />
|
||||
{/* <Home /> */}
|
||||
</div>
|
||||
</ToastProvider>
|
||||
);
|
||||
}
|
||||
|
@ -1,11 +1,17 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { FocusStyleManager } from '@blueprintjs/core';
|
||||
import { Provider } from 'react-redux';
|
||||
|
||||
import { ConnectedRouter } from 'connected-react-router';
|
||||
import { hot } from 'react-hot-loader/root';
|
||||
import { History } from 'history';
|
||||
import { Store } from '../store';
|
||||
import Routes from '../Routes';
|
||||
import i18n from '../configs/i18next.config.client';
|
||||
import { SettingsProvider } from './SettingsProvider';
|
||||
import { ConnectedDevicesProvider } from './ConnectedDevicesProvider';
|
||||
|
||||
FocusStyleManager.onlyShowFocusOnTabs();
|
||||
|
||||
type Props = {
|
||||
store: Store;
|
||||
@ -23,9 +29,13 @@ const Root = ({ store, history }: Props) => {
|
||||
|
||||
return (
|
||||
<Provider store={store}>
|
||||
<ConnectedRouter history={history}>
|
||||
<Routes />
|
||||
</ConnectedRouter>
|
||||
<SettingsProvider>
|
||||
<ConnectedDevicesProvider>
|
||||
<ConnectedRouter history={history}>
|
||||
<Routes />
|
||||
</ConnectedRouter>
|
||||
</ConnectedDevicesProvider>
|
||||
</SettingsProvider>
|
||||
</Provider>
|
||||
);
|
||||
};
|
||||
|
61
app/containers/SettingsProvider.tsx
Normal file
61
app/containers/SettingsProvider.tsx
Normal file
@ -0,0 +1,61 @@
|
||||
/* eslint-disable @typescript-eslint/no-empty-interface */
|
||||
/* eslint-disable react/prop-types */
|
||||
/* eslint-disable import/prefer-default-export */
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import settings from 'electron-settings';
|
||||
import { Classes } from '@blueprintjs/core';
|
||||
|
||||
export const LIGHT_UI_BACKGROUND = 'rgba(240, 248, 250, 1)';
|
||||
export const DARK_UI_BACKGROUND = '#293742';
|
||||
|
||||
interface SettingsContextInterface {
|
||||
isDarkTheme: boolean;
|
||||
setIsDarkThemeHook: (val: boolean) => void;
|
||||
}
|
||||
|
||||
const defaultSettingsContextValue = {
|
||||
isDarkTheme: false,
|
||||
setIsDarkThemeHook: () => {},
|
||||
};
|
||||
|
||||
export const SettingsContext = React.createContext<SettingsContextInterface>(
|
||||
defaultSettingsContextValue
|
||||
);
|
||||
|
||||
export const SettingsProvider: React.FC = ({ children }) => {
|
||||
const [isDarkTheme, setIsDarkTheme] = useState(false);
|
||||
|
||||
const loadDarkThemeFromSettings = () => {
|
||||
const gotIsDarkThemeFromSettings = settings.hasSync('appIsDarkTheme')
|
||||
? settings.getSync('appIsDarkTheme') === 'true'
|
||||
: false;
|
||||
|
||||
if (gotIsDarkThemeFromSettings) {
|
||||
document.body.classList.toggle(Classes.DARK);
|
||||
// if ()
|
||||
document.body.style.backgroundColor = LIGHT_UI_BACKGROUND;
|
||||
}
|
||||
|
||||
setIsDarkTheme(gotIsDarkThemeFromSettings);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
loadDarkThemeFromSettings();
|
||||
}, []);
|
||||
|
||||
const setIsDarkThemeHook = (val: boolean) => {
|
||||
settings.setSync('appIsDarkTheme', `${val}`);
|
||||
setIsDarkTheme(val);
|
||||
// if (!val) {
|
||||
// document.body.style.backgroundColor = `${LIGHT_UI_BACKGROUND} !important`;
|
||||
// }
|
||||
};
|
||||
|
||||
const value = { isDarkTheme, setIsDarkThemeHook };
|
||||
|
||||
return (
|
||||
<SettingsContext.Provider value={value}>
|
||||
{children}
|
||||
</SettingsContext.Provider>
|
||||
);
|
||||
};
|
23
app/containers/Stepper.spec.tsx
Normal file
23
app/containers/Stepper.spec.tsx
Normal file
@ -0,0 +1,23 @@
|
||||
import React from 'react';
|
||||
import Enzyme, { mount } from 'enzyme';
|
||||
import EnzymeToJson from 'enzyme-to-json';
|
||||
import Adapter from 'enzyme-adapter-react-16';
|
||||
import { BrowserRouter as Router } from 'react-router-dom';
|
||||
import { ToastProvider } from 'react-toast-notifications';
|
||||
import DeskreenStepper from './Stepper';
|
||||
|
||||
Enzyme.configure({ adapter: new Adapter() });
|
||||
jest.useFakeTimers();
|
||||
|
||||
it('should match exact snapshot', () => {
|
||||
const subject = mount(
|
||||
<>
|
||||
<ToastProvider placement="top-center">
|
||||
<Router>
|
||||
<DeskreenStepper />
|
||||
</Router>
|
||||
</ToastProvider>
|
||||
</>
|
||||
);
|
||||
expect(EnzymeToJson(subject)).toMatchSnapshot();
|
||||
});
|
267
app/containers/Stepper.tsx
Normal file
267
app/containers/Stepper.tsx
Normal file
@ -0,0 +1,267 @@
|
||||
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
||||
import React, { useState, useCallback, useContext, useEffect } from 'react';
|
||||
import { makeStyles, createStyles } from '@material-ui/core/styles';
|
||||
import Stepper from '@material-ui/core/Stepper';
|
||||
import Step from '@material-ui/core/Step';
|
||||
import StepLabel from '@material-ui/core/StepLabel';
|
||||
import { Row, Col } from 'react-flexbox-grid';
|
||||
import { Text } from '@blueprintjs/core';
|
||||
|
||||
import { useToasts } from 'react-toast-notifications';
|
||||
|
||||
import SuccessStep from '../components/StepsOfStepper/SuccessStep';
|
||||
import IntermediateStep from '../components/StepsOfStepper/IntermediateStep';
|
||||
import { ConnectedDevicesContext } from './ConnectedDevicesProvider';
|
||||
import AllowConnectionForDeviceAlert from '../components/AllowConnectionForDeviceAlert';
|
||||
import DeviceConnectedInfoButton from '../components/StepperPanel/DeviceConnectedInfoButton';
|
||||
import ColorlibStepIcon, {
|
||||
StepIconPropsDeskreen,
|
||||
} from '../components/StepperPanel/ColorlibStepIcon';
|
||||
import ColorlibConnector from '../components/StepperPanel/ColorlibConnector';
|
||||
import { SettingsContext } from './SettingsProvider';
|
||||
import isProduction from '../utils/isProduction';
|
||||
|
||||
const Fade = require('react-reveal/Fade');
|
||||
const Zoom = require('react-reveal/Zoom');
|
||||
const Pulse = require('react-reveal/Pulse');
|
||||
|
||||
const useStyles = makeStyles(() =>
|
||||
createStyles({
|
||||
stepContent: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
stepLabelContent: {
|
||||
marginTop: '10px !important',
|
||||
height: '110px',
|
||||
},
|
||||
stepperComponent: {
|
||||
paddingBottom: '0px',
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
function getSteps() {
|
||||
return ['Connect', 'Select', 'Confirm'];
|
||||
}
|
||||
|
||||
// eslint-disable-next-line react/display-name
|
||||
const DeskreenStepper = React.forwardRef((_props, ref) => {
|
||||
const classes = useStyles();
|
||||
|
||||
const [isInterShow, setIsInterShow] = useState(false);
|
||||
|
||||
const { isDarkTheme } = useContext(SettingsContext);
|
||||
|
||||
const { addToast } = useToasts();
|
||||
|
||||
const [isAlertOpen, setIsAlertOpen] = useState(false);
|
||||
const [isUserAllowedConnection, setIsUserAllowedConnection] = useState(false);
|
||||
|
||||
const { addPendingConnectedDeviceListener } = useContext(
|
||||
ConnectedDevicesContext
|
||||
);
|
||||
|
||||
const [
|
||||
pendingConnectionDevice,
|
||||
setPendingConnectionDevice,
|
||||
] = useState<Device | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
addPendingConnectedDeviceListener((device: Device) => {
|
||||
setPendingConnectionDevice(device);
|
||||
setIsAlertOpen(true);
|
||||
});
|
||||
|
||||
setTimeout(
|
||||
() => {
|
||||
setIsInterShow(true);
|
||||
},
|
||||
isProduction() ? 500 : 0
|
||||
);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
const [activeStep, setActiveStep] = useState(0);
|
||||
const [isEntireScreenSelected, setIsEntireScreenSelected] = useState(false);
|
||||
const [
|
||||
isApplicationWindowSelected,
|
||||
setIsApplicationWindowSelected,
|
||||
] = useState(false);
|
||||
const steps = getSteps();
|
||||
|
||||
const makeSmoothIntermediateStepTransition = () => {
|
||||
if (!isProduction()) return;
|
||||
setIsInterShow(false);
|
||||
setTimeout(() => {
|
||||
setIsInterShow(true);
|
||||
}, 500);
|
||||
};
|
||||
|
||||
const handleNext = useCallback(() => {
|
||||
makeSmoothIntermediateStepTransition();
|
||||
if (activeStep === steps.length - 1) {
|
||||
setIsEntireScreenSelected(false);
|
||||
setIsApplicationWindowSelected(false);
|
||||
}
|
||||
setActiveStep((prevActiveStep) => prevActiveStep + 1);
|
||||
}, [activeStep, steps]);
|
||||
|
||||
const handleNextEntireScreen = useCallback(() => {
|
||||
makeSmoothIntermediateStepTransition();
|
||||
setActiveStep((prevActiveStep) => prevActiveStep + 1);
|
||||
setIsEntireScreenSelected(true);
|
||||
}, []);
|
||||
|
||||
const handleNextApplicationWindow = useCallback(() => {
|
||||
makeSmoothIntermediateStepTransition();
|
||||
setActiveStep((prevActiveStep) => prevActiveStep + 1);
|
||||
setIsApplicationWindowSelected(true);
|
||||
}, []);
|
||||
|
||||
const handleBack = useCallback(() => {
|
||||
makeSmoothIntermediateStepTransition();
|
||||
setActiveStep((prevActiveStep) => prevActiveStep - 1);
|
||||
}, []);
|
||||
|
||||
const handleReset = useCallback(() => {
|
||||
makeSmoothIntermediateStepTransition();
|
||||
setActiveStep(0);
|
||||
}, []);
|
||||
|
||||
React.useImperativeHandle(ref, () => ({
|
||||
handleReset() {
|
||||
handleReset();
|
||||
},
|
||||
}));
|
||||
|
||||
const handleCancelAlert = () => {
|
||||
setIsAlertOpen(false);
|
||||
};
|
||||
|
||||
const handleConfirmAlert = useCallback(() => {
|
||||
setIsAlertOpen(false);
|
||||
setIsUserAllowedConnection(true);
|
||||
handleNext();
|
||||
}, [handleNext]);
|
||||
|
||||
const handleUserClickedDeviceDisconnectButton = useCallback(() => {
|
||||
handleReset();
|
||||
setPendingConnectionDevice(null);
|
||||
setIsUserAllowedConnection(false);
|
||||
|
||||
addToast(
|
||||
<Text>
|
||||
Device is successfully disconnected by you. You can connect new device
|
||||
</Text>,
|
||||
{
|
||||
appearance: 'info',
|
||||
autoDismiss: true,
|
||||
// @ts-ignore: works fine here, ignore
|
||||
isdarktheme: `${isDarkTheme}`,
|
||||
}
|
||||
);
|
||||
}, [addToast, handleReset, isDarkTheme]);
|
||||
|
||||
const renderIntermediateOrSuccessStepContent = useCallback(() => {
|
||||
return activeStep === steps.length ? (
|
||||
<Zoom duration={300} when={isInterShow}>
|
||||
<Row middle="xs" center="xs">
|
||||
<SuccessStep handleReset={handleReset} />
|
||||
</Row>
|
||||
</Zoom>
|
||||
) : (
|
||||
<Fade duration={isProduction() ? 300 : 0} when={isInterShow}>
|
||||
<IntermediateStep
|
||||
activeStep={activeStep}
|
||||
steps={steps}
|
||||
handleNext={handleNext}
|
||||
handleBack={handleBack}
|
||||
handleNextEntireScreen={handleNextEntireScreen}
|
||||
handleNextApplicationWindow={handleNextApplicationWindow}
|
||||
resetPendingConnectionDevice={() => setPendingConnectionDevice(null)}
|
||||
resetUserAllowedConnection={() => setIsUserAllowedConnection(false)}
|
||||
/>
|
||||
</Fade>
|
||||
);
|
||||
}, [
|
||||
activeStep,
|
||||
steps,
|
||||
isInterShow,
|
||||
handleReset,
|
||||
handleNext,
|
||||
handleBack,
|
||||
handleNextEntireScreen,
|
||||
handleNextApplicationWindow,
|
||||
]);
|
||||
|
||||
const renderStepLabelContent = useCallback(
|
||||
(label, idx) => {
|
||||
return (
|
||||
<StepLabel
|
||||
id="step-label-deskreen"
|
||||
className={classes.stepLabelContent}
|
||||
StepIconComponent={ColorlibStepIcon}
|
||||
StepIconProps={
|
||||
{
|
||||
isEntireScreenSelected,
|
||||
isApplicationWindowSelected,
|
||||
} as StepIconPropsDeskreen
|
||||
}
|
||||
>
|
||||
{pendingConnectionDevice && idx === 0 && isUserAllowedConnection ? (
|
||||
<DeviceConnectedInfoButton
|
||||
device={pendingConnectionDevice}
|
||||
onDisconnect={handleUserClickedDeviceDisconnectButton}
|
||||
/>
|
||||
) : (
|
||||
<Text className="bp3-text-muted">{label}</Text>
|
||||
)}
|
||||
</StepLabel>
|
||||
);
|
||||
},
|
||||
[
|
||||
classes.stepLabelContent,
|
||||
handleUserClickedDeviceDisconnectButton,
|
||||
isApplicationWindowSelected,
|
||||
isEntireScreenSelected,
|
||||
isUserAllowedConnection,
|
||||
pendingConnectionDevice,
|
||||
]
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Row>
|
||||
<Col xs={12}>
|
||||
<Pulse top duration={isProduction() ? 1500 : 0}>
|
||||
<Stepper
|
||||
className={classes.stepperComponent}
|
||||
activeStep={activeStep}
|
||||
alternativeLabel
|
||||
style={{ background: 'transparent' }}
|
||||
connector={<ColorlibConnector />}
|
||||
>
|
||||
{steps.map((label, idx) => (
|
||||
<Step key={label}>{renderStepLabelContent(label, idx)}</Step>
|
||||
))}
|
||||
</Stepper>
|
||||
</Pulse>
|
||||
</Col>
|
||||
<Col className={classes.stepContent} xs={12}>
|
||||
{renderIntermediateOrSuccessStepContent()}
|
||||
</Col>
|
||||
</Row>
|
||||
<AllowConnectionForDeviceAlert
|
||||
device={pendingConnectionDevice}
|
||||
isOpen={isAlertOpen}
|
||||
onCancel={handleCancelAlert}
|
||||
onConfirm={handleConfirmAlert}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
||||
export default DeskreenStepper;
|
30
app/containers/__mocks__/electron-settings.ts
Normal file
30
app/containers/__mocks__/electron-settings.ts
Normal file
@ -0,0 +1,30 @@
|
||||
/* eslint-disable import/prefer-default-export */
|
||||
|
||||
// export const hasSync = (name: string) => {
|
||||
// if (name === 'appLanguage') {
|
||||
// return true;
|
||||
// }
|
||||
// return false;
|
||||
// };
|
||||
|
||||
// export const getSync = (name: string) => {
|
||||
// if (name === 'appLanguage') {
|
||||
// return 'en';
|
||||
// }
|
||||
// return 'en';
|
||||
// };
|
||||
|
||||
export default {
|
||||
hasSync: (name: string) => {
|
||||
if (name === 'appLanguage') {
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
getSync: (name: string) => {
|
||||
if (name === 'appLanguage') {
|
||||
return 'en';
|
||||
}
|
||||
return 'en';
|
||||
},
|
||||
};
|
10
app/containers/__mocks__/electron.ts
Normal file
10
app/containers/__mocks__/electron.ts
Normal file
@ -0,0 +1,10 @@
|
||||
/* eslint-disable import/prefer-default-export */
|
||||
|
||||
export const remote = {
|
||||
getGlobal: (name: string) => {
|
||||
if (name === 'appPath') {
|
||||
return __dirname;
|
||||
}
|
||||
return '';
|
||||
},
|
||||
};
|
19
app/containers/__mocks__/react-i18next.ts
Normal file
19
app/containers/__mocks__/react-i18next.ts
Normal file
@ -0,0 +1,19 @@
|
||||
/* eslint-disable import/prefer-default-export */
|
||||
|
||||
import { ThirdPartyModule } from 'i18next';
|
||||
|
||||
export const useTranslation = () => {
|
||||
return {
|
||||
t: (key: string) => {
|
||||
if (key === 'Language') {
|
||||
return 'Language';
|
||||
}
|
||||
return '';
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export const initReactI18next: ThirdPartyModule = {
|
||||
type: '3rdParty',
|
||||
init: () => {},
|
||||
};
|
2276
app/containers/__snapshots__/HomePage.spec.tsx.snap
Normal file
2276
app/containers/__snapshots__/HomePage.spec.tsx.snap
Normal file
File diff suppressed because it is too large
Load Diff
1556
app/containers/__snapshots__/Stepper.spec.tsx.snap
Normal file
1556
app/containers/__snapshots__/Stepper.spec.tsx.snap
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,3 +1,5 @@
|
||||
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
||||
/* eslint-disable no-new */
|
||||
import React, { Fragment, Suspense } from 'react';
|
||||
import { render } from 'react-dom';
|
||||
import { AppContainer as ReactHotAppContainer } from 'react-hot-loader';
|
||||
@ -10,6 +12,19 @@ const store = configuredStore();
|
||||
const AppContainer = process.env.PLAIN_HMR ? Fragment : ReactHotAppContainer;
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
if (process.platform === 'darwin') {
|
||||
const windowTopBar = document.createElement('div');
|
||||
windowTopBar.style.width = '100%';
|
||||
windowTopBar.style.height = '50px';
|
||||
windowTopBar.style.position = 'absolute';
|
||||
windowTopBar.style.top = '0';
|
||||
windowTopBar.style.left = '0';
|
||||
// @ts-ignore: all good here
|
||||
windowTopBar.style.webkitAppRegion = 'drag';
|
||||
windowTopBar.style.pointerEvents = 'none';
|
||||
document.body.appendChild(windowTopBar);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line global-require
|
||||
const Root = require('./containers/Root').default;
|
||||
render(
|
||||
|
@ -1,6 +1,7 @@
|
||||
{
|
||||
"Language": "🌐 Language",
|
||||
"Language": "Language 🇬🇧 / 🇺🇸",
|
||||
"Signaling server is running on port": "Signaling server is running on port ⚓",
|
||||
"ru": "Русский",
|
||||
"en": "English"
|
||||
"en": "English",
|
||||
"ua": "Українська"
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
{
|
||||
"Language": "🌐 Язык",
|
||||
"Language": "Язык 🇷🇺",
|
||||
"Signaling server is running on port": "Сигнальный сервер работает на порте ⚓",
|
||||
"ru": "Русский",
|
||||
"en": "English"
|
||||
"en": "English",
|
||||
"ua": "Українська"
|
||||
}
|
||||
|
7
app/locales/ua/translation.json
Normal file
7
app/locales/ua/translation.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"Language": "Мова 🇺🇦",
|
||||
"Signaling server is running on port": "Сигнальный сервер працює на порту ⚓",
|
||||
"ru": "Русский",
|
||||
"en": "English",
|
||||
"ua": "Українська"
|
||||
}
|
0
app/locales/ua/translation.missing.json
Normal file
0
app/locales/ua/translation.missing.json
Normal file
@ -15,7 +15,7 @@ import path from 'path';
|
||||
import { app, BrowserWindow, ipcMain } from 'electron';
|
||||
import { autoUpdater } from 'electron-updater';
|
||||
import log from 'electron-log';
|
||||
import config from './configs/app.config';
|
||||
import settings from 'electron-settings';
|
||||
import i18n from './configs/i18next.config';
|
||||
import signalingServer from './server';
|
||||
import MenuBuilder from './menu';
|
||||
@ -25,6 +25,8 @@ globalAny.appPath = __dirname;
|
||||
|
||||
signalingServer.start();
|
||||
|
||||
log.error(process.platform);
|
||||
|
||||
export default class AppUpdater {
|
||||
constructor() {
|
||||
log.transports.file.level = 'info';
|
||||
@ -68,8 +70,13 @@ const createWindow = async () => {
|
||||
|
||||
mainWindow = new BrowserWindow({
|
||||
show: false,
|
||||
width: 1024,
|
||||
height: 728,
|
||||
width: 820,
|
||||
height: 480,
|
||||
// maxWidth: 820,
|
||||
// maxHeight: 480,
|
||||
minHeight: 400,
|
||||
minWidth: 600,
|
||||
titleBarStyle: 'hiddenInset',
|
||||
webPreferences:
|
||||
(process.env.NODE_ENV === 'development' ||
|
||||
process.env.E2E_BUILD === 'true') &&
|
||||
@ -115,8 +122,12 @@ const createWindow = async () => {
|
||||
if (mainWindow === null) return;
|
||||
menuBuilder = new MenuBuilder(mainWindow, i18n);
|
||||
menuBuilder.buildMenu();
|
||||
mainWindow.webContents.send('sending-language-from-main', lng);
|
||||
console.log(`Language changed! ${lng}`);
|
||||
setTimeout(async () => {
|
||||
if (lng !== 'en' && i18n.language !== lng) {
|
||||
i18n.changeLanguage(lng);
|
||||
await settings.set('appLanguage', lng);
|
||||
}
|
||||
}, 400);
|
||||
});
|
||||
|
||||
// Remove this if your app does not use auto updates
|
||||
@ -154,15 +165,7 @@ ipcMain.handle('get-signaling-server-port', () => {
|
||||
mainWindow.webContents.send('sending-port-from-main', signalingServer.port);
|
||||
});
|
||||
|
||||
// ipcMain.on('get-initial-translations', (event, arg) => {
|
||||
ipcMain.on('get-initial-translations', (event) => {
|
||||
// i18n.loadLanguages('en', (err, t) => {
|
||||
i18n.loadLanguages('en', () => {
|
||||
const initial = {
|
||||
en: {
|
||||
translation: i18n.getResourceBundle('en', config.namespace),
|
||||
},
|
||||
};
|
||||
event.returnValue = initial;
|
||||
});
|
||||
ipcMain.on('client-changed-language', async (_, newLangCode) => {
|
||||
i18n.changeLanguage(newLangCode);
|
||||
await settings.set('appLanguage', newLangCode);
|
||||
});
|
||||
|
@ -305,3 +305,15 @@
|
||||
* Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
|
||||
* Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
|
||||
*/
|
||||
|
||||
/**
|
||||
* @preserve
|
||||
* JS Implementation of incremental MurmurHash3 (r150) (as of May 10, 2013)
|
||||
*
|
||||
* @author <a href="mailto:jensyt@gmail.com">Jens Taylor</a>
|
||||
* @see http://github.com/homebrewing/brauhaus-diff
|
||||
* @author <a href="mailto:gary.court@gmail.com">Gary Court</a>
|
||||
* @see http://github.com/garycourt/murmurhash-js
|
||||
* @author <a href="mailto:aappleby@gmail.com">Austin Appleby</a>
|
||||
* @see http://sites.google.com/site/murmurhash/
|
||||
*/
|
||||
|
23
app/menu.ts
23
app/menu.ts
@ -7,7 +7,7 @@ import {
|
||||
MenuItemConstructorOptions,
|
||||
} from 'electron';
|
||||
|
||||
import config from './configs/app.config';
|
||||
import config from './configs/app.lang.config';
|
||||
|
||||
import signalingServer from './server';
|
||||
|
||||
@ -26,7 +26,7 @@ export default class MenuBuilder {
|
||||
this.i18n = i18n;
|
||||
}
|
||||
|
||||
buildMenu(): Menu {
|
||||
buildMenu() {
|
||||
if (
|
||||
process.env.NODE_ENV === 'development' ||
|
||||
process.env.DEBUG_PROD === 'true'
|
||||
@ -34,15 +34,16 @@ export default class MenuBuilder {
|
||||
this.setupDevelopmentEnvironment();
|
||||
}
|
||||
|
||||
const template =
|
||||
process.platform === 'darwin'
|
||||
? this.buildDarwinTemplate()
|
||||
: this.buildDefaultTemplate();
|
||||
|
||||
const menu = Menu.buildFromTemplate(template);
|
||||
Menu.setApplicationMenu(menu);
|
||||
|
||||
return menu;
|
||||
if (process.platform === 'darwin') {
|
||||
const menu = Menu.buildFromTemplate(this.buildDarwinTemplate());
|
||||
Menu.setApplicationMenu(menu);
|
||||
} else if (process.env.NODE_ENV === 'development') {
|
||||
const menu = Menu.buildFromTemplate(this.buildDefaultTemplate());
|
||||
Menu.setApplicationMenu(menu);
|
||||
} else {
|
||||
// for production, no menu for non MacOS app
|
||||
Menu.setApplicationMenu(null);
|
||||
}
|
||||
}
|
||||
|
||||
setupDevelopmentEnvironment(): void {
|
||||
|
2
app/package-lock.json
generated
2
app/package-lock.json
generated
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "deskreen",
|
||||
"version": "0.0.2-alpha",
|
||||
"version": "0.0.3-alpha",
|
||||
"lockfileVersion": 1
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "deskreen",
|
||||
"productName": "deskreen",
|
||||
"version": "0.0.2-alpha",
|
||||
"version": "0.0.3-alpha",
|
||||
"description": "TODO: write description about this project",
|
||||
"main": "./main.prod.js",
|
||||
"author": {
|
||||
|
@ -20,17 +20,10 @@ import pollForInactiveRooms from './inactiveRooms';
|
||||
import getStore from './store';
|
||||
|
||||
import Logger from '../utils/logger';
|
||||
import isProduction from '../utils/isProduction';
|
||||
|
||||
const log = new Logger('app/server/index.ts');
|
||||
|
||||
let isDev;
|
||||
try {
|
||||
// eslint-disable-next-line global-require
|
||||
isDev = require('electron-is-dev');
|
||||
} catch (e) {
|
||||
isDev = true;
|
||||
}
|
||||
|
||||
const app = new Koa();
|
||||
|
||||
const router = new Router();
|
||||
@ -54,9 +47,9 @@ function setStaticFileHeaders(
|
||||
});
|
||||
}
|
||||
|
||||
const clientDistDirectory = isDev
|
||||
? `${__dirname}/../client/build`
|
||||
: `${__dirname}/client/build`;
|
||||
const clientDistDirectory = isProduction()
|
||||
? `${__dirname}/client/build`
|
||||
: `${__dirname}/../client/build`;
|
||||
|
||||
if (clientDistDirectory) {
|
||||
app.use(async (ctx, next) => {
|
||||
|
8
app/utils/isProduction.ts
Normal file
8
app/utils/isProduction.ts
Normal file
@ -0,0 +1,8 @@
|
||||
export default function isProduction() {
|
||||
return (
|
||||
process.env.NODE_ENV === 'production' &&
|
||||
process.env.RUN_MODE !== 'dev' &&
|
||||
process.env.RUN_MODE !== 'test'
|
||||
);
|
||||
// return true; // for animations and other things debugging as in production mode
|
||||
}
|
36
package.json
36
package.json
@ -1,16 +1,20 @@
|
||||
{
|
||||
"name": "deskreen",
|
||||
"productName": "Deskreen",
|
||||
"version": "0.0.2-alpha",
|
||||
"version": "0.0.3-alpha",
|
||||
"description": "TODO: write description of this app",
|
||||
"scripts": {
|
||||
"build": "concurrently \"yarn build-main\" \"yarn build-renderer\" \"yarn build-client\"",
|
||||
"build-test": "concurrently \"yarn build-main-test\" \"yarn build-renderer-test\" \"yarn build-client\"",
|
||||
"build-dll": "cross-env NODE_ENV=development webpack --config ./configs/webpack.config.renderer.dev.dll.babel.js --colors",
|
||||
"build-e2e": "cross-env E2E_BUILD=true yarn build",
|
||||
"build-ux": "cross-env E2E_BUILD=true RUN_MODE=test yarn build-test",
|
||||
"build-main": "cross-env NODE_ENV=production webpack --config ./configs/webpack.config.main.prod.babel.js --colors",
|
||||
"build-main-test": "cross-env RUN_MODE=test NODE_ENV=production webpack --config ./configs/webpack.config.main.prod.babel.js --colors",
|
||||
"build-renderer": "cross-env NODE_ENV=production webpack --config ./configs/webpack.config.renderer.prod.babel.js --colors",
|
||||
"build-renderer-test": "cross-env RUN_MODE=test NODE_ENV=production webpack --config ./configs/webpack.config.renderer.prod.babel.js --colors",
|
||||
"build-client": "cd app/client && cross-env SKIP_PREFLIGHT_CHECK=true yarn build",
|
||||
"dev": "cross-env START_HOT=1 node -r @babel/register ./internals/scripts/CheckPortInUse.js && concurrently \"cross-env START_HOT=1 yarn start-renderer-dev\" \"yarn start-client-dev\"",
|
||||
"dev": "cross-env START_HOT=1 node -r @babel/register ./internals/scripts/CheckPortInUse.js && concurrently \"cross-env START_HOT=1 RUN_MODE=dev yarn start-renderer-dev\" \"yarn start-client-dev\"",
|
||||
"coverage": "cross-env BABEL_DISABLE_CACHE=1 jest --coverage && yarn coverage-client",
|
||||
"coverage-client": "cd app/client && cross-env SKIP_PREFLIGHT_CHECK=true cross-env BABEL_DISABLE_CACHE=1 yarn test -- --coverage --watchAll=false",
|
||||
"electron-rebuild": "electron-rebuild --parallel --force --types prod,dev,optional --module-dir app",
|
||||
@ -36,12 +40,15 @@
|
||||
"start-main-dev": "cross-env START_HOT=1 NODE_ENV=development electron -r ./internals/scripts/BabelRegister ./app/main.dev.ts",
|
||||
"start-renderer-dev": "cross-env NODE_ENV=development webpack-dev-server --config configs/webpack.config.renderer.dev.babel.js",
|
||||
"start-client-dev": "cd app/client && cross-env SKIP_PREFLIGHT_CHECK=true yarn start",
|
||||
"test": "cross-env BABEL_DISABLE_CACHE=1 jest && yarn test-client",
|
||||
"test": "cross-env BABEL_DISABLE_CACHE=1 jest --silent && yarn test-client",
|
||||
"test-client": "cd app/client && cross-env BABEL_DISABLE_CACHE=1 SKIP_PREFLIGHT_CHECK=true yarn test:nowatch",
|
||||
"test-all": "yarn lint && yarn tsc && yarn build && yarn test",
|
||||
"test-e2e": "node -r @babel/register ./internals/scripts/CheckBuildsExist.js && cross-env NODE_ENV=test testcafe electron:./app ./test/e2e/HomePage.e2e.ts",
|
||||
"test-e2e-live": "node -r @babel/register ./internals/scripts/CheckBuildsExist.js && cross-env NODE_ENV=test testcafe --live electron:./app ./test/e2e/HomePage.e2e.ts",
|
||||
"test-watch": "yarn test --watch",
|
||||
"test-ux": "node -r @babel/register ./internals/scripts/CheckBuildsExist.js && cross-env NODE_ENV=test RUN_MODE=test testcafe electron:./app ./test/ux/Stepper.ux.ts",
|
||||
"test-ux-live": "node -r @babel/register ./internals/scripts/CheckBuildsExist.js && cross-env NODE_ENV=test RUN_MODE=test testcafe --live electron:./app ./test/ux/Stepper.ux.ts",
|
||||
"test-watch": "yarn jest --watch --silent",
|
||||
"test-watch-no-silent": "yarn jest --watch",
|
||||
"sonar": "concurrently \"sonar-scanner\" \"cd app/client && sonar-scanner\" "
|
||||
},
|
||||
"lint-staged": {
|
||||
@ -184,7 +191,6 @@
|
||||
"testResultsProcessor": "jest-sonar-reporter"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@amilajack/testcafe-browser-provider-electron": "^0.0.15-alpha.1",
|
||||
"@babel/core": "^7.11.1",
|
||||
"@babel/plugin-proposal-class-properties": "^7.10.4",
|
||||
"@babel/plugin-proposal-decorators": "^7.10.5",
|
||||
@ -209,6 +215,7 @@
|
||||
"@babel/preset-react": "^7.10.4",
|
||||
"@babel/preset-typescript": "^7.10.4",
|
||||
"@babel/register": "^7.10.5",
|
||||
"@types/classnames": "^2.2.10",
|
||||
"@types/enzyme": "^3.10.5",
|
||||
"@types/enzyme-adapter-react-16": "^1.0.6",
|
||||
"@types/express": "^4.17.7",
|
||||
@ -222,12 +229,15 @@
|
||||
"@types/koa-static": "^4.0.1",
|
||||
"@types/node": "12",
|
||||
"@types/node-forge": "^0.9.5",
|
||||
"@types/qrcode.react": "^1.0.1",
|
||||
"@types/react": "^16.9.44",
|
||||
"@types/react-dom": "^16.9.8",
|
||||
"@types/react-redux": "^7.1.9",
|
||||
"@types/react-router": "^5.1.8",
|
||||
"@types/react-router-dom": "^5.1.5",
|
||||
"@types/react-test-renderer": "^16.9.2",
|
||||
"@types/react-toast-notifications": "^2.4.0",
|
||||
"@types/react-toastify": "^4.1.0",
|
||||
"@types/redux-logger": "^3.0.8",
|
||||
"@types/shortid": "^0.0.29",
|
||||
"@types/socket.io": "^2.1.11",
|
||||
@ -289,7 +299,7 @@
|
||||
"stylelint-config-prettier": "^8.0.2",
|
||||
"stylelint-config-standard": "^20.0.0",
|
||||
"terser-webpack-plugin": "^3.0.7",
|
||||
"testcafe": "^1.8.8",
|
||||
"testcafe": "^1.9.2",
|
||||
"testcafe-browser-provider-electron": "^0.0.15",
|
||||
"testcafe-react-selectors": "^4.0.0",
|
||||
"ts-jest": "^26.1.4",
|
||||
@ -304,35 +314,47 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@blueprintjs/core": "^3.31.0",
|
||||
"@blueprintjs/select": "^3.13.7",
|
||||
"@fortawesome/fontawesome-free": "^5.14.0",
|
||||
"@hot-loader/react-dom": "^16.13.0",
|
||||
"@material-ui/core": "^4.11.0",
|
||||
"@reduxjs/toolkit": "^1.4.0",
|
||||
"axios": "^0.19.2",
|
||||
"classnames": "^2.2.6",
|
||||
"clsx": "^1.1.1",
|
||||
"connected-react-router": "^6.6.1",
|
||||
"electron-debug": "^3.1.0",
|
||||
"electron-is-dev": "^1.2.0",
|
||||
"electron-log": "^4.2.2",
|
||||
"electron-settings": "^4.0.2",
|
||||
"electron-updater": "^4.3.1",
|
||||
"express": "^4.17.1",
|
||||
"fontsource-lexend-peta": "^3.0.9",
|
||||
"get-port": "^5.1.1",
|
||||
"history": "^4.7.2",
|
||||
"i18next": "^19.6.3",
|
||||
"i18next-fs-backend": "^1.0.7",
|
||||
"i18next-node-fs-backend": "^2.1.3",
|
||||
"i18next-sync-fs-backend": "^1.1.1",
|
||||
"internal-ip": "^6.1.0",
|
||||
"kcors": "^2.2.2",
|
||||
"koa": "^2.13.0",
|
||||
"koa-router": "^9.4.0",
|
||||
"koa-send": "^5.0.1",
|
||||
"koa-static": "^5.0.0",
|
||||
"node-forge": "^0.9.1",
|
||||
"qrcode.react": "^1.0.0",
|
||||
"react": "^16.13.1",
|
||||
"react-awesome-reveal": "^3.2.1",
|
||||
"react-dom": "^16.12.0",
|
||||
"react-flexbox-grid": "^2.1.2",
|
||||
"react-hot-loader": "^4.12.21",
|
||||
"react-i18next": "^11.7.0",
|
||||
"react-qrcode-logo": "^2.2.1",
|
||||
"react-redux": "^7.2.0",
|
||||
"react-reveal": "^1.2.2",
|
||||
"react-router-dom": "^5.2.0",
|
||||
"react-toast-notifications": "^2.4.0",
|
||||
"react-toastify": "^6.0.8",
|
||||
"redux": "^4.0.5",
|
||||
"redux-thunk": "^2.3.0",
|
||||
"regenerator-runtime": "^0.13.5",
|
||||
|
@ -20,11 +20,11 @@ const assertNoConsoleErrors = async (t) => {
|
||||
fixture`Home Page`.page('../../app/app.html').afterEach(assertNoConsoleErrors);
|
||||
|
||||
test('e2e', async (t) => {
|
||||
await t.expect(getPageTitle()).eql('Hello Deskreen!');
|
||||
await t.expect(getPageTitle()).eql('Deskreen');
|
||||
});
|
||||
|
||||
test('should open window and contain expected page title', async (t) => {
|
||||
await t.expect(getPageTitle()).eql('Hello Deskreen!');
|
||||
await t.expect(getPageTitle()).eql('Deskreen');
|
||||
});
|
||||
|
||||
test(
|
||||
|
488
test/ux/Stepper.ux.ts
Normal file
488
test/ux/Stepper.ux.ts
Normal file
@ -0,0 +1,488 @@
|
||||
/* eslint jest/expect-expect: off, jest/no-test-callback: off */
|
||||
import { ClientFunction, Selector } from 'testcafe';
|
||||
|
||||
const getPageTitle = ClientFunction(() => document.title);
|
||||
const assertNoConsoleErrors = async (t) => {
|
||||
const { error } = await t.getBrowserConsoleMessages();
|
||||
await t.expect(error).eql([]);
|
||||
};
|
||||
|
||||
// Deskreen selectors
|
||||
const connectTestDeviceButton = Selector('button').withText(
|
||||
'Connect Test Device'
|
||||
);
|
||||
const crossCloseDialogButton = Selector('svg').withAttribute(
|
||||
'data-icon',
|
||||
'cross'
|
||||
);
|
||||
const allowToConnectButton = Selector('button').withText('Allow');
|
||||
const denyToConnectButton = Selector('button').withText('Deny');
|
||||
const shareEntireScreenButton = Selector('button').withText('Entire Screen');
|
||||
const shareApplicationWindowButton = Selector('button').withText(
|
||||
'Application Window'
|
||||
);
|
||||
const magnifyQRCodeButton = Selector('#magnify-qr-code-button');
|
||||
const largeQRCodeDialog = Selector('#qr-code-dialog-inner');
|
||||
const connectedInfoStepperButton = Selector(
|
||||
'#connected-device-info-stepper-button'
|
||||
);
|
||||
const popoverDivWithDeviceIP = Selector(
|
||||
'#connected-button-popover-div-with-ip'
|
||||
);
|
||||
const disconnectOneDeviceButton = Selector('button').withExactText(
|
||||
'Disconnect'
|
||||
);
|
||||
const disconnectAllDevicesButton = Selector('button').withText(
|
||||
'Disconnect all'
|
||||
);
|
||||
const reactToastNotificationsContainer = Selector(
|
||||
'.react-toast-notifications__container'
|
||||
);
|
||||
const headerWithTextSelectEntireScreen = Selector('h3').withText(
|
||||
'Select Entire Screen to Share'
|
||||
);
|
||||
const headerWithTextSelectAppWindow = Selector('h3').withText(
|
||||
'Select App Window to Share'
|
||||
);
|
||||
const previewShareButton = Selector('.preview-share-thumb-container');
|
||||
const step3ConfirmButton = Selector('button').withText('Confirm');
|
||||
const noINeedToShareOtherThingButton = Selector('button').withText(
|
||||
'No, I need to share other thing'
|
||||
);
|
||||
const step4ConnectNewDeviceButton = Selector('button').withText(
|
||||
'Connect New Device'
|
||||
);
|
||||
const connectedDevicesButton = Selector(
|
||||
'#top-panel-connected-devices-list-button'
|
||||
);
|
||||
const connectedDevicesHeader = Selector('.bp3-text-muted').withText(
|
||||
'Connected Devices'
|
||||
);
|
||||
const getDeviceIPContainerByIP = (ip) =>
|
||||
Selector('.device-ip-container').withText(ip);
|
||||
const yesDisconnectAllButton = Selector('button').withText(
|
||||
'Yes, Disconnect All'
|
||||
);
|
||||
const settingsButtonOfTopPanel = Selector('span').withAttribute('icon', 'cog');
|
||||
const openedSettingsOverlay = Selector('#settings-overlay-inner');
|
||||
const darkColorAppSettingButton = Selector('button').withText('Dark');
|
||||
const lightColorAppSettingButton = Selector('button').withText('Light');
|
||||
const darkUIClassName = Selector('.bp3-dark');
|
||||
|
||||
async function getConnectedDeviceIPFromAllowToConnectDeviceAlert() {
|
||||
const deviceIPTextElement = Selector(
|
||||
'#allow-connection-device-alert-device-ip-span'
|
||||
);
|
||||
const textWithIp = await deviceIPTextElement.innerText;
|
||||
return textWithIp.trim();
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
async function connectTestDeviceAndGetIP(t) {
|
||||
await t.click(connectTestDeviceButton());
|
||||
return getConnectedDeviceIPFromAllowToConnectDeviceAlert();
|
||||
}
|
||||
|
||||
async function connectTestDevice(t) {
|
||||
await t.click(connectTestDeviceButton());
|
||||
}
|
||||
|
||||
async function connectAndAllowTestDeviceAndGetIP(t) {
|
||||
await connectTestDevice(t);
|
||||
const ip = getConnectedDeviceIPFromAllowToConnectDeviceAlert();
|
||||
await t.click(allowToConnectButton());
|
||||
return ip;
|
||||
}
|
||||
|
||||
async function connectAndAllowTestDevice(t) {
|
||||
await connectTestDevice(t);
|
||||
await t.click(allowToConnectButton());
|
||||
}
|
||||
|
||||
async function openLargeQRCodeDialog(t) {
|
||||
await t.click(magnifyQRCodeButton());
|
||||
}
|
||||
|
||||
async function clickCrossButtonToCloseDialog(t) {
|
||||
await t.click(crossCloseDialogButton());
|
||||
}
|
||||
|
||||
async function openConnectedDeviceInfoPopover(t) {
|
||||
await t.click(connectedInfoStepperButton());
|
||||
}
|
||||
|
||||
async function goToStep3SharingEntireScreen(t) {
|
||||
await connectAndAllowTestDevice(t);
|
||||
await t.click(shareEntireScreenButton());
|
||||
await t.click(previewShareButton());
|
||||
}
|
||||
|
||||
async function goToStep3SharingAppWindow(t) {
|
||||
await connectAndAllowTestDevice(t);
|
||||
await t.click(shareApplicationWindowButton());
|
||||
await t.click(previewShareButton());
|
||||
}
|
||||
|
||||
async function goToStep4SharingAppWindow(t) {
|
||||
await goToStep3SharingAppWindow(t);
|
||||
await t.click(step3ConfirmButton());
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
async function goToStep4SharingEntireScreen(t) {
|
||||
await goToStep3SharingEntireScreen(t);
|
||||
await t.click(step3ConfirmButton());
|
||||
}
|
||||
|
||||
async function connectDeviceSharingAppWindow(t) {
|
||||
await goToStep4SharingAppWindow(t);
|
||||
}
|
||||
|
||||
async function connectDeviceSharingAppWindowAndGetIP(t) {
|
||||
const ip = await connectAndAllowTestDeviceAndGetIP(t);
|
||||
await t.click(shareApplicationWindowButton());
|
||||
await t.click(previewShareButton());
|
||||
await t.click(step3ConfirmButton());
|
||||
await t.click(step4ConnectNewDeviceButton());
|
||||
return ip;
|
||||
}
|
||||
|
||||
async function connectDeviceSharingEntireScreenAndGetIP(t) {
|
||||
const ip = await connectAndAllowTestDeviceAndGetIP(t);
|
||||
await t.click(shareEntireScreenButton());
|
||||
await t.click(previewShareButton());
|
||||
await t.click(step3ConfirmButton());
|
||||
await t.click(step4ConnectNewDeviceButton());
|
||||
return ip;
|
||||
}
|
||||
|
||||
async function openConnectedDevicesListDrawer(t) {
|
||||
await t.click(connectedDevicesButton());
|
||||
}
|
||||
|
||||
fixture`Home Page`.page('../../app/app.html').afterEach(assertNoConsoleErrors);
|
||||
|
||||
test(`when app is launched,
|
||||
|
||||
it should have correct app title as "Deskreen"`, async (t) => {
|
||||
await t.expect(getPageTitle()).eql('Deskreen');
|
||||
});
|
||||
|
||||
test(`when on Scan QR code step (step 1),
|
||||
and when device is connected,
|
||||
|
||||
it should show alert with Allow or Deny buttons`, async (t) => {
|
||||
await t.click(connectTestDeviceButton());
|
||||
|
||||
const allowButtonExists = allowToConnectButton().exists;
|
||||
const denyButtonExists = denyToConnectButton().exists;
|
||||
await t.expect(allowButtonExists).ok();
|
||||
await t.expect(denyButtonExists).ok();
|
||||
});
|
||||
|
||||
test(`when on Scan QR code step (step 1),
|
||||
and when device is connected,
|
||||
and when user pressed "Deny" button
|
||||
|
||||
it should close alert with Allow or Deny buttons`, async (t) => {
|
||||
await connectTestDevice(t);
|
||||
await t.click(denyToConnectButton());
|
||||
|
||||
const allowButtonExists = allowToConnectButton().exists;
|
||||
const denyButtonExists = denyToConnectButton().exists;
|
||||
await t.expect(allowButtonExists).notOk();
|
||||
await t.expect(denyButtonExists).notOk();
|
||||
});
|
||||
|
||||
test(`when on Scan QR code step (step 1),
|
||||
and when device is connected,
|
||||
and when user pressed "Allow" button,
|
||||
|
||||
it should go to "Share App or Screen" step (step 2)`, async (t) => {
|
||||
await connectAndAllowTestDeviceAndGetIP(t);
|
||||
|
||||
const EntireScreenButtonExists = shareEntireScreenButton().exists;
|
||||
const AppWindoScreenButtonExists = shareApplicationWindowButton().exists;
|
||||
await t.expect(EntireScreenButtonExists).ok();
|
||||
await t.expect(AppWindoScreenButtonExists).ok();
|
||||
});
|
||||
|
||||
test(`when on Scan QR code step (step 1),
|
||||
and when "Magnify QR code" button is clicked,
|
||||
|
||||
it should open large QR code overflow`, async (t) => {
|
||||
await openLargeQRCodeDialog(t);
|
||||
|
||||
const largeQRCodeDialogExists = largeQRCodeDialog().exists;
|
||||
await t.expect(largeQRCodeDialogExists).ok();
|
||||
});
|
||||
|
||||
test(`when large QR overflow is opened,
|
||||
and when user clicks cross button,
|
||||
|
||||
it should close large QR code overflow`, async (t) => {
|
||||
await openLargeQRCodeDialog(t);
|
||||
await clickCrossButtonToCloseDialog(t);
|
||||
|
||||
const largeQrCodeDialogExists = largeQRCodeDialog().exists;
|
||||
await t.expect(largeQrCodeDialogExists).notOk();
|
||||
});
|
||||
|
||||
test(`when on step 2,
|
||||
and when device is connected,
|
||||
|
||||
it should show Connected (info) button in UI`, async (t) => {
|
||||
await connectAndAllowTestDeviceAndGetIP(t);
|
||||
const connectedInfoStepperButtonExists = connectedInfoStepperButton().exists;
|
||||
|
||||
await t.expect(connectedInfoStepperButtonExists).ok();
|
||||
});
|
||||
|
||||
test(`when on step 2,
|
||||
and when device is connected,
|
||||
and when user clicked Connected (info) button of stepper panel,
|
||||
|
||||
it should show connected device popover with IP of connected device`, async (t) => {
|
||||
const ip = await connectAndAllowTestDeviceAndGetIP(t);
|
||||
await openConnectedDeviceInfoPopover(t);
|
||||
|
||||
const textWithIp = await popoverDivWithDeviceIP().innerText;
|
||||
await t.expect(textWithIp.includes(ip)).ok();
|
||||
});
|
||||
|
||||
test(`when on step 2,
|
||||
and when user Clicks "Disconnect" button of
|
||||
Connected (info) popover,
|
||||
|
||||
it should go back to Scan QR code step 1`, async (t) => {
|
||||
await connectAndAllowTestDeviceAndGetIP(t);
|
||||
await openConnectedDeviceInfoPopover(t);
|
||||
await t.click(disconnectOneDeviceButton());
|
||||
|
||||
const magnifyQRCodeButtonExists = magnifyQRCodeButton().exists;
|
||||
await t.expect(magnifyQRCodeButtonExists).ok();
|
||||
});
|
||||
|
||||
test(`when on step 2,
|
||||
and when user Clicks "Disconnect" button of
|
||||
Connected (info) popover,
|
||||
|
||||
it should display react toast notification that device has been disconnected`, async (t) => {
|
||||
await connectAndAllowTestDeviceAndGetIP(t);
|
||||
await openConnectedDeviceInfoPopover(t);
|
||||
await t.click(disconnectOneDeviceButton());
|
||||
|
||||
const toastText = await reactToastNotificationsContainer().innerText;
|
||||
await t.expect(toastText !== '').ok();
|
||||
});
|
||||
|
||||
test(`when on step 2,
|
||||
and when user clicks "Share Entire Screen" button,
|
||||
|
||||
it should display "Select Entire Screen to Share" overlay`, async (t) => {
|
||||
await connectAndAllowTestDeviceAndGetIP(t);
|
||||
await t.click(shareEntireScreenButton());
|
||||
|
||||
const headerWithTextSelectEntireScreenExists = headerWithTextSelectEntireScreen()
|
||||
.exists;
|
||||
await t.expect(headerWithTextSelectEntireScreenExists).ok();
|
||||
});
|
||||
|
||||
test(`when on step 2,
|
||||
and when user clicks "Share Application Window" button,
|
||||
|
||||
it should display "Select App Window to Share" overlay`, async (t) => {
|
||||
await connectAndAllowTestDeviceAndGetIP(t);
|
||||
await t.click(shareApplicationWindowButton());
|
||||
|
||||
const headerWithTextSelectAppWindowExists = headerWithTextSelectAppWindow()
|
||||
.exists;
|
||||
await t.expect(headerWithTextSelectAppWindowExists).ok();
|
||||
});
|
||||
|
||||
test(`when on step 2,
|
||||
and when user clicks "Share Entire Screen" button,
|
||||
and when user clicks on previev button,
|
||||
|
||||
it should go to step 3 and display a "Confirm" button`, async (t) => {
|
||||
await goToStep3SharingEntireScreen(t);
|
||||
|
||||
const step3ConfirmButtonExists = step3ConfirmButton().exists;
|
||||
await t.expect(step3ConfirmButtonExists).ok();
|
||||
});
|
||||
|
||||
test(`when on step 2,
|
||||
and when user clicks "Share Application Window" button,
|
||||
and when user clicks on previev button,
|
||||
|
||||
it should go to step 3 and display a "Confirm" button`, async (t) => {
|
||||
await goToStep3SharingAppWindow(t);
|
||||
|
||||
const step3ConfirmButtonExists = step3ConfirmButton().exists;
|
||||
await t.expect(step3ConfirmButtonExists).ok();
|
||||
});
|
||||
|
||||
test(`when on step 3,
|
||||
and when user clicks "No, I need to share other thing" button,
|
||||
|
||||
it should go back to step 2 and display a OR button group`, async (t) => {
|
||||
await goToStep3SharingAppWindow(t);
|
||||
await t.click(noINeedToShareOtherThingButton());
|
||||
|
||||
const EntireScreenButtonExists = shareEntireScreenButton().exists;
|
||||
const AppWindoScreenButtonExists = shareApplicationWindowButton().exists;
|
||||
await t.expect(EntireScreenButtonExists).ok();
|
||||
await t.expect(AppWindoScreenButtonExists).ok();
|
||||
});
|
||||
|
||||
test(`when on step 3,
|
||||
and when user clicks "Confirm" button,
|
||||
|
||||
it should go back to step 4 (Success Step) and display a "Connect New Device" button`, async (t) => {
|
||||
await goToStep3SharingAppWindow(t);
|
||||
await t.click(step3ConfirmButton());
|
||||
|
||||
const ConnectNewDeviceButtonExists = step4ConnectNewDeviceButton().exists;
|
||||
await t.expect(ConnectNewDeviceButtonExists).ok();
|
||||
});
|
||||
|
||||
test(`when on step 4 (Success Step),
|
||||
and when user clicks "Connect New Device" button,
|
||||
|
||||
it should go back to step 1 and display a QR code`, async (t) => {
|
||||
await goToStep4SharingAppWindow(t);
|
||||
await t.click(step4ConnectNewDeviceButton());
|
||||
|
||||
const MagnifyQRCodeButtonExists = magnifyQRCodeButton().exists;
|
||||
await t.expect(MagnifyQRCodeButtonExists).ok();
|
||||
});
|
||||
|
||||
test(`when device is connected,
|
||||
and when "Connected Devices List" drawer is opened",
|
||||
|
||||
it should open "Connected Devices List" panel`, async (t) => {
|
||||
await connectDeviceSharingAppWindow(t);
|
||||
await t.click(connectedDevicesButton());
|
||||
|
||||
const ConnectedDevicesHeaderExists = connectedDevicesHeader().exists;
|
||||
await t.expect(ConnectedDevicesHeaderExists).ok();
|
||||
});
|
||||
|
||||
test(`when on step 4 (Success Step),
|
||||
and when user clicks "Connected Devices" button,
|
||||
|
||||
it should open "Connected Devices List" panel with a connected device listed in it`, async (t) => {
|
||||
const ip = await connectDeviceSharingAppWindowAndGetIP(t);
|
||||
await openConnectedDevicesListDrawer(t);
|
||||
|
||||
await t.expect(getDeviceIPContainerByIP(ip).exists).ok();
|
||||
});
|
||||
|
||||
test(`when multiple devices are connected,
|
||||
and when user clicks "Connected Devices" button,
|
||||
and when "Connected Devices List" drawer is opened,
|
||||
|
||||
it should list all connected devices with IPs in "Connected Devices List" drawer`, async (t) => {
|
||||
const ipOne = await connectDeviceSharingAppWindowAndGetIP(t);
|
||||
const ipTwo = await connectDeviceSharingAppWindowAndGetIP(t);
|
||||
const ipThree = await connectDeviceSharingEntireScreenAndGetIP(t);
|
||||
const ipFour = await connectDeviceSharingEntireScreenAndGetIP(t);
|
||||
|
||||
await openConnectedDevicesListDrawer(t);
|
||||
|
||||
await t.expect(getDeviceIPContainerByIP(ipOne).exists).ok();
|
||||
await t.expect(getDeviceIPContainerByIP(ipTwo).exists).ok();
|
||||
await t.expect(getDeviceIPContainerByIP(ipThree).exists).ok();
|
||||
await t.expect(getDeviceIPContainerByIP(ipFour).exists).ok();
|
||||
});
|
||||
|
||||
test(`when device is connected,
|
||||
and when "Connected Devices List" drawer is opened,
|
||||
and when user clicks "Disconnect" button of just connected device,
|
||||
|
||||
it should remove a device from connected devices list drawer`, async (t) => {
|
||||
const ip = await connectDeviceSharingAppWindowAndGetIP(t);
|
||||
await openConnectedDevicesListDrawer(t);
|
||||
await t.click(disconnectOneDeviceButton());
|
||||
|
||||
await t.expect(getDeviceIPContainerByIP(ip).exists).notOk();
|
||||
});
|
||||
|
||||
test(`when multiple devices are connected,
|
||||
and when "Connected Devices List" drawer is opened,
|
||||
and when user clicked "Disconnect all" button,
|
||||
and when user clicked "Yes, Disconnect All" button in alert,
|
||||
and when "Connected Devices List" drawer is opened again,
|
||||
|
||||
it should remove remove all devices from "Connected Devices List" drawer`, async (t) => {
|
||||
const ipOne = await connectDeviceSharingAppWindowAndGetIP(t);
|
||||
const ipTwo = await connectDeviceSharingAppWindowAndGetIP(t);
|
||||
const ipThree = await connectDeviceSharingEntireScreenAndGetIP(t);
|
||||
const ipFour = await connectDeviceSharingEntireScreenAndGetIP(t);
|
||||
await openConnectedDevicesListDrawer(t);
|
||||
await t.click(disconnectAllDevicesButton());
|
||||
await t.click(yesDisconnectAllButton());
|
||||
|
||||
await openConnectedDevicesListDrawer(t);
|
||||
|
||||
await t.expect(getDeviceIPContainerByIP(ipOne).exists).notOk();
|
||||
await t.expect(getDeviceIPContainerByIP(ipTwo).exists).notOk();
|
||||
await t.expect(getDeviceIPContainerByIP(ipThree).exists).notOk();
|
||||
await t.expect(getDeviceIPContainerByIP(ipFour).exists).notOk();
|
||||
});
|
||||
|
||||
test(`when device is connected,
|
||||
and when user is on "Success" step, (step 4),
|
||||
and when "Connected Devices List" drawer is opened,
|
||||
and when user clicked "Disconnect all" button,
|
||||
and when user clicked "Yes, Disconnect All" in alert,
|
||||
|
||||
it should go back to Scan QR code step`, async (t) => {
|
||||
await goToStep4SharingAppWindow(t);
|
||||
await openConnectedDevicesListDrawer(t);
|
||||
await t.click(disconnectAllDevicesButton());
|
||||
await t.click(yesDisconnectAllButton());
|
||||
|
||||
await t.expect(magnifyQRCodeButton().exists).ok();
|
||||
});
|
||||
|
||||
test(`when device is connected,
|
||||
and when user clicks "Connected Devices List" drawer is opened,
|
||||
and when user clicks "Disconnect all" button of connected device
|
||||
|
||||
it should display "Are you sure you want to disconnect all devices..." alert`, async (t) => {
|
||||
await connectDeviceSharingAppWindowAndGetIP(t);
|
||||
await openConnectedDevicesListDrawer(t);
|
||||
await t.click(Selector('button').withText('Disconnect all'));
|
||||
|
||||
await t.expect(yesDisconnectAllButton().exists).ok();
|
||||
});
|
||||
|
||||
/*
|
||||
//////////////////////////////////////////////////
|
||||
/////////// SETTINGS OVERLAY TESTING START ///////
|
||||
//////////////////////////////////////////////////
|
||||
*/
|
||||
|
||||
test(`when clicks "Settings" button of top panel,
|
||||
|
||||
it should open "Settings" panel`, async (t) => {
|
||||
await t.click(settingsButtonOfTopPanel());
|
||||
|
||||
await t.expect(openedSettingsOverlay().exists).ok();
|
||||
});
|
||||
|
||||
test(`when "Settings" Panel is opened,
|
||||
and when user clicks "Dark" and "Light" buttons,
|
||||
|
||||
it should change application colors accordingly`, async (t) => {
|
||||
await t.click(settingsButtonOfTopPanel());
|
||||
|
||||
// action and assertion 1
|
||||
await t.click(darkColorAppSettingButton());
|
||||
await t.expect(darkUIClassName().exists).ok();
|
||||
|
||||
// action and assertion 2
|
||||
await t.click(lightColorAppSettingButton());
|
||||
await t.expect(darkUIClassName().exists).notOk();
|
||||
});
|
564
yarn.lock
564
yarn.lock
@ -12,25 +12,6 @@
|
||||
resolved "https://packages.deskreen.com/7zip/-/7zip-0.0.6.tgz#9cafb171af82329490353b4816f03347aa150a30"
|
||||
integrity sha1-nK+xca+CMpSQNTtIFvAzR6oVCjA=
|
||||
|
||||
"@amilajack/testcafe-browser-provider-electron@^0.0.15-alpha.1":
|
||||
version "0.0.15-alpha.1"
|
||||
resolved "https://packages.deskreen.com/@amilajack%2ftestcafe-browser-provider-electron/-/testcafe-browser-provider-electron-0.0.15-alpha.1.tgz#506080ec623c1509fae489b13cb2a2894ec6fbb9"
|
||||
integrity sha512-05JwzcV59rxArehDWPM0Lw4YNvVr5c3J/j2ikJeQKHAQSoA0TsRSdqSMjGDaT8LGem0HAATPLh7hRhI481alIQ==
|
||||
dependencies:
|
||||
babel-runtime "^6.25.0"
|
||||
chrome-remote-interface "^0.27.0"
|
||||
debug "4.1.1"
|
||||
dedent "^0.7.0"
|
||||
endpoint-utils "^1.0.2"
|
||||
lodash "^4.17.4"
|
||||
mustache "^2.3.0"
|
||||
node-ipc "^9.1.0"
|
||||
os-family "^1.0.0"
|
||||
pify "^2.3.0"
|
||||
pinkie "^2.0.4"
|
||||
promisify-event "^1.0.0"
|
||||
proxyquire "^1.7.10"
|
||||
|
||||
"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4":
|
||||
version "7.10.4"
|
||||
resolved "https://packages.deskreen.com/@babel%2fcode-frame/-/code-frame-7.10.4.tgz#168da1a36e90da68ae8d49c0f1b48c7c6249213a"
|
||||
@ -188,7 +169,7 @@
|
||||
dependencies:
|
||||
"@babel/types" "^7.11.0"
|
||||
|
||||
"@babel/helper-module-imports@^7.10.4":
|
||||
"@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.10.4":
|
||||
version "7.10.4"
|
||||
resolved "https://packages.deskreen.com/@babel%2fhelper-module-imports/-/helper-module-imports-7.10.4.tgz#4c5c54be04bd31670a7382797d75b9fa2e5b5620"
|
||||
integrity sha512-nEQJHqYavI217oD9+s5MUBzk6x1IlvoS9WTPfgG43CbMEeStE0v+r+TucWdx8KFGowPGvyOkDT9+7DHedIDnVw==
|
||||
@ -1093,7 +1074,7 @@
|
||||
core-js-pure "^3.0.0"
|
||||
regenerator-runtime "^0.13.4"
|
||||
|
||||
"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.1", "@babel/runtime@^7.10.2", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.4":
|
||||
"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.1", "@babel/runtime@^7.10.2", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7":
|
||||
version "7.11.2"
|
||||
resolved "https://packages.deskreen.com/@babel%2fruntime/-/runtime-7.11.2.tgz#f549c13c754cc40b87644b9fa9f09a6a95fe0736"
|
||||
integrity sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw==
|
||||
@ -1163,6 +1144,15 @@
|
||||
classnames "^2.2"
|
||||
tslib "~1.13.0"
|
||||
|
||||
"@blueprintjs/select@^3.13.7":
|
||||
version "3.13.7"
|
||||
resolved "https://packages.deskreen.com/@blueprintjs%2fselect/-/select-3.13.7.tgz#166675a8caeccacdb31216e92ef114f29888dbf6"
|
||||
integrity sha512-kJVtbDDGVwIIC1+cN7H0DUrlumSVZGNEq2CnczQNI07RkHpPzuIR5stjn3LU+NjtCa3pidPNr4w78JRTesZzLg==
|
||||
dependencies:
|
||||
"@blueprintjs/core" "^3.31.0"
|
||||
classnames "^2.2"
|
||||
tslib "~1.13.0"
|
||||
|
||||
"@cnakazawa/watch@^1.0.3":
|
||||
version "1.0.4"
|
||||
resolved "https://packages.deskreen.com/@cnakazawa%2fwatch/-/watch-1.0.4.tgz#f864ae85004d0fcab6f50be9141c4da368d1656a"
|
||||
@ -1204,6 +1194,108 @@
|
||||
global-agent "^2.0.2"
|
||||
global-tunnel-ng "^2.7.1"
|
||||
|
||||
"@emotion/cache@^10.0.27":
|
||||
version "10.0.29"
|
||||
resolved "https://packages.deskreen.com/@emotion%2fcache/-/cache-10.0.29.tgz#87e7e64f412c060102d589fe7c6dc042e6f9d1e0"
|
||||
integrity sha512-fU2VtSVlHiF27empSbxi1O2JFdNWZO+2NFHfwO0pxgTep6Xa3uGb+3pVKfLww2l/IBGLNEZl5Xf/++A4wAYDYQ==
|
||||
dependencies:
|
||||
"@emotion/sheet" "0.9.4"
|
||||
"@emotion/stylis" "0.8.5"
|
||||
"@emotion/utils" "0.11.3"
|
||||
"@emotion/weak-memoize" "0.2.5"
|
||||
|
||||
"@emotion/core@^10.0.14", "@emotion/core@^10.0.35":
|
||||
version "10.0.35"
|
||||
resolved "https://packages.deskreen.com/@emotion%2fcore/-/core-10.0.35.tgz#513fcf2e22cd4dfe9d3894ed138c9d7a859af9b3"
|
||||
integrity sha512-sH++vJCdk025fBlRZSAhkRlSUoqSqgCzYf5fMOmqqi3bM6how+sQpg3hkgJonj8GxXM4WbD7dRO+4tegDB9fUw==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.5.5"
|
||||
"@emotion/cache" "^10.0.27"
|
||||
"@emotion/css" "^10.0.27"
|
||||
"@emotion/serialize" "^0.11.15"
|
||||
"@emotion/sheet" "0.9.4"
|
||||
"@emotion/utils" "0.11.3"
|
||||
|
||||
"@emotion/css@^10.0.27":
|
||||
version "10.0.27"
|
||||
resolved "https://packages.deskreen.com/@emotion%2fcss/-/css-10.0.27.tgz#3a7458198fbbebb53b01b2b87f64e5e21241e14c"
|
||||
integrity sha512-6wZjsvYeBhyZQYNrGoR5yPMYbMBNEnanDrqmsqS1mzDm1cOTu12shvl2j4QHNS36UaTE0USIJawCH9C8oW34Zw==
|
||||
dependencies:
|
||||
"@emotion/serialize" "^0.11.15"
|
||||
"@emotion/utils" "0.11.3"
|
||||
babel-plugin-emotion "^10.0.27"
|
||||
|
||||
"@emotion/hash@0.8.0", "@emotion/hash@^0.8.0":
|
||||
version "0.8.0"
|
||||
resolved "https://packages.deskreen.com/@emotion%2fhash/-/hash-0.8.0.tgz#bbbff68978fefdbe68ccb533bc8cbe1d1afb5413"
|
||||
integrity sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==
|
||||
|
||||
"@emotion/is-prop-valid@0.8.8":
|
||||
version "0.8.8"
|
||||
resolved "https://packages.deskreen.com/@emotion%2fis-prop-valid/-/is-prop-valid-0.8.8.tgz#db28b1c4368a259b60a97311d6a952d4fd01ac1a"
|
||||
integrity sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==
|
||||
dependencies:
|
||||
"@emotion/memoize" "0.7.4"
|
||||
|
||||
"@emotion/memoize@0.7.4":
|
||||
version "0.7.4"
|
||||
resolved "https://packages.deskreen.com/@emotion%2fmemoize/-/memoize-0.7.4.tgz#19bf0f5af19149111c40d98bb0cf82119f5d9eeb"
|
||||
integrity sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==
|
||||
|
||||
"@emotion/serialize@^0.11.15", "@emotion/serialize@^0.11.16":
|
||||
version "0.11.16"
|
||||
resolved "https://packages.deskreen.com/@emotion%2fserialize/-/serialize-0.11.16.tgz#dee05f9e96ad2fb25a5206b6d759b2d1ed3379ad"
|
||||
integrity sha512-G3J4o8by0VRrO+PFeSc3js2myYNOXVJ3Ya+RGVxnshRYgsvErfAOglKAiy1Eo1vhzxqtUvjCyS5gtewzkmvSSg==
|
||||
dependencies:
|
||||
"@emotion/hash" "0.8.0"
|
||||
"@emotion/memoize" "0.7.4"
|
||||
"@emotion/unitless" "0.7.5"
|
||||
"@emotion/utils" "0.11.3"
|
||||
csstype "^2.5.7"
|
||||
|
||||
"@emotion/sheet@0.9.4":
|
||||
version "0.9.4"
|
||||
resolved "https://packages.deskreen.com/@emotion%2fsheet/-/sheet-0.9.4.tgz#894374bea39ec30f489bbfc3438192b9774d32e5"
|
||||
integrity sha512-zM9PFmgVSqBw4zL101Q0HrBVTGmpAxFZH/pYx/cjJT5advXguvcgjHFTCaIO3enL/xr89vK2bh0Mfyj9aa0ANA==
|
||||
|
||||
"@emotion/styled-base@^10.0.27":
|
||||
version "10.0.31"
|
||||
resolved "https://packages.deskreen.com/@emotion%2fstyled-base/-/styled-base-10.0.31.tgz#940957ee0aa15c6974adc7d494ff19765a2f742a"
|
||||
integrity sha512-wTOE1NcXmqMWlyrtwdkqg87Mu6Rj1MaukEoEmEkHirO5IoHDJ8LgCQL4MjJODgxWxXibGR3opGp1p7YvkNEdXQ==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.5.5"
|
||||
"@emotion/is-prop-valid" "0.8.8"
|
||||
"@emotion/serialize" "^0.11.15"
|
||||
"@emotion/utils" "0.11.3"
|
||||
|
||||
"@emotion/styled@^10.0.27":
|
||||
version "10.0.27"
|
||||
resolved "https://packages.deskreen.com/@emotion%2fstyled/-/styled-10.0.27.tgz#12cb67e91f7ad7431e1875b1d83a94b814133eaf"
|
||||
integrity sha512-iK/8Sh7+NLJzyp9a5+vIQIXTYxfT4yB/OJbjzQanB2RZpvmzBQOHZWhpAMZWYEKRNNbsD6WfBw5sVWkb6WzS/Q==
|
||||
dependencies:
|
||||
"@emotion/styled-base" "^10.0.27"
|
||||
babel-plugin-emotion "^10.0.27"
|
||||
|
||||
"@emotion/stylis@0.8.5":
|
||||
version "0.8.5"
|
||||
resolved "https://packages.deskreen.com/@emotion%2fstylis/-/stylis-0.8.5.tgz#deacb389bd6ee77d1e7fcaccce9e16c5c7e78e04"
|
||||
integrity sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ==
|
||||
|
||||
"@emotion/unitless@0.7.5":
|
||||
version "0.7.5"
|
||||
resolved "https://packages.deskreen.com/@emotion%2funitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed"
|
||||
integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==
|
||||
|
||||
"@emotion/utils@0.11.3":
|
||||
version "0.11.3"
|
||||
resolved "https://packages.deskreen.com/@emotion%2futils/-/utils-0.11.3.tgz#a759863867befa7e583400d322652a3f44820924"
|
||||
integrity sha512-0o4l6pZC+hI88+bzuaX/6BgOvQVhbt2PfmxauVaYOGgbsAw14wdKyvMCZXnsnsHys94iadcF+RG/wZyx6+ZZBw==
|
||||
|
||||
"@emotion/weak-memoize@0.2.5":
|
||||
version "0.2.5"
|
||||
resolved "https://packages.deskreen.com/@emotion%2fweak-memoize/-/weak-memoize-0.2.5.tgz#8eed982e2ee6f7f4e44c253e12962980791efd46"
|
||||
integrity sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA==
|
||||
|
||||
"@fortawesome/fontawesome-free@^5.14.0":
|
||||
version "5.14.0"
|
||||
resolved "https://packages.deskreen.com/@fortawesome%2ffontawesome-free/-/fontawesome-free-5.14.0.tgz#a371e91029ebf265015e64f81bfbf7d228c9681f"
|
||||
@ -1416,6 +1508,70 @@
|
||||
"@types/yargs" "^15.0.0"
|
||||
chalk "^4.0.0"
|
||||
|
||||
"@material-ui/core@^4.11.0":
|
||||
version "4.11.0"
|
||||
resolved "https://packages.deskreen.com/@material-ui%2fcore/-/core-4.11.0.tgz#b69b26e4553c9e53f2bfaf1053e216a0af9be15a"
|
||||
integrity sha512-bYo9uIub8wGhZySHqLQ833zi4ZML+XCBE1XwJ8EuUVSpTWWG57Pm+YugQToJNFsEyiKFhPh8DPD0bgupz8n01g==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.4.4"
|
||||
"@material-ui/styles" "^4.10.0"
|
||||
"@material-ui/system" "^4.9.14"
|
||||
"@material-ui/types" "^5.1.0"
|
||||
"@material-ui/utils" "^4.10.2"
|
||||
"@types/react-transition-group" "^4.2.0"
|
||||
clsx "^1.0.4"
|
||||
hoist-non-react-statics "^3.3.2"
|
||||
popper.js "1.16.1-lts"
|
||||
prop-types "^15.7.2"
|
||||
react-is "^16.8.0"
|
||||
react-transition-group "^4.4.0"
|
||||
|
||||
"@material-ui/styles@^4.10.0":
|
||||
version "4.10.0"
|
||||
resolved "https://packages.deskreen.com/@material-ui%2fstyles/-/styles-4.10.0.tgz#2406dc23aa358217aa8cc772e6237bd7f0544071"
|
||||
integrity sha512-XPwiVTpd3rlnbfrgtEJ1eJJdFCXZkHxy8TrdieaTvwxNYj42VnnCyFzxYeNW9Lhj4V1oD8YtQ6S5Gie7bZDf7Q==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.4.4"
|
||||
"@emotion/hash" "^0.8.0"
|
||||
"@material-ui/types" "^5.1.0"
|
||||
"@material-ui/utils" "^4.9.6"
|
||||
clsx "^1.0.4"
|
||||
csstype "^2.5.2"
|
||||
hoist-non-react-statics "^3.3.2"
|
||||
jss "^10.0.3"
|
||||
jss-plugin-camel-case "^10.0.3"
|
||||
jss-plugin-default-unit "^10.0.3"
|
||||
jss-plugin-global "^10.0.3"
|
||||
jss-plugin-nested "^10.0.3"
|
||||
jss-plugin-props-sort "^10.0.3"
|
||||
jss-plugin-rule-value-function "^10.0.3"
|
||||
jss-plugin-vendor-prefixer "^10.0.3"
|
||||
prop-types "^15.7.2"
|
||||
|
||||
"@material-ui/system@^4.9.14":
|
||||
version "4.9.14"
|
||||
resolved "https://packages.deskreen.com/@material-ui%2fsystem/-/system-4.9.14.tgz#4b00c48b569340cefb2036d0596b93ac6c587a5f"
|
||||
integrity sha512-oQbaqfSnNlEkXEziDcJDDIy8pbvwUmZXWNqlmIwDqr/ZdCK8FuV3f4nxikUh7hvClKV2gnQ9djh5CZFTHkZj3w==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.4.4"
|
||||
"@material-ui/utils" "^4.9.6"
|
||||
csstype "^2.5.2"
|
||||
prop-types "^15.7.2"
|
||||
|
||||
"@material-ui/types@^5.1.0":
|
||||
version "5.1.0"
|
||||
resolved "https://packages.deskreen.com/@material-ui%2ftypes/-/types-5.1.0.tgz#efa1c7a0b0eaa4c7c87ac0390445f0f88b0d88f2"
|
||||
integrity sha512-7cqRjrY50b8QzRSYyhSpx4WRw2YuO0KKIGQEVk5J8uoz2BanawykgZGoWEqKm7pVIbzFDN0SpPcVV4IhOFkl8A==
|
||||
|
||||
"@material-ui/utils@^4.10.2", "@material-ui/utils@^4.9.6":
|
||||
version "4.10.2"
|
||||
resolved "https://packages.deskreen.com/@material-ui%2futils/-/utils-4.10.2.tgz#3fd5470ca61b7341f1e0468ac8f29a70bf6df321"
|
||||
integrity sha512-eg29v74P7W5r6a4tWWDAAfZldXIzfyO1am2fIsC39hdUUHm/33k6pGOKPbgDjg/U/4ifmgAePy/1OjkKN6rFRw==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.4.4"
|
||||
prop-types "^15.7.2"
|
||||
react-is "^16.8.0"
|
||||
|
||||
"@mrmlnc/readdir-enhanced@^2.2.1":
|
||||
version "2.2.1"
|
||||
resolved "https://packages.deskreen.com/@mrmlnc%2freaddir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde"
|
||||
@ -1568,6 +1724,11 @@
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/classnames@^2.2.10":
|
||||
version "2.2.10"
|
||||
resolved "https://packages.deskreen.com/@types%2fclassnames/-/classnames-2.2.10.tgz#cc658ca319b6355399efc1f5b9e818f1a24bf999"
|
||||
integrity sha512-1UzDldn9GfYYEsWWnn/P4wkTlkZDH7lDb0wBMGbtIQc9zXEQq7FlKBdZUn6OBqD8sKZZ2RQO2mAjGpXiDGoRmQ==
|
||||
|
||||
"@types/color-name@^1.1.1":
|
||||
version "1.1.1"
|
||||
resolved "https://packages.deskreen.com/@types%2fcolor-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0"
|
||||
@ -1880,6 +2041,13 @@
|
||||
resolved "https://packages.deskreen.com/@types%2fq/-/q-1.5.4.tgz#15925414e0ad2cd765bfef58842f7e26a7accb24"
|
||||
integrity sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug==
|
||||
|
||||
"@types/qrcode.react@^1.0.1":
|
||||
version "1.0.1"
|
||||
resolved "https://packages.deskreen.com/@types%2fqrcode.react/-/qrcode.react-1.0.1.tgz#0904e7a075a6274a5258f19567b4f64013c159d8"
|
||||
integrity sha512-PcVCjpsiT2KFKfJibOgTQtkt0QQT/6GbQUp1Np/hMPhwUzMJ2DRUkR9j7tXN9Q8X06qukw+RbaJ8lJ22SBod+Q==
|
||||
dependencies:
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/qs@*":
|
||||
version "6.9.4"
|
||||
resolved "https://packages.deskreen.com/@types%2fqs/-/qs-6.9.4.tgz#a59e851c1ba16c0513ea123830dd639a0a15cb6a"
|
||||
@ -1931,6 +2099,27 @@
|
||||
dependencies:
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/react-toast-notifications@^2.4.0":
|
||||
version "2.4.0"
|
||||
resolved "https://packages.deskreen.com/@types%2freact-toast-notifications/-/react-toast-notifications-2.4.0.tgz#0ca0732cfae5a6ef5939a676fffac6e64c78bc25"
|
||||
integrity sha512-nBI6gQ0E5gwi3IcTrVOR3oKoMGRfH1gK67kI6RIKUmiV5Sc3ZC/eymYBFt6iDo0dhlYET6kdtR0tcUh9h5L0sQ==
|
||||
dependencies:
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/react-toastify@^4.1.0":
|
||||
version "4.1.0"
|
||||
resolved "https://packages.deskreen.com/@types%2freact-toastify/-/react-toastify-4.1.0.tgz#604e712855dd677916d5c66af595d3b590f5d95d"
|
||||
integrity sha512-u7Ie/7LHBsPVz/iJxi/WlRDS7Gh9csCJACTDXx+pSLuZCm94xpkwzhM3jV1L5ZxP/in0Gp2tFbJ91VrSGr1gyQ==
|
||||
dependencies:
|
||||
react-toastify "*"
|
||||
|
||||
"@types/react-transition-group@^4.2.0":
|
||||
version "4.4.0"
|
||||
resolved "https://packages.deskreen.com/@types%2freact-transition-group/-/react-transition-group-4.4.0.tgz#882839db465df1320e4753e6e9f70ca7e9b4d46d"
|
||||
integrity sha512-/QfLHGpu+2fQOqQaXh8MG9q03bFENooTb/it4jr5kKaZlDQfWvjqWZg48AwzPVMBHlRuTRAY7hRHCEOXz5kV6w==
|
||||
dependencies:
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/react@*", "@types/react@^16.9.44":
|
||||
version "16.9.48"
|
||||
resolved "https://packages.deskreen.com/@types%2freact/-/react-16.9.48.tgz#d3387329f070d1b1bc0ff4a54a54ceefd5a8485c"
|
||||
@ -3077,6 +3266,22 @@ babel-plugin-dynamic-import-node@^2.3.3:
|
||||
dependencies:
|
||||
object.assign "^4.1.0"
|
||||
|
||||
babel-plugin-emotion@^10.0.27:
|
||||
version "10.0.33"
|
||||
resolved "https://packages.deskreen.com/babel-plugin-emotion/-/babel-plugin-emotion-10.0.33.tgz#ce1155dcd1783bbb9286051efee53f4e2be63e03"
|
||||
integrity sha512-bxZbTTGz0AJQDHm8k6Rf3RQJ8tX2scsfsRyKVgAbiUPUNIRtlK+7JxP+TAd1kRLABFxe0CFm2VdK4ePkoA9FxQ==
|
||||
dependencies:
|
||||
"@babel/helper-module-imports" "^7.0.0"
|
||||
"@emotion/hash" "0.8.0"
|
||||
"@emotion/memoize" "0.7.4"
|
||||
"@emotion/serialize" "^0.11.16"
|
||||
babel-plugin-macros "^2.0.0"
|
||||
babel-plugin-syntax-jsx "^6.18.0"
|
||||
convert-source-map "^1.5.0"
|
||||
escape-string-regexp "^1.0.5"
|
||||
find-root "^1.1.0"
|
||||
source-map "^0.5.7"
|
||||
|
||||
babel-plugin-istanbul@^6.0.0:
|
||||
version "6.0.0"
|
||||
resolved "https://packages.deskreen.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz#e159ccdc9af95e0b570c75b4573b7c34d671d765"
|
||||
@ -3098,6 +3303,15 @@ babel-plugin-jest-hoist@^26.2.0:
|
||||
"@types/babel__core" "^7.0.0"
|
||||
"@types/babel__traverse" "^7.0.6"
|
||||
|
||||
babel-plugin-macros@^2.0.0:
|
||||
version "2.8.0"
|
||||
resolved "https://packages.deskreen.com/babel-plugin-macros/-/babel-plugin-macros-2.8.0.tgz#0f958a7cc6556b1e65344465d99111a1e5e10138"
|
||||
integrity sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.7.2"
|
||||
cosmiconfig "^6.0.0"
|
||||
resolve "^1.12.0"
|
||||
|
||||
babel-plugin-syntax-async-functions@^6.8.0:
|
||||
version "6.13.0"
|
||||
resolved "https://packages.deskreen.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95"
|
||||
@ -3133,7 +3347,7 @@ babel-plugin-syntax-flow@^6.18.0:
|
||||
resolved "https://packages.deskreen.com/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.18.0.tgz#4c3ab20a2af26aa20cd25995c398c4eb70310c8d"
|
||||
integrity sha1-TDqyCiryaqIM0lmVw5jE63AxDI0=
|
||||
|
||||
babel-plugin-syntax-jsx@^6.3.13, babel-plugin-syntax-jsx@^6.8.0:
|
||||
babel-plugin-syntax-jsx@^6.18.0, babel-plugin-syntax-jsx@^6.3.13, babel-plugin-syntax-jsx@^6.8.0:
|
||||
version "6.18.0"
|
||||
resolved "https://packages.deskreen.com/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz#0af32a9a6e13ca7a3fd5069e62d7b0f58d0d8946"
|
||||
integrity sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY=
|
||||
@ -4426,7 +4640,7 @@ class-utils@^0.3.5:
|
||||
isobject "^3.0.0"
|
||||
static-extend "^0.1.1"
|
||||
|
||||
classnames@^2.2:
|
||||
classnames@^2.2, classnames@^2.2.6:
|
||||
version "2.2.6"
|
||||
resolved "https://packages.deskreen.com/classnames/-/classnames-2.2.6.tgz#43935bffdd291f326dad0a205309b38d00f650ce"
|
||||
integrity sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q==
|
||||
@ -4514,6 +4728,11 @@ clone@^1.0.2:
|
||||
resolved "https://packages.deskreen.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e"
|
||||
integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4=
|
||||
|
||||
clsx@^1.0.4, clsx@^1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://packages.deskreen.com/clsx/-/clsx-1.1.1.tgz#98b3134f9abbdf23b2663491ace13c5c03a73188"
|
||||
integrity sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==
|
||||
|
||||
co@^4.6.0:
|
||||
version "4.6.0"
|
||||
resolved "https://packages.deskreen.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
|
||||
@ -4798,7 +5017,7 @@ content-type@^1.0.4, content-type@~1.0.4:
|
||||
resolved "https://packages.deskreen.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b"
|
||||
integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==
|
||||
|
||||
convert-source-map@^1.4.0, convert-source-map@^1.5.1, convert-source-map@^1.6.0, convert-source-map@^1.7.0:
|
||||
convert-source-map@^1.4.0, convert-source-map@^1.5.0, convert-source-map@^1.5.1, convert-source-map@^1.6.0, convert-source-map@^1.7.0:
|
||||
version "1.7.0"
|
||||
resolved "https://packages.deskreen.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442"
|
||||
integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==
|
||||
@ -5081,6 +5300,14 @@ css-tree@1.0.0-alpha.39:
|
||||
mdn-data "2.0.6"
|
||||
source-map "^0.6.1"
|
||||
|
||||
css-vendor@^2.0.8:
|
||||
version "2.0.8"
|
||||
resolved "https://packages.deskreen.com/css-vendor/-/css-vendor-2.0.8.tgz#e47f91d3bd3117d49180a3c935e62e3d9f7f449d"
|
||||
integrity sha512-x9Aq0XTInxrkuFeHKbYC7zWY8ai7qJ04Kxd9MnvbC1uO5DagxoHQjm4JvG+vCdXOoFtCjbL2XSZfxmoYa9uQVQ==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.8.3"
|
||||
is-in-browser "^1.0.2"
|
||||
|
||||
css-what@2.1:
|
||||
version "2.1.3"
|
||||
resolved "https://packages.deskreen.com/css-what/-/css-what-2.1.3.tgz#a6d7604573365fe74686c3f311c56513d88285f2"
|
||||
@ -5198,6 +5425,11 @@ cssstyle@^2.2.0:
|
||||
dependencies:
|
||||
cssom "~0.3.6"
|
||||
|
||||
csstype@^2.5.2, csstype@^2.5.7:
|
||||
version "2.6.13"
|
||||
resolved "https://packages.deskreen.com/csstype/-/csstype-2.6.13.tgz#a6893015b90e84dd6e85d0e3b442a1e84f2dbe0f"
|
||||
integrity sha512-ul26pfSQTZW8dcOnD2iiJssfXw0gdNVX9IJDH/X3K5DGPfj+fUYe3kB+swUY6BF3oZDxaID3AJt+9/ojSAE05A==
|
||||
|
||||
csstype@^3.0.2:
|
||||
version "3.0.3"
|
||||
resolved "https://packages.deskreen.com/csstype/-/csstype-3.0.3.tgz#2b410bbeba38ba9633353aff34b05d9755d065f8"
|
||||
@ -5364,6 +5596,13 @@ default-gateway@^4.2.0:
|
||||
execa "^1.0.0"
|
||||
ip-regex "^2.1.0"
|
||||
|
||||
default-gateway@^6.0.0:
|
||||
version "6.0.2"
|
||||
resolved "https://packages.deskreen.com/default-gateway/-/default-gateway-6.0.2.tgz#fc14f4a2ae1cbc699c2b40cedd941ab312609ea4"
|
||||
integrity sha512-bWrj9HZWNXJ/RUkWmBIp67JawNrPGz0il43IGWU84dazEYbNFQ52HbIiqgRQdYUHK3RyGrENrDV9QkwArt6IAQ==
|
||||
dependencies:
|
||||
execa "^4.0.3"
|
||||
|
||||
defaults@^1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://packages.deskreen.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d"
|
||||
@ -5621,6 +5860,14 @@ dom-helpers@^3.4.0:
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.1.2"
|
||||
|
||||
dom-helpers@^5.0.1:
|
||||
version "5.2.0"
|
||||
resolved "https://packages.deskreen.com/dom-helpers/-/dom-helpers-5.2.0.tgz#57fd054c5f8f34c52a3eeffdb7e7e93cd357d95b"
|
||||
integrity sha512-Ru5o9+V8CpunKnz5LGgWXkmrH/20cGKwcHwS4m73zIvs54CN9epEmT/HLqFJW3kXpakAFkEdzgy1hzlJe3E4OQ==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.8.7"
|
||||
csstype "^3.0.2"
|
||||
|
||||
dom-serializer@0:
|
||||
version "0.2.2"
|
||||
resolved "https://packages.deskreen.com/dom-serializer/-/dom-serializer-0.2.2.tgz#1afb81f533717175d478655debc5e332d9f9bb51"
|
||||
@ -5802,7 +6049,7 @@ electron-is-accelerator@^0.1.0:
|
||||
resolved "https://packages.deskreen.com/electron-is-accelerator/-/electron-is-accelerator-0.1.2.tgz#509e510c26a56b55e17f863a4b04e111846ab27b"
|
||||
integrity sha1-UJ5RDCala1Xhf4Y6SwThEYRqsns=
|
||||
|
||||
electron-is-dev@^1.1.0, electron-is-dev@^1.2.0:
|
||||
electron-is-dev@^1.1.0:
|
||||
version "1.2.0"
|
||||
resolved "https://packages.deskreen.com/electron-is-dev/-/electron-is-dev-1.2.0.tgz#2e5cea0a1b3ccf1c86f577cee77363ef55deb05e"
|
||||
integrity sha512-R1oD5gMBPS7PVU8gJwH6CtT0e6VSoD0+SzSnYpNm+dBkcijgA+K7VAMHDfnRq/lkKPZArpzplTW6jfiMYosdzw==
|
||||
@ -5851,6 +6098,18 @@ electron-rebuild@^1.10.0:
|
||||
spawn-rx "^3.0.0"
|
||||
yargs "^14.2.0"
|
||||
|
||||
electron-settings@^4.0.2:
|
||||
version "4.0.2"
|
||||
resolved "https://packages.deskreen.com/electron-settings/-/electron-settings-4.0.2.tgz#26ef242397393e0e69119f6fb879fc2287d0f508"
|
||||
integrity sha512-WnUlrnBsO784oXcag0ym+A3ySoIwonz5GhYFsWroMHVzslzmsP+81f/Fof41T9UrRUxuPPKiZPZMwGO+yvWChg==
|
||||
dependencies:
|
||||
lodash.get "^4.4.2"
|
||||
lodash.has "^4.5.2"
|
||||
lodash.set "^4.3.2"
|
||||
lodash.unset "^4.5.2"
|
||||
mkdirp "^1.0.4"
|
||||
write-file-atomic "^3.0.3"
|
||||
|
||||
electron-to-chromium@^1.3.47, electron-to-chromium@^1.3.523:
|
||||
version "1.3.555"
|
||||
resolved "https://packages.deskreen.com/electron-to-chromium/-/electron-to-chromium-1.3.555.tgz#a096716ff77cf8da9a608eb628fd6927869503d2"
|
||||
@ -7005,6 +7264,11 @@ follow-redirects@^1.0.0:
|
||||
resolved "https://packages.deskreen.com/follow-redirects/-/follow-redirects-1.13.0.tgz#b42e8d93a2a7eea5ed88633676d6597bc8e384db"
|
||||
integrity sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA==
|
||||
|
||||
fontsource-lexend-peta@^3.0.9:
|
||||
version "3.0.9"
|
||||
resolved "https://packages.deskreen.com/fontsource-lexend-peta/-/fontsource-lexend-peta-3.0.9.tgz#c11994728d50d95a348b6f87926c6eb1c086c892"
|
||||
integrity sha512-pqOcFyjC8RkZcSC9EoXLk2fb2HssgWcvMREk7DvNJInWP+v3/htZaQjlF1el6EQoVuOx9lJwNxqqNiQvW3B8/w==
|
||||
|
||||
for-in@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://packages.deskreen.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
|
||||
@ -7626,7 +7890,7 @@ hmac-drbg@^1.0.0:
|
||||
minimalistic-assert "^1.0.0"
|
||||
minimalistic-crypto-utils "^1.0.1"
|
||||
|
||||
hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.0:
|
||||
hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2:
|
||||
version "3.3.2"
|
||||
resolved "https://packages.deskreen.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45"
|
||||
integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==
|
||||
@ -7858,6 +8122,11 @@ husky@^4.2.5:
|
||||
slash "^3.0.0"
|
||||
which-pm-runs "^1.0.0"
|
||||
|
||||
hyphenate-style-name@^1.0.3:
|
||||
version "1.0.4"
|
||||
resolved "https://packages.deskreen.com/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz#691879af8e220aea5750e8827db4ef62a54e361d"
|
||||
integrity sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ==
|
||||
|
||||
i18next-fs-backend@^1.0.7:
|
||||
version "1.0.7"
|
||||
resolved "https://packages.deskreen.com/i18next-fs-backend/-/i18next-fs-backend-1.0.7.tgz#00ca4587e306f8948740408389dda73461a5d07f"
|
||||
@ -8063,6 +8332,14 @@ internal-ip@^4.3.0:
|
||||
default-gateway "^4.2.0"
|
||||
ipaddr.js "^1.9.0"
|
||||
|
||||
internal-ip@^6.1.0:
|
||||
version "6.1.0"
|
||||
resolved "https://packages.deskreen.com/internal-ip/-/internal-ip-6.1.0.tgz#3ce3a9155dc9e2a423af0059efcf5f4b0de3399c"
|
||||
integrity sha512-Cs1iaqrl3z3KJ2ejWyfKkMcuv9NTEJWXtUBSGVc+Eg9BjBLS0k11CsOkf/p5quOkVhhRuq9zwZ/PuJpPUuDP9Q==
|
||||
dependencies:
|
||||
default-gateway "^6.0.0"
|
||||
ipaddr.js "^1.9.1"
|
||||
|
||||
internal-slot@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://packages.deskreen.com/internal-slot/-/internal-slot-1.0.2.tgz#9c2e9fb3cd8e5e4256c6f45fe310067fcfa378a3"
|
||||
@ -8094,7 +8371,7 @@ ip@^1.1.0, ip@^1.1.3, ip@^1.1.5:
|
||||
resolved "https://packages.deskreen.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a"
|
||||
integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=
|
||||
|
||||
ipaddr.js@1.9.1, ipaddr.js@^1.9.0:
|
||||
ipaddr.js@1.9.1, ipaddr.js@^1.9.0, ipaddr.js@^1.9.1:
|
||||
version "1.9.1"
|
||||
resolved "https://packages.deskreen.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3"
|
||||
integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==
|
||||
@ -8353,6 +8630,11 @@ is-hexadecimal@^1.0.0:
|
||||
resolved "https://packages.deskreen.com/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz#cc35c97588da4bd49a8eedd6bc4082d44dcb23a7"
|
||||
integrity sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==
|
||||
|
||||
is-in-browser@^1.0.2, is-in-browser@^1.1.3:
|
||||
version "1.1.3"
|
||||
resolved "https://packages.deskreen.com/is-in-browser/-/is-in-browser-1.1.3.tgz#56ff4db683a078c6082eb95dad7dc62e1d04f835"
|
||||
integrity sha1-Vv9NtoOgeMYILrldrX3GLh0E+DU=
|
||||
|
||||
is-installed-globally@^0.3.1:
|
||||
version "0.3.2"
|
||||
resolved "https://packages.deskreen.com/is-installed-globally/-/is-installed-globally-0.3.2.tgz#fd3efa79ee670d1187233182d5b0a1dd00313141"
|
||||
@ -9243,6 +9525,76 @@ jsprim@^1.2.2:
|
||||
json-schema "0.2.3"
|
||||
verror "1.10.0"
|
||||
|
||||
jss-plugin-camel-case@^10.0.3:
|
||||
version "10.4.0"
|
||||
resolved "https://packages.deskreen.com/jss-plugin-camel-case/-/jss-plugin-camel-case-10.4.0.tgz#46c75ff7fd61c304984c21af5817823f0f501ceb"
|
||||
integrity sha512-9oDjsQ/AgdBbMyRjc06Kl3P8lDCSEts2vYZiPZfGAxbGCegqE4RnMob3mDaBby5H9vL9gWmyyImhLRWqIkRUCw==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.3.1"
|
||||
hyphenate-style-name "^1.0.3"
|
||||
jss "10.4.0"
|
||||
|
||||
jss-plugin-default-unit@^10.0.3:
|
||||
version "10.4.0"
|
||||
resolved "https://packages.deskreen.com/jss-plugin-default-unit/-/jss-plugin-default-unit-10.4.0.tgz#2b10f01269eaea7f36f0f5fd1cfbfcc76ed42854"
|
||||
integrity sha512-BYJ+Y3RUYiMEgmlcYMLqwbA49DcSWsGgHpVmEEllTC8MK5iJ7++pT9TnKkKBnNZZxTV75ycyFCR5xeLSOzVm4A==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.3.1"
|
||||
jss "10.4.0"
|
||||
|
||||
jss-plugin-global@^10.0.3:
|
||||
version "10.4.0"
|
||||
resolved "https://packages.deskreen.com/jss-plugin-global/-/jss-plugin-global-10.4.0.tgz#19449425a94e4e74e113139b629fd44d3577f97d"
|
||||
integrity sha512-b8IHMJUmv29cidt3nI4bUI1+Mo5RZE37kqthaFpmxf5K7r2aAegGliAw4hXvA70ca6ckAoXMUl4SN/zxiRcRag==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.3.1"
|
||||
jss "10.4.0"
|
||||
|
||||
jss-plugin-nested@^10.0.3:
|
||||
version "10.4.0"
|
||||
resolved "https://packages.deskreen.com/jss-plugin-nested/-/jss-plugin-nested-10.4.0.tgz#017d0c02c0b6b454fd9d7d3fc33470a15eea9fd1"
|
||||
integrity sha512-cKgpeHIxAP0ygeWh+drpLbrxFiak6zzJ2toVRi/NmHbpkNaLjTLgePmOz5+67ln3qzJiPdXXJB1tbOyYKAP4Pw==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.3.1"
|
||||
jss "10.4.0"
|
||||
tiny-warning "^1.0.2"
|
||||
|
||||
jss-plugin-props-sort@^10.0.3:
|
||||
version "10.4.0"
|
||||
resolved "https://packages.deskreen.com/jss-plugin-props-sort/-/jss-plugin-props-sort-10.4.0.tgz#7110bf0b6049cc2080b220b506532bf0b70c0e07"
|
||||
integrity sha512-j/t0R40/2fp+Nzt6GgHeUFnHVY2kPGF5drUVlgkcwYoHCgtBDOhTTsOfdaQFW6sHWfoQYgnGV4CXdjlPiRrzwA==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.3.1"
|
||||
jss "10.4.0"
|
||||
|
||||
jss-plugin-rule-value-function@^10.0.3:
|
||||
version "10.4.0"
|
||||
resolved "https://packages.deskreen.com/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.4.0.tgz#7cff4a91e84973536fa49b6ebbdbf7f339b01c82"
|
||||
integrity sha512-w8504Cdfu66+0SJoLkr6GUQlEb8keHg8ymtJXdVHWh0YvFxDG2l/nS93SI5Gfx0fV29dO6yUugXnKzDFJxrdFQ==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.3.1"
|
||||
jss "10.4.0"
|
||||
tiny-warning "^1.0.2"
|
||||
|
||||
jss-plugin-vendor-prefixer@^10.0.3:
|
||||
version "10.4.0"
|
||||
resolved "https://packages.deskreen.com/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.4.0.tgz#2a78f3c5d57d1e024fe7ad7c41de34d04e72ecc0"
|
||||
integrity sha512-DpF+/a+GU8hMh/948sBGnKSNfKkoHg2p9aRFUmyoyxgKjOeH9n74Ht3Yt8lOgdZsuWNJbPrvaa3U4PXKwxVpTQ==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.3.1"
|
||||
css-vendor "^2.0.8"
|
||||
jss "10.4.0"
|
||||
|
||||
jss@10.4.0, jss@^10.0.3:
|
||||
version "10.4.0"
|
||||
resolved "https://packages.deskreen.com/jss/-/jss-10.4.0.tgz#473a6fbe42e85441020a07e9519dac1e8a2e79ca"
|
||||
integrity sha512-l7EwdwhsDishXzqTc3lbsbyZ83tlUl5L/Hb16pHCvZliA9lRDdNBZmHzeJHP0sxqD0t1mrMmMR8XroR12JBYzw==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.3.1"
|
||||
csstype "^3.0.2"
|
||||
is-in-browser "^1.1.3"
|
||||
tiny-warning "^1.0.2"
|
||||
|
||||
jsx-ast-utils@^2.4.1:
|
||||
version "2.4.1"
|
||||
resolved "https://packages.deskreen.com/jsx-ast-utils/-/jsx-ast-utils-2.4.1.tgz#1114a4c1209481db06c690c2b4f488cc665f657e"
|
||||
@ -9594,6 +9946,16 @@ lodash.flattendeep@^4.4.0:
|
||||
resolved "https://packages.deskreen.com/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz#fb030917f86a3134e5bc9bec0d69e0013ddfedb2"
|
||||
integrity sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=
|
||||
|
||||
lodash.get@^4.4.2:
|
||||
version "4.4.2"
|
||||
resolved "https://packages.deskreen.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99"
|
||||
integrity sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=
|
||||
|
||||
lodash.has@^4.5.2:
|
||||
version "4.5.2"
|
||||
resolved "https://packages.deskreen.com/lodash.has/-/lodash.has-4.5.2.tgz#d19f4dc1095058cccbe2b0cdf4ee0fe4aa37c862"
|
||||
integrity sha1-0Z9NwQlQWMzL4rDN9O4P5Ko3yGI=
|
||||
|
||||
lodash.isequal@^4.5.0:
|
||||
version "4.5.0"
|
||||
resolved "https://packages.deskreen.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0"
|
||||
@ -9604,6 +9966,11 @@ lodash.memoize@4.1.2, lodash.memoize@4.x, lodash.memoize@^4.1.2:
|
||||
resolved "https://packages.deskreen.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
|
||||
integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=
|
||||
|
||||
lodash.set@^4.3.2:
|
||||
version "4.3.2"
|
||||
resolved "https://packages.deskreen.com/lodash.set/-/lodash.set-4.3.2.tgz#d8757b1da807dde24816b0d6a84bea1a76230b23"
|
||||
integrity sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM=
|
||||
|
||||
lodash.sortby@^4.7.0:
|
||||
version "4.7.0"
|
||||
resolved "https://packages.deskreen.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438"
|
||||
@ -9614,6 +9981,11 @@ lodash.uniq@^4.5.0:
|
||||
resolved "https://packages.deskreen.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
|
||||
integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=
|
||||
|
||||
lodash.unset@^4.5.2:
|
||||
version "4.5.2"
|
||||
resolved "https://packages.deskreen.com/lodash.unset/-/lodash.unset-4.5.2.tgz#370d1d3e85b72a7e1b0cdf2d272121306f23e4ed"
|
||||
integrity sha1-Nw0dPoW3Kn4bDN8tJyEhMG8j5O0=
|
||||
|
||||
"lodash@4.6.1 || ^4.16.1", lodash@^4.14.0, lodash@^4.15.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.4, lodash@^4.17.5:
|
||||
version "4.17.20"
|
||||
resolved "https://packages.deskreen.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52"
|
||||
@ -10193,11 +10565,6 @@ nan@^2.12.1:
|
||||
resolved "https://packages.deskreen.com/nan/-/nan-2.14.1.tgz#d7be34dfa3105b91494c3147089315eff8874b01"
|
||||
integrity sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw==
|
||||
|
||||
nanoid@^0.2.2:
|
||||
version "0.2.2"
|
||||
resolved "https://packages.deskreen.com/nanoid/-/nanoid-0.2.2.tgz#e2ebc6ad3db5e0454fd8124d30ca39b06555fe56"
|
||||
integrity sha512-GHoRrvNEKiwdkwQ/enKL8AhQkkrBC/2KxMZkDvQzp8OtkpX8ZAmoYJWFVl7l8F2+HcEJUfdg21Ab2wXXfrvACQ==
|
||||
|
||||
nanoid@^1.0.1:
|
||||
version "1.3.4"
|
||||
resolved "https://packages.deskreen.com/nanoid/-/nanoid-1.3.4.tgz#ad89f62c9d1f4fd69710d4a90953d2893d2d31f4"
|
||||
@ -10208,6 +10575,11 @@ nanoid@^2.1.0, nanoid@^2.1.3:
|
||||
resolved "https://packages.deskreen.com/nanoid/-/nanoid-2.1.11.tgz#ec24b8a758d591561531b4176a01e3ab4f0f0280"
|
||||
integrity sha512-s/snB+WGm6uwi0WjsZdaVcuf3KJXlfGl2LcxgwkEwJF0D/BWzVWAZW/XY4bFaiR7s0Jk3FPvlnepg1H1b1UwlA==
|
||||
|
||||
nanoid@^3.1.12:
|
||||
version "3.1.12"
|
||||
resolved "https://packages.deskreen.com/nanoid/-/nanoid-3.1.12.tgz#6f7736c62e8d39421601e4a0c77623a97ea69654"
|
||||
integrity sha512-1qstj9z5+x491jfiC4Nelk+f8XBad7LN20PmyWINJEMRSf3wcAjAWysw1qaA8z6NSKe2sjq1hRSDpBH5paCb6A==
|
||||
|
||||
nanomatch@^1.2.9:
|
||||
version "1.2.13"
|
||||
resolved "https://packages.deskreen.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119"
|
||||
@ -11107,16 +11479,16 @@ pinkie-promise@^2.0.0:
|
||||
dependencies:
|
||||
pinkie "^2.0.0"
|
||||
|
||||
pinkie@1.0.0, pinkie@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://packages.deskreen.com/pinkie/-/pinkie-1.0.0.tgz#5a47f28ba1015d0201bda7bf0f358e47bec8c7e4"
|
||||
integrity sha1-Wkfyi6EBXQIBvae/DzWOR77Ix+Q=
|
||||
|
||||
pinkie@^2.0.0, pinkie@^2.0.1, pinkie@^2.0.4:
|
||||
pinkie@2.0.4, pinkie@^2.0.0, pinkie@^2.0.1, pinkie@^2.0.4:
|
||||
version "2.0.4"
|
||||
resolved "https://packages.deskreen.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870"
|
||||
integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA=
|
||||
|
||||
pinkie@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://packages.deskreen.com/pinkie/-/pinkie-1.0.0.tgz#5a47f28ba1015d0201bda7bf0f358e47bec8c7e4"
|
||||
integrity sha1-Wkfyi6EBXQIBvae/DzWOR77Ix+Q=
|
||||
|
||||
pirates@^4.0.0, pirates@^4.0.1:
|
||||
version "4.0.1"
|
||||
resolved "https://packages.deskreen.com/pirates/-/pirates-4.0.1.tgz#643a92caf894566f91b2b986d2c66950a8e2fb87"
|
||||
@ -11157,6 +11529,11 @@ pngjs@^3.3.1:
|
||||
resolved "https://packages.deskreen.com/pngjs/-/pngjs-3.4.0.tgz#99ca7d725965fb655814eaf65f38f12bbdbf555f"
|
||||
integrity sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==
|
||||
|
||||
popper.js@1.16.1-lts:
|
||||
version "1.16.1-lts"
|
||||
resolved "https://packages.deskreen.com/popper.js/-/popper.js-1.16.1-lts.tgz#cf6847b807da3799d80ee3d6d2f90df8a3f50b05"
|
||||
integrity sha512-Kjw8nKRl1m+VrSFCoVGPph93W/qrSO7ZkqPpTf7F4bk/sqcfWK019dWBUpE/fBOsOQY1dks/Bmcbfn1heM/IsA==
|
||||
|
||||
popper.js@^1.14.4, popper.js@^1.16.1:
|
||||
version "1.16.1"
|
||||
resolved "https://packages.deskreen.com/popper.js/-/popper.js-1.16.1.tgz#2a223cb3dc7b6213d740e40372be40de43e65b1b"
|
||||
@ -11655,7 +12032,7 @@ prop-types-exact@^1.2.0:
|
||||
object.assign "^4.1.0"
|
||||
reflect.ownkeys "^0.2.0"
|
||||
|
||||
prop-types@^15.5.8, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2:
|
||||
prop-types@^15.5.10, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2:
|
||||
version "15.7.2"
|
||||
resolved "https://packages.deskreen.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
|
||||
integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
|
||||
@ -11760,11 +12137,30 @@ q@^1.1.2:
|
||||
resolved "https://packages.deskreen.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7"
|
||||
integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=
|
||||
|
||||
qr.js@0.0.0:
|
||||
version "0.0.0"
|
||||
resolved "https://packages.deskreen.com/qr.js/-/qr.js-0.0.0.tgz#cace86386f59a0db8050fa90d9b6b0e88a1e364f"
|
||||
integrity sha1-ys6GOG9ZoNuAUPqQ2baw6IoeNk8=
|
||||
|
||||
qrcode-generator@^1.4.1:
|
||||
version "1.4.4"
|
||||
resolved "https://packages.deskreen.com/qrcode-generator/-/qrcode-generator-1.4.4.tgz#63f771224854759329a99048806a53ed278740e7"
|
||||
integrity sha512-HM7yY8O2ilqhmULxGMpcHSF1EhJJ9yBj8gvDEuZ6M+KGJ0YY2hKpnXvRD+hZPLrDVck3ExIGhmPtSdcjC+guuw==
|
||||
|
||||
qrcode-terminal@^0.10.0:
|
||||
version "0.10.0"
|
||||
resolved "https://packages.deskreen.com/qrcode-terminal/-/qrcode-terminal-0.10.0.tgz#a76a48e2610a18f97fa3a2bd532b682acff86c53"
|
||||
integrity sha1-p2pI4mEKGPl/o6K9UytoKs/4bFM=
|
||||
|
||||
qrcode.react@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://packages.deskreen.com/qrcode.react/-/qrcode.react-1.0.0.tgz#7e8889db3b769e555e8eb463d4c6de221c36d5de"
|
||||
integrity sha512-jBXleohRTwvGBe1ngV+62QvEZ/9IZqQivdwzo9pJM4LQMoCM2VnvNBnKdjvGnKyDZ/l0nCDgsPod19RzlPvm/Q==
|
||||
dependencies:
|
||||
loose-envify "^1.4.0"
|
||||
prop-types "^15.6.0"
|
||||
qr.js "0.0.0"
|
||||
|
||||
qs@6.7.0:
|
||||
version "6.7.0"
|
||||
resolved "https://packages.deskreen.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc"
|
||||
@ -11863,7 +12259,17 @@ rc@^1.2.8:
|
||||
minimist "^1.2.0"
|
||||
strip-json-comments "~2.0.1"
|
||||
|
||||
react-dom@^16.12.0:
|
||||
react-awesome-reveal@^3.2.1:
|
||||
version "3.2.1"
|
||||
resolved "https://packages.deskreen.com/react-awesome-reveal/-/react-awesome-reveal-3.2.1.tgz#a1c3d876b666c807219c5ceb6eaa4b75a6bb16fb"
|
||||
integrity sha512-/jxX6lTjVyARwOIZBth88G+5Curb9/wEjPRd3QV6FDsgEfkCwZ3z8AStR43uCDqOeKlJq5d5Hzm4dLoXt0Lb6g==
|
||||
dependencies:
|
||||
"@emotion/core" "^10.0.35"
|
||||
"@emotion/styled" "^10.0.27"
|
||||
react-intersection-observer "^8.27.1"
|
||||
react-is "^16.13.1"
|
||||
|
||||
react-dom@^16.12.0, react-dom@^16.4.1:
|
||||
version "16.13.1"
|
||||
resolved "https://packages.deskreen.com/react-dom/-/react-dom-16.13.1.tgz#c1bd37331a0486c078ee54c4740720993b2e0e7f"
|
||||
integrity sha512-81PIMmVLnCNLO/fFOQxdQkvEq/+Hfpv24XNJfpyZhTRfO0QcmQIF/PgCa1zCOj2w1hrn12MFLyaJ/G0+Mxtfag==
|
||||
@ -11903,7 +12309,12 @@ react-i18next@^11.7.0:
|
||||
"@babel/runtime" "^7.3.1"
|
||||
html-parse-stringify2 "2.0.1"
|
||||
|
||||
react-is@^16.12.0, react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.6, react-is@^16.9.0:
|
||||
react-intersection-observer@^8.27.1:
|
||||
version "8.28.2"
|
||||
resolved "https://packages.deskreen.com/react-intersection-observer/-/react-intersection-observer-8.28.2.tgz#6504423575905bb9312be6ff0d22e7bbc78af63f"
|
||||
integrity sha512-JzyBn3QylXSJmM7P9dxxAioC4F3xHt4Uc3A6ZBXY27PeSNFraqnsd9jBdo7LJOMtzeXxyfJ6rYdDTl35LQ5TnQ==
|
||||
|
||||
react-is@^16.12.0, react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.0, react-is@^16.8.1, react-is@^16.8.6, react-is@^16.9.0:
|
||||
version "16.13.1"
|
||||
resolved "https://packages.deskreen.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
|
||||
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
|
||||
@ -11926,6 +12337,16 @@ react-popper@^1.3.7:
|
||||
typed-styles "^0.0.7"
|
||||
warning "^4.0.2"
|
||||
|
||||
react-qrcode-logo@^2.2.1:
|
||||
version "2.2.1"
|
||||
resolved "https://packages.deskreen.com/react-qrcode-logo/-/react-qrcode-logo-2.2.1.tgz#c409a1a37bc8eb76ef10343ff2e6f00b94facac8"
|
||||
integrity sha512-eXFSJW8HVPMT2ea4pLkbG8apHJ/aIPpQ4kX0HmsSm0wN+K+bleRNgElbjIPS4G7n0lxcA7N6pw+KAxMWPJFoqA==
|
||||
dependencies:
|
||||
lodash.isequal "^4.5.0"
|
||||
qrcode-generator "^1.4.1"
|
||||
react "^16.4.1"
|
||||
react-dom "^16.4.1"
|
||||
|
||||
react-redux@^7.2.0:
|
||||
version "7.2.1"
|
||||
resolved "https://packages.deskreen.com/react-redux/-/react-redux-7.2.1.tgz#8dedf784901014db2feca1ab633864dee68ad985"
|
||||
@ -11937,6 +12358,13 @@ react-redux@^7.2.0:
|
||||
prop-types "^15.7.2"
|
||||
react-is "^16.9.0"
|
||||
|
||||
react-reveal@^1.2.2:
|
||||
version "1.2.2"
|
||||
resolved "https://packages.deskreen.com/react-reveal/-/react-reveal-1.2.2.tgz#f47fbc44debc4c185ae2163a215a9e822c7adfef"
|
||||
integrity sha512-JCv3fAoU6Z+Lcd8U48bwzm4pMZ79qsedSXYwpwt6lJNtj/v5nKJYZZbw3yhaQPPgYePo3Y0NOCoYOq/jcsisuw==
|
||||
dependencies:
|
||||
prop-types "^15.5.10"
|
||||
|
||||
react-router-dom@^5.2.0:
|
||||
version "5.2.0"
|
||||
resolved "https://packages.deskreen.com/react-router-dom/-/react-router-dom-5.2.0.tgz#9e65a4d0c45e13289e66c7b17c7e175d0ea15662"
|
||||
@ -11976,6 +12404,23 @@ react-test-renderer@^16.0.0-0, react-test-renderer@^16.12.0:
|
||||
react-is "^16.8.6"
|
||||
scheduler "^0.19.1"
|
||||
|
||||
react-toast-notifications@^2.4.0:
|
||||
version "2.4.0"
|
||||
resolved "https://packages.deskreen.com/react-toast-notifications/-/react-toast-notifications-2.4.0.tgz#6213730bd1fe158fc01aeef200687ea94c5c5b24"
|
||||
integrity sha512-8tkrbNh7LxkiFmtqAL/AiI55efIeI+fBk3c6ImsiZ0VObb4yvOq0cqYuJHyUiv9fuD2aBxvXGVH+n4Snt8qoWA==
|
||||
dependencies:
|
||||
"@emotion/core" "^10.0.14"
|
||||
react-transition-group "^4.3.0"
|
||||
|
||||
react-toastify@*, react-toastify@^6.0.8:
|
||||
version "6.0.8"
|
||||
resolved "https://packages.deskreen.com/react-toastify/-/react-toastify-6.0.8.tgz#84625d81d0fd01902a7f4c6f317eb074cb3bba67"
|
||||
integrity sha512-NSqCNwv+C4IfR+c92PFZiNyeBwOJvigrP2bcRi2f6Hg3WqcHhEHOknbSQOs9QDFuqUjmK3SOrdvScQ3z63ifXg==
|
||||
dependencies:
|
||||
classnames "^2.2.6"
|
||||
prop-types "^15.7.2"
|
||||
react-transition-group "^4.4.1"
|
||||
|
||||
react-transition-group@^2.9.0:
|
||||
version "2.9.0"
|
||||
resolved "https://packages.deskreen.com/react-transition-group/-/react-transition-group-2.9.0.tgz#df9cdb025796211151a436c69a8f3b97b5b07c8d"
|
||||
@ -11986,7 +12431,17 @@ react-transition-group@^2.9.0:
|
||||
prop-types "^15.6.2"
|
||||
react-lifecycles-compat "^3.0.4"
|
||||
|
||||
react@^16.13.1:
|
||||
react-transition-group@^4.3.0, react-transition-group@^4.4.0, react-transition-group@^4.4.1:
|
||||
version "4.4.1"
|
||||
resolved "https://packages.deskreen.com/react-transition-group/-/react-transition-group-4.4.1.tgz#63868f9325a38ea5ee9535d828327f85773345c9"
|
||||
integrity sha512-Djqr7OQ2aPUiYurhPalTrVy9ddmFCCzwhqQmtN+J3+3DzLO209Fdr70QrN8Z3DsglWql6iY1lDWAfpFiBtuKGw==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.5.5"
|
||||
dom-helpers "^5.0.1"
|
||||
loose-envify "^1.4.0"
|
||||
prop-types "^15.6.2"
|
||||
|
||||
react@^16.13.1, react@^16.4.1:
|
||||
version "16.13.1"
|
||||
resolved "https://packages.deskreen.com/react/-/react-16.13.1.tgz#2e818822f1a9743122c063d6410d85c1e3afe48e"
|
||||
integrity sha512-YMZQQq32xHLX0bz5Mnibv1/LHb3Sqzngu7xstSM+vrkE5Kzr9xE0yMByK5kMoTK30YVJE61WfbxIFFvfeDKT1w==
|
||||
@ -13864,10 +14319,10 @@ testcafe-browser-tools@2.0.13:
|
||||
read-file-relative "^1.2.0"
|
||||
which-promise "^1.0.0"
|
||||
|
||||
testcafe-hammerhead@17.1.13:
|
||||
version "17.1.13"
|
||||
resolved "https://packages.deskreen.com/testcafe-hammerhead/-/testcafe-hammerhead-17.1.13.tgz#e2ab9589e48aa145fa886c2303891e9e997d33fa"
|
||||
integrity sha512-swNsC4gbs1vhKM9F9zmCcStA8oMg2FUTJZYUE30xL5ZdHae87x2tfg9T58jUcZK3CX0S9B2NCU1AJbwCsS0uqw==
|
||||
testcafe-hammerhead@17.1.15:
|
||||
version "17.1.15"
|
||||
resolved "https://packages.deskreen.com/testcafe-hammerhead/-/testcafe-hammerhead-17.1.15.tgz#2855db1d795f598ee331eda4ff7b0ca0309255d9"
|
||||
integrity sha512-FvuaODbFUkoqyzH0OapiMO3/ISCB/v+0kKi0+5DhcIz1tRBishzyfLbHFyKXUf6rm0IhGJlME93uKFOM9NNOMw==
|
||||
dependencies:
|
||||
acorn-hammerhead "^0.3.0"
|
||||
asar "^2.0.1"
|
||||
@ -13884,10 +14339,10 @@ testcafe-hammerhead@17.1.13:
|
||||
merge-stream "^1.0.1"
|
||||
mime "~1.4.1"
|
||||
mustache "^2.1.1"
|
||||
nanoid "^0.2.2"
|
||||
nanoid "^3.1.12"
|
||||
os-family "^1.0.0"
|
||||
parse5 "2.2.3"
|
||||
pinkie "1.0.0"
|
||||
pinkie "2.0.4"
|
||||
read-file-relative "^1.2.0"
|
||||
semver "5.5.0"
|
||||
tough-cookie "2.3.3"
|
||||
@ -13943,10 +14398,10 @@ testcafe-reporter-xunit@^2.1.0:
|
||||
resolved "https://packages.deskreen.com/testcafe-reporter-xunit/-/testcafe-reporter-xunit-2.1.0.tgz#e6d66c572ce15af266706af0fd610b2a841dd443"
|
||||
integrity sha1-5tZsVyzhWvJmcGrw/WELKoQd1EM=
|
||||
|
||||
testcafe@^1.8.8:
|
||||
version "1.9.1"
|
||||
resolved "https://packages.deskreen.com/testcafe/-/testcafe-1.9.1.tgz#2e3183d69561bf90da611408436c5b34b22f799c"
|
||||
integrity sha512-18yGuCJvcdaGFhS3l4NhDwRnvJ24/mwXVfM+gqZm6vxNdw2NCujzXh36/BNr0qP2MhAEN56Y96G8XKkzn+5zYg==
|
||||
testcafe@^1.9.2:
|
||||
version "1.9.2"
|
||||
resolved "https://packages.deskreen.com/testcafe/-/testcafe-1.9.2.tgz#35f3603bdc5241033eda9ad55d600d8c005a2801"
|
||||
integrity sha512-85du0zDvzFWleVqRTTsAr8Lo+3gn4yETs9qFZBIEufk6oN1fLzgv6Q14GeaH3/IaKi+/smv55umTce/OXX0mbA==
|
||||
dependencies:
|
||||
"@types/node" "^10.12.19"
|
||||
async-exit-hook "^1.1.2"
|
||||
@ -13977,6 +14432,7 @@ testcafe@^1.8.8:
|
||||
emittery "^0.4.1"
|
||||
endpoint-utils "^1.0.2"
|
||||
error-stack-parser "^1.3.6"
|
||||
execa "^4.0.3"
|
||||
globby "^9.2.0"
|
||||
graceful-fs "^4.1.11"
|
||||
graphlib "^2.1.5"
|
||||
@ -14012,7 +14468,7 @@ testcafe@^1.8.8:
|
||||
source-map-support "^0.5.16"
|
||||
strip-bom "^2.0.0"
|
||||
testcafe-browser-tools "2.0.13"
|
||||
testcafe-hammerhead "17.1.13"
|
||||
testcafe-hammerhead "17.1.15"
|
||||
testcafe-legacy-api "4.0.0"
|
||||
testcafe-reporter-json "^2.1.0"
|
||||
testcafe-reporter-list "^2.1.0"
|
||||
@ -14079,7 +14535,7 @@ tiny-invariant@^1.0.2:
|
||||
resolved "https://packages.deskreen.com/tiny-invariant/-/tiny-invariant-1.1.0.tgz#634c5f8efdc27714b7f386c35e6760991d230875"
|
||||
integrity sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw==
|
||||
|
||||
tiny-warning@^1.0.0, tiny-warning@^1.0.3:
|
||||
tiny-warning@^1.0.0, tiny-warning@^1.0.2, tiny-warning@^1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://packages.deskreen.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754"
|
||||
integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==
|
||||
|
Loading…
x
Reference in New Issue
Block a user