Skip to content

Commit

Permalink
Migrated palette to TS
Browse files Browse the repository at this point in the history
  • Loading branch information
GermanBluefox committed Apr 27, 2024
1 parent 52fe07b commit da51b5f
Show file tree
Hide file tree
Showing 6 changed files with 165 additions and 119 deletions.
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import React from 'react';
import {
Blinds,
DirectionsRun,
Expand All @@ -20,7 +21,8 @@ import {
} from '@mui/icons-material';

import { TbVacuumCleaner } from 'react-icons/tb';
import ChannelDetector from '@iobroker/type-detector';
import ChannelDetector, { DetectOptions, Types } from '@iobroker/type-detector';
import { LegacyConnection } from '@iobroker/adapter-react-v5';
import { getNewWidgetIdNumber, getNewWidgetId } from '@/Utils/utils';

const deviceIcons = {
Expand Down Expand Up @@ -52,23 +54,23 @@ const deviceIcons = {
unknown: <QuestionMark />,
};

const allObjects = async socket => {
const states = await socket.getObjectView('', '\u9999', 'state');
const channels = await socket.getObjectView('', '\u9999', 'channel');
const devices = await socket.getObjectView('', '\u9999', 'device');
const folders = await socket.getObjectView('', '\u9999', 'folder');
const enums = await socket.getObjectView('', '\u9999', 'enum');
const allObjects = async (socket: LegacyConnection) => {
const states = await socket.getObjectViewSystem('state', '', '\u9999');
const channels = await socket.getObjectViewSystem('channel', '', '\u9999');
const devices = await socket.getObjectViewSystem('device', '', '\u9999');
const folders = await socket.getObjectViewSystem('folder', '', '\u9999');
const enums = await socket.getObjectViewSystem('enum', '', '\u9999');

return Object.values(states)
.concat(Object.values(channels))
.concat(Object.values(devices))
.concat(Object.values(folders))
.concat(Object.values(enums))
// eslint-disable-next-line
.reduce((obj, item) => (obj[item._id] = item, obj), {});
.reduce((obj: Record<string, ioBroker.Object>, item: ioBroker.Object) => (obj[item._id] = item, obj), {});
};

function getObjectIcon(obj, id, imagePrefix) {
function getObjectIcon(obj: ioBroker.Object, id: string, imagePrefix?: string): string {
imagePrefix = imagePrefix || '.'; // http://localhost:8081';
let src = '';
const common = obj?.common;
Expand Down Expand Up @@ -110,22 +112,45 @@ function getObjectIcon(obj, id, imagePrefix) {
return src || null;
}

const detectDevices = async socket => {
const devicesObject = await allObjects(socket);
interface ObjectForDetector {
_id: string;
common: ioBroker.StateCommon | ioBroker.EnumCommon;
name?: ioBroker.StringOrTranslated;
type: ioBroker.ObjectType;
}

interface DetectorDevice {
_id: string;
common: ioBroker.StateCommon;
type: ioBroker.ObjectType;
deviceType: Types;
states: ObjectForDetector[];
name?: ioBroker.StringOrTranslated;
roomName?: ioBroker.StringOrTranslated;
}

interface DetectorResult {
_id: string;
common: ioBroker.StateCommon;
devices: ObjectForDetector[];
}

const detectDevices = async (socket: LegacyConnection) => {
const devicesObject: Record<string, ObjectForDetector> = await allObjects(socket) as Record<string, ObjectForDetector>;
const keys = Object.keys(devicesObject).sort();
const detector = new ChannelDetector();

const usedIds = [];
const usedIds: string[] = [];
const ignoreIndicators = ['UNREACH_STICKY']; // Ignore indicators by name
const excludedTypes = ['info'];
const enums = [];
const rooms = [];
const list = [];
const excludedTypes: Types[] = [Types.info];
const enums: string[] = [];
const rooms: string[] = [];
const list: string[] = [];

keys.forEach(id => {
if (devicesObject[id]?.type === 'enum') {
enums.push(id);
} else if (devicesObject[id]?.common?.smartName) {
} else if ((devicesObject[id]?.common as ioBroker.StateCommon)?.smartName) {
list.push(id);
}
});
Expand All @@ -134,10 +159,10 @@ const detectDevices = async socket => {
if (id.startsWith('enum.rooms.')) {
rooms.push(id);
}
const members = devicesObject[id].common.members;
const members = (devicesObject[id].common as ioBroker.EnumCommon).members;

if (members && members.length) {
members.forEach(member => {
members.forEach((member: string) => {
// if an object really exists
if (devicesObject[member]) {
if (!list.includes(member)) {
Expand All @@ -148,15 +173,16 @@ const detectDevices = async socket => {
}
});

const options = {
objects: devicesObject,
const options: DetectOptions = {
id: '',
objects: devicesObject as Record<string, ioBroker.Object>,
_keysOptional: keys,
_usedIdsOptional: usedIds,
ignoreIndicators,
excludedTypes,
};

const result = [];
const result: DetectorResult[] = [];

list.forEach(id => {
options.id = id;
Expand All @@ -170,9 +196,9 @@ const detectDevices = async socket => {
if (result.find(item => item.devices.find(st => st._id === stateId))) {
return;
}
const deviceObject = {
const deviceObject: DetectorDevice = {
_id: stateId,
common: devicesObject[stateId].common,
common: devicesObject[stateId].common as ioBroker.StateCommon,
type: devicesObject[stateId].type,
deviceType: control.type,
states: control.states
Expand All @@ -185,8 +211,8 @@ const detectDevices = async socket => {
};

const parts = stateId.split('.');
let channelId;
let deviceId;
let channelId: string;
let deviceId: string;
if (devicesObject[stateId].type === 'channel' || devicesObject[stateId].type === 'state') {
parts.pop();
channelId = parts.join('.');
Expand All @@ -202,21 +228,21 @@ const detectDevices = async socket => {
}
// try to detect room
const room = rooms.find(roomId => {
if (devicesObject[roomId].common.members.includes(stateId)) {
if ((devicesObject[roomId].common as ioBroker.EnumCommon).members.includes(stateId)) {
return true;
}
if (channelId && devicesObject[roomId].common.members.includes(channelId)) {
if (channelId && (devicesObject[roomId].common as ioBroker.EnumCommon).members.includes(channelId)) {
return true;
}
return deviceId && devicesObject[roomId].common.members.includes(deviceId);
return deviceId && (devicesObject[roomId].common as ioBroker.EnumCommon).members.includes(deviceId);
});
let roomObj;
let roomObj: DetectorResult;
if (room) {
roomObj = result.find(obj => obj._id === room);
if (!roomObj) {
roomObj = {
_id: room,
common: devicesObject[room].common,
common: devicesObject[room].common as ioBroker.StateCommon,
devices: [],
};
result.push(roomObj);
Expand All @@ -229,7 +255,7 @@ const detectDevices = async socket => {
common: {
name: 'unknown',
icon: '?',
},
} as ioBroker.StateCommon,
devices: [],
};
result.push(roomObj);
Expand All @@ -254,23 +280,23 @@ const detectDevices = async socket => {
if (parentObject && (parentObject.type === 'channel' || parentObject.type === 'device' || parentObject.type === 'folder')) {
deviceObj.common.name = parentObject.common?.name || deviceObj.common.name;
if (parentObject.common.icon) {
deviceObj.common.icon = getObjectIcon(parentObject, parentObject._id, '../..');
deviceObj.common.icon = getObjectIcon(parentObject as ioBroker.Object, parentObject._id, '../..');
}
idArray.pop();
// read device
const grandParentObject = devicesObject[idArray.join('.')];
if (grandParentObject?.type === 'device' && grandParentObject.common?.icon) {
deviceObj.common.name = grandParentObject.common.name || deviceObj.common.name;
deviceObj.common.icon = getObjectIcon(grandParentObject, grandParentObject._id, '../..');
deviceObj.common.icon = getObjectIcon(grandParentObject as ioBroker.Object, grandParentObject._id, '../..');
}
} else {
deviceObj.common.name = parentObject?.common?.name || deviceObj.common.name;
if (parentObject?.common?.icon) {
deviceObj.common.icon = getObjectIcon(parentObject, parentObject._id, '../..');
deviceObj.common.icon = getObjectIcon(parentObject as ioBroker.Object, parentObject._id, '../..');
}
}
} else {
deviceObj.common.icon = getObjectIcon(deviceObj, deviceObj._id, '../..');
deviceObj.common.icon = getObjectIcon(deviceObj as ioBroker.Object, deviceObj._id, '../..');
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { useEffect, useRef } from 'react';
import PropTypes from 'prop-types';
import React, { useEffect, useRef } from 'react';
import { withStyles } from '@mui/styles';
import { useDrag } from 'react-dnd';
import { getEmptyImage } from 'react-dnd-html5-backend';
Expand All @@ -11,14 +10,17 @@ import {
Block as DeletedIcon,
} from '@mui/icons-material';

import { I18n, Utils } from '@iobroker/adapter-react-v5';
import { I18n, LegacyConnection, Utils } from '@iobroker/adapter-react-v5';
import { ThemeType } from '@iobroker/adapter-react-v5/types';
import { MarketplaceWidgetRevision, Project } from '@iobroker/types-vis-2';

import { store } from '@/Store';
import { WidgetType } from '@/Vis/visWidgetsCatalog';
import helpers from '../Components/WizardHelpers';

const IMAGE_TYPES = ['.png', '.jpg', '.svg', '.gif', '.apng', '.avif', '.webp'];

const styles = () => ({
const styles: Record<string, any> = {
widget: {
borderStyle: 'solid',
borderColor: 'gray',
Expand Down Expand Up @@ -74,12 +76,35 @@ const styles = () => ({
marginTop: 9,
color: '#F00',
},
});
};

const WIDGET_ICON_HEIGHT = 34;
const Widget = props => {
const imageRef = useRef();
const style = {};

interface WidgetProps {
classes: Record<string, string>;
widgetSetProps?: Record<string, any>;
widgetSet: string;
widgetType: WidgetType;
widgetTypeName: string;
socket?: LegacyConnection;
themeType: ThemeType;
changeProject?: (project: Project, ignoreHistory?: boolean) => Promise<void>;
changeView?: (view: string) => void;
editMode: boolean;
widgetMarketplaceId?: string;
selectedView: string;

/** Used for a marketplace */
updateWidgets?: (widget: MarketplaceWidgetRevision) => void;
uninstallWidget?: (widgetId: string) => void;
marketplace?: MarketplaceWidgetRevision;
marketplaceUpdates?: MarketplaceWidgetRevision[];
marketplaceDeleted?: string[];
}

const Widget = (props: WidgetProps) => {
const imageRef = useRef<HTMLSpanElement>();
const style: React.CSSProperties = {};

useEffect(() => {
if (imageRef.current?.children[0]) {
Expand All @@ -98,7 +123,7 @@ const Widget = props => {
style.backgroundColor = window.visSets[props.widgetSet].color;
}

const titleStyle = {};
const titleStyle: React.CSSProperties = {};
if (style.backgroundColor) {
if (Utils.isUseBright(style.backgroundColor)) {
titleStyle.color = 'white';
Expand All @@ -111,15 +136,15 @@ const Widget = props => {
if (props.widgetType.preview?.startsWith('<img')) {
const m = props.widgetType.preview.match(/src="([^"]+)"/) || props.widgetType.preview.match(/src='([^']+)'/);
if (m) {
img = <img src={m[1]} className={props.classes.widgetImageWithSrc} alt={props.widgetType.id} />;
img = <img src={m[1]} className={props.classes.widgetImageWithSrc} alt={props.widgetType.name} />;
}
} else if (props.widgetType.preview &&
(
IMAGE_TYPES.find(ext => props.widgetType.preview.toLowerCase().endsWith(ext)) ||
props.widgetSet === '__marketplace'
)
) {
img = <img src={props.widgetType.preview} className={props.classes.widgetImageWithSrc} alt={props.widgetType.id} />;
img = <img src={props.widgetType.preview} className={props.classes.widgetImageWithSrc} alt={props.widgetType.name} />;
}

if (!img) {
Expand All @@ -137,11 +162,11 @@ const Widget = props => {
label = label.split('<span')[0];
label = label.split('<div')[0];

let marketplaceUpdate;
let marketplaceUpdate: MarketplaceWidgetRevision | null = null;
let marketplaceDeleted;
if (props.widgetSet === '__marketplace') {
marketplaceUpdate = props.marketplaceUpdates?.find(u => u.widget_id === props.widgetType.widget_id);
marketplaceDeleted = props.marketplaceDeleted?.includes(props.widgetType.widget_id);
marketplaceUpdate = props.marketplaceUpdates?.find(u => u.widget_id === props.widgetMarketplaceId);
marketplaceDeleted = props.marketplaceDeleted?.includes(props.widgetMarketplaceId);
}

const result = <Tooltip
Expand All @@ -161,7 +186,7 @@ const Widget = props => {
</div>
{props.widgetSet === '__marketplace' && <>
<Tooltip title={I18n.t('Uninstall')}>
<IconButton onClick={() => props.uninstallWidget(props.widgetType.id)}>
<IconButton onClick={() => props.uninstallWidget(props.widgetType.name)}>
<DeleteIcon />
</IconButton>
</Tooltip>
Expand All @@ -183,13 +208,13 @@ const Widget = props => {
</div>
</Tooltip>;

const widthRef = useRef();
const widthRef = useRef<HTMLSpanElement>();
const [, dragRef, preview] = useDrag({
type: 'widget',
item: () => ({
widgetType: props.widgetType,
widgetSet: props.widgetSet,
preview: <div style={{ width: widthRef.current.offsetWidth }}>
preview: <div style={{ width: widthRef.current?.offsetWidth || 100 }}>
{result}
</div>,
}),
Expand Down Expand Up @@ -225,22 +250,4 @@ const Widget = props => {
</span>;
};

Widget.propTypes = {
classes: PropTypes.object,
widgetSetProps: PropTypes.object,
widgetSet: PropTypes.string,
widgetType: PropTypes.object,
widgetTypeName: PropTypes.string,
updateWidgets: PropTypes.func,
marketplace: PropTypes.object,
marketplaceUpdates: PropTypes.array,
marketplaceDeleted: PropTypes.array,
uninstallWidget: PropTypes.func,
socket: PropTypes.object,
themeType: PropTypes.string,
changeProject: PropTypes.func,
changeView: PropTypes.func,
editMode: PropTypes.bool,
};

export default withStyles(styles)(Widget);
Loading

0 comments on commit da51b5f

Please sign in to comment.