aboutsummaryrefslogtreecommitdiffstats
path: root/src/features
diff options
context:
space:
mode:
Diffstat (limited to 'src/features')
-rw-r--r--src/features/todos/actions.ts14
-rw-r--r--src/features/todos/components/TodosWebview.tsx (renamed from src/features/todos/components/TodosWebview.js)112
-rw-r--r--src/features/todos/containers/TodosScreen.tsx (renamed from src/features/todos/containers/TodosScreen.js)41
-rw-r--r--src/features/utils/FeatureStore.ts (renamed from src/features/utils/FeatureStore.js)24
-rw-r--r--src/features/workspaces/components/WorkspaceSwitchingIndicator.tsx (renamed from src/features/workspaces/components/WorkspaceSwitchingIndicator.js)46
5 files changed, 130 insertions, 107 deletions
diff --git a/src/features/todos/actions.ts b/src/features/todos/actions.ts
index b47a076b9..31b14d40b 100644
--- a/src/features/todos/actions.ts
+++ b/src/features/todos/actions.ts
@@ -1,17 +1,19 @@
1import { Webview } from 'react-electron-web-view';
1import PropTypes from 'prop-types'; 2import PropTypes from 'prop-types';
2import { ReactElement } from 'react';
3import { createActionsFromDefinitions } from '../../actions/lib/actions'; 3import { createActionsFromDefinitions } from '../../actions/lib/actions';
4 4
5export interface TodoClientMessage {
6 action: string;
7 data: object;
8}
9
5interface TodoActionsType { 10interface TodoActionsType {
6 resize: (width: number) => void; 11 resize: (width: number) => void;
7 toggleTodosPanel: () => void; 12 toggleTodosPanel: () => void;
8 toggleTodosFeatureVisibility: () => void; 13 toggleTodosFeatureVisibility: () => void;
9 setTodosWebview: (webview: ReactElement) => void; 14 setTodosWebview: (webview: Webview) => void;
10 handleHostMessage: (action: string, data: object) => void; 15 handleHostMessage: (action: string, data: object) => void;
11 handleClientMessage: ( 16 handleClientMessage: (channel: string, message: TodoClientMessage) => void;
12 channel: string,
13 message: { action: string; data: object },
14 ) => void;
15 openDevTools: () => void; 17 openDevTools: () => void;
16 reload: () => void; 18 reload: () => void;
17} 19}
diff --git a/src/features/todos/components/TodosWebview.js b/src/features/todos/components/TodosWebview.tsx
index 780864b91..3385ff74c 100644
--- a/src/features/todos/components/TodosWebview.js
+++ b/src/features/todos/components/TodosWebview.tsx
@@ -1,11 +1,10 @@
1import { Component } from 'react'; 1import { Component, createRef, ReactElement, MouseEvent } from 'react';
2import PropTypes from 'prop-types';
3import { observer } from 'mobx-react'; 2import { observer } from 'mobx-react';
4import injectSheet from 'react-jss'; 3import withStyles, { WithStylesProps } from 'react-jss';
5import Webview from 'react-electron-web-view'; 4import Webview from 'react-electron-web-view';
6import classnames from 'classnames'; 5import classnames from 'classnames';
7
8import { TODOS_PARTITION_ID } from '../../../config'; 6import { TODOS_PARTITION_ID } from '../../../config';
7import { TodoClientMessage } from '../actions';
9 8
10const styles = theme => ({ 9const styles = theme => ({
11 root: { 10 root: {
@@ -48,51 +47,71 @@ const styles = theme => ({
48 }, 47 },
49}); 48});
50 49
51class TodosWebview extends Component { 50interface IProps extends WithStylesProps<typeof styles> {
52 static propTypes = { 51 isTodosServiceActive: boolean;
53 classes: PropTypes.object.isRequired, 52 isVisible: boolean;
54 isTodosServiceActive: PropTypes.bool.isRequired, 53 handleClientMessage: (channel: string, message: TodoClientMessage) => void;
55 isVisible: PropTypes.bool.isRequired, 54 setTodosWebview: (webView: Webview) => void;
56 handleClientMessage: PropTypes.func.isRequired, 55 resize: (newWidth: number) => void;
57 setTodosWebview: PropTypes.func.isRequired, 56 width: number;
58 resize: PropTypes.func.isRequired, 57 minWidth: number;
59 width: PropTypes.number.isRequired, 58 userAgent: string;
60 minWidth: PropTypes.number.isRequired, 59 todoUrl: string;
61 userAgent: PropTypes.string.isRequired, 60 isTodoUrlValid: boolean;
62 todoUrl: PropTypes.string.isRequired, 61}
63 isTodoUrlValid: PropTypes.bool.isRequired, 62
64 }; 63interface IState {
65 64 isDragging: boolean;
66 state = { 65 width: number;
67 isDragging: false, 66 initialPos: number;
68 width: 300, 67 delta: number;
69 }; 68}
69
70@observer
71class TodosWebview extends Component<IProps, IState> {
72 private node = createRef<HTMLDivElement>();
73
74 private webview: Webview;
75
76 constructor(props: IProps) {
77 super(props);
78
79 this.state = {
80 isDragging: false,
81 width: 300,
82 initialPos: 0,
83 delta: 0,
84 };
85 this.resizePanel = this.resizePanel.bind(this);
86 this.stopResize = this.stopResize.bind(this);
87 }
70 88
71 componentDidMount() { 89 componentDidMount() {
72 this.setState({ 90 this.setState({
73 width: this.props.width, 91 width: this.props.width,
74 }); 92 });
75 93
76 this.node.addEventListener('mousemove', this.resizePanel.bind(this)); 94 if (this.node.current) {
77 this.node.addEventListener('mouseup', this.stopResize.bind(this)); 95 this.node.current.addEventListener('mousemove', this.resizePanel);
78 this.node.addEventListener('mouseleave', this.stopResize.bind(this)); 96 this.node.current.addEventListener('mouseup', this.stopResize);
97 this.node.current.addEventListener('mouseleave', this.stopResize);
98 }
79 } 99 }
80 100
81 startResize = event => { 101 startResize(e: MouseEvent<HTMLDivElement>): void {
82 this.setState({ 102 this.setState({
83 isDragging: true, 103 isDragging: true,
84 initialPos: event.clientX, 104 initialPos: e.clientX,
85 delta: 0, 105 delta: 0,
86 }); 106 });
87 }; 107 }
88 108
89 resizePanel(e) { 109 resizePanel(e: MouseEventInit): void {
90 const { minWidth } = this.props; 110 const { minWidth } = this.props;
91
92 const { isDragging, initialPos } = this.state; 111 const { isDragging, initialPos } = this.state;
93 112
94 if (isDragging && Math.abs(e.clientX - window.innerWidth) > minWidth) { 113 if (isDragging && Math.abs(e.clientX! - window.innerWidth) > minWidth) {
95 const delta = e.clientX - initialPos; 114 const delta = e.clientX! - initialPos;
96 115
97 this.setState({ 116 this.setState({
98 delta, 117 delta,
@@ -100,9 +119,8 @@ class TodosWebview extends Component {
100 } 119 }
101 } 120 }
102 121
103 stopResize() { 122 stopResize(): void {
104 const { resize, minWidth } = this.props; 123 const { resize, minWidth } = this.props;
105
106 const { isDragging, delta, width } = this.state; 124 const { isDragging, delta, width } = this.state;
107 125
108 if (isDragging) { 126 if (isDragging) {
@@ -123,14 +141,17 @@ class TodosWebview extends Component {
123 } 141 }
124 142
125 startListeningToIpcMessages() { 143 startListeningToIpcMessages() {
144 if (!this.webview) {
145 return;
146 }
147
126 const { handleClientMessage } = this.props; 148 const { handleClientMessage } = this.props;
127 if (!this.webview) return;
128 this.webview.addEventListener('ipc-message', e => { 149 this.webview.addEventListener('ipc-message', e => {
129 handleClientMessage({ channel: e.channel, message: e.args[0] }); 150 handleClientMessage(e.channel, e.args[0]);
130 }); 151 });
131 } 152 }
132 153
133 render() { 154 render(): ReactElement {
134 const { 155 const {
135 classes, 156 classes,
136 isTodosServiceActive, 157 isTodosServiceActive,
@@ -141,10 +162,9 @@ class TodosWebview extends Component {
141 } = this.props; 162 } = this.props;
142 163
143 const { width, delta, isDragging } = this.state; 164 const { width, delta, isDragging } = this.state;
144
145 let displayedWidth = isVisible ? width : 0; 165 let displayedWidth = isVisible ? width : 0;
146 if (isTodosServiceActive) { 166 if (isTodosServiceActive) {
147 displayedWidth = null; 167 displayedWidth = 0;
148 } 168 }
149 169
150 return ( 170 return (
@@ -157,9 +177,7 @@ class TodosWebview extends Component {
157 })} 177 })}
158 style={{ width: displayedWidth }} 178 style={{ width: displayedWidth }}
159 onMouseUp={() => this.stopResize()} 179 onMouseUp={() => this.stopResize()}
160 ref={node => { 180 ref={this.node}
161 this.node = node;
162 }}
163 id="todos-panel" 181 id="todos-panel"
164 > 182 >
165 <div 183 <div
@@ -168,7 +186,7 @@ class TodosWebview extends Component {
168 left: delta, 186 left: delta,
169 ...(isDragging ? { width: 600, marginLeft: -200 } : {}), 187 ...(isDragging ? { width: 600, marginLeft: -200 } : {}),
170 }} // This hack is required as resizing with webviews beneath behaves quite bad 188 }} // This hack is required as resizing with webviews beneath behaves quite bad
171 onMouseDown={e => this.startResize(e)} 189 onMouseDown={this.startResize}
172 /> 190 />
173 {isDragging && ( 191 {isDragging && (
174 <div 192 <div
@@ -178,7 +196,7 @@ class TodosWebview extends Component {
178 )} 196 )}
179 {isTodoUrlValid && ( 197 {isTodoUrlValid && (
180 <Webview 198 <Webview
181 className={classes.webview} 199 // className={classes.webview} // TODO - [TS DEBT] style not found
182 onDidAttach={() => { 200 onDidAttach={() => {
183 const { setTodosWebview } = this.props; 201 const { setTodosWebview } = this.props;
184 setTodosWebview(this.webview); 202 setTodosWebview(this.webview);
@@ -198,6 +216,4 @@ class TodosWebview extends Component {
198 } 216 }
199} 217}
200 218
201export default injectSheet(styles, { injectTheme: true })( 219export default withStyles(styles, { injectTheme: true })(TodosWebview);
202 observer(TodosWebview),
203);
diff --git a/src/features/todos/containers/TodosScreen.js b/src/features/todos/containers/TodosScreen.tsx
index b97506767..17f61bd95 100644
--- a/src/features/todos/containers/TodosScreen.js
+++ b/src/features/todos/containers/TodosScreen.tsx
@@ -1,22 +1,26 @@
1import { Component } from 'react'; 1import { Component, ReactElement } from 'react';
2import { observer, inject } from 'mobx-react'; 2import { observer, inject } from 'mobx-react';
3import PropTypes from 'prop-types';
4
5import FeaturesStore from '../../../stores/FeaturesStore';
6import TodosWebview from '../components/TodosWebview'; 3import TodosWebview from '../components/TodosWebview';
7import ErrorBoundary from '../../../components/util/ErrorBoundary'; 4import ErrorBoundary from '../../../components/util/ErrorBoundary';
8import { todosStore } from '..'; 5import { todosStore } from '..';
9import { TODOS_MIN_WIDTH } from '../../../config'; 6import { TODOS_MIN_WIDTH } from '../../../config';
10import { todoActions } from '../actions'; 7import { todoActions } from '../actions';
11import ServicesStore from '../../../stores/ServicesStore'; 8import { RealStores } from '../../../stores';
9
10interface IProps {
11 stores?: RealStores;
12}
12 13
13class TodosScreen extends Component { 14@inject('stores', 'actions')
14 render() { 15@observer
15 if ( 16class TodosScreen extends Component<IProps> {
17 render(): ReactElement | null {
18 const showTodoScreen =
16 !todosStore || 19 !todosStore ||
17 !todosStore.isFeatureActive || 20 !todosStore.isFeatureActive ||
18 todosStore.isTodosPanelForceHidden 21 todosStore.isTodosPanelForceHidden;
19 ) { 22
23 if (showTodoScreen) {
20 return null; 24 return null;
21 } 25 }
22 26
@@ -24,15 +28,15 @@ class TodosScreen extends Component {
24 <ErrorBoundary> 28 <ErrorBoundary>
25 <TodosWebview 29 <TodosWebview
26 isTodosServiceActive={ 30 isTodosServiceActive={
27 this.props.stores.services.isTodosServiceActive || false 31 this.props.stores!.services.isTodosServiceActive || false
28 } 32 }
29 isVisible={todosStore.isTodosPanelVisible} 33 isVisible={todosStore.isTodosPanelVisible}
30 togglePanel={todoActions.toggleTodosPanel} 34 // togglePanel={todoActions.toggleTodosPanel} // TODO - [TECH DEBT][PROP NOT USED IN COMPONENT] check it later
31 handleClientMessage={todoActions.handleClientMessage} 35 handleClientMessage={todoActions.handleClientMessage}
32 setTodosWebview={webview => todoActions.setTodosWebview({ webview })} 36 setTodosWebview={webview => todoActions.setTodosWebview(webview)}
33 width={todosStore.width} 37 width={todosStore.width}
34 minWidth={TODOS_MIN_WIDTH} 38 minWidth={TODOS_MIN_WIDTH}
35 resize={width => todoActions.resize({ width })} 39 resize={width => todoActions.resize(width)}
36 userAgent={todosStore.userAgent} 40 userAgent={todosStore.userAgent}
37 todoUrl={todosStore.todoUrl} 41 todoUrl={todosStore.todoUrl}
38 isTodoUrlValid={todosStore.isTodoUrlValid} 42 isTodoUrlValid={todosStore.isTodoUrlValid}
@@ -42,11 +46,4 @@ class TodosScreen extends Component {
42 } 46 }
43} 47}
44 48
45export default inject('stores', 'actions')(observer(TodosScreen)); 49export default TodosScreen;
46
47TodosScreen.propTypes = {
48 stores: PropTypes.shape({
49 features: PropTypes.instanceOf(FeaturesStore).isRequired,
50 services: PropTypes.instanceOf(ServicesStore).isRequired,
51 }).isRequired,
52};
diff --git a/src/features/utils/FeatureStore.js b/src/features/utils/FeatureStore.ts
index eada332d7..2bdd167f3 100644
--- a/src/features/utils/FeatureStore.js
+++ b/src/features/utils/FeatureStore.ts
@@ -1,7 +1,9 @@
1import Reaction from '../../stores/lib/Reaction';
2
1export default class FeatureStore { 3export default class FeatureStore {
2 _actions = []; 4 _actions: any = [];
3 5
4 _reactions = []; 6 _reactions: Reaction[] = [];
5 7
6 stop() { 8 stop() {
7 this._stopActions(); 9 this._stopActions();
@@ -9,32 +11,38 @@ export default class FeatureStore {
9 } 11 }
10 12
11 // ACTIONS 13 // ACTIONS
12
13 _registerActions(actions) { 14 _registerActions(actions) {
14 this._actions = actions; 15 this._actions = actions;
15 this._startActions(); 16 this._startActions();
16 } 17 }
17 18
18 _startActions(actions = this._actions) { 19 _startActions(actions = this._actions) {
19 for (const a of actions) a.start(); 20 for (const action of actions) {
21 action.start();
22 }
20 } 23 }
21 24
22 _stopActions(actions = this._actions) { 25 _stopActions(actions = this._actions) {
23 for (const a of actions) a.stop(); 26 for (const action of actions) {
27 action.stop();
28 }
24 } 29 }
25 30
26 // REACTIONS 31 // REACTIONS
27
28 _registerReactions(reactions) { 32 _registerReactions(reactions) {
29 this._reactions = reactions; 33 this._reactions = reactions;
30 this._startReactions(); 34 this._startReactions();
31 } 35 }
32 36
33 _startReactions(reactions = this._reactions) { 37 _startReactions(reactions = this._reactions) {
34 for (const r of reactions) r.start(); 38 for (const reaction of reactions) {
39 reaction.start();
40 }
35 } 41 }
36 42
37 _stopReactions(reactions = this._reactions) { 43 _stopReactions(reactions = this._reactions) {
38 for (const r of reactions) r.stop(); 44 for (const reaction of reactions) {
45 reaction.stop();
46 }
39 } 47 }
40} 48}
diff --git a/src/features/workspaces/components/WorkspaceSwitchingIndicator.js b/src/features/workspaces/components/WorkspaceSwitchingIndicator.tsx
index ff73758c1..c9af22c96 100644
--- a/src/features/workspaces/components/WorkspaceSwitchingIndicator.js
+++ b/src/features/workspaces/components/WorkspaceSwitchingIndicator.tsx
@@ -1,12 +1,11 @@
1import { Component } from 'react'; 1import { Component, ReactElement } from 'react';
2import PropTypes from 'prop-types';
3import { observer } from 'mobx-react'; 2import { observer } from 'mobx-react';
4import injectSheet from 'react-jss'; 3import withStyles, { WithStylesProps } from 'react-jss';
5import classnames from 'classnames'; 4import classnames from 'classnames';
6import { defineMessages, injectIntl } from 'react-intl'; 5import { defineMessages, injectIntl, WrappedComponentProps } from 'react-intl';
7
8import Loader from '../../../components/ui/loader/index'; 6import Loader from '../../../components/ui/loader/index';
9import { workspaceStore } from '../index'; 7import { workspaceStore } from '../index';
8import { Theme } from '../../../themes';
10 9
11const messages = defineMessages({ 10const messages = defineMessages({
12 switchingTo: { 11 switchingTo: {
@@ -15,11 +14,10 @@ const messages = defineMessages({
15 }, 14 },
16}); 15});
17 16
18let wrapperTransition = 'none'; 17const wrapperTransition =
19 18 window && window.matchMedia('(prefers-reduced-motion: no-preference)')
20if (window && window.matchMedia('(prefers-reduced-motion: no-preference)')) { 19 ? 'width 0.5s ease'
21 wrapperTransition = 'width 0.5s ease'; 20 : 'none';
22}
23 21
24const styles = theme => ({ 22const styles = theme => ({
25 wrapper: { 23 wrapper: {
@@ -53,26 +51,30 @@ const styles = theme => ({
53 }, 51 },
54}); 52});
55 53
56class WorkspaceSwitchingIndicator extends Component { 54interface IProps extends WithStylesProps<typeof styles>, WrappedComponentProps {
57 static propTypes = { 55 theme?: Theme;
58 classes: PropTypes.object.isRequired, 56}
59 theme: PropTypes.object.isRequired,
60 };
61 57
62 render() { 58@observer
63 const { classes, theme } = this.props; 59class WorkspaceSwitchingIndicator extends Component<IProps> {
64 const { intl } = this.props; 60 render(): ReactElement | null {
61 const { classes, intl, theme } = this.props;
65 const { isSwitchingWorkspace, nextWorkspace } = workspaceStore; 62 const { isSwitchingWorkspace, nextWorkspace } = workspaceStore;
66 if (!isSwitchingWorkspace) return null; 63
64 if (!isSwitchingWorkspace) {
65 return null;
66 }
67
67 const nextWorkspaceName = nextWorkspace 68 const nextWorkspaceName = nextWorkspace
68 ? nextWorkspace.name 69 ? nextWorkspace.name
69 : 'All services'; 70 : 'All services';
71
70 return ( 72 return (
71 <div className={classnames([classes.wrapper])}> 73 <div className={classnames([classes.wrapper])}>
72 <div className={classes.component}> 74 <div className={classes.component}>
73 <Loader 75 <Loader
74 className={classes.spinner} 76 className={classes.spinner}
75 color={theme.workspaces.switchingIndicator.spinnerColor} 77 color={theme?.workspaces.switchingIndicator.spinnerColor}
76 /> 78 />
77 <p className={classes.message}> 79 <p className={classes.message}>
78 {`${intl.formatMessage(messages.switchingTo)} ${nextWorkspaceName}`} 80 {`${intl.formatMessage(messages.switchingTo)} ${nextWorkspaceName}`}
@@ -84,7 +86,5 @@ class WorkspaceSwitchingIndicator extends Component {
84} 86}
85 87
86export default injectIntl( 88export default injectIntl(
87 injectSheet(styles, { injectTheme: true })( 89 withStyles(styles, { injectTheme: true })(WorkspaceSwitchingIndicator),
88 observer(WorkspaceSwitchingIndicator),
89 ),
90); 90);