@iobroker/gui-components 10.3.5 → 10.3.7

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.
@@ -5,6 +5,20 @@ export declare class Router<P = {}, S = {}> extends Component<P, S> {
5
5
  componentDidMount(): void;
6
6
  componentWillUnmount(): void;
7
7
  onHashChanged(): void;
8
+ /**
9
+ * Put a free-form part of the route into the hash.
10
+ *
11
+ * {@link Router.getLocation} splits the hash at "/" and decodes every part, so everything written
12
+ * here has to be encoded: an object ID may contain a "/" (e.g.
13
+ * `ocpp.0./TACW1142021G1543.1.meterValues.Power_Active_Import`) and a file ID always does.
14
+ * Without this, such an ID is cut off at its first slash when the route is read back, and the
15
+ * rest of it lands in `arg`.
16
+ *
17
+ * Callers pass the raw ID; they must not encode it themselves, or it is encoded twice.
18
+ *
19
+ * @param part the value to write into one segment of the hash
20
+ */
21
+ private static encodeSegment;
8
22
  /**
9
23
  * Gets the location object.
10
24
  */
@@ -16,6 +16,22 @@ export class Router extends Component {
16
16
  onHashChanged() {
17
17
  // override this function
18
18
  }
19
+ /**
20
+ * Put a free-form part of the route into the hash.
21
+ *
22
+ * {@link Router.getLocation} splits the hash at "/" and decodes every part, so everything written
23
+ * here has to be encoded: an object ID may contain a "/" (e.g.
24
+ * `ocpp.0./TACW1142021G1543.1.meterValues.Power_Active_Import`) and a file ID always does.
25
+ * Without this, such an ID is cut off at its first slash when the route is read back, and the
26
+ * rest of it lands in `arg`.
27
+ *
28
+ * Callers pass the raw ID; they must not encode it themselves, or it is encoded twice.
29
+ *
30
+ * @param part the value to write into one segment of the hash
31
+ */
32
+ static encodeSegment(part) {
33
+ return encodeURIComponent(part);
34
+ }
19
35
  /**
20
36
  * Gets the location object.
21
37
  */
@@ -62,9 +78,12 @@ export class Router extends Component {
62
78
  if (dialog) {
63
79
  hash += `/${dialog}`;
64
80
  if (id) {
65
- hash += `/${id}`;
81
+ // `id` and `arg` carry free-form values - an ID with a "/" in it would otherwise
82
+ // be read back as two segments. `tab` and `dialog` are fixed names of the
83
+ // application and are left as they are.
84
+ hash += `/${Router.encodeSegment(id)}`;
66
85
  if (arg !== undefined) {
67
- hash += `/${arg}`;
86
+ hash += `/${arg === null ? arg : Router.encodeSegment(arg)}`;
68
87
  }
69
88
  }
70
89
  }
@@ -1 +1 @@
1
- {"version":3,"file":"Router.js","sourceRoot":"./src/","sources":["Components/Router.tsx"],"names":[],"mappings":"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","sourcesContent":["import { Component } from 'react';\n\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\nexport class Router<P = {}, S = {}> extends Component<P, S> {\n protected onHashChangedBound: () => void;\n\n constructor(props: P) {\n super(props);\n this.onHashChangedBound = this.onHashChanged.bind(this);\n }\n\n componentDidMount(): void {\n window.addEventListener('hashchange', this.onHashChangedBound);\n }\n\n componentWillUnmount(): void {\n window.removeEventListener('hashchange', this.onHashChangedBound);\n }\n\n // eslint-disable-next-line class-methods-use-this\n onHashChanged(): void {\n // override this function\n }\n\n /**\n * Gets the location object.\n */\n static getLocation(): { tab: string; dialog: string; id: string; arg: string } {\n let hash = window.location.hash;\n hash = hash.replace(/^#/, '');\n const parts = hash.split('/').map(item => {\n try {\n return item ? decodeURIComponent(item) : '';\n } catch {\n console.error(`Router: Cannot decode ${item}`);\n return item;\n }\n });\n // #tabName/dialogName/deviceId\n return {\n tab: parts[0] || '',\n dialog: parts[1] || '',\n id: parts[2] || '',\n arg: parts[3] || '',\n };\n }\n\n /**\n * Navigate to a new location. Any parameters that are not set will be taken from the current location.\n */\n static doNavigate(\n tab: string | undefined | null,\n dialog?: string | null,\n id?: string | null,\n arg?: string | null,\n ): void {\n let hash = '';\n const location = Router.getLocation();\n if (arg !== undefined && !id) {\n id = location.id;\n }\n if (id && !dialog) {\n dialog = location.dialog;\n }\n if (dialog && !tab) {\n tab = location.tab;\n } else if (tab === null) {\n tab = location.tab;\n }\n\n if (tab) {\n hash = `#${tab}`;\n if (dialog) {\n hash += `/${dialog}`;\n\n if (id) {\n hash += `/${id}`;\n if (arg !== undefined) {\n hash += `/${arg}`;\n }\n }\n }\n }\n if (window.location.hash !== hash) {\n window.location.hash = hash;\n }\n }\n}\n"]}
1
+ {"version":3,"file":"Router.js","sourceRoot":"./src/","sources":["Components/Router.tsx"],"names":[],"mappings":"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","sourcesContent":["import { Component } from 'react';\n\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\nexport class Router<P = {}, S = {}> extends Component<P, S> {\n protected onHashChangedBound: () => void;\n\n constructor(props: P) {\n super(props);\n this.onHashChangedBound = this.onHashChanged.bind(this);\n }\n\n componentDidMount(): void {\n window.addEventListener('hashchange', this.onHashChangedBound);\n }\n\n componentWillUnmount(): void {\n window.removeEventListener('hashchange', this.onHashChangedBound);\n }\n\n // eslint-disable-next-line class-methods-use-this\n onHashChanged(): void {\n // override this function\n }\n\n /**\n * Put a free-form part of the route into the hash.\n *\n * {@link Router.getLocation} splits the hash at \"/\" and decodes every part, so everything written\n * here has to be encoded: an object ID may contain a \"/\" (e.g.\n * `ocpp.0./TACW1142021G1543.1.meterValues.Power_Active_Import`) and a file ID always does.\n * Without this, such an ID is cut off at its first slash when the route is read back, and the\n * rest of it lands in `arg`.\n *\n * Callers pass the raw ID; they must not encode it themselves, or it is encoded twice.\n *\n * @param part the value to write into one segment of the hash\n */\n private static encodeSegment(part: string): string {\n return encodeURIComponent(part);\n }\n\n /**\n * Gets the location object.\n */\n static getLocation(): { tab: string; dialog: string; id: string; arg: string } {\n let hash = window.location.hash;\n hash = hash.replace(/^#/, '');\n const parts = hash.split('/').map(item => {\n try {\n return item ? decodeURIComponent(item) : '';\n } catch {\n console.error(`Router: Cannot decode ${item}`);\n return item;\n }\n });\n // #tabName/dialogName/deviceId\n return {\n tab: parts[0] || '',\n dialog: parts[1] || '',\n id: parts[2] || '',\n arg: parts[3] || '',\n };\n }\n\n /**\n * Navigate to a new location. Any parameters that are not set will be taken from the current location.\n */\n static doNavigate(\n tab: string | undefined | null,\n dialog?: string | null,\n id?: string | null,\n arg?: string | null,\n ): void {\n let hash = '';\n const location = Router.getLocation();\n if (arg !== undefined && !id) {\n id = location.id;\n }\n if (id && !dialog) {\n dialog = location.dialog;\n }\n if (dialog && !tab) {\n tab = location.tab;\n } else if (tab === null) {\n tab = location.tab;\n }\n\n if (tab) {\n hash = `#${tab}`;\n if (dialog) {\n hash += `/${dialog}`;\n\n if (id) {\n // `id` and `arg` carry free-form values - an ID with a \"/\" in it would otherwise\n // be read back as two segments. `tab` and `dialog` are fixed names of the\n // application and are left as they are.\n hash += `/${Router.encodeSegment(id)}`;\n if (arg !== undefined) {\n hash += `/${arg === null ? arg : Router.encodeSegment(arg)}`;\n }\n }\n }\n }\n if (window.location.hash !== hash) {\n window.location.hash = hash;\n }\n }\n}\n"]}
@@ -34,9 +34,14 @@ interface CardTitleProps {
34
34
  text: string;
35
35
  onClick: () => void;
36
36
  };
37
+ /**
38
+ * Anything else that belongs on the right, e.g. an icon button that collapses the card. Shown
39
+ * behind `action` when both are given.
40
+ */
41
+ actions?: ReactNode;
37
42
  }
38
43
  /** Heading of a content card, with an optional action on the right */
39
- export declare function CardTitle({ title, action }: CardTitleProps): JSX.Element;
44
+ export declare function CardTitle({ title, action, actions }: CardTitleProps): JSX.Element;
40
45
  interface InfoRowProps {
41
46
  name: string;
42
47
  /** A node, not only a string, so that a value can carry a chip or an icon */
@@ -32,10 +32,12 @@ export function StatCard(props) {
32
32
  props.hint ? (React.createElement(Typography, { variant: "caption", color: "text.secondary", sx: { display: 'block', mt: 1.5 } }, props.hint)) : null));
33
33
  }
34
34
  /** Heading of a content card, with an optional action on the right */
35
- export function CardTitle({ title, action }) {
36
- return (React.createElement(Box, { sx: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', mb: 2 } },
35
+ export function CardTitle({ title, action, actions }) {
36
+ return (React.createElement(Box, { sx: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 1, mb: 2 } },
37
37
  React.createElement(Typography, { sx: { fontSize: '1rem', fontWeight: 600 } }, title),
38
- action ? (React.createElement(Link, { component: "button", underline: "none", sx: { fontSize: '0.8125rem' }, onClick: action.onClick }, action.text)) : null));
38
+ action || actions ? (React.createElement(Box, { sx: { display: 'flex', alignItems: 'center', gap: 1, flexShrink: 0 } },
39
+ action ? (React.createElement(Link, { component: "button", underline: "none", sx: { fontSize: '0.8125rem' }, onClick: action.onClick }, action.text)) : null,
40
+ actions)) : null));
39
41
  }
40
42
  /** One line "name .......... value" inside a card */
41
43
  export function InfoRow({ name, value }) {
@@ -1 +1 @@
1
- {"version":3,"file":"StatCard.js","sourceRoot":"./src/","sources":["Components/StatCard.tsx"],"names":[],"mappings":"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","sourcesContent":["import React, { type JSX, type ReactNode } from 'react';\n\nimport { alpha, Box, Card, Chip, Link, Typography } from '@mui/material';\n\ninterface StatCardProps {\n /** Small line above the value, e.g. \"Adapters\" */\n title: string;\n /** The value itself - a string so that \"--\" can be shown while it is still unknown */\n value: string;\n /** Quiet line below, e.g. \"6 active / 102 inactive\" */\n hint?: string;\n /** Accent color: tints the icon square and can color the value */\n color: string;\n /** Color of the value, defaults to the normal text color */\n valueColor?: string;\n icon: JSX.Element;\n /** Marker next to the value, e.g. the number of available updates */\n chip?: { label: string; color: 'warning' | 'primary' | 'success' | 'error' };\n onClick?: () => void;\n /** Overrides the flex basis - by default the card grows from 220px */\n flex?: string;\n}\n\n/**\n * A number with a title, an accented icon and a hint - the tile that a dashboard is built from.\n *\n * Kept here rather than in one GUI so that the admin, devices, javascript and the rest can show the\n * same tile instead of each rebuilding its own.\n */\nexport function StatCard(props: StatCardProps): JSX.Element {\n return (\n <Card\n sx={{\n flex: props.flex || '1 1 220px',\n p: 2.5,\n cursor: props.onClick ? 'pointer' : undefined,\n }}\n onClick={props.onClick}\n >\n <Box sx={{ display: 'flex', gap: 2, alignItems: 'flex-start' }}>\n <Box\n sx={{\n width: 40,\n height: 40,\n borderRadius: 2,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n backgroundColor: alpha(props.color, 0.16),\n color: props.color,\n flexShrink: 0,\n }}\n >\n {props.icon}\n </Box>\n <Box sx={{ minWidth: 0 }}>\n <Typography\n variant=\"body2\"\n color=\"text.secondary\"\n >\n {props.title}\n </Typography>\n <Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>\n <Typography sx={{ fontSize: 30, fontWeight: 700, color: props.valueColor, lineHeight: 1.2 }}>\n {props.value}\n </Typography>\n {props.chip ? (\n <Chip\n size=\"small\"\n color={props.chip.color}\n label={props.chip.label}\n />\n ) : null}\n </Box>\n </Box>\n </Box>\n {props.hint ? (\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n sx={{ display: 'block', mt: 1.5 }}\n >\n {props.hint}\n </Typography>\n ) : null}\n </Card>\n );\n}\n\ninterface CardTitleProps {\n title: string;\n /** Optional link on the right, e.g. \"Show all\" */\n action?: { text: string; onClick: () => void };\n}\n\n/** Heading of a content card, with an optional action on the right */\nexport function CardTitle({ title, action }: CardTitleProps): JSX.Element {\n return (\n <Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', mb: 2 }}>\n <Typography sx={{ fontSize: '1rem', fontWeight: 600 }}>{title}</Typography>\n {action ? (\n <Link\n component=\"button\"\n underline=\"none\"\n sx={{ fontSize: '0.8125rem' }}\n onClick={action.onClick}\n >\n {action.text}\n </Link>\n ) : null}\n </Box>\n );\n}\n\ninterface InfoRowProps {\n name: string;\n /** A node, not only a string, so that a value can carry a chip or an icon */\n value: ReactNode;\n}\n\n/** One line \"name .......... value\" inside a card */\nexport function InfoRow({ name, value }: InfoRowProps): JSX.Element {\n return (\n <Box sx={{ display: 'flex', justifyContent: 'space-between', gap: 2, py: 1 }}>\n <Typography\n variant=\"body2\"\n color=\"text.secondary\"\n >\n {name}\n </Typography>\n <Typography\n variant=\"body2\"\n sx={{ fontWeight: 500, textAlign: 'right' }}\n >\n {value}\n </Typography>\n </Box>\n );\n}\n"]}
1
+ {"version":3,"file":"StatCard.js","sourceRoot":"./src/","sources":["Components/StatCard.tsx"],"names":[],"mappings":"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","sourcesContent":["import React, { type JSX, type ReactNode } from 'react';\n\nimport { alpha, Box, Card, Chip, Link, Typography } from '@mui/material';\n\ninterface StatCardProps {\n /** Small line above the value, e.g. \"Adapters\" */\n title: string;\n /** The value itself - a string so that \"--\" can be shown while it is still unknown */\n value: string;\n /** Quiet line below, e.g. \"6 active / 102 inactive\" */\n hint?: string;\n /** Accent color: tints the icon square and can color the value */\n color: string;\n /** Color of the value, defaults to the normal text color */\n valueColor?: string;\n icon: JSX.Element;\n /** Marker next to the value, e.g. the number of available updates */\n chip?: { label: string; color: 'warning' | 'primary' | 'success' | 'error' };\n onClick?: () => void;\n /** Overrides the flex basis - by default the card grows from 220px */\n flex?: string;\n}\n\n/**\n * A number with a title, an accented icon and a hint - the tile that a dashboard is built from.\n *\n * Kept here rather than in one GUI so that the admin, devices, javascript and the rest can show the\n * same tile instead of each rebuilding its own.\n */\nexport function StatCard(props: StatCardProps): JSX.Element {\n return (\n <Card\n sx={{\n flex: props.flex || '1 1 220px',\n p: 2.5,\n cursor: props.onClick ? 'pointer' : undefined,\n }}\n onClick={props.onClick}\n >\n <Box sx={{ display: 'flex', gap: 2, alignItems: 'flex-start' }}>\n <Box\n sx={{\n width: 40,\n height: 40,\n borderRadius: 2,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n backgroundColor: alpha(props.color, 0.16),\n color: props.color,\n flexShrink: 0,\n }}\n >\n {props.icon}\n </Box>\n <Box sx={{ minWidth: 0 }}>\n <Typography\n variant=\"body2\"\n color=\"text.secondary\"\n >\n {props.title}\n </Typography>\n <Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>\n <Typography sx={{ fontSize: 30, fontWeight: 700, color: props.valueColor, lineHeight: 1.2 }}>\n {props.value}\n </Typography>\n {props.chip ? (\n <Chip\n size=\"small\"\n color={props.chip.color}\n label={props.chip.label}\n />\n ) : null}\n </Box>\n </Box>\n </Box>\n {props.hint ? (\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n sx={{ display: 'block', mt: 1.5 }}\n >\n {props.hint}\n </Typography>\n ) : null}\n </Card>\n );\n}\n\ninterface CardTitleProps {\n title: string;\n /** Optional link on the right, e.g. \"Show all\" */\n action?: { text: string; onClick: () => void };\n /**\n * Anything else that belongs on the right, e.g. an icon button that collapses the card. Shown\n * behind `action` when both are given.\n */\n actions?: ReactNode;\n}\n\n/** Heading of a content card, with an optional action on the right */\nexport function CardTitle({ title, action, actions }: CardTitleProps): JSX.Element {\n return (\n <Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 1, mb: 2 }}>\n <Typography sx={{ fontSize: '1rem', fontWeight: 600 }}>{title}</Typography>\n {action || actions ? (\n <Box sx={{ display: 'flex', alignItems: 'center', gap: 1, flexShrink: 0 }}>\n {action ? (\n <Link\n component=\"button\"\n underline=\"none\"\n sx={{ fontSize: '0.8125rem' }}\n onClick={action.onClick}\n >\n {action.text}\n </Link>\n ) : null}\n {actions}\n </Box>\n ) : null}\n </Box>\n );\n}\n\ninterface InfoRowProps {\n name: string;\n /** A node, not only a string, so that a value can carry a chip or an icon */\n value: ReactNode;\n}\n\n/** One line \"name .......... value\" inside a card */\nexport function InfoRow({ name, value }: InfoRowProps): JSX.Element {\n return (\n <Box sx={{ display: 'flex', justifyContent: 'space-between', gap: 2, py: 1 }}>\n <Typography\n variant=\"body2\"\n color=\"text.secondary\"\n >\n {name}\n </Typography>\n <Typography\n variant=\"body2\"\n sx={{ fontWeight: 500, textAlign: 'right' }}\n >\n {value}\n </Typography>\n </Box>\n );\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iobroker/gui-components",
3
- "version": "10.3.5",
3
+ "version": "10.3.7",
4
4
  "description": "Shared React components (React 19 / MUI 9) to develop ioBroker interfaces. Successor of @iobroker/adapter-react-v5.",
5
5
  "author": {
6
6
  "name": "bluefox",
@@ -57,10 +57,10 @@
57
57
  "dependencies": {
58
58
  "@iobroker/js-controller-common": "^7.2.3",
59
59
  "@iobroker/js-controller-common-db": "^7.2.3",
60
- "@iobroker/socket-client": "^5.3.0",
60
+ "@iobroker/socket-client": "^5.4.0",
61
61
  "@iobroker/type-detector": "^6.0.1",
62
62
  "@iobroker/types": "^7.2.3",
63
- "@sentry/browser": "^11.0.0",
63
+ "@sentry/browser": "^11.1.0",
64
64
  "cronstrue": "^3.27.0",
65
65
  "file-selector": "^5.0.1",
66
66
  "react-colorful": "^5.8.1",
@@ -85,7 +85,7 @@
85
85
  "@mdi/js": "^7.4.47",
86
86
  "@mui/icons-material": "^9.4.0",
87
87
  "@mui/material": "^9.4.0",
88
- "@types/node": "^26.6.2",
88
+ "@types/node": "^26.6.3",
89
89
  "@types/react": "^19.3.0",
90
90
  "@types/react-dom": "^19.3.0",
91
91
  "ajv": "^8.20.0",