• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

jumpinjackie / mapguide-react-layout / 15160437878

21 May 2025 11:00AM UTC coverage: 21.631% (-42.6%) from 64.24%
15160437878

Pull #1552

github

web-flow
Merge 8b7153d9e into 236e2ea07
Pull Request #1552: Feature/package updates 2505

839 of 1165 branches covered (72.02%)

11 of 151 new or added lines in 25 files covered. (7.28%)

1332 existing lines in 50 files now uncovered.

4794 of 22163 relevant lines covered (21.63%)

6.89 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

6.94
/src/actions/init.ts
1
import { Client } from "../api/client";
1✔
2
import { ReduxDispatch, IMapView, Dictionary } from "../api/common";
3
import {
4
    ApplicationDefinition,
5
    MapConfiguration
6
} from "../api/contracts/fusion";
7
import {
8
    IExternalBaseLayer,
9
    ReduxThunkedAction,
10
    IMapViewer
11
} from "../api/common";
12
import { strIsNullOrEmpty, strReplaceAll } from "../utils/string";
1✔
13
import { IAcknowledgeStartupWarningsAction, IInitAppActionPayload } from './defs';
14
import { ActionType } from '../constants/actions';
1✔
15
import { getViewer } from '../api/runtime';
1✔
16
import { tr } from '../api/i18n';
1✔
17
import { IViewerInitCommand } from './init-command';
18
import { getLayoutCapabilities } from "../api/registry/layout";
1✔
19
import { debug } from "../utils/logger";
1✔
20

21
export function applyInitialBaseLayerVisibility(externalBaseLayers: IExternalBaseLayer[]) {
1✔
22
    if (externalBaseLayers.length > 0) {
×
23
        // First visual base layer, first served
24
        const firstBase = externalBaseLayers.find(bl => bl.kind != "UTFGrid");
×
25
        if (firstBase) {
×
26
            firstBase.visible = true;
×
UNCOV
27
        }
×
28
        // Make all non-visual base layers (ie. UTFGrid) visible
29
        const nonVisuals = externalBaseLayers.filter(bl => bl.kind == "UTFGrid");
×
30
        for (const nv of nonVisuals) {
×
31
            nv.visible = true;
×
UNCOV
32
        }
×
UNCOV
33
    }
×
UNCOV
34
}
×
35

UNCOV
36
function processAndDispatchInitError(error: Error, includeStack: boolean, dispatch: ReduxDispatch, opts: IInitAsyncOptions): void {
×
37
    if (error.stack) {
×
38
        dispatch({
×
UNCOV
39
            type: ActionType.INIT_ERROR,
×
UNCOV
40
            payload: {
×
UNCOV
41
                error: {
×
UNCOV
42
                    message: error.message,
×
UNCOV
43
                    stack: (error.stack || "").split("\n")
×
UNCOV
44
                },
×
UNCOV
45
                includeStack: includeStack,
×
UNCOV
46
                options: opts
×
UNCOV
47
            }
×
UNCOV
48
        });
×
UNCOV
49
    } else {
×
50
        dispatch({
×
UNCOV
51
            type: ActionType.INIT_ERROR,
×
UNCOV
52
            payload: {
×
UNCOV
53
                error: {
×
UNCOV
54
                    message: error.message,
×
UNCOV
55
                    stack: []
×
UNCOV
56
                },
×
UNCOV
57
                includeStack: includeStack,
×
UNCOV
58
                options: opts
×
UNCOV
59
            }
×
UNCOV
60
        });
×
UNCOV
61
    }
×
UNCOV
62
}
×
63

