Skip to content

Commit c259daf

Browse files
authored
Merge pull request #776 from PHOENIXCONTACT/feature/launcher-config
Using ConfigManager in Launcher
2 parents 6fc7ddb + c4a54d8 commit c259daf

File tree

11 files changed

+154
-59
lines changed

11 files changed

+154
-59
lines changed

docs/articles/launcher/Launcher.md

Lines changed: 32 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,51 @@
11
# Launcher
22

3-
## Sorting
3+
## Configuration
44

5-
To sort your modules in the launcher, you can use the `SortIndex` property within the `appsettings.json`. This property allows you to define the order of modules by assigning them an index value. Modules with lower index values will appear before those with higher values.
5+
The launcher generates a config file named `Moryx.Launcher.LauncherConfig.json` in your configuration directory. This file contains settings for the launcher, including module sort-indices and external modules.
6+
7+
### Sorting
8+
9+
To sort your modules in the launcher, you can use the `ModuleSortIndices` property. This property allows you to define the order of modules by assigning them an index value. Modules with lower index values will appear before those with higher values.
610

711
````json
812
{
9-
"Shell": {
10-
"SortIndex": {
11-
"moduleA-route": 10,
12-
"moduleB-route": 20,
13-
"moduleC-route": 15
13+
"ModuleSortIndices": [
14+
{
15+
"Route": "Orders",
16+
"SortIndex": 1
17+
},
18+
{
19+
"Route": "WorkerSupport",
20+
"SortIndex": 10
21+
},
22+
{
23+
"Route": "example",
24+
"SortIndex": 100
1425
}
15-
}
26+
]
1627
}
28+
1729
````
1830

19-
## External Modules
31+
### External Modules
2032

21-
To define external modules in the launcher configuration, you can use the `ExternalModules` property within the `appsettings.json`. This allows you to specify
33+
To define external modules in the launcher configuration, you can use the `ExternalModules` property. This allows you to specify
2234
modules that should be loaded from external sources rather than being bundled with your application.
2335

2436
External modules are integrated with the `<embed>` tag; the external web-page must support being embedded in an iframe.
2537

2638
````json
2739
{
28-
"Shell": {
29-
"SortIndex": {
30-
"example": 10
31-
},
32-
"ExternalModules": [
33-
{
34-
"Route": "example",
35-
"Title": "Example",
36-
"Url": "http://www.example.com",
37-
"Icon": "globe"
38-
}
39-
]
40-
}
40+
"ExternalModules": [
41+
{
42+
"Title": "Example",
43+
"Url": "http://www.example.com",
44+
"Icon": "globe",
45+
"Description": "Example description of the external module.",
46+
"Route": "example"
47+
}
48+
]
4149
}
50+
4251
````

docs/migrations/v8_to_v10.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ With MORYX 10, several changes have been made to the data model to improve perfo
4444
- If you were using `ProductFileEntity`, consider using alternative storage solutions such as file systems or dedicated file storage services to manage product-related files.
4545
- The `ProductFile` was removed completely.
4646

47+
## Launcher
48+
49+
- The `SortIndex` configuration was moved to the `Moryx.Launcher.LauncherConfig.json` configuration file. Refer to the [Launcher](/docs/articles/launcher/Launcher.md) documentation for more information.
50+
4751
## Removal of Modules-Analytics
4852

4953
The analytics module was doing nothing and the web module was replaced by supporting external modules in `Launcher`. Its now supported to embed external web-pages into the shell. Refer to the [Launcher](/docs/articles/launcher/Launcher.md) documentation for more information.

src/Moryx.Launcher/Config/ExternalModuleConfig.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright (c) 2025, Phoenix Contact GmbH & Co. KG
22
// Licensed under the Apache License, Version 2.0
33

4-
namespace Moryx.Launcher.Config;
4+
namespace Moryx.Launcher;
55

66
/// <summary>
77
/// Configuration for an external module
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright (c) 2025, Phoenix Contact GmbH & Co. KG
2+
// Licensed under the Apache License, Version 2.0
3+
4+
using System.Runtime.Serialization;
5+
using Moryx.Configuration;
6+
7+
namespace Moryx.Launcher;
8+
9+
/// <summary>
10+
/// Configuration for the launcher
11+
/// </summary>
12+
[DataContract]
13+
public class LauncherConfig : ConfigBase
14+
{
15+
/// <summary>
16+
/// Sort indices for modules
17+
/// </summary>
18+
[DataMember]
19+
public ModuleSortIndexConfig[] ModuleSortIndices { get; set; }
20+
21+
/// <summary>
22+
/// Definition of external modules
23+
/// </summary>
24+
[DataMember]
25+
public ExternalModuleConfig[] ExternalModules { get; set; }
26+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright (c) 2025, Phoenix Contact GmbH & Co. KG
2+
// Licensed under the Apache License, Version 2.0
3+
4+
using System.Runtime.Serialization;
5+
6+
namespace Moryx.Launcher;
7+
8+
/// <summary>
9+
/// Configuration for module sort indices
10+
/// </summary>
11+
[DataContract]
12+
public class ModuleSortIndexConfig
13+
{
14+
/// <summary>
15+
/// Base route of the module
16+
/// </summary>
17+
[DataMember]
18+
public string Route { get; set; }
19+
20+
/// <summary>
21+
/// Target index of the module in the shell navigation
22+
/// </summary>
23+
[DataMember]
24+
public int SortIndex { get; set; }
25+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
2+
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=config/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

src/Moryx.Launcher/Pages/External.cshtml

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
@page "{*_}"
22
@using Microsoft.AspNetCore.Authorization
33
@using Microsoft.Extensions.Configuration
4+
@using Moryx.Configuration
45
@using Moryx.Launcher
5-
@using Moryx.Launcher.Config
6-
@inject IConfiguration _configuration
6+
@inject IConfigManager _configManager
77
@{
88
ViewData["Title"] = "External";
99
ViewData["BaseRef"] = "external";
@@ -18,8 +18,7 @@
1818
if (routeValues.Count > 1)
1919
externalRouteName = routeValues["_"]?.ToString();
2020

21-
var externalModuleConfigs = _configuration.GetSection("Shell:ExternalModules").Get<ExternalModuleConfig[]>();
22-
21+
var externalModuleConfigs = _configManager.GetConfiguration<LauncherConfig>().ExternalModules;
2322
var config = externalModuleConfigs.FirstOrDefault(c => c.Route.Equals(externalRouteName));
2423

2524
if (config != null)

src/Moryx.Launcher/ShellNavigator.cs

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,38 +7,36 @@
77
using Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure;
88
using Microsoft.AspNetCore.Routing;
99
using Microsoft.Extensions.Caching.Memory;
10-
using Microsoft.Extensions.Configuration;
1110
using Microsoft.Extensions.Logging;
1211
using Microsoft.Extensions.Options;
1312
using Moryx.Asp.Integration;
13+
using Moryx.Configuration;
1414
using Moryx.Identity;
15-
using Moryx.Launcher.Config;
1615
using Moryx.Tools;
1716

1817
namespace Moryx.Launcher
1918
{
2019
/// <inheritdoc />
2120
public class ShellNavigator : IShellNavigator
2221
{
23-
private readonly IConfiguration _configuration;
2422
private readonly ILogger _logger;
2523
private readonly MoryxAccessManagementClient _client;
2624
private readonly IReadOnlyList<ExternalModuleItem> _externalModules;
25+
private readonly LauncherConfig _launcherConfig;
2726

28-
public EndpointDataSource EndpointsDataSource { get; }
29-
public PageLoader PageLoader { get; }
27+
private readonly EndpointDataSource _endpointsDataSource;
28+
private readonly PageLoader _pageLoader;
3029

3130
public ShellNavigator(
3231
EndpointDataSource endpointsDataSource,
3332
PageLoader pageLoader,
34-
IConfiguration configuration,
33+
IConfigManager configManager,
3534
IOptionsMonitor<MoryxIdentityOptions> options,
3635
IMemoryCache memoryCache,
3736
ILoggerFactory logger)
3837
{
39-
EndpointsDataSource = endpointsDataSource;
40-
PageLoader = pageLoader;
41-
_configuration = configuration;
38+
_endpointsDataSource = endpointsDataSource;
39+
_pageLoader = pageLoader;
4240
_logger = logger.CreateLogger(nameof(ShellNavigator));
4341
if (options?.CurrentValue?.BaseAddress is not null)
4442
{
@@ -49,18 +47,19 @@ public ShellNavigator(
4947
);
5048
}
5149

50+
_launcherConfig = GetConfiguration(configManager);
5251
_externalModules = LoadExternalModules();
5352
}
5453

5554
/// <inheritdoc />
5655
public async Task<IReadOnlyList<ModuleItem>> GetModuleItems(HttpContext context)
5756
{
5857
// Filter pages
59-
var pageActionDescriptors = EndpointsDataSource.Endpoints.SelectMany(endpoint => endpoint.Metadata)
58+
var pageActionDescriptors = _endpointsDataSource.Endpoints.SelectMany(endpoint => endpoint.Metadata)
6059
.OfType<PageActionDescriptor>()
6160
.Where(pad => !pad.ViewEnginePath.Contains("Index"));
6261
// Retrieve all Metadata
63-
var compiledPageActionDescriptors = await Task.WhenAll(pageActionDescriptors.Select(async pad => await PageLoader.LoadAsync(pad, EndpointMetadataCollection.Empty)));
62+
var compiledPageActionDescriptors = await Task.WhenAll(pageActionDescriptors.Select(async pad => await _pageLoader.LoadAsync(pad, EndpointMetadataCollection.Empty)));
6463

6564
// Filter permission
6665
if (context is not null && _client is not null)
@@ -87,16 +86,22 @@ public async Task<IReadOnlyList<ModuleItem>> GetModuleItems(HttpContext context)
8786
foreach (var module in modules.OrderBy(m => m.Title))
8887
{
8988
var route = module is ExternalModuleItem ? module.Route.Replace("external/", "") : module.Route;
90-
var sortIndex = _configuration[$"Shell:SortIndex:{route}"];
91-
module.SortIndex = int.TryParse(sortIndex, out var customIndex) ? customIndex : index++;
89+
var indexConfig = _launcherConfig.ModuleSortIndices.FirstOrDefault(m => m.Route == route);
90+
if (indexConfig != null)
91+
{
92+
module.SortIndex = indexConfig.SortIndex;
93+
continue;
94+
}
95+
96+
module.SortIndex = index++;
9297
}
9398

9499
return modules;
95100
}
96101

97102
private ExternalModuleItem[] LoadExternalModules()
98103
{
99-
var externalModuleConfigs = _configuration.GetSection("Shell:ExternalModules").Get<ExternalModuleConfig[]>();
104+
var externalModuleConfigs = _launcherConfig.ExternalModules;
100105
return externalModuleConfigs?.Select(CreateExternalModuleItem).ToArray() ?? [];
101106
}
102107

@@ -127,8 +132,22 @@ private static WebModuleItem CreateWebModuleItem(CompiledPageActionDescriptor pa
127132
Icon = webModuleAttribute.Icon,
128133
Description = pageActionDescriptor.PageTypeInfo.GetDescription() ?? "",
129134
Category = webModuleAttribute.Category,
130-
EventStream = streamAttribute?.EventStreamUrl ?? null
135+
EventStream = streamAttribute?.EventStreamUrl
131136
};
132137
}
138+
139+
private LauncherConfig GetConfiguration(IConfigManager configManager)
140+
{
141+
var launcherConfig = configManager.GetConfiguration<LauncherConfig>();
142+
143+
// If configuration is generated, save it back to persist defaults
144+
if (launcherConfig.ConfigState == ConfigState.Generated)
145+
{
146+
launcherConfig.ConfigState = ConfigState.Valid;
147+
configManager.SaveConfiguration(_launcherConfig);
148+
}
149+
150+
return launcherConfig;
151+
}
133152
}
134153
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{
2+
"ModuleSortIndices": [
3+
{
4+
"Route": "Orders",
5+
"SortIndex": 1
6+
},
7+
{
8+
"Route": "WorkerSupport",
9+
"SortIndex": 10
10+
},
11+
{
12+
"Route": "example",
13+
"SortIndex": 100
14+
}
15+
],
16+
"ExternalModules": [
17+
{
18+
"Title": "Example",
19+
"Url": "http://www.example.com",
20+
"Icon": "globe",
21+
"Description": "Example description of the external module.",
22+
"Route": "example"
23+
}
24+
],
25+
"ConfigState": "Valid"
26+
}

src/StartProject.Asp/Properties/launchSettings.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,4 @@
1010
}
1111
}
1212
}
13-
}
13+
}

0 commit comments

Comments
 (0)