cncjs

Форк
0
/
PrimaryWidgets.jsx 
255 строк · 7.7 Кб
1
import chainedFunction from 'chained-function';
2
import classNames from 'classnames';
3
import ensureArray from 'ensure-array';
4
import get from 'lodash/get';
5
import includes from 'lodash/includes';
6
import isEqual from 'lodash/isEqual';
7
import pubsub from 'pubsub-js';
8
import PropTypes from 'prop-types';
9
import React, { Component } from 'react';
10
import Sortable from 'react-sortablejs';
11
import uuid from 'uuid';
12
import { GRBL, MARLIN, SMOOTHIE, TINYG } from 'app/constants';
13
import { Button } from 'app/components/Buttons';
14
import Modal from 'app/components/Modal';
15
import controller from 'app/lib/controller';
16
import i18n from 'app/lib/i18n';
17
import log from 'app/lib/log';
18
import portal from 'app/lib/portal';
19
import store from 'app/store';
20
import Widget from './Widget';
21
import styles from './widgets.styl';
22

23
class PrimaryWidgets extends Component {
24
    static propTypes = {
25
      onForkWidget: PropTypes.func.isRequired,
26
      onRemoveWidget: PropTypes.func.isRequired,
27
      onDragStart: PropTypes.func.isRequired,
28
      onDragEnd: PropTypes.func.isRequired
29
    };
30

31
    state = {
32
      widgets: store.get('workspace.container.primary.widgets')
33
    };
34

35
    forkWidget = (widgetId) => () => {
36
      portal(({ onClose }) => (
37
        <Modal size="xs" onClose={onClose}>
38
          <Modal.Header>
39
            <Modal.Title>
40
              {i18n._('Fork Widget')}
41
            </Modal.Title>
42
          </Modal.Header>
43
          <Modal.Body>
44
            {i18n._('Are you sure you want to fork this widget?')}
45
          </Modal.Body>
46
          <Modal.Footer>
47
            <Button
48
              onClick={onClose}
49
            >
50
              {i18n._('Cancel')}
51
            </Button>
52
            <Button
53
              btnStyle="primary"
54
              onClick={chainedFunction(
55
                () => {
56
                  const name = widgetId.split(':')[0];
57
                  if (!name) {
58
                    log.error(`Failed to fork widget: widgetId=${widgetId}`);
59
                    return;
60
                  }
61

62
                  // Use the same widget settings in a new widget
63
                  const forkedWidgetId = `${name}:${uuid.v4()}`;
64
                  const defaultSettings = store.get(`widgets["${name}"]`);
65
                  const clonedSettings = store.get(`widgets["${widgetId}"]`, defaultSettings);
66
                  store.set(`widgets["${forkedWidgetId}"]`, clonedSettings);
67

68
                  const widgets = [...this.state.widgets, forkedWidgetId];
69
                  this.setState({ widgets: widgets });
70

71
                  this.props.onForkWidget(widgetId);
72
                },
73
                onClose
74
              )}
75
            >
76
              {i18n._('OK')}
77
            </Button>
78
          </Modal.Footer>
79
        </Modal>
80
      ));
81
    };
82

83
    removeWidget = (widgetId) => () => {
84
      portal(({ onClose }) => (
85
        <Modal size="xs" onClose={onClose}>
86
          <Modal.Header>
87
            <Modal.Title>
88
              {i18n._('Remove Widget')}
89
            </Modal.Title>
90
          </Modal.Header>
91
          <Modal.Body>
92
            {i18n._('Are you sure you want to remove this widget?')}
93
          </Modal.Body>
94
          <Modal.Footer>
95
            <Button
96
              onClick={onClose}
97
            >
98
              {i18n._('Cancel')}
99
            </Button>
100
            <Button
101
              btnStyle="primary"
102
              onClick={chainedFunction(
103
                () => {
104
                  const widgets = this.state.widgets.filter(n => n !== widgetId);
105
                  this.setState({ widgets: widgets });
106

107
                  if (widgetId.match(/\w+:[\w\-]+/)) {
108
                    // Remove forked widget settings
109
                    store.unset(`widgets["${widgetId}"]`);
110
                  }
111

112
                  this.props.onRemoveWidget(widgetId);
113
                },
114
                onClose
115
              )}
116
            >
117
              {i18n._('OK')}
118
            </Button>
119
          </Modal.Footer>
120
        </Modal>
121
      ));
122
    };
123

124
    pubsubTokens = [];
125

126
    widgetMap = {};
127

128
    componentDidMount() {
129
      this.subscribe();
130
    }
131

132
    componentWillUnmount() {
133
      this.unsubscribe();
134
    }
135

136
    shouldComponentUpdate(nextProps, nextState) {
137
      // Do not compare props for performance considerations
138
      return !isEqual(nextState, this.state);
139
    }
140

141
    componentDidUpdate() {
142
      const { widgets } = this.state;
143

144
      // Calling store.set() will merge two different arrays into one.
145
      // Remove the property first to avoid duplication.
146
      store.replace('workspace.container.primary.widgets', widgets);
147
    }
148

149
    subscribe() {
150
      { // updatePrimaryWidgets
151
        const token = pubsub.subscribe('updatePrimaryWidgets', (msg, widgets) => {
152
          this.setState({ widgets: widgets });
153
        });
154
        this.pubsubTokens.push(token);
155
      }
156
    }
157

158
    unsubscribe() {
159
      this.pubsubTokens.forEach((token) => {
160
        pubsub.unsubscribe(token);
161
      });
162
      this.pubsubTokens = [];
163
    }
164

165
    expandAll() {
166
      const len = this.state.widgets.length;
167
      for (let i = 0; i < len; ++i) {
168
        const widget = this.widgetMap[this.state.widgets[i]];
169
        const expand = get(widget, 'expand');
170
        if (typeof expand === 'function') {
171
          expand();
172
        }
173
      }
174
    }
175

176
    collapseAll() {
177
      const len = this.state.widgets.length;
178
      for (let i = 0; i < len; ++i) {
179
        const widget = this.widgetMap[this.state.widgets[i]];
180
        const collapse = get(widget, 'collapse');
181
        if (typeof collapse === 'function') {
182
          collapse();
183
        }
184
      }
185
    }
186

187
    render() {
188
      const { className } = this.props;
189
      const widgets = this.state.widgets
190
        .filter(widgetId => {
191
          // e.g. "webcam" or "webcam:d8e6352f-80a9-475f-a4f5-3e9197a48a23"
192
          const name = widgetId.split(':')[0];
193
          if (name === 'grbl' && !includes(controller.loadedControllers, GRBL)) {
194
            return false;
195
          }
196
          if (name === 'marlin' && !includes(controller.loadedControllers, MARLIN)) {
197
            return false;
198
          }
199
          if (name === 'smoothie' && !includes(controller.loadedControllers, SMOOTHIE)) {
200
            return false;
201
          }
202
          if (name === 'tinyg' && !includes(controller.loadedControllers, TINYG)) {
203
            return false;
204
          }
205
          return true;
206
        })
207
        .map(widgetId => (
208
          <div data-widget-id={widgetId} key={widgetId}>
209
            <Widget
210
              ref={node => {
211
                if (node && node.widget) {
212
                  this.widgetMap[widgetId] = node.widget;
213
                }
214
              }}
215
              widgetId={widgetId}
216
              onFork={this.forkWidget(widgetId)}
217
              onRemove={this.removeWidget(widgetId)}
218
              sortable={{
219
                handleClassName: 'sortable-handle',
220
                filterClassName: 'sortable-filter'
221
              }}
222
            />
223
          </div>
224
        ));
225

226
      return (
227
        <Sortable
228
          className={classNames(className, styles.widgets)}
229
          options={{
230
            animation: 150,
231
            delay: 0, // Touch and hold delay
232
            group: {
233
              name: 'primary',
234
              pull: true,
235
              put: ['secondary']
236
            },
237
            handle: '.sortable-handle', // Drag handle selector within list items
238
            filter: '.sortable-filter', // Selectors that do not lead to dragging
239
            chosenClass: 'sortable-chosen', // Class name for the chosen item
240
            ghostClass: 'sortable-ghost', // Class name for the drop placeholder
241
            dataIdAttr: 'data-widget-id',
242
            onStart: this.props.onDragStart,
243
            onEnd: this.props.onDragEnd
244
          }}
245
          onChange={(order) => {
246
            this.setState({ widgets: ensureArray(order) });
247
          }}
248
        >
249
          {widgets}
250
        </Sortable>
251
      );
252
    }
253
}
254

255
export default PrimaryWidgets;
256

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.