64
export interface IInitAppLayout {
65
    locale: string;
66
    resourceId: string | (() => Promise<ApplicationDefinition>);
67
    externalBaseLayers?: IExternalBaseLayer[];
68
    session?: string;
69
    initialView?: IMapView;
70
    /**
71
     * 
72
     * @since 0.11
73
     * @type {string}
74
     * @memberof IInitAppLayout
75
     */
76
    initialActiveMap?: string;
77
    /**
78
     * 
79
     * @since 0.11
80
     * @type {string[]}
81
     * @memberof IInitAppLayout
82
     */
83
    initialShowLayers?: string[];
84
    /**
85
     * 
86
     * @since 0.11
87
     * @type {string[]}
88
     * @memberof IInitAppLayout
89
     */
90
    initialShowGroups?: string[];
91
    /**
92
     * 
93
     * @since 0.11
94
     * @type {string[]}
95
     * @memberof IInitAppLayout
96
     */
97
    initialHideLayers?: string[];
98
    /**
99
     * 
100
     * @since 0.11
101
     * @type {string[]}
102
     * @memberof IInitAppLayout
103
     */
104
    initialHideGroups?: string[];
105
    onInit?: (viewer: IMapViewer) => void;
106
    /**
107
     * Sets whether feature tooltips should be initially enabled
108
     * 
109
     * @since 0.13
110
     */
111
    featureTooltipsEnabled?: boolean;
112
    /**
113
     * @since 0.14
114
     */
115
    layout?: string;
116
    /**
117
     * @since 0.14.8
118
     */
119
    appSettings?: Dictionary<string> | undefined;
120
}
121

122
/**
123
 * @hidden
124
 */
125
export function normalizeInitPayload(payload: IInitAppActionPayload, layout: string | undefined): IInitAppActionPayload {
1✔
126
    if (!strIsNullOrEmpty(layout)) {
×
127
        const caps = getLayoutCapabilities(layout);
×
128
        if (caps) {
×
129
            if (!caps.hasTaskPane) {
×
130
                debug("Overriding hasTaskPane capability to false");
×
131
                payload.capabilities.hasTaskPane = false;
×
UNCOV
132
            }
×
UNCOV
133
        }
×
UNCOV
134
    }
×
135
    return payload;
×
UNCOV
136
}
×
137

138
export interface IInitAsyncOptions extends IInitAppLayout {
139
    locale: string;
140
}
141

142
let _counter = 0;
1✔
143

