Skip to content

Commit c66e914

Browse files
committed
fix: resolve api key issues
1 parent 79d4ae1 commit c66e914

10 files changed

Lines changed: 288 additions & 52 deletions

File tree

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
schema: spec-driven
2+
created: 2026-06-17
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
## Context
2+
3+
The Maps widget `getProperties()` function in `Maps.editorConfig.ts` contains branching logic for `platform === "desktop"` vs `"web"`. This separation no longer exists — Studio Pro uses a single editor. The `advanced` boolean property gates visibility of `mapProvider` and marker style options, adding unnecessary friction. The static `apiKey` string field should be deprecated in favor of the expression-based `apiKeyExp`.
4+
5+
Current `getProperties()` flow:
6+
7+
```
8+
if (platform === "desktop") {
9+
// show/hide apiKey vs apiKeyExp (static priority)
10+
// hide "advanced" prop itself
11+
} else {
12+
// show/hide apiKey vs apiKeyExp (expression priority)
13+
// gate mapProvider and marker styles behind "advanced"
14+
}
15+
```
16+
17+
## Goals / Non-Goals
18+
19+
**Goals:**
20+
21+
- Single unified property visibility logic (no platform branching)
22+
- Remove `advanced` property — all options always visible
23+
- `apiKeyExp` always visible (never hidden)
24+
- Deprecation warning when `apiKey` (static string) is used
25+
26+
**Non-Goals:**
27+
28+
- Removing `apiKey` from XML entirely (backward compatibility — existing apps use it)
29+
- Changing runtime behavior (how the key is resolved at runtime stays the same)
30+
- Touching `geodecodeApiKey` / `geodecodeApiKeyExp` show/hide logic beyond removing platform branching
31+
32+
## Decisions
33+
34+
**1. Remove `advanced` from XML entirely**
35+
36+
The property serves no purpose once all options are always shown. Removing it from XML means Mendix will ignore any persisted value in existing apps — no migration needed. The widget typings will regenerate without it.
37+
38+
Alternative considered: Keep in XML but ignore it. Rejected — dead props confuse future developers.
39+
40+
**2. Unified apiKey/apiKeyExp visibility logic**
41+
42+
After removing platform branching, the logic becomes:
43+
44+
- `apiKeyExp` is always shown (never hidden)
45+
- Hide `apiKey` if falsy, show otherwise
46+
47+
This preserves backward compat: users with only `apiKey` set still see their field, plus the new expression field.
48+
49+
**3. Deprecation via `check()` warning**
50+
51+
Add a `"warning"` severity problem in the `check()` function when `values.apiKey` is non-empty. Message directs users to use `apiKeyExp` instead. Using `check()` (not `getProperties()`) because that's where validation problems are surfaced in Studio Pro.
52+
53+
**4. Marker style visibility — always show**
54+
55+
Currently gated behind `!values.advanced` on web platform. After removing `advanced`, `markerStyle`/`customMarker` and `markerStyleDynamic`/`customMarkerDynamic` are always visible (conditional on `markerStyle === "image"` for the custom image field stays).
56+
57+
## Risks / Trade-offs
58+
59+
- **[Breaking: `advanced` prop removed]** → Existing apps with `advanced: true` silently lose the property. No runtime impact — it was editor-only. Studio Pro handles missing props gracefully.
60+
- **[Deprecation noise]** → Users with static `apiKey` see a new warning. This is intentional nudge, not an error. Using `"warning"` severity, not `"error"`.
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
## Why
2+
3+
The Maps widget editor config still has a web/desktop platform split that no longer exists in modern Studio Pro. This adds dead code paths and hides useful properties (like `mapProvider`) behind an "advanced" toggle that confuses users. Additionally, `apiKey` (static string) should be deprecated in favor of `apiKeyExp` (expression) for flexibility.
4+
5+
## What Changes
6+
7+
- **BREAKING**: Remove the `advanced` boolean property from XML and editor config. Properties gated behind it (`mapProvider`, marker styles) become always visible.
8+
- Remove the platform `"web"` / `"desktop"` conditional branching in `getProperties()`. All property visibility logic uses a single unified path.
9+
- Stop hiding `apiKeyExp` — it is always shown as the primary API key field.
10+
- Add a deprecation warning when the static `apiKey` property has a value, guiding users to use the `apiKeyExp` expression field instead.
11+
12+
## Capabilities
13+
14+
### New Capabilities
15+
16+
- `editor-config-simplified`: Unified property visibility logic without platform branching, removal of `advanced` toggle, and `apiKey` deprecation warning.
17+
18+
### Modified Capabilities
19+
20+
_(none — no existing specs)_
21+
22+
## Impact
23+
24+
- `src/Maps.xml` — remove `advanced` property definition
25+
- `src/Maps.editorConfig.ts` — rewrite `getProperties()` logic, add deprecation check to `check()`
26+
- `typings/MapsProps.d.ts` — regenerated (loses `advanced` prop)
27+
- Any container/config code referencing `props.advanced` (likely none beyond editor config)
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
## ADDED Requirements
2+
3+
### Requirement: No platform branching in property visibility
4+
5+
The `getProperties()` function SHALL NOT branch on the `platform` parameter. All property visibility logic MUST use a single unified code path.
6+
7+
#### Scenario: Same properties shown regardless of platform argument
8+
9+
- **WHEN** `getProperties()` is called with platform `"web"` or `"desktop"`
10+
- **THEN** the returned properties are identical for both values
11+
12+
### Requirement: Advanced property removed
13+
14+
The widget XML SHALL NOT define an `advanced` property. The editor config SHALL NOT reference `advanced` in any visibility logic.
15+
16+
#### Scenario: mapProvider always visible
17+
18+
- **WHEN** the widget is placed on a page
19+
- **THEN** the `mapProvider` property is visible without any toggle
20+
21+
#### Scenario: Marker style options always visible
22+
23+
- **WHEN** a static or dynamic marker is configured
24+
- **THEN** the `markerStyle` / `markerStyleDynamic` and `customMarker` / `customMarkerDynamic` properties are visible (custom marker still conditional on style being "image")
25+
26+
### Requirement: apiKeyExp always visible
27+
28+
The `apiKeyExp` expression property SHALL never be hidden by `getProperties()`.
29+
30+
#### Scenario: Fresh widget shows expression field
31+
32+
- **WHEN** a new Maps widget is placed on a page with no configuration
33+
- **THEN** `apiKeyExp` is visible to the user
34+
35+
#### Scenario: apiKeyExp visible even when apiKey has value
36+
37+
- **WHEN** `apiKey` (static) has a value set
38+
- **THEN** `apiKeyExp` remains visible
39+
40+
### Requirement: Static apiKey deprecation warning
41+
42+
The `check()` function SHALL return a warning-severity problem when `values.apiKey` is non-empty, informing the user that the static API key is deprecated and `apiKeyExp` (expression) should be used instead.
43+
44+
#### Scenario: Warning shown when static apiKey is set
45+
46+
- **WHEN** `values.apiKey` is a non-empty string
47+
- **THEN** `check()` returns a problem with `severity: "warning"` on property `"apiKey"` with a message indicating deprecation
48+
49+
#### Scenario: No warning when apiKey is empty
50+
51+
- **WHEN** `values.apiKey` is empty or undefined
52+
- **THEN** no deprecation warning is returned
53+
54+
### Requirement: apiKey hidden when empty
55+
56+
The static `apiKey` field SHALL be hidden when it has no value. It SHALL only be shown when the user already has a value configured (for backward compatibility).
57+
58+
#### Scenario: apiKey hidden when empty
59+
60+
- **WHEN** `values.apiKey` is falsy (empty or undefined)
61+
- **THEN** `apiKey` is hidden from the properties panel
62+
63+
#### Scenario: apiKey visible when it has a value
64+
65+
- **WHEN** `values.apiKey` is a non-empty string
66+
- **THEN** `apiKey` is visible (for backward compatibility with existing configurations)
67+
68+
## REMOVED Requirements
69+
70+
### Requirement: Platform-specific property visibility
71+
72+
**Reason**: Web/desktop platform separation no longer exists in Studio Pro.
73+
**Migration**: All properties use unified visibility logic. No user action needed.
74+
75+
### Requirement: Advanced toggle for map options
76+
77+
**Reason**: Unnecessary UX friction. All options should be directly accessible.
78+
**Migration**: Properties previously gated behind `advanced` are now always visible. Existing widgets with `advanced: true` will continue to work — the property is simply ignored.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
## 1. Remove `advanced` property
2+
3+
- [x] 1.1 Remove `advanced` property definition from `src/Maps.xml`
4+
- [x] 1.2 Remove `advanced` from `mock-container-props.ts`
5+
6+
## 2. Rewrite `getProperties()` in `src/Maps.editorConfig.ts`
7+
8+
- [x] 2.1 Remove the `platform` parameter and all platform branching (`if (platform === "desktop") / else`)
9+
- [x] 2.2 Unify apiKey/apiKeyExp visibility: always show `apiKeyExp`, hide `apiKey` when it's falsy (only show if user has a value set)
10+
- [x] 2.3 Remove all `advanced`-gated hiding logic (mapProvider, markerStyle, customMarker)
11+
- [x] 2.4 Keep remaining conditional logic: Google-only props, OpenStreet hides apiKey, address/latLng toggle, customMarker conditional on style "image", geodecode keys hidden when no address markers
12+
13+
## 3. Add deprecation warning
14+
15+
- [x] 3.1 In `check()`, add a warning-severity problem when `values.apiKey` is non-empty, message: "Static API key is deprecated. Use the 'API Key' expression instead."
16+
17+
## 4. Cleanup and verify
18+
19+
- [x] 4.1 Regenerate typings (ensure `advanced` is gone from `MapsPreviewProps` and `MapsContainerProps`)
20+
- [x] 4.2 Run lint and fix any issues
21+
- [x] 4.3 Run tests and update snapshots if needed
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
## Purpose
2+
3+
Editor config property visibility logic for the Maps widget. Defines how properties are shown/hidden in Studio Pro based on widget configuration state.
4+
5+
## Requirements
6+
7+
### Requirement: No platform branching in property visibility
8+
9+
The `getProperties()` function SHALL NOT branch on the `platform` parameter. All property visibility logic MUST use a single unified code path.
10+
11+
#### Scenario: Same properties shown regardless of platform argument
12+
13+
- **WHEN** `getProperties()` is called with platform `"web"` or `"desktop"`
14+
- **THEN** the returned properties are identical for both values
15+
16+
### Requirement: Advanced property removed
17+
18+
The widget XML SHALL NOT define an `advanced` property. The editor config SHALL NOT reference `advanced` in any visibility logic.
19+
20+
#### Scenario: mapProvider always visible
21+
22+
- **WHEN** the widget is placed on a page
23+
- **THEN** the `mapProvider` property is visible without any toggle
24+
25+
#### Scenario: Marker style options always visible
26+
27+
- **WHEN** a static or dynamic marker is configured
28+
- **THEN** the `markerStyle` / `markerStyleDynamic` and `customMarker` / `customMarkerDynamic` properties are visible (custom marker still conditional on style being "image")
29+
30+
### Requirement: apiKeyExp always visible
31+
32+
The `apiKeyExp` expression property SHALL never be hidden by `getProperties()`, except when `mapProvider` is `"openStreet"` (OpenStreetMap requires no API key).
33+
34+
#### Scenario: Fresh widget shows expression field
35+
36+
- **WHEN** a new Maps widget is placed on a page with no configuration
37+
- **THEN** `apiKeyExp` is visible to the user
38+
39+
#### Scenario: apiKeyExp visible even when apiKey has value
40+
41+
- **WHEN** `apiKey` (static) has a value set
42+
- **THEN** `apiKeyExp` remains visible
43+
44+
#### Scenario: apiKeyExp hidden for OpenStreetMap
45+
46+
- **WHEN** `mapProvider` is `"openStreet"`
47+
- **THEN** both `apiKey` and `apiKeyExp` are hidden (no API key needed)
48+
49+
### Requirement: Static apiKey deprecation warning
50+
51+
The `check()` function SHALL return a warning-severity problem when `values.apiKey` is non-empty, informing the user that the static API key is deprecated and `apiKeyExp` (expression) should be used instead.
52+
53+
#### Scenario: Warning shown when static apiKey is set
54+
55+
- **WHEN** `values.apiKey` is a non-empty string
56+
- **THEN** `check()` returns a problem with `severity: "warning"` on property `"apiKey"` with a message indicating deprecation
57+
58+
#### Scenario: No warning when apiKey is empty
59+
60+
- **WHEN** `values.apiKey` is empty or undefined
61+
- **THEN** no deprecation warning is returned
62+
63+
### Requirement: apiKey hidden when empty
64+
65+
The static `apiKey` field SHALL be hidden when it has no value. It SHALL only be shown when the user already has a value configured (for backward compatibility).
66+
67+
#### Scenario: apiKey hidden when empty
68+
69+
- **WHEN** `values.apiKey` is falsy (empty or undefined)
70+
- **THEN** `apiKey` is hidden from the properties panel
71+
72+
#### Scenario: apiKey visible when it has a value
73+
74+
- **WHEN** `values.apiKey` is a non-empty string
75+
- **THEN** `apiKey` is visible (for backward compatibility with existing configurations)

