@c8y/ngx-components 1024.21.3 → 1024.21.5

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.
Files changed (29) hide show
  1. package/fesm2022/c8y-ngx-components-ai-agents-scada.mjs +82 -19
  2. package/fesm2022/c8y-ngx-components-ai-agents-scada.mjs.map +1 -1
  3. package/fesm2022/{c8y-ngx-components-computed-asset-properties-c8y-ngx-components-computed-asset-properties-1WsTSnO_.mjs → c8y-ngx-components-computed-asset-properties-c8y-ngx-components-computed-asset-properties-B0EYpohd.mjs} +31 -17
  4. package/fesm2022/c8y-ngx-components-computed-asset-properties-c8y-ngx-components-computed-asset-properties-B0EYpohd.mjs.map +1 -0
  5. package/fesm2022/{c8y-ngx-components-computed-asset-properties-fieldbus-item-status-config.component-C3KZGqlc.mjs → c8y-ngx-components-computed-asset-properties-fieldbus-item-status-config.component-BqbzREl7.mjs} +2 -2
  6. package/fesm2022/{c8y-ngx-components-computed-asset-properties-fieldbus-item-status-config.component-C3KZGqlc.mjs.map → c8y-ngx-components-computed-asset-properties-fieldbus-item-status-config.component-BqbzREl7.mjs.map} +1 -1
  7. package/fesm2022/c8y-ngx-components-computed-asset-properties-last-measurement-config.component-d3JeKEr4.mjs +108 -0
  8. package/fesm2022/c8y-ngx-components-computed-asset-properties-last-measurement-config.component-d3JeKEr4.mjs.map +1 -0
  9. package/fesm2022/c8y-ngx-components-computed-asset-properties.mjs +1 -1
  10. package/fesm2022/c8y-ngx-components-widgets-implementations-scada.mjs +93 -9
  11. package/fesm2022/c8y-ngx-components-widgets-implementations-scada.mjs.map +1 -1
  12. package/locales/de.po +0 -3
  13. package/locales/es.po +0 -3
  14. package/locales/fr.po +0 -3
  15. package/locales/ja_JP.po +0 -3
  16. package/locales/ko.po +0 -3
  17. package/locales/locales.pot +9 -0
  18. package/locales/nl.po +0 -3
  19. package/locales/pl.po +0 -3
  20. package/locales/pt_BR.po +0 -3
  21. package/locales/zh_CN.po +0 -3
  22. package/locales/zh_TW.po +0 -3
  23. package/package.json +1 -1
  24. package/types/c8y-ngx-components-ai-agents-scada.d.ts.map +1 -1
  25. package/types/c8y-ngx-components-widgets-implementations-scada.d.ts +28 -2
  26. package/types/c8y-ngx-components-widgets-implementations-scada.d.ts.map +1 -1
  27. package/fesm2022/c8y-ngx-components-computed-asset-properties-c8y-ngx-components-computed-asset-properties-1WsTSnO_.mjs.map +0 -1
  28. package/fesm2022/c8y-ngx-components-computed-asset-properties-last-measurement-config.component-DOmwNU6m.mjs +0 -86
  29. package/fesm2022/c8y-ngx-components-computed-asset-properties-last-measurement-config.component-DOmwNU6m.mjs.map +0 -1
@@ -189,13 +189,13 @@ const INITIAL_SVG_CODE = `<?xml version="1.0" encoding="utf-8"?>
189
189
  <text x="60" y="495" class="label">Examples:</text>
190
190
 
191
191
  <text x="60" y="525" class="label">Device name:</text>
192
- <text x="180" y="525" class="placeholder">\${this.c8yScadaValues?.deviceName || '-'}</text>
192
+ <text x="180" y="525" class="placeholder">\${this.c8yScadaValues?.deviceName ?? '-'}</text>
193
193
 
194
194
  <text x="60" y="550" class="label">Temperature:</text>
195
- <text x="180" y="550" class="placeholder">\${this.c8yScadaValues?.temperature || '-'} °C</text>
195
+ <text x="180" y="550" class="placeholder">\${this.c8yScadaValues?.temperature ?? '-'} °C</text>
196
196
 
197
197
  <text x="60" y="575" class="label">Status:</text>
198
- <text x="180" y="575" class="placeholder">\${this.c8yScadaValues?.status || '-'}</text>
198
+ <text x="180" y="575" class="placeholder">\${this.c8yScadaValues?.status ?? '-'}</text>
199
199
 
200
200
  <!-- STEP 4: Advanced Customization -->
201
201
  <circle cx="55" cy="630" r="15" class="step-circle" />
@@ -453,6 +453,13 @@ function restoreLitExpressions(svg, litExpressions) {
453
453
  return `\${${expr}}`;
454
454
  });
455
455
  }
456
+ /**
457
+ * The expression inserted for a text turned into a placeholder. It shows `[name]` until the
458
+ * placeholder has a value; `??` keeps a value of `0` visible.
459
+ */
460
+ function placeholderExpressionWithFallback(placeholderName) {
461
+ return `\${this.c8yScadaValues?.${placeholderName} ?? '[${placeholderName}]'}`;
462
+ }
456
463
  /**
457
464
  * Generates Lit web component code for rendering SCADA SVG elements.
458
465
  *
@@ -600,6 +607,7 @@ export default class ScadaElement extends LitElement {
600
607
  }`;