144
export function processLayerInMapGroup(map: MapConfiguration, warnings: string[], config: any, appDef: ApplicationDefinition, externalBaseLayers: IExternalBaseLayer[]) {
1✔
145
    switch (map.Type) {
×
UNCOV
146
        case "Google":
×
147
            warnings.push(tr("INIT_WARNING_UNSUPPORTED_GOOGLE_MAPS", config.locale));
×
148
            break;
×
UNCOV
149
        case "VirtualEarth":
×
UNCOV
150
            {
×
151
                //HACK: De-arrayification of arbitrary extension elements
152
                //is shallow (hence name/type is string[]). Do we bother to fix this?
153
                const { name, type } = map.Extension.Options;
×
154
                const sName = Array.isArray(name) ? name[0] : name;
×
155
                const sType = Array.isArray(type) ? type[0] : type;
×
156
                const options: any = {};
×
157
                let bAdd = true;
×
158
                switch (sType) {
×
UNCOV
159
                    case "Aerial":
×
UNCOV
160
                    case "a":
×
161
                        options.imagerySet = "Aerial";
×
162
                        break;
×
UNCOV
163
                    case "AerialWithLabels":
×
164
                        options.imagerySet = "AerialWithLabels";
×
165
                        break;
×
UNCOV
166
                    case "Road":
×
167
                        options.imagerySet = "Road";
×
168
                        break;
×
UNCOV
169
                    default:
×
170
                        bAdd = false;
×
171
                        warnings.push(tr("INIT_WARNING_BING_UNKNOWN_LAYER", config.locale, { type: type }));
×
172
                        break;
×
UNCOV
173
                }
×
174
                if (appDef.Extension.BingMapKey) {
×
175
                    options.key = appDef.Extension.BingMapKey;
×
UNCOV
176
                }
×
UNCOV
177
                else {
×
178
                    bAdd = false;
×
179
                    warnings.push(tr("INIT_WARNING_BING_API_KEY_REQD", config.locale));
×
UNCOV
180
                }
×
181
                if (bAdd) {
×
182
                    externalBaseLayers.push({
×
UNCOV
183
                        name: sName,
×
UNCOV
184
                        kind: "BingMaps",
×
UNCOV
185
                        options: options
×
UNCOV
186
                    });
×
UNCOV
187
                }
×
UNCOV
188
            }
×
189
            break;
×
UNCOV
190
        case "OpenStreetMap":
×
UNCOV
191
            {
×
192
                //HACK: De-arrayification of arbitrary extension elements
193
                //is shallow (hence name/type is string[]). Do we bother to fix this?
194
                const { name, type } = map.Extension.Options;
×
195
                const sName = Array.isArray(name) ? name[0] : name;
×
196
                const sType = Array.isArray(type) ? type[0] : type;
×
197
                const options: any = {};
×
198
                switch (sType) {
×
UNCOV
199
                    case "CycleMap":
×
200
                        options.url = "http://{a-c}.tile.opencyclemap.org/cycle/{z}/{x}/{y}.png";
×
201
                        break;
×
UNCOV
202
                    case "TransportMap":
×
203
                        options.url = "http://tile2.opencyclemap.org/transport/{z}/{x}/{y}.png";
×
204
                        break;
×
UNCOV
205
                }
×
206
                externalBaseLayers.push({
×
UNCOV
207
                    name: sName,
×
UNCOV
208
                    kind: "OSM",
×
UNCOV
209
                    options: options
×
UNCOV
210
                });
×
UNCOV
211
            }
×
212
            break;
×
NEW
213
        case "StadiaMaps":
×
UNCOV
214
        case "Stamen":
×
UNCOV
215
            {
×
216
                //HACK: De-arrayification of arbitrary extension elements
217
                //is shallow (hence name/type is string[]). Do we bother to fix this?
218
                const { name, type } = map.Extension.Options;
×
219
                const sName = Array.isArray(name) ? name[0] : name;
×
220
                const sType = Array.isArray(type) ? type[0] : type;
×
221

NEW
222
                const options: any = {
×
NEW
223
                    layer: sType
×
NEW
224
                };
×
NEW
225
                let bAdd = true;
×
NEW
226
                if (appDef.Extension?.StadiaMapsKey) {
×
NEW
227
                    options.key = appDef.Extension.StadiaMapsKey;
×
NEW
228
                }
×
NEW
229
                else {
×
NEW
230
                    bAdd = false;
×
NEW
231
                    warnings.push(tr("INIT_WARNING_STADIAMAPS_API_KEY_REQD", config.locale));
×
NEW
232
                }
×
NEW
233
                if (bAdd) {
×
NEW
234
                    externalBaseLayers.push({
×
NEW
235
                        name: sName,
×
NEW
236
                        kind: map.Type,
×
NEW
237
                        options: options
×
NEW
238
                    });
×
NEW
239
                }
×
240
            }
×
241
            break;
×
UNCOV
242
        case "UTFGrid":
×
UNCOV
243
            {
×
244
                externalBaseLayers.push({
×
UNCOV
245
                    name: `UTFGridSource${_counter++}`,
×
UNCOV
246
                    kind: "UTFGrid",
×
UNCOV
247
                    options: {
×
UNCOV
248
                        tileJSON: {
×
UNCOV
249
                            scheme: "xyz",
×
UNCOV
250
                            grids: Array.isArray(map.Extension.UrlTemplate) ? [...map.Extension.UrlTemplate] : [map.Extension.UrlTemplate]
×
UNCOV
251
                        }
×
UNCOV
252
                    }
×
UNCOV
253
                })
×
UNCOV
254
            }
×
255
            break;
×
UNCOV
256
        case "XYZDebug":
×
257
            //HACK: De-arrayification of arbitrary extension elements
258
            //is shallow (hence name/type is string[]). Do we bother to fix this?
259
            const { name } = map.Extension.Options;
×
260
            const sName = Array.isArray(name) ? name[0] : name;
×
261
            externalBaseLayers.push({
×
UNCOV
262
                name: sName,
×
UNCOV
263
                kind: "XYZDebug"
×
UNCOV
264
            });
×
265
            break;
×
UNCOV
266
        case "XYZ":
×
UNCOV
267
            {
×
268
                //HACK: De-arrayification of arbitrary extension elements
269
                //is shallow (hence name/type is string[]). Do we bother to fix this?
270
                const { name, type, attributions } = map.Extension.Options;
×
271
                const sName = Array.isArray(name) ? name[0] : name;
×
272
                const sType = Array.isArray(type) ? type[0] : type;
×
273
                let tilePixelRatio = 1;
×
274
                if (map.Extension.Options.tilePixelRatio) {
×
275
                    tilePixelRatio = parseInt(map.Extension.Options.tilePixelRatio[0], 10);
×
UNCOV
276
                }
×
277
                //NOTE: From a fusion appdef, we're expecting placeholder tokens to be in ${this_format} instead of
278
                //{this_format} as the primary consumer is the Fusion viewer that is based on OpenLayers 2
279
                //As we're not using OL2, but OL4+ the expected format is {this_format}, so we need to convert these
280
                //placeholder tokens
281
                const urls = (map.Extension.Options.urls || []).map((s: string) => strReplaceAll(s, "${", "{"));
×
282
                externalBaseLayers.push({
×
UNCOV
283
                    name: sName,
×
UNCOV
284
                    kind: "XYZ",
×
UNCOV
285
                    options: {
×
UNCOV
286
                        layer: sType,
×
UNCOV
287
                        urls,
×
UNCOV
288
                        attributions,
×
UNCOV
289
                        tilePixelRatio
×
UNCOV
290
                    }
×
UNCOV
291
                });
×
UNCOV
292
            }
×
293
            break;
×
UNCOV
294
    }
×
UNCOV
295
}
×
296

297
/**
298
 * Initializes the viewer
299
 *
300
 * @export
301
 * @param {IViewerInitCommand} cmd
302
 * @param {IInitAppLayout} options
303
 * @returns {ReduxThunkedAction}
304
 */
305
export function initLayout(cmd: IViewerInitCommand, options: IInitAppLayout): ReduxThunkedAction {
1✔
306
    const opts: IInitAsyncOptions = { ...options };
×
307
    return (dispatch, getState) => {
×
308
        const args = getState().config;
×
309
        //TODO: Fetch and init the string bundle earlier if "locale" is present
310
        //so the English init messages are seen only for a blink if requesting a
311
        //non-english string bundle
312
        if (args.agentUri && args.agentKind) {
×
313
            const client = new Client(args.agentUri, args.agentKind);
×
314
            cmd.attachClient(client);
×
UNCOV
315
        }
×
316
        cmd.runAsync(options).then(payload => {
×
317
            let initPayload = payload;
×
318
            if (opts.initialView) {
×
319
                initPayload.initialView = {
×
UNCOV
320
                    ...opts.initialView
×
UNCOV
321
                };
×
UNCOV
322
            }
×
323
            if (opts.initialActiveMap) {
×
324
                initPayload.activeMapName = opts.initialActiveMap;
×
UNCOV
325
            }
×
326
            initPayload.initialHideGroups = opts.initialHideGroups;
×
327
            initPayload.initialHideLayers = opts.initialHideLayers;
×
328
            initPayload.initialShowGroups = opts.initialShowGroups;
×
329
            initPayload.initialShowLayers = opts.initialShowLayers;
×
330
            initPayload.featureTooltipsEnabled = opts.featureTooltipsEnabled;
×
331
            // Merge in appSettings from loaded appDef, any setting in appDef
332
            // already specified at viewer mount will be overwritten
333
            const appSettings = opts.appSettings ?? {};
×
334
            const inAppSettings = payload.appSettings ?? {};
×
335
            for (const k in inAppSettings) {
×
336
                appSettings[k] = inAppSettings[k];
×
UNCOV
337
            }
×
338
            initPayload.appSettings = appSettings;
×
339
            dispatch({
×
UNCOV
340
                type: ActionType.INIT_APP,
×
UNCOV
341
                payload
×
UNCOV
342
            });
×
343
            if (options.onInit) {
×
344
                const viewer = getViewer();
×
345
                if (viewer) {
×
346
                    options.onInit(viewer);
×
UNCOV
347
                }
×
UNCOV
348
            }
×
UNCOV
349
        }).catch(err => {
×
350
            processAndDispatchInitError(err, false, dispatch, opts);
×
UNCOV
351
        })
×
UNCOV
352
    };
×
UNCOV
353
}
×
354

355
export function acknowledgeInitWarnings(): IAcknowledgeStartupWarningsAction {
1✔
356
    return {
1✔
357
        type: ActionType.INIT_ACKNOWLEDGE_WARNINGS
1✔
358
    }
1✔
359
}
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc