@iobroker/json-config 8.4.6 → 8.4.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.
package/README.md CHANGED
@@ -852,11 +852,11 @@ select a certificate collection or just use all collections or don't use let's e
852
852
 
853
853
  select a credential from the central credential storage. The user manages the credentials in the admin settings
854
854
  (Settings → Credentials), and the adapter configuration only stores the ID of the selected credential
855
- (like `system.credentials.ai.main`) in the given attribute.
855
+ (like `system.credentials.anthropic`) in the given attribute.
856
856
 
857
- | Property | Description |
858
- |------------------|-------------------------------------------------------------------------------------------------------------|
859
- | `credentialType` | show only credentials of this type: `email`, `cloud`, `ai` or `custom`. If not defined, all credentials are listed |
857
+ | Property | Description |
858
+ |------------------|--------------------------------------------------------------------------------------------------------------------|
859
+ | `credentialType | show only credentials of this type: `email`, `cloud`, `ai` or `custom`. If not defined, all credentials are listed |
860
860
 
861
861
  Example:
862
862
 
@@ -871,13 +871,16 @@ Example:
871
871
  }
872
872
  ```
873
873
 
874
- In the adapter, read and decrypt the credential with `@iobroker/adapter-core`:
874
+ Every credential has one of two forms: `login` (a `login` and a `password` field) or `key`
875
+ (a single `key` field, e.g. an API key). In the adapter, read and decrypt the credential
876
+ with `@iobroker/adapter-core`:
875
877
 
876
878
  ```typescript
877
879
  import { Credentials } from '@iobroker/adapter-core';
878
880
 
879
- const cred = await Credentials.getCredentials<Credentials.EmailCredentials>(this, this.config.credentialId);
880
- // cred.values.host, cred.values.user, cred.values.password (already decrypted), ...
881
+ const cred = await Credentials.getCredentials<Credentials.LoginPasswordCredentials>(this, this.config.credentialId);
882
+ // cred.values.login, cred.values.password (already decrypted)
883
+ // or for the key form: Credentials.KeyCredentials -> cred.values.key
881
884
  ```
882
885
 
883
886
  ### `custom`
@@ -1810,7 +1813,7 @@ The schema is used here: https://github.com/SchemaStore/schemastore/blob/6da29cd
1810
1813
  ### **WORK IN PROGRESS**
1811
1814
  -->
1812
1815
  ## Changelog
1813
- ### 8.4.6 (2026-06-06)
1816
+ ### 8.4.7 (2026-06-07)
1814
1817
  - (@GermanBluefox) Added credential component
1815
1818
 
1816
1819
  ### 8.4.5 (2026-05-30)
@@ -4,11 +4,14 @@ import ConfigGeneric, { type ConfigGenericProps, type ConfigGenericState } from
4
4
  interface ConfigCredentialSelectProps extends ConfigGenericProps {
5
5
  schema: ConfigItemCredentialSelect;
6
6
  }
7
+ interface CredentialSelectOption {
8
+ label: string;
9
+ value: string;
10
+ /** Icon of the credential (data URL from `common.icon`) */
11
+ icon?: string;
12
+ }
7
13
  interface ConfigCredentialSelectState extends ConfigGenericState {
8
- selectOptions?: {
9
- label: string;
10
- value: string;
11
- }[];
14
+ selectOptions?: CredentialSelectOption[];
12
15
  }
13
16
  export default class ConfigCredentialSelect extends ConfigGeneric<ConfigCredentialSelectProps, ConfigCredentialSelectState> {
14
17
  componentDidMount(): Promise<void>;
@@ -1,26 +1,33 @@
1
1
  import React from 'react';
2
2
  import { InputLabel, MenuItem, FormControl, Select, FormHelperText } from '@mui/material';
3
- import { I18n } from '@iobroker/adapter-react-v5';
3
+ import { I18n, Icon } from '@iobroker/adapter-react-v5';
4
4
  import ConfigGeneric from './ConfigGeneric';
5
5
  /** Prefix of all credential object IDs. Synchronized with `@iobroker/adapter-core` (src/credentials.ts) */
6
6
  const CREDENTIALS_PREFIX = 'system.credentials.';
7
+ function renderCredentialItem(option, label, anyIcon) {
8
+ return (React.createElement("span", { style: { display: 'flex', alignItems: 'center', gap: 8 } },
9
+ option?.icon ? (React.createElement(Icon, { src: option.icon, style: { width: 20, height: 20 } })) : anyIcon ? (
10
+ // if at least one option has an icon, keep the labels aligned
11
+ React.createElement("span", { style: { width: 20, height: 20, flexShrink: 0 } })) : null,
12
+ label));
13
+ }
7
14
  export default class ConfigCredentialSelect extends ConfigGeneric {
8
15
  async componentDidMount() {
9
16
  await super.componentDidMount();
10
17
  const value = ConfigGeneric.getValue(this.props.data, this.props.attr);
11
18
  // Credentials are managed in admin: Settings -> Credentials.
12
- // They are stored as objects "system.credentials.<type>.<name>".
13
- const prefix = this.props.schema.credentialType
14
- ? `${CREDENTIALS_PREFIX}${this.props.schema.credentialType}.`
15
- : CREDENTIALS_PREFIX;
19
+ // They are stored as objects "system.credentials.<name>" with the category in native.type.
16
20
  let selectOptions = [];
17
21
  try {
18
- const objs = await this.props.oContext.socket.getObjectViewSystem('config', prefix, `${prefix}香`);
22
+ const objs = await this.props.oContext.socket.getObjectViewSystem('config', CREDENTIALS_PREFIX, `${CREDENTIALS_PREFIX}香`);
19
23
  selectOptions = Object.values(objs)
20
- .filter(obj => !!obj)
24
+ .filter(obj => !!obj &&
25
+ (!this.props.schema.credentialType ||
26
+ obj.native?.type === this.props.schema.credentialType))
21
27
  .map(obj => ({
22
28
  label: ConfigCredentialSelect.getCredentialName(obj),
23
29
  value: obj._id,
30
+ icon: typeof obj.common?.icon === 'string' ? obj.common.icon : undefined,
24
31
  }))
25
32
  .sort((a, b) => a.label.localeCompare(b.label));
26
33
  }
@@ -48,11 +55,13 @@ export default class ConfigCredentialSelect extends ConfigGeneric {
48
55
  const item = this.state.selectOptions?.find(_item => _item.value === this.state.value);
49
56
  // The stored value could point to a meanwhile deleted credential
50
57
  const unknownValue = this.state.value && this.state.value !== ConfigGeneric.NONE_VALUE && !item ? this.state.value : null;
58
+ // if at least one option has an icon, options without icon get a placeholder for alignment
59
+ const anyIcon = this.state.selectOptions.some(option => !!option.icon);
51
60
  return (React.createElement(FormControl, { style: { width: '100%' }, variant: "standard" },
52
61
  this.props.schema.label ? (React.createElement(InputLabel, { shrink: true }, this.getText(this.props.schema.label))) : null,
53
62
  React.createElement(Select, { variant: "standard", error: !!error || !!unknownValue, displayEmpty: true, disabled: !!disabled, value: this.state.value || ConfigGeneric.NONE_VALUE, renderValue: () => unknownValue
54
63
  ? unknownValue
55
- : this.getText(item?.label, this.props.schema.noTranslation !== false), onChange: e => this.setState({ value: e.target.value === ConfigGeneric.NONE_VALUE ? '' : e.target.value }, () => this.onChange(this.props.attr, this.state.value)) }, this.state.selectOptions?.map(item_ => (React.createElement(MenuItem, { key: item_.value, value: item_.value, style: item_.value === ConfigGeneric.NONE_VALUE ? { opacity: 0.5 } : {} }, this.getText(item_.label, this.props.schema.noTranslation !== false))))),
64
+ : renderCredentialItem(item, this.getText(item?.label, this.props.schema.noTranslation !== false), anyIcon), onChange: e => this.setState({ value: e.target.value === ConfigGeneric.NONE_VALUE ? '' : e.target.value }, () => this.onChange(this.props.attr, this.state.value)) }, this.state.selectOptions?.map(item_ => (React.createElement(MenuItem, { key: item_.value, value: item_.value, style: item_.value === ConfigGeneric.NONE_VALUE ? { opacity: 0.5 } : {} }, renderCredentialItem(item_, this.getText(item_.label, this.props.schema.noTranslation !== false), anyIcon))))),
56
65
  this.props.schema.help ? (React.createElement(FormHelperText, null, this.renderHelp(this.props.schema.help, this.props.schema.helpLink, this.props.schema.noTranslation))) : null));
57
66
  }
58
67
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ConfigCredentialSelect.js","sourceRoot":"./src/","sources":["JsonConfigComponent/ConfigCredentialSelect.tsx"],"names":[],"mappings":"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","sourcesContent":["import React, { type JSX } from 'react';\n\nimport { InputLabel, MenuItem, FormControl, Select, FormHelperText } from '@mui/material';\n\nimport { I18n } from '@iobroker/adapter-react-v5';\nimport type { ConfigItemCredentialSelect } from '../types';\nimport ConfigGeneric, { type ConfigGenericProps, type ConfigGenericState } from './ConfigGeneric';\n\n/** Prefix of all credential object IDs. Synchronized with `@iobroker/adapter-core` (src/credentials.ts) */\nconst CREDENTIALS_PREFIX = 'system.credentials.';\n\ninterface ConfigCredentialSelectProps extends ConfigGenericProps {\n schema: ConfigItemCredentialSelect;\n}\n\ninterface ConfigCredentialSelectState extends ConfigGenericState {\n selectOptions?: { label: string; value: string }[];\n}\n\nexport default class ConfigCredentialSelect extends ConfigGeneric<\n ConfigCredentialSelectProps,\n ConfigCredentialSelectState\n> {\n async componentDidMount(): Promise<void> {\n await super.componentDidMount();\n const value = ConfigGeneric.getValue(this.props.data, this.props.attr);\n\n // Credentials are managed in admin: Settings -> Credentials.\n // They are stored as objects \"system.credentials.<type>.<name>\".\n const prefix = this.props.schema.credentialType\n ? `${CREDENTIALS_PREFIX}${this.props.schema.credentialType}.`\n : CREDENTIALS_PREFIX;\n\n let selectOptions: { label: string; value: string }[] = [];\n try {\n const objs = await this.props.oContext.socket.getObjectViewSystem('config', prefix, `${prefix}香`);\n selectOptions = Object.values(objs)\n .filter(obj => !!obj)\n .map(obj => ({\n label: ConfigCredentialSelect.getCredentialName(obj as ioBroker.Object),\n value: obj._id,\n }))\n .sort((a, b) => a.label.localeCompare(b.label));\n } catch (e) {\n console.error(`Cannot read credentials: ${e}`);\n }\n\n selectOptions.unshift({ label: I18n.t(ConfigGeneric.NONE_LABEL), value: ConfigGeneric.NONE_VALUE });\n\n this.setState({ value, selectOptions });\n }\n\n static getCredentialName(obj: ioBroker.Object): string {\n const name = obj.common?.name;\n let text: string;\n if (name && typeof name === 'object') {\n text = name[I18n.getLanguage()] || name.en || Object.values(name)[0] || '';\n } else {\n text = (name as string) || '';\n }\n return text || obj._id.substring(CREDENTIALS_PREFIX.length);\n }\n\n renderItem(error: unknown, disabled: boolean /* , defaultValue */): JSX.Element | null {\n if (!this.state.selectOptions) {\n return null;\n }\n\n const item = this.state.selectOptions?.find(_item => _item.value === this.state.value);\n // The stored value could point to a meanwhile deleted credential\n const unknownValue =\n this.state.value && this.state.value !== ConfigGeneric.NONE_VALUE && !item ? this.state.value : null;\n\n return (\n <FormControl\n style={{ width: '100%' }}\n variant=\"standard\"\n >\n {this.props.schema.label ? (\n <InputLabel shrink>{this.getText(this.props.schema.label)}</InputLabel>\n ) : null}\n <Select\n variant=\"standard\"\n error={!!error || !!unknownValue}\n displayEmpty\n disabled={!!disabled}\n value={this.state.value || ConfigGeneric.NONE_VALUE}\n renderValue={() =>\n unknownValue\n ? unknownValue\n : this.getText(item?.label, this.props.schema.noTranslation !== false)\n }\n onChange={e =>\n this.setState(\n { value: e.target.value === ConfigGeneric.NONE_VALUE ? '' : e.target.value },\n () => this.onChange(this.props.attr, this.state.value),\n )\n }\n >\n {this.state.selectOptions?.map(item_ => (\n <MenuItem\n key={item_.value}\n value={item_.value}\n style={item_.value === ConfigGeneric.NONE_VALUE ? { opacity: 0.5 } : {}}\n >\n {this.getText(item_.label, this.props.schema.noTranslation !== false)}\n </MenuItem>\n ))}\n </Select>\n {this.props.schema.help ? (\n <FormHelperText>\n {this.renderHelp(\n this.props.schema.help,\n this.props.schema.helpLink,\n this.props.schema.noTranslation,\n )}\n </FormHelperText>\n ) : null}\n </FormControl>\n );\n }\n}\n"]}
1
+ {"version":3,"file":"ConfigCredentialSelect.js","sourceRoot":"./src/","sources":["JsonConfigComponent/ConfigCredentialSelect.tsx"],"names":[],"mappings":"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","sourcesContent":["import React, { type JSX } from 'react';\n\nimport { InputLabel, MenuItem, FormControl, Select, FormHelperText } from '@mui/material';\n\nimport { I18n, Icon } from '@iobroker/adapter-react-v5';\nimport type { ConfigItemCredentialSelect } from '../types';\nimport ConfigGeneric, { type ConfigGenericProps, type ConfigGenericState } from './ConfigGeneric';\n\n/** Prefix of all credential object IDs. Synchronized with `@iobroker/adapter-core` (src/credentials.ts) */\nconst CREDENTIALS_PREFIX = 'system.credentials.';\n\ninterface ConfigCredentialSelectProps extends ConfigGenericProps {\n schema: ConfigItemCredentialSelect;\n}\n\ninterface CredentialSelectOption {\n label: string;\n value: string;\n /** Icon of the credential (data URL from `common.icon`) */\n icon?: string;\n}\n\ninterface ConfigCredentialSelectState extends ConfigGenericState {\n selectOptions?: CredentialSelectOption[];\n}\n\nfunction renderCredentialItem(\n option: CredentialSelectOption | undefined,\n label: string,\n anyIcon: boolean,\n): JSX.Element {\n return (\n <span style={{ display: 'flex', alignItems: 'center', gap: 8 }}>\n {option?.icon ? (\n <Icon\n src={option.icon}\n style={{ width: 20, height: 20 }}\n />\n ) : anyIcon ? (\n // if at least one option has an icon, keep the labels aligned\n <span style={{ width: 20, height: 20, flexShrink: 0 }} />\n ) : null}\n {label}\n </span>\n );\n}\n\nexport default class ConfigCredentialSelect extends ConfigGeneric<\n ConfigCredentialSelectProps,\n ConfigCredentialSelectState\n> {\n async componentDidMount(): Promise<void> {\n await super.componentDidMount();\n const value = ConfigGeneric.getValue(this.props.data, this.props.attr);\n\n // Credentials are managed in admin: Settings -> Credentials.\n // They are stored as objects \"system.credentials.<name>\" with the category in native.type.\n let selectOptions: CredentialSelectOption[] = [];\n try {\n const objs = await this.props.oContext.socket.getObjectViewSystem(\n 'config',\n CREDENTIALS_PREFIX,\n `${CREDENTIALS_PREFIX}香`,\n );\n selectOptions = Object.values(objs)\n .filter(\n obj =>\n !!obj &&\n (!this.props.schema.credentialType ||\n (obj.native as Record<string, any>)?.type === this.props.schema.credentialType),\n )\n .map(obj => ({\n label: ConfigCredentialSelect.getCredentialName(obj as ioBroker.Object),\n value: obj._id,\n icon: typeof obj.common?.icon === 'string' ? obj.common.icon : undefined,\n }))\n .sort((a, b) => a.label.localeCompare(b.label));\n } catch (e) {\n console.error(`Cannot read credentials: ${e}`);\n }\n\n selectOptions.unshift({ label: I18n.t(ConfigGeneric.NONE_LABEL), value: ConfigGeneric.NONE_VALUE });\n\n this.setState({ value, selectOptions });\n }\n\n static getCredentialName(obj: ioBroker.Object): string {\n const name = obj.common?.name;\n let text: string;\n if (name && typeof name === 'object') {\n text = name[I18n.getLanguage()] || name.en || Object.values(name)[0] || '';\n } else {\n text = (name as string) || '';\n }\n return text || obj._id.substring(CREDENTIALS_PREFIX.length);\n }\n\n renderItem(error: unknown, disabled: boolean /* , defaultValue */): JSX.Element | null {\n if (!this.state.selectOptions) {\n return null;\n }\n\n const item = this.state.selectOptions?.find(_item => _item.value === this.state.value);\n // The stored value could point to a meanwhile deleted credential\n const unknownValue =\n this.state.value && this.state.value !== ConfigGeneric.NONE_VALUE && !item ? this.state.value : null;\n // if at least one option has an icon, options without icon get a placeholder for alignment\n const anyIcon = this.state.selectOptions.some(option => !!option.icon);\n\n return (\n <FormControl\n style={{ width: '100%' }}\n variant=\"standard\"\n >\n {this.props.schema.label ? (\n <InputLabel shrink>{this.getText(this.props.schema.label)}</InputLabel>\n ) : null}\n <Select\n variant=\"standard\"\n error={!!error || !!unknownValue}\n displayEmpty\n disabled={!!disabled}\n value={this.state.value || ConfigGeneric.NONE_VALUE}\n renderValue={() =>\n unknownValue\n ? unknownValue\n : renderCredentialItem(\n item,\n this.getText(item?.label, this.props.schema.noTranslation !== false),\n anyIcon,\n )\n }\n onChange={e =>\n this.setState(\n { value: e.target.value === ConfigGeneric.NONE_VALUE ? '' : e.target.value },\n () => this.onChange(this.props.attr, this.state.value),\n )\n }\n >\n {this.state.selectOptions?.map(item_ => (\n <MenuItem\n key={item_.value}\n value={item_.value}\n style={item_.value === ConfigGeneric.NONE_VALUE ? { opacity: 0.5 } : {}}\n >\n {renderCredentialItem(\n item_,\n this.getText(item_.label, this.props.schema.noTranslation !== false),\n anyIcon,\n )}\n </MenuItem>\n ))}\n </Select>\n {this.props.schema.help ? (\n <FormHelperText>\n {this.renderHelp(\n this.props.schema.help,\n this.props.schema.helpLink,\n this.props.schema.noTranslation,\n )}\n </FormHelperText>\n ) : null}\n </FormControl>\n );\n }\n}\n"]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@iobroker/json-config",
3
3
  "description": "This package contains the ioBroker JSON config UI components",
4
- "version": "8.4.6",
4
+ "version": "8.4.7",
5
5
  "author": {
6
6
  "name": "bluefox",
7
7
  "email": "dogafox@gmail.com"