@iobroker/dm-gui-components 0.0.2 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/DeviceCard.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import React from 'react';
1
+ import React, { Component } from 'react';
2
2
  import { Connection } from '@iobroker/adapter-react-v5';
3
- import { DeviceInfo } from '@iobroker/dm-utils';
3
+ import { DeviceDetails, DeviceInfo } from '@iobroker/dm-utils';
4
4
  import { ActionBase, ControlBase, ControlState } from '@iobroker/dm-utils/build/types/base';
5
5
  interface DeviceCardProps {
6
6
  title?: string;
@@ -12,9 +12,41 @@ interface DeviceCardProps {
12
12
  deviceHandler: (deviceId: string, action: ActionBase<'api'>, refresh: () => void) => () => void;
13
13
  controlHandler: (deviceId: string, control: ControlBase, state: ControlState) => () => Promise<ioBroker.State | null>;
14
14
  controlStateHandler: (deviceId: string, control: ControlBase) => () => Promise<ioBroker.State | null>;
15
+ smallCards?: boolean;
16
+ }
17
+ interface DeviceCardState {
18
+ open: boolean;
19
+ details: DeviceDetails | null;
20
+ data: Record<string, any>;
21
+ icon: string | undefined;
22
+ showControlDialog: boolean;
15
23
  }
16
24
  /**
17
25
  * Device Card Component
18
26
  */
19
- export default function DeviceCard(params: DeviceCardProps): React.JSX.Element;
20
- export {};
27
+ declare class DeviceCard extends Component<DeviceCardProps, DeviceCardState> {
28
+ constructor(props: DeviceCardProps);
29
+ fetchIcon(): Promise<void>;
30
+ componentDidMount(): void;
31
+ /**
32
+ * Load the device details
33
+ */
34
+ loadDetails(): Promise<void>;
35
+ /**
36
+ * Refresh the device details
37
+ */
38
+ refresh: () => void;
39
+ /**
40
+ * Copy the device ID to the clipboard
41
+ * @returns {void}
42
+ */
43
+ copyToClipboard: () => Promise<void>;
44
+ renderDialog(): React.JSX.Element;
45
+ renderControlDialog(): React.JSX.Element;
46
+ renderControls(): React.JSX.Element;
47
+ renderActions(): React.JSX.Element[];
48
+ renderSmall(): React.JSX.Element;
49
+ renderBig(): React.JSX.Element;
50
+ render(): React.JSX.Element;
51
+ }
52
+ export default DeviceCard;
package/DeviceCard.js CHANGED
@@ -47,162 +47,291 @@ function getText(text) {
47
47
  /**
48
48
  * Device Card Component
49
49
  */
50
- function DeviceCard(params) {
51
- var _a, _b, _c, _d;
52
- const { title, device, instanceId, socket, deviceHandler, uploadImagesToInstance, controlHandler, controlStateHandler, } = params;
53
- const [open, setOpen] = (0, react_1.useState)(false);
54
- const [details, setDetails] = (0, react_1.useState)(null);
55
- const [data, setData] = (0, react_1.useState)({});
56
- const [icon, setIcon] = (0, react_1.useState)(device.icon);
57
- const [showControlDialog, setShowControlDialog] = (0, react_1.useState)(false);
58
- // const [uploadedImage, setUploadedImage] = useState(null);
59
- const hasDetails = device.hasDetails;
60
- const status = !device.status ? [] : Array.isArray(device.status) ? device.status : [device.status];
61
- const colors = { primary: '#111', secondary: '#888' };
62
- (0, react_1.useEffect)(() => {
63
- async function fetchIcon() {
64
- if (!device.icon) {
65
- // try to load the icon from file storage
66
- const fileName = `${device.manufacturer ? `${device.manufacturer}_` : ''}${device.model ? device.model : device.id}`;
67
- try {
68
- const file = await socket.readFile(instanceId.replace('system.adapter.', ''), `${fileName}.webp`, true);
69
- setIcon(`data:image/${file.mimeType},${file}`);
70
- // const response = await fetch(url);
71
- // if (response.ok) {
72
- // const blob = await response.blob();
73
- // const reader = new FileReader();
74
- // reader.onloadend = () => {
75
- // setIcon(reader.result);
76
- // };
77
- // reader.readAsDataURL(blob);
78
- // } else {
79
- // throw new Error('Response not ok');
80
- // }
81
- }
82
- catch (error) {
83
- setIcon('');
84
- }
50
+ class DeviceCard extends react_1.Component {
51
+ constructor(props) {
52
+ super(props);
53
+ /**
54
+ * Refresh the device details
55
+ */
56
+ this.refresh = () => {
57
+ this.setState({ details: null });
58
+ this.loadDetails().catch(console.error);
59
+ };
60
+ /**
61
+ * Copy the device ID to the clipboard
62
+ * @returns {void}
63
+ */
64
+ this.copyToClipboard = async () => {
65
+ const textToCopy = this.props.device.id;
66
+ adapter_react_v5_1.Utils.copyToClipboard(textToCopy);
67
+ alert(`${(0, Utils_1.getTranslation)('copied')} ${textToCopy} ${(0, Utils_1.getTranslation)('toClipboard')}!`);
68
+ };
69
+ this.state = {
70
+ open: false,
71
+ details: null,
72
+ data: {},
73
+ icon: props.device.icon,
74
+ showControlDialog: false,
75
+ };
76
+ }
77
+ async fetchIcon() {
78
+ if (!this.props.device.icon) {
79
+ // try to load the icon from file storage
80
+ const fileName = `${this.props.device.manufacturer ? `${this.props.device.manufacturer}_` : ''}${this.props.device.model ? this.props.device.model : this.props.device.id}`;
81
+ try {
82
+ const file = await this.props.socket.readFile(this.props.instanceId.replace('system.adapter.', ''), `${fileName}.webp`, true);
83
+ this.setState({ icon: `data:image/${file.mimeType},${file}` });
84
+ // const response = await fetch(url);
85
+ // if (response.ok) {
86
+ // const blob = await response.blob();
87
+ // const reader = new FileReader();
88
+ // reader.onloadend = () => {
89
+ // setIcon(reader.result);
90
+ // };
91
+ // reader.readAsDataURL(blob);
92
+ // } else {
93
+ // throw new Error('Response not ok');
94
+ // }
95
+ }
96
+ catch (error) {
97
+ this.state.icon && this.setState({ icon: '' });
85
98
  }
86
99
  }
87
- fetchIcon()
100
+ }
101
+ componentDidMount() {
102
+ this.fetchIcon()
88
103
  .catch(e => console.error(e));
89
- }, [device, instanceId]);
104
+ }
90
105
  /**
91
106
  * Load the device details
92
107
  */
93
- const loadDetails = async () => {
94
- console.log(`Loading device details for ${device.id}... from ${instanceId}`);
95
- const result = await socket.sendTo(instanceId, 'dm:deviceDetails', device.id);
96
- console.log(`Got device details for ${device.id}:`, result);
97
- setDetails(result);
98
- };
99
- /**
100
- * Refresh the device details
101
- */
102
- const refresh = () => {
103
- setDetails(null);
104
- loadDetails().catch(console.error);
105
- };
106
- /**
107
- * Open the modal
108
- */
109
- const openModal = () => {
110
- if (!open) {
111
- loadDetails().catch(console.error);
112
- setOpen(true);
108
+ async loadDetails() {
109
+ console.log(`Loading device details for ${this.props.device.id}... from ${this.props.instanceId}`);
110
+ const details = await this.props.socket.sendTo(this.props.instanceId, 'dm:deviceDetails', this.props.device.id);
111
+ console.log(`Got device details for ${this.props.device.id}:`, details);
112
+ this.setState({ details, data: (details === null || details === void 0 ? void 0 : details.data) || {} });
113
+ }
114
+ ;
115
+ renderDialog() {
116
+ if (!this.state.open || !this.state.details) {
117
+ return null;
113
118
  }
114
- };
115
- /**
116
- * Close the modal
117
- */
118
- const handleClose = () => setOpen(false);
119
- const handleImageClick = async (imageData) => imageData && setIcon(imageData);
120
- /**
121
- * Copy the device ID to the clipboard
122
- * @returns {void}
123
- */
124
- const copyToClipboard = async () => {
125
- const textToCopy = device.id;
126
- adapter_react_v5_1.Utils.copyToClipboard(textToCopy);
127
- alert(`${(0, Utils_1.getTranslation)('copied')} ${textToCopy} ${(0, Utils_1.getTranslation)('toClipboard')}!`);
128
- };
129
- react_1.default.useEffect(() => setData((details === null || details === void 0 ? void 0 : details.data) || {}), [details]);
130
- const renderedDialog = open && details ? react_1.default.createElement(material_1.Dialog, { open: !0, maxWidth: "md", onClose: handleClose },
131
- react_1.default.createElement(material_1.DialogContent, null,
132
- react_1.default.createElement(JsonConfig_1.default, { instanceId: instanceId, socket: socket, schema: details.schema, data: data, onChange: setData })),
133
- react_1.default.createElement(material_1.DialogActions, null,
134
- react_1.default.createElement(material_1.Button, { variant: "contained", color: "primary", onClick: handleClose, autoFocus: true }, (0, Utils_1.getTranslation)('closeButtonText')))) : null;
135
- let renderedControls;
136
- let controlDialog;
137
- const firstControl = (_a = device.controls) === null || _a === void 0 ? void 0 : _a[0];
138
- if (((_b = device.controls) === null || _b === void 0 ? void 0 : _b.length) === 1 && firstControl && ((firstControl.type === 'icon' || firstControl.type === 'switch') && !firstControl.label)) {
139
- // control can be placed in button icon
140
- renderedControls = react_1.default.createElement(DeviceControl_1.default, { control: firstControl, colors: colors, socket: socket, deviceId: device.id, controlHandler: controlHandler, controlStateHandler: controlStateHandler });
119
+ return react_1.default.createElement(material_1.Dialog, { open: !0, maxWidth: "md", onClose: () => this.setState({ open: false }) },
120
+ react_1.default.createElement(material_1.DialogContent, null,
121
+ react_1.default.createElement(JsonConfig_1.default, { instanceId: this.props.instanceId, socket: this.props.socket, schema: this.state.details.schema, data: this.state.data, onChange: (data) => this.setState({ data }) })),
122
+ react_1.default.createElement(material_1.DialogActions, null,
123
+ react_1.default.createElement(material_1.Button, { variant: "contained", color: "primary", onClick: () => this.setState({ open: false }), autoFocus: true }, (0, Utils_1.getTranslation)('closeButtonText'))));
141
124
  }
142
- else if ((_c = device.controls) === null || _c === void 0 ? void 0 : _c.length) {
143
- // place button and show controls dialog
144
- renderedControls = react_1.default.createElement(material_1.Fab, { size: "small", onClick: () => setShowControlDialog(true) },
145
- react_1.default.createElement(icons_material_1.VideogameAsset, null));
146
- if (showControlDialog) {
147
- controlDialog = react_1.default.createElement(material_1.Dialog, { open: !0, onClose: () => setShowControlDialog(false) },
148
- react_1.default.createElement(material_1.DialogTitle, null,
149
- title,
150
- react_1.default.createElement(material_1.IconButton, { style: {
151
- position: 'absolute',
152
- top: 5,
153
- right: 5,
154
- zIndex: 10,
155
- }, onClick: () => setShowControlDialog(false) },
156
- react_1.default.createElement(icons_material_1.Close, null))),
157
- react_1.default.createElement(material_1.DialogContent, null, device.controls.map(control => react_1.default.createElement(DeviceControl_1.default, { key: control.id, control: control, socket: socket, colors: colors, deviceId: device.id, controlHandler: controlHandler, controlStateHandler: controlStateHandler }))));
125
+ renderControlDialog() {
126
+ var _a;
127
+ if (!this.state.showControlDialog) {
128
+ return null;
129
+ }
130
+ const colors = { primary: '#111', secondary: '#888' };
131
+ return react_1.default.createElement(material_1.Dialog, { open: !0, onClose: () => this.setState({ showControlDialog: false }) },
132
+ react_1.default.createElement(material_1.DialogTitle, null,
133
+ this.props.title,
134
+ react_1.default.createElement(material_1.IconButton, { style: {
135
+ position: 'absolute',
136
+ top: 5,
137
+ right: 5,
138
+ zIndex: 10,
139
+ }, onClick: () => this.setState({ showControlDialog: false }) },
140
+ react_1.default.createElement(icons_material_1.Close, null))),
141
+ react_1.default.createElement(material_1.DialogContent, null, (_a = this.props.device.controls) === null || _a === void 0 ? void 0 : _a.map(control => react_1.default.createElement(DeviceControl_1.default, { key: control.id, control: control, socket: this.props.socket, colors: colors, deviceId: this.props.device.id, controlHandler: this.props.controlHandler, controlStateHandler: this.props.controlStateHandler }))));
142
+ }
143
+ renderControls() {
144
+ var _a, _b, _c;
145
+ const colors = { primary: '#111', secondary: '#888' };
146
+ const firstControl = (_a = this.props.device.controls) === null || _a === void 0 ? void 0 : _a[0];
147
+ if (((_b = this.props.device.controls) === null || _b === void 0 ? void 0 : _b.length) === 1 && firstControl && ((firstControl.type === 'icon' || firstControl.type === 'switch') && !firstControl.label)) {
148
+ // control can be placed in button icon
149
+ return react_1.default.createElement(DeviceControl_1.default, { control: firstControl, colors: colors, socket: this.props.socket, deviceId: this.props.device.id, controlHandler: this.props.controlHandler, controlStateHandler: this.props.controlStateHandler });
150
+ }
151
+ if ((_c = this.props.device.controls) === null || _c === void 0 ? void 0 : _c.length) {
152
+ // place button and show controls dialog
153
+ return react_1.default.createElement(material_1.Fab, { size: "small", onClick: () => this.setState({ showControlDialog: true }) },
154
+ react_1.default.createElement(icons_material_1.VideogameAsset, null));
158
155
  }
156
+ return null;
159
157
  }
160
- const renderedActions = ((_d = device.actions) === null || _d === void 0 ? void 0 : _d.length) ? device.actions.map(a => react_1.default.createElement(DeviceActionButton_1.default, { key: a.id, deviceId: device.id, action: a, deviceHandler: deviceHandler, refresh: refresh })) : null;
161
- return react_1.default.createElement(material_1.Card, { sx: {
162
- maxWidth: 345,
163
- minWidth: 200,
164
- } },
165
- react_1.default.createElement(material_1.CardHeader, { sx: theme => ({
166
- backgroundColor: device.color || theme.palette.secondary.main,
167
- color: device.color ? adapter_react_v5_1.Utils.invertColor(device.color, true) : theme.palette.secondary.contrastText,
168
- }), avatar: react_1.default.createElement("div", null,
169
- uploadImagesToInstance ? react_1.default.createElement(DeviceImageUpload_1.default, { uploadImagesToInstance: uploadImagesToInstance, deviceId: device.id, manufacturer: getText(device.manufacturer), model: getText(device.model), onImageSelect: handleImageClick, socket: socket }) : null,
170
- icon ? react_1.default.createElement(adapter_react_v5_1.Icon, { src: icon }) : react_1.default.createElement(NoImageIcon, null)), action: hasDetails ? react_1.default.createElement(material_1.IconButton, { "aria-label": "settings", onClick: openModal },
171
- react_1.default.createElement(icons_material_1.MoreVert, null)) : null, title: title, subheader: device.manufacturer ? react_1.default.createElement("span", null,
172
- react_1.default.createElement("b", { style: { marginRight: 4 } },
173
- (0, Utils_1.getTranslation)('manufacturer'),
174
- ":"),
175
- getText(device.manufacturer)) : null }),
176
- react_1.default.createElement(material_1.CardContent, { style: { position: 'relative' } },
177
- (status === null || status === void 0 ? void 0 : status.length) ? react_1.default.createElement("div", { style: {
178
- display: 'flex',
179
- position: 'absolute',
180
- top: -11,
181
- background: '#88888880',
182
- padding: '0 8px',
183
- borderRadius: 5,
184
- width: 'calc(100% - 46px)',
185
- } }, status.map((s, i) => react_1.default.createElement(DeviceStatus_1.default, { key: i, status: s }))) : null,
186
- react_1.default.createElement("div", null,
187
- react_1.default.createElement(material_1.Typography, { variant: "body1" },
188
- react_1.default.createElement("div", { onClick: copyToClipboard },
158
+ renderActions() {
159
+ var _a;
160
+ return ((_a = this.props.device.actions) === null || _a === void 0 ? void 0 : _a.length) ? this.props.device.actions.map(a => react_1.default.createElement(DeviceActionButton_1.default, { key: a.id, deviceId: this.props.device.id, action: a, deviceHandler: this.props.deviceHandler, refresh: this.refresh })) : null;
161
+ }
162
+ renderSmall() {
163
+ const hasDetails = this.props.device.hasDetails;
164
+ const status = !this.props.device.status ? [] : Array.isArray(this.props.device.status) ? this.props.device.status : [this.props.device.status];
165
+ return react_1.default.createElement(material_1.Card, { sx: {
166
+ maxWidth: 345,
167
+ minWidth: 200,
168
+ } },
169
+ react_1.default.createElement(material_1.CardHeader, { sx: theme => ({
170
+ backgroundColor: this.props.device.color || theme.palette.secondary.main,
171
+ color: this.props.device.color ? adapter_react_v5_1.Utils.invertColor(this.props.device.color, true) : theme.palette.secondary.contrastText,
172
+ maxWidth: 345,
173
+ }), avatar: react_1.default.createElement("div", null,
174
+ this.props.uploadImagesToInstance ? react_1.default.createElement(DeviceImageUpload_1.default, { uploadImagesToInstance: this.props.uploadImagesToInstance, deviceId: this.props.device.id, manufacturer: getText(this.props.device.manufacturer), model: getText(this.props.device.model), onImageSelect: async (imageData) => imageData && this.setState({ icon: imageData }), socket: this.props.socket }) : null,
175
+ this.state.icon ? react_1.default.createElement(adapter_react_v5_1.Icon, { src: this.state.icon }) : react_1.default.createElement(NoImageIcon, null)), action: hasDetails ? react_1.default.createElement(material_1.IconButton, { "aria-label": "settings", onClick: () => {
176
+ if (!this.state.open) {
177
+ this.loadDetails().catch(console.error);
178
+ this.setState({ open: true });
179
+ }
180
+ } },
181
+ react_1.default.createElement(icons_material_1.MoreVert, null)) : null, title: this.props.title, subheader: this.props.device.manufacturer ? react_1.default.createElement("span", null,
182
+ react_1.default.createElement("b", { style: { marginRight: 4 } },
183
+ (0, Utils_1.getTranslation)('manufacturer'),
184
+ ":"),
185
+ getText(this.props.device.manufacturer)) : null }),
186
+ react_1.default.createElement(material_1.CardContent, { style: { position: 'relative' } },
187
+ (status === null || status === void 0 ? void 0 : status.length) ? react_1.default.createElement("div", { style: {
188
+ display: 'flex',
189
+ position: 'absolute',
190
+ top: -11,
191
+ background: '#88888880',
192
+ padding: '0 8px',
193
+ borderRadius: 5,
194
+ width: 'calc(100% - 46px)',
195
+ } }, status.map((s, i) => react_1.default.createElement(DeviceStatus_1.default, { key: i, status: s }))) : null,
196
+ react_1.default.createElement("div", null,
197
+ react_1.default.createElement(material_1.Typography, { variant: "body1" },
198
+ react_1.default.createElement("div", { onClick: this.copyToClipboard },
199
+ react_1.default.createElement("b", null, "ID:"),
200
+ react_1.default.createElement("span", { style: { marginLeft: 4 } }, this.props.device.id.replace(/.*\.\d\./, ''))),
201
+ this.props.device.manufacturer ? react_1.default.createElement("div", null,
202
+ react_1.default.createElement("b", { style: { marginRight: 4 } },
203
+ (0, Utils_1.getTranslation)('manufacturer'),
204
+ ":"),
205
+ getText(this.props.device.manufacturer)) : null,
206
+ this.props.device.model ? react_1.default.createElement("div", null,
207
+ react_1.default.createElement("b", { style: { marginRight: 4 } },
208
+ (0, Utils_1.getTranslation)('model'),
209
+ ":"),
210
+ getText(this.props.device.model)) : null))),
211
+ react_1.default.createElement(material_1.CardActions, { disableSpacing: true },
212
+ this.renderActions(),
213
+ react_1.default.createElement("div", { style: { flexGrow: 1 } }),
214
+ this.renderControls()),
215
+ this.renderDialog(),
216
+ this.renderControlDialog());
217
+ }
218
+ renderBig() {
219
+ var _a;
220
+ const cardStyle = {
221
+ // backgroundColor: '#fafafa',
222
+ width: 300,
223
+ minHeight: 280,
224
+ margin: 10,
225
+ overflow: 'hidden',
226
+ };
227
+ /** @type {CSSProperties} */
228
+ const headerStyle = {
229
+ display: 'flex',
230
+ position: 'relative',
231
+ justifyContent: 'space-between',
232
+ minHeight: 60,
233
+ color: '#000',
234
+ padding: '0 10px 0 10px',
235
+ backgroundColor: '#77c7ff8c',
236
+ borderRadius: '4px 4px 0 0',
237
+ };
238
+ /** @type {CSSProperties} */
239
+ const imgAreaStyle = {
240
+ height: 45,
241
+ width: 45,
242
+ margin: 'auto',
243
+ justifyContent: 'center',
244
+ display: 'grid',
245
+ };
246
+ /** @type {CSSProperties} */
247
+ const imgStyle = {
248
+ zIndex: 2,
249
+ maxWidth: '100%',
250
+ maxHeight: '100%',
251
+ };
252
+ /** @type {CSSProperties} */
253
+ const titleStyle = {
254
+ color: '#333',
255
+ width: '100%',
256
+ fontSize: 16,
257
+ fontWeight: 'bold',
258
+ paddingTop: 16,
259
+ paddingLeft: 8,
260
+ whiteSpace: 'nowrap',
261
+ overflow: 'hidden',
262
+ textOverflow: 'ellipsis',
263
+ };
264
+ /** @type {CSSProperties} */
265
+ const detailsButtonStyle = {
266
+ right: 20,
267
+ bottom: -20,
268
+ position: 'absolute',
269
+ };
270
+ /** @type {CSSProperties} */
271
+ const bodyStyle = {
272
+ height: 'calc(100% - 116px)',
273
+ };
274
+ /** @type {CSSProperties} */
275
+ const deviceInfoStyle = {
276
+ padding: '20px 16px 0 16px',
277
+ height: 133,
278
+ };
279
+ /** @type {CSSProperties} */
280
+ const statusStyle = {
281
+ padding: '15px 15px 0 15px',
282
+ height: 41,
283
+ };
284
+ const status = !this.props.device.status ? [] : Array.isArray(this.props.device.status) ? this.props.device.status : [this.props.device.status];
285
+ return react_1.default.createElement(material_1.Paper, { style: cardStyle, key: this.props.id },
286
+ react_1.default.createElement("div", { style: headerStyle },
287
+ react_1.default.createElement("div", { style: imgAreaStyle },
288
+ this.props.uploadImagesToInstance ? react_1.default.createElement(DeviceImageUpload_1.default, { uploadImagesToInstance: this.props.uploadImagesToInstance, deviceId: this.props.device.id, manufacturer: getText(this.props.device.manufacturer), model: getText(this.props.device.model), onImageSelect: async (imageData) => imageData && this.setState({ icon: imageData }), socket: this.props.socket }) : null,
289
+ react_1.default.createElement(adapter_react_v5_1.Icon, { src: this.state.icon, style: imgStyle })),
290
+ react_1.default.createElement("div", { style: titleStyle }, this.props.title),
291
+ this.props.device.hasDetails ? react_1.default.createElement(material_1.Fab, { size: "small", style: detailsButtonStyle, onClick: () => {
292
+ if (!this.state.open) {
293
+ this.loadDetails().catch(console.error);
294
+ this.setState({ open: true });
295
+ }
296
+ }, color: "primary" },
297
+ react_1.default.createElement(icons_material_1.MoreVert, null)) : null),
298
+ react_1.default.createElement("div", { style: statusStyle }, status.map((s, i) => react_1.default.createElement(DeviceStatus_1.default, { key: i, status: s }))),
299
+ react_1.default.createElement("div", { style: bodyStyle },
300
+ react_1.default.createElement(material_1.Typography, { variant: "body1", style: deviceInfoStyle },
301
+ react_1.default.createElement("div", { onClick: this.copyToClipboard },
189
302
  react_1.default.createElement("b", null, "ID:"),
190
- react_1.default.createElement("span", { style: { marginLeft: 4 } }, device.id.replace(/.*\.\d\./, ''))),
191
- device.manufacturer ? react_1.default.createElement("div", null,
192
- react_1.default.createElement("b", { style: { marginRight: 4 } },
303
+ " ",
304
+ this.props.device.id.replace(/.*\.\d\./, '')),
305
+ this.props.device.manufacturer ? react_1.default.createElement("div", null,
306
+ react_1.default.createElement("b", null,
193
307
  (0, Utils_1.getTranslation)('manufacturer'),
194
308
  ":"),
195
- getText(device.manufacturer)) : null,
196
- device.model ? react_1.default.createElement("div", null,
197
- react_1.default.createElement("b", { style: { marginRight: 4 } },
309
+ " ",
310
+ getText(this.props.device.manufacturer)) : null,
311
+ this.props.device.model ? react_1.default.createElement("div", null,
312
+ react_1.default.createElement("b", null,
198
313
  (0, Utils_1.getTranslation)('model'),
199
314
  ":"),
200
- getText(device.model)) : null))),
201
- react_1.default.createElement(material_1.CardActions, { disableSpacing: true },
202
- renderedActions,
203
- react_1.default.createElement("div", { style: { flexGrow: 1 } }),
204
- renderedControls),
205
- renderedDialog,
206
- controlDialog);
315
+ " ",
316
+ getText(this.props.device.model)) : null),
317
+ !!((_a = this.props.device.actions) === null || _a === void 0 ? void 0 : _a.length) && react_1.default.createElement("div", { style: {
318
+ flex: 1,
319
+ position: 'relative',
320
+ display: 'flex',
321
+ gap: 8,
322
+ paddingBottom: 5,
323
+ height: 34,
324
+ paddingLeft: 10,
325
+ paddingRight: 10,
326
+ } }, this.renderActions())),
327
+ this.renderDialog(),
328
+ this.renderControlDialog());
329
+ }
330
+ render() {
331
+ if (this.props.smallCards) {
332
+ return this.renderSmall();
333
+ }
334
+ return this.renderBig();
335
+ }
207
336
  }
208
337
  exports.default = DeviceCard;
package/DeviceList.d.ts CHANGED
@@ -4,9 +4,10 @@ import Communication, { CommunicationProps, CommunicationState } from './Communi
4
4
  interface DeviceListProps extends CommunicationProps {
5
5
  uploadImagesToInstance?: string;
6
6
  filter?: string;
7
- empbedded?: boolean;
7
+ embedded?: boolean;
8
8
  title?: string;
9
9
  style: React.CSSProperties;
10
+ smallCards: boolean;
10
11
  }
11
12
  interface DeviceListState extends CommunicationState {
12
13
  devices: DeviceInfo[];
@@ -33,7 +34,7 @@ export default class DeviceList extends Communication<DeviceListProps, DeviceLis
33
34
  private lastPropsFilter;
34
35
  private lastInstance;
35
36
  private filterTimeout;
36
- private language;
37
+ private readonly language;
37
38
  constructor(props: DeviceListProps);
38
39
  componentDidMount(): Promise<void>;
39
40
  componentWillUnmount(): void;
package/DeviceList.js CHANGED
@@ -67,7 +67,7 @@ class DeviceList extends Communication_1.default {
67
67
  });
68
68
  }
69
69
  // @ts-ignore
70
- Object.assing(this.state, {
70
+ Object.assign(this.state, {
71
71
  devices: [],
72
72
  filteredDevices: [],
73
73
  filter: '',
@@ -81,7 +81,7 @@ class DeviceList extends Communication_1.default {
81
81
  this.language = adapter_react_v5_1.I18n.getLanguage();
82
82
  }
83
83
  async componentDidMount() {
84
- if (!this.props.empbedded) {
84
+ if (!this.props.embedded) {
85
85
  try {
86
86
  // check if instance is alive
87
87
  const alive = await this.props.socket.getState(`system.adapter.${this.props.selectedInstance}.alive`);
@@ -106,7 +106,7 @@ class DeviceList extends Communication_1.default {
106
106
  }
107
107
  }
108
108
  componentWillUnmount() {
109
- if (!this.props.empbedded) {
109
+ if (!this.props.embedded) {
110
110
  this.props.socket.unsubscribeState(`system.adapter.${this.props.selectedInstance}.alive`, this.aliveHandler);
111
111
  }
112
112
  }
@@ -129,7 +129,7 @@ class DeviceList extends Communication_1.default {
129
129
  return text;
130
130
  }
131
131
  applyFilter() {
132
- const filter = this.props.empbedded ? this.props.filter : this.state.filter;
132
+ const filter = this.props.embedded ? this.props.filter : this.state.filter;
133
133
  // filter devices name
134
134
  if (filter) {
135
135
  const filteredDevices = this.state.devices.filter(device => this.getText(device.name).toLowerCase().includes(filter.toLowerCase()));
@@ -154,16 +154,16 @@ class DeviceList extends Communication_1.default {
154
154
  const emptyStyle = {
155
155
  padding: 25,
156
156
  };
157
- if (this.props.empbedded && this.lastPropsFilter !== this.props.filter) {
157
+ if (this.props.embedded && this.lastPropsFilter !== this.props.filter) {
158
158
  this.lastPropsFilter = this.props.filter;
159
159
  setTimeout(() => this.applyFilter(), 50);
160
160
  }
161
- if (this.props.empbedded && this.lastInstance !== this.props.selectedInstance) {
161
+ if (this.props.embedded && this.lastInstance !== this.props.selectedInstance) {
162
162
  this.lastInstance = this.props.selectedInstance;
163
163
  setTimeout(() => this.loadData().catch(console.error), 50);
164
164
  }
165
165
  let list;
166
- if (!this.props.empbedded && !this.state.alive) {
166
+ if (!this.props.embedded && !this.state.alive) {
167
167
  list = react_1.default.createElement("div", { style: emptyStyle },
168
168
  react_1.default.createElement("span", null, (0, Utils_1.getTranslation)('instanceNotAlive')));
169
169
  }
@@ -178,7 +178,7 @@ class DeviceList extends Communication_1.default {
178
178
  else {
179
179
  list = this.state.filteredDevices.map(device => react_1.default.createElement(DeviceCard_1.default, { key: device.id, id: device.id, title: this.getText(device.name), device: device, instanceId: this.props.selectedInstance, uploadImagesToInstance: this.props.uploadImagesToInstance, deviceHandler: this.deviceHandler, controlHandler: this.controlHandler, controlStateHandler: this.controlStateHandler, socket: this.props.socket }));
180
180
  }
181
- if (this.props.empbedded) {
181
+ if (this.props.embedded) {
182
182
  return list;
183
183
  }
184
184
  return react_1.default.createElement("div", { style: { width: '100%', height: '100%', overflow: 'hidden' } },
package/README.md CHANGED
@@ -20,7 +20,10 @@ render() {
20
20
  -->
21
21
 
22
22
  ## Changelog
23
- ### 0.0.2 (2023-12-12)
23
+ ### 0.0.4 (2023-12-12)
24
+ * (bluefox) return the style of big cards
25
+
26
+ ### 0.0.3 (2023-12-12)
24
27
  * (bluefox) initial commit
25
28
 
26
29
  ## License
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iobroker/dm-gui-components",
3
- "version": "0.0.2",
3
+ "version": "0.0.4",
4
4
  "description": "ReactJS components to develop admin interface for ioBroker device manager.",
5
5
  "author": {
6
6
  "name": "Jey Cee",