packages/pluggableWidgets/maps-web/src/Maps.editorConfig.ts

Lines changed: 25 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,23 @@
1-
import { StructurePreviewProps } from "@mendix/widget-plugin-platform/preview/structure-preview-api";
21
import { hidePropertiesIn, hidePropertyIn, Problem, Properties } from "@mendix/pluggable-widgets-tools";
2+
import { StructurePreviewProps } from "@mendix/widget-plugin-platform/preview/structure-preview-api";
33

44
import { MapsPreviewProps } from "../typings/MapsProps";
55

66
import GoogleMapsSVG from "./assets/GoogleMaps.svg";
7+
import HereMapsSVG from "./assets/HereMaps.svg";
78
import MapboxSVG from "./assets/Mapbox.svg";
89
import OpenStreetMapSVG from "./assets/OpenStreetMap.svg";
9-
import HereMapsSVG from "./assets/HereMaps.svg";
1010

11-
export function getProperties(
12-
values: MapsPreviewProps,
13-
defaultProperties: Properties,
14-
platform: "web" | "desktop"
15-
): Properties {
11+
export function getProperties(values: MapsPreviewProps, defaultProperties: Properties): Properties {
1612
const containsAddress =
1713
values.markers.some(marker => marker.locationType === "address") ||
1814
values.dynamicMarkers.some(marker => marker.locationType === "address");
1915

20-
if (platform === "desktop") {
21-
if (values.apiKey) {
22-
hidePropertyIn(defaultProperties, values, "apiKeyExp");
23-
} else {
24-
hidePropertyIn(defaultProperties, values, "apiKey");
25-
}
26-
if (values.geodecodeApiKey) {
27-
hidePropertyIn(defaultProperties, values, "geodecodeApiKeyExp");
28-
} else {
29-
hidePropertyIn(defaultProperties, values, "geodecodeApiKey");
30-
}
31-
32-
hidePropertyIn(defaultProperties, values, "advanced");
33-
} else {
34-
if (values.apiKeyExp) {
35-
hidePropertyIn(defaultProperties, values, "apiKey");
36-
} else {
37-
hidePropertyIn(defaultProperties, values, "apiKeyExp");
38-
}
39-
if (values.geodecodeApiKeyExp) {
40-
hidePropertyIn(defaultProperties, values, "geodecodeApiKey");
41-
} else {
42-
hidePropertyIn(defaultProperties, values, "geodecodeApiKeyExp");
43-
}
44-
45-
if (!values.advanced) {
46-
hidePropertyIn(defaultProperties, values, "mapProvider");
47-
}
16+
if (!values.apiKey) {
17+
hidePropertyIn(defaultProperties, values, "apiKey");
18+
}
19+
if (!values.geodecodeApiKey) {
20+
hidePropertyIn(defaultProperties, values, "geodecodeApiKey");
4821
}
4922

5023
values.markers.forEach((f, index) => {
@@ -54,10 +27,6 @@ export function getProperties(
5427
} else {
5528
hidePropertyIn(defaultProperties, values, "markers", index, "address");
5629
}
57-
if (platform === "web" && !values.advanced) {
58-
hidePropertyIn(defaultProperties, values, "markers", index, "markerStyle");
59-
hidePropertyIn(defaultProperties, values, "markers", index, "customMarker");
60-
}
6130
if (f.markerStyle === "default") {
6231
hidePropertyIn(defaultProperties, values, "markers", index, "customMarker");
6332
}
@@ -70,10 +39,6 @@ export function getProperties(
7039
} else {
7140
hidePropertyIn(defaultProperties, values, "dynamicMarkers", index, "address");
7241
}
73-
if (platform === "web" && !values.advanced) {
74-
hidePropertyIn(defaultProperties, values, "dynamicMarkers", index, "markerStyleDynamic");
75-
hidePropertyIn(defaultProperties, values, "dynamicMarkers", index, "customMarkerDynamic");
76-
}
7742
if (f.markerStyleDynamic === "default") {
7843
hidePropertyIn(defaultProperties, values, "dynamicMarkers", index, "customMarkerDynamic");
7944
}
@@ -103,6 +68,23 @@ export function getProperties(
10368

10469
export function check(values: MapsPreviewProps): Problem[] {
10570
const errors: Problem[] = [];
71+
72+
if (values.apiKey) {
73+
errors.push({
74+
property: "apiKey",
75+
severity: "warning",
76+
message: "Static API key is deprecated. Use the 'API Key' expression instead."
77+
});
78+
}
79+
80+
if (values.geodecodeApiKey) {
81+
errors.push({
82+
property: "geodecodeApiKey",
83+
severity: "warning",
84+
message: "Static Geo location API key is deprecated. Use the 'Geo location API key' expression instead."
85+
});
86+
}
87+
10688
const containsAddress =
10789
values.markers.some(marker => marker.locationType === "address") ||
10890
values.dynamicMarkers.some(marker => marker.locationType === "address");

packages/pluggableWidgets/maps-web/src/Maps.xml

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,6 @@
88
<properties>
99
<!-- Data source -->
1010
<propertyGroup caption="General">
11-
<propertyGroup caption="General">
12-
<property key="advanced" type="boolean" defaultValue="false">
13-
<caption>Enable advanced options</caption>
14-
<description />
15-
</property>
16-
</propertyGroup>
1711
<propertyGroup caption="Markers">
1812
<property key="markers" type="object" isList="true" required="false">
1913
<caption>Marker</caption>

packages/pluggableWidgets/maps-web/src/utils/mock-container-props.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ export function mockContainerProps(overrides?: Partial<MapsContainerProps>): Map
77
class: "",
88
style: {},
99
tabIndex: 0,
10-
advanced: false,
1110
apiKey: "",
1211
apiKeyExp: { value: "test-api-key" } as DynamicValue<string>,
1312
geodecodeApiKey: "",

0 commit comments

Comments
 (0)