601
608
  }
602
609
 
610
+ const LAST_MEASUREMENT = 'lastMeasurement';
603
611
  class ScadaWidgetConfigService {
604
612
  constructor() {
605
613
  this.widgetConfigService = inject(WidgetConfigService);
@@ -618,6 +626,8 @@ class ScadaWidgetConfigService {
618
626
  if (!migratedConfig.config?.htmlWidgetConfig) {
619
627
  migratedConfig = await this.updateConfigWithSvgCode(migratedConfig, INITIAL_SVG_CODE);
620
628
  }
629
+ this.addKeyPathToSavedLegacyMappings(migratedConfig);
630
+ this.addRawValueToSavedLegacyLastMeasurements(migratedConfig);
621
631
  return migratedConfig;
622
632
  }
623
633
  save(config) {
@@ -740,6 +750,65 @@ class ScadaWidgetConfigService {
740
750
  }
741
751
  config.config.mappings = newMappings;
742
752
  }
753
+ /**
754
+ * A widget migrated and saved before the migration set `keyPath` is never migrated again, so
755
+ * its nested property mappings get it on load. It comes from the stored 1.0 mapping, or from
756
+ * splitting the dotted `name` the migration built from it.
757
+ */
758
+ addKeyPathToSavedLegacyMappings(config) {
759
+ if (!config.config?.htmlWidgetConfig?.config?.legacy) {
760
+ return;
761
+ }
762
+ for (const [placeholder, mapping] of Object.entries(config.config.mappings || {})) {
763
+ const property = mapping?.assetProperty;
764
+ const isNestedPropertyWithoutKeyPath = property && !property.computed && !('keyPath' in property) && property.name?.includes('.');
765
+ if (!isNestedPropertyWithoutKeyPath) {
766
+ continue;
767
+ }
768
+ const legacyKeyPath = config.mapping?.[placeholder]?.keyPath;
769
+ const keyPath = Array.isArray(legacyKeyPath) && legacyKeyPath.join('.') === property.name
770
+ ? [...legacyKeyPath]
771
+ : property.name.split('.');
772
+ mapping.assetProperty = { ...property, keyPath };
773
+ }
774
+ }
775
+ /**
776
+ * A widget migrated and saved before the migration set `rawValue` is never migrated again,
777
+ * so its "Last measurement" mappings get it on load.
778
+ */
779
+ addRawValueToSavedLegacyLastMeasurements(config) {
780
+ if (!config.config?.htmlWidgetConfig?.config?.legacy) {
781
+ return;
782
+ }
783
+ for (const [placeholder, mapping] of Object.entries(config.config.mappings || {})) {
784
+ const legacyMapping = config.mapping?.[placeholder];
785
+ if (this.isUnchangedMigratedLastMeasurement(mapping?.assetProperty, legacyMapping)) {
786
+ mapping.assetProperty = {
787
+ ...mapping.assetProperty,
788
+ config: { ...mapping.assetProperty.config, rawValue: true }
789
+ };
790
+ }
791
+ }
792
+ }
793
+ /**
794
+ * True while the mapping still holds the "Last measurement" it was migrated from, and nobody
795
+ * has chosen its formatting since.
796
+ */
797
+ isUnchangedMigratedLastMeasurement(property, legacyMapping) {
798
+ const propertyConfig = property?.config;
799
+ return (!!property?.computed &&
800
+ property.name === LAST_MEASUREMENT &&
801
+ !!propertyConfig?._id &&
802
+ propertyConfig._id === legacyMapping?.config?._id &&
803
+ !('rawValue' in propertyConfig));
804
+ }
805
+ /**
806
+ * SCADA 1.0 drawings compare the measured value as the device sent it. A rounded string
807
+ * reads differently: `"0.00"` is truthy in `ng-if="LangHL"`, where `0` is not.
808
+ */
809
+ withRawValueForLastMeasurement(computedPropertyName, config) {
810
+ return computedPropertyName === LAST_MEASUREMENT ? { ...config, rawValue: true } : config;
811
+ }
743
812
  /**
744
813
  * Removes hardcoded width and height attributes from the root SVG element.
745
814
  *
@@ -866,9 +935,13 @@ class ScadaWidgetConfigService {
866
935
  const binary = await this.inventoryBinary.download(binaryId);
867
936
  const svgCode = await binary.text();
868
937
  const mappings = {};
869
- for (const key of Object.keys(config.mapping)) {
870
- mappings[key] = {
871
- assetProperty: await this.migrateProperty(config.mapping[key], config.deviceIds[key])
938
+ const legacyMappings = config.mapping;
939
+ for (const [placeholder, legacyProperty] of Object.entries(legacyMappings)) {
940
+ const isUnmapped = !legacyProperty;
941
+ mappings[placeholder] = {
942
+ assetProperty: isUnmapped
943
+ ? null
944
+ : await this.migrateProperty(legacyProperty, config.deviceIds[placeholder])
872
945
  };
873
946
  }
874
947
  return {
@@ -915,7 +988,7 @@ class ScadaWidgetConfigService {
915
988
  active: true,
916
989
  temporary: true,
917
990
  contextAssetId: assetId,
918
- config: legacyProperty.config,
991
+ config: this.withRawValueForLastMeasurement(computedPropertyName, legacyProperty.config),
919
992
  asset: {
920
993
  id: asset.id,
921
994
  name: asset.name
@@ -947,6 +1020,8 @@ class ScadaWidgetConfigService {
947
1020
  c8y_JsonSchema: {
948
1021
  properties: buildJsonSchema(legacyProperty.keyPath, legacyProperty.label, legacyProperty.type)
949
1022
  },
1023
+ // Without `keyPath`, the dotted `name` is looked up as a single top-level key.
1024
+ keyPath: legacyProperty.keyPath,
950
1025
  name: legacyProperty.keyPath.join('.'),
951
1026
  active: true,
952
1027
  label: legacyProperty.label,
@@ -1543,7 +1618,7 @@ class ScadaWidgetViewComponent {
1543
1618
  this.scadaWidgetService.getSvgComputedStyling(this.svgDisplaySettings());
1544
1619
  }
1545
1620
  if (this.legacyScopeRef) {
1546
- Object.assign(this.legacyScopeRef, scadaValues);
1621
+ Object.assign(this.legacyScopeRef, this.withEmptyStringForMissingValues(scadaValues));
1547
1622
  Object.assign(this.legacyScopeRef, scadaFunctions);
1548
1623
  }
1549
1624
  },
@@ -1558,6 +1633,15 @@ class ScadaWidgetViewComponent {
1558
1633
  }
1559
1634
  });
1560
1635
  }
1636
+ /**
1637
+ * SCADA 1.0 resolved a placeholder without a value to `''`, and its drawings rely on it:
1638
+ * `ng-if="state==0"` matches `''` but not `undefined`. Lit drawings keep `undefined`.
1639
+ */
1640
+ withEmptyStringForMissingValues(values) {
1641
+ const placeholders = Object.keys(this.effectiveConfig()?.config?.mappings ?? {});
1642
+ const emptyValues = Object.fromEntries(placeholders.map(placeholder => [placeholder, '']));
1643
+ return { ...emptyValues, ...values };
1644
+ }
1561
1645
  handleFetchError(err) {
1562
1646
  this.alerts?.addAlerts(new DynamicComponentAlert({
1563
1647
  type: 'warning',
@@ -1639,7 +1723,7 @@ class ScadaWidgetAdvancedEditorComponent {
1639
1723
  const proposedName = textContent && textContent.trim() ? camelCase(textContent) : '';
1640
1724
  try {
1641
1725
  const placeholderName = await this.confirmPlaceholderName(proposedName);
1642
- node.textContent = `\${${this.PROPERTY_PREFIX}?.${placeholderName} || '[${placeholderName}]'}`;
1726
+ node.textContent = placeholderExpressionWithFallback(placeholderName);
1643
1727
  node.classList.remove('potential-placeholder');
1644
1728
  }
1645
1729
  catch (e) {