From e6d6bcb90acbe727cf0cfe7457478590ce6f53b4 Mon Sep 17 00:00:00 2001 From: Michael Hoffmeister Date: Mon, 23 Dec 2024 12:06:15 +0100 Subject: [PATCH] * update before refactor ProgressChanged --- .../AdminShellCollections.cs | 10 +++ .../Extensions/ExtendEnvironment.cs | 15 ++++ .../AasxPluginOptionsBase.cs | 17 +++- src/AasxPackageExplorer/App.xaml.cs | 1 - .../MainWindow.CommandBindings.cs | 81 +++++++++++++++++- src/AasxPackageExplorer/MainWindow.xaml.cs | 77 ++++++++++++----- src/AasxPackageExplorer/debug.MIHO.script | 1 + .../options-debug.MIHO.json | 8 +- src/AasxPackageLogic/DispEditHelperModules.cs | 4 + .../DispEditHelperSammModules.cs | 2 +- src/AasxPackageLogic/ExplorerMenuFactory.cs | 4 +- src/AasxPackageLogic/IExecuteMainCommand.cs | 13 +++ src/AasxPackageLogic/Options.cs | 8 +- .../PackageCentral/PackageContainerFactory.cs | 5 ++ .../PackageContainerHttpRepoSubset.cs | 83 ++++++++++++++++++- src/AasxPackageLogic/Plugins.cs | 4 + src/AasxPackageLogic/VisualAasxElements.cs | 39 ++++++++- .../PackageContainerListOfListControl.xaml.cs | 66 ++++++++++++--- 18 files changed, 391 insertions(+), 47 deletions(-) create mode 100644 src/AasxPackageLogic/IExecuteMainCommand.cs diff --git a/src/AasxCsharpLibrary/AdminShellCollections.cs b/src/AasxCsharpLibrary/AdminShellCollections.cs index b93c0f03..838211ff 100644 --- a/src/AasxCsharpLibrary/AdminShellCollections.cs +++ b/src/AasxCsharpLibrary/AdminShellCollections.cs @@ -39,6 +39,16 @@ public void Add(K key, V value) dict.Add(key, new List { value }); } + public void AddIfValueIsNew(K key, V value) + { + if (dict.TryGetValue(key, out var list)) + { + if (!list.Contains(value)) + list.Add(value); + } + else + dict.Add(key, new List { value }); + } public void Remove(K key) { if (dict.ContainsKey(key)) diff --git a/src/AasxCsharpLibrary/Extensions/ExtendEnvironment.cs b/src/AasxCsharpLibrary/Extensions/ExtendEnvironment.cs index d8670225..bd37a999 100644 --- a/src/AasxCsharpLibrary/Extensions/ExtendEnvironment.cs +++ b/src/AasxCsharpLibrary/Extensions/ExtendEnvironment.cs @@ -1071,6 +1071,21 @@ public static IEnumerable FindAllSemanticIdsForAas( return refs; } + /// + /// Warning: very inefficient! + /// + public static IEnumerable FindAllReferencedSemanticIds( + this AasCore.Aas3_0.IEnvironment env) + { + // unique set of references + var refs = new List(); + + foreach (var aas in env.AllAssetAdministrationShells()) + refs.AddRange(env.FindAllSemanticIdsForAas(aas)); + + return refs; + } + /// /// Warning: very inefficient! /// diff --git a/src/AasxIntegrationBase/AasxPluginOptionsBase.cs b/src/AasxIntegrationBase/AasxPluginOptionsBase.cs index c1fde47e..d9f84b95 100644 --- a/src/AasxIntegrationBase/AasxPluginOptionsBase.cs +++ b/src/AasxIntegrationBase/AasxPluginOptionsBase.cs @@ -23,6 +23,20 @@ This source code may use other Open Source software components (see LICENSE.txt) namespace AasxIntegrationBase { + + /// + /// With a lot of reluctance, this forms a global variable to be exchanged among all plugins. + /// Note: as not all plugins do have default options, this is the only way to make plugin + /// behaviour configurable by main application. + /// + public static class AasxPluginsGlobal + { + /// + /// Only check the value (id) field of keys of semanticId for Submodels. + /// + public static bool SubmodelCheckOnlyId = false; + } + /// /// Base class for an options record. This is a piece of options information, which is /// associated with an id of a Submodel template. @@ -249,13 +263,12 @@ public AasxPluginLookupOptionsBase( } #endif - private string GenerateIndexKey(Aas.IKey key) { if (key == null) return null; var k = new Aas.Key(key.Type, key.Value); - var ndx = k?.ToStringExtended(); + var ndx = k?.ToStringExtended(format: AasxPluginsGlobal.SubmodelCheckOnlyId ? 2 : 0); return ndx; } diff --git a/src/AasxPackageExplorer/App.xaml.cs b/src/AasxPackageExplorer/App.xaml.cs index be754d24..743934bf 100644 --- a/src/AasxPackageExplorer/App.xaml.cs +++ b/src/AasxPackageExplorer/App.xaml.cs @@ -88,7 +88,6 @@ public static OptionsInformation InferOptions(string exePath, string[] args) var loadedPlugins = Plugins.TryActivatePlugins(pluginDllInfos); Plugins.TrySetOptionsForPlugins(pluginDllInfos, loadedPlugins); - return loadedPlugins; } diff --git a/src/AasxPackageExplorer/MainWindow.CommandBindings.cs b/src/AasxPackageExplorer/MainWindow.CommandBindings.cs index 2d8c19e2..916f8b15 100644 --- a/src/AasxPackageExplorer/MainWindow.CommandBindings.cs +++ b/src/AasxPackageExplorer/MainWindow.CommandBindings.cs @@ -33,12 +33,12 @@ This source code may use other Open Source software components (see LICENSE.txt) using Aas = AasCore.Aas3_0; namespace AasxPackageExplorer -{ +{ /// /// This partial class contains all command bindings, such as for the main menu, in order to reduce the /// complexity of MainWindow.xaml.cs /// - public partial class MainWindow : Window, IFlyoutProvider + public partial class MainWindow : Window, IFlyoutProvider, IExecuteMainCommand { private string lastFnForInitialDirectory = null; @@ -49,7 +49,6 @@ public partial class MainWindow : Window, IFlyoutProvider //// //// .AddWpf\(name: "\5", header: "\1", inputGesture: "\3", \4\) - public void RememberForInitialDirectory(string fn) { this.lastFnForInitialDirectory = fn; @@ -97,6 +96,82 @@ public void CommandExecution_RedrawAll() /// Set to true, if the application shall be shut down via script /// public bool ScriptModeShutdown = false; + + public async Task ExecuteMainMenuCommand(string menuItemName, params object[] args) + { + if (menuItemName?.HasContent() != true) + { + Log.Singleton.Error("MainWindow execute menu command: menu item name missing!"); + return -1; + } + + // name of tool, find it + var foundMenu = this.GetMainMenu(); + var mi = foundMenu.FindName(menuItemName); + if (mi == null) + { + foundMenu = this.GetDynamicMenu(); + mi = foundMenu.FindName(menuItemName); + } + if (mi == null) + { + Log.Singleton.Error($"MainWindow execute menu command: menu item name invalid: {menuItemName}"); + return -1; + } + + // create a ticket + var ticket = new AasxMenuActionTicket() + { + MenuItem = mi, + ScriptMode = true, + ArgValue = new AasxMenuArgDictionary() + }; + + // go thru the remaining arguments and find arg names and values + var argi = 0; + while (args != null && argi < args.Length) + { + // get arg name + if (!(args[argi] is string argname)) + { + Log.Singleton.Error($"MainWindow execute menu command: Argument at index {argi} is " + + $"not string type for argument name."); + return -1; + } + + // find argname? + var ad = mi.ArgDefs?.Find(argname); + if (ad == null) + { + Log.Singleton.Error($"MainWindow execute menu command: Argument at index {argi} is " + + $"not valid argument name."); + return -1; + } + + // create arg value (not available is okay) + object av = null; + if (argi + 1 < args.Length) + av = args[argi + 1]; + + // into ticket + ticket.ArgValue.Add(ad, av); + + // 2 forward! + argi += 2; + } + + // invoke action + await foundMenu.ActivateAction(mi, ticket); + + // perform UI updates if required + if (ticket.UiLambdaAction != null && !(ticket.UiLambdaAction is AnyUiLambdaActionNone)) + { + // add to "normal" event quoue + this.AddWishForToplevelAction(ticket.UiLambdaAction); + } + + return 0; + } private async Task CommandBinding_GeneralDispatch( string cmd, diff --git a/src/AasxPackageExplorer/MainWindow.xaml.cs b/src/AasxPackageExplorer/MainWindow.xaml.cs index 4b2ed638..c6592a95 100644 --- a/src/AasxPackageExplorer/MainWindow.xaml.cs +++ b/src/AasxPackageExplorer/MainWindow.xaml.cs @@ -404,6 +404,7 @@ public void UiLoadPackageWithNew( if (info == null) info = loadLocalFilename; Log.Singleton.Info("Loading new AASX from: {0} as auxiliary {1} ..", info, onlyAuxiliary); + if (!packItem.Load(PackageCentral, loadLocalFilename, loadLocalFilename, overrideLoadResident: true, PackageContainerOptionsBase.CreateDefault(Options.Curr))) @@ -965,6 +966,7 @@ private async void Window_Loaded(object sender, RoutedEventArgs e) RepoListControl.PackageCentral = PackageCentral; RepoListControl.FlyoutProvider = this; RepoListControl.ManageVisuElems = DisplayElements; + RepoListControl.ExecuteMainCommand = this; this.UiShowRepositories(visible: false); // event viewer @@ -1011,26 +1013,63 @@ private async void Window_Loaded(object sender, RoutedEventArgs e) if (repo is PackageContainerListHttpRestRepository restRepo) { - var fetchContext = new PackageContainerHttpRepoSubsetFetchContext() + // find a specific location + if (PackageContainerHttpRepoSubset.IsValidUriAnyMatch(fi?.Location)) { - Record = new ConnectExtendedRecord() + // try load that specific location + // check if load fresh or aggregate + if (PackageCentral.Main is AdminShellPackageDynamicFetchEnv) { - BaseType = ConnectExtendedRecord.BaseTypeEnum.Repository, - BaseAddress = restRepo.Endpoint?.ToString() + // load aggregate + Log.Singleton.Info("Aggregating location {0} ..", fi.Location); + var res = await UiSearchRepoAndExtendEnvironmentAsync( + PackageCentral.Main, + fullItemLocation: fi.Location, + trySelect: true); + + // error? + if (res == null) + Log.Singleton.Error("Not able to access location {0}", fi.Location); + + // in any case, stop here + return; + } + else + { + // load + Log.Singleton.Info("Switching to location {0} ..", fi.Location); + UiLoadPackageWithNew(PackageCentral.MainItem, null, + fi.Location, onlyAuxiliary: false, preserveEditMode: true); + + // in any case, stop here + return; } - }; - - // refer to (static) function - var res = await DispEditHelperEntities.ExecuteUiForFetchOfElements( - PackageCentral, DisplayContext, - ticket : null, - mainWindow: this, - fetchContext: fetchContext, - preserveEditMode: true, - doEditNewRecord: true, - doCheckTainted: true, - doFetchGoNext: false, - doFetchExec: true); + } + + // if not a specific location is available, display general dialogue + if (true) + { + var fetchContext = new PackageContainerHttpRepoSubsetFetchContext() + { + Record = new ConnectExtendedRecord() + { + BaseType = ConnectExtendedRecord.BaseTypeEnum.Repository, + BaseAddress = restRepo.Endpoint?.ToString() + } + }; + + // refer to (static) function + var res = await DispEditHelperEntities.ExecuteUiForFetchOfElements( + PackageCentral, DisplayContext, + ticket: null, + mainWindow: this, + fetchContext: fetchContext, + preserveEditMode: true, + doEditNewRecord: true, + doCheckTainted: true, + doFetchGoNext: false, + doFetchExec: true); + } } // @@ -1766,7 +1805,7 @@ private void UiHandleReRenderAnyUiInEntityPanel( AdminShellPackageEnvBase packEnv, Aas.IReference workRef = null, string fullItemLocation = null, - bool tryDisplay = false) + bool trySelect = false) { await Task.Yield(); @@ -1841,7 +1880,7 @@ private void UiHandleReRenderAnyUiInEntityPanel( var newIdf = newIdfs.FirstOrDefault(); // display - if (tryDisplay) + if (trySelect) { var veFound = this.DisplayElements.SearchVisualElementOnMainDataObject(newIdf, alsoDereferenceObjects: true); if (veFound != null) diff --git a/src/AasxPackageExplorer/debug.MIHO.script b/src/AasxPackageExplorer/debug.MIHO.script index cb304c0e..5ef369c6 100644 --- a/src/AasxPackageExplorer/debug.MIHO.script +++ b/src/AasxPackageExplorer/debug.MIHO.script @@ -10,6 +10,7 @@ // Tool("exportsmtasciidoc", "File", "C:\\HOMI\\Develop\\Aasx\\repo\\new.zip", "AntoraStyle", "true"); Tool("editkey"); // Tool("createrepofromapi", "BaseAddress", "http://localhost:5001/api/v3.0/", "BaseType", "Repository"); +Tool("connectextended", "BaseAddress", "http://smt-repo.admin-shell-io.com/api/v3.0", "BaseType", "Repository", "AasId", "https://admin-shell.io/idta/aas/DigitalNameplate/3/0", "AutoLoadOnDemand", "false", "AutoLoadCds", "true"); // Tool("connectextended", "BaseAddress", "http://localhost:5001/api/v3.0/", "BaseType", "Repository", "GetSingleAas", "false", "GetAllAas", "true", "PageLimit", "99", "AutoLoadOnDemand", "false"); // Tool("connectextended", "BaseAddress", "http://localhost:5001/api/v3.0/", "BaseType", "Repository", "GetSingleAas", "true", "AasId", "http://smart.festo.com/id/demo-box/aas/instance/99920202206560529000071817", "AutoLoadOnDemand", "false"); // Tool("connectextended", "BaseAddress", "https://eis-data.aas-voyager.com/", "BaseType", "Repository", "GetSingleAas", "true", "PageLimit", "2", "AutoLoadOnDemand", "false", "AasId", "https://new.abb.com/products/de/2CSF204101R1400/aas"); diff --git a/src/AasxPackageExplorer/options-debug.MIHO.json b/src/AasxPackageExplorer/options-debug.MIHO.json index 4236bdd3..e5b8228c 100644 --- a/src/AasxPackageExplorer/options-debug.MIHO.json +++ b/src/AasxPackageExplorer/options-debug.MIHO.json @@ -50,10 +50,11 @@ // "AasxToLoad": "C:\\Users\\homi0002\\Desktop\\tmp\\Syn2tecMachine_P2518_AAS__V3_DL2.aasx", // "AasxToLoad": "C:\\MIHO\\Develop\\Aasx\\repo\\Syn2tecMachine_P2518_AAS__V3_DL2.aasx", // "AasxToLoad": "C:\\HOMI\\Develop\\Aasx\\test-data\\MTP\\test-data-SMT_MTP.aasx", + "AasxToLoad": "C:\\Users\\Micha\\Desktop\\Demo\\AASX\\8001203_SPAU-P10R-T-R18M-L-PNLK-PNVBA-M8D_060ff64f-9fd2-422d-81ce-b17e49f007c5_work.aasx", // "AasxToLoad": "C:\\Users\\homi0002\\Desktop\\tmp\\00_FestoDemoBox-Module-2-Kopie.aasx", // "AasxToLoad": "C:\\Users\\homi0002\\Desktop\\tmp\\8001203_SPAU-P10R-T-R18M-L-PNLK-PNVBA-M8D_060ff64f-9fd2-422d-81ce-b17e49f007c5_work_spiel.aasx", // "AasxToLoad": "C:\\Users\\homi0002\\Desktop\\1449600_NEBM-SM12G8-E-1.5-Q5-LE6_511946fb-00c1-4aa8-9877-9ba23d86146e.aasx", - "AasxToLoad": "C:\\HOMI\\Develop\\Aasx\\repo\\1449600_NEBM-SM12G8-E-1.5-Q5-LE6_511946fb-00c1-4aa8-9877-9ba23d86146e.aasx", + // "AasxToLoad": "C:\\HOMI\\Develop\\Aasx\\repo\\1449600_NEBM-SM12G8-E-1.5-Q5-LE6_511946fb-00c1-4aa8-9877-9ba23d86146e.aasx", // "AasxToLoad": "C:\\Users\\homi0002\\Desktop\\a33.aasx", // "AasxToLoad": "C:\\MIHO\\Develop\\Aasx\\repo\\SMT_and_SAMM_Showcase_v02.aasx", // "AasxToLoad": "C:\\MIHO\\Develop\\Aasx\\repo\\SMT_and_SAMM_Showcase_v01.aasx", @@ -72,7 +73,9 @@ // "AasxToLoad": "C:\\Users\\homi0002\\Desktop\\SMT_ProductChangeNotification\\SMT_ProductChangeNotification_Draft_play_02.aasx", "AasxRepositoryFns": [ "C:\\HOMI\\Develop\\Aasx\\repo_Festo_demo_case_V3\\Festo-DemoCase-repo-V3-local.json", - "C:\\HOMI\\Develop\\Aasx\\repo\\local-5001.json" + "C:\\HOMI\\Develop\\Aasx\\repo\\local-5001.json", + "C:\\HOMI\\Develop\\Aasx\\repo\\eis-voyager.json", + "C:\\HOMI\\Develop\\Aasx\\repo\\smt-repo.json" ], // "AasxRepositoryFn": "C:\\HOMI\\Develop\\Aasx\\repo\\local-5001.json", // "AasxRepositoryFn": "C:\\Users\\homi0002\\Desktop\\test3\\new-aasx-repo.json" , @@ -135,6 +138,7 @@ "VerboseConnect": true, "WorkDir": ".\\work", "CdSortOrder": "Structured", + "SubmodelCheckOnlyId": true, "ObserveEvents": true, "CompressEvents": true, "CheckSmtElements": false, diff --git a/src/AasxPackageLogic/DispEditHelperModules.cs b/src/AasxPackageLogic/DispEditHelperModules.cs index 3861be7d..6377efb8 100644 --- a/src/AasxPackageLogic/DispEditHelperModules.cs +++ b/src/AasxPackageLogic/DispEditHelperModules.cs @@ -1818,6 +1818,10 @@ public void DisplayOrEditEntityDataSpecificationIec61360( return new AnyUiLambdaActionRedrawEntity(); })) { + // TODO (MIHO, 2024-12-09): check if to allow further Iec data types such as "File": + // comboBoxItems: (AdminShellUtil.GetEnumValues() + // .Select((dt) => dt.ToString())).ToArray(), + AddKeyValueExRef( stack, "dataType", dsiec, Aas.Stringification.ToString(dsiec.DataType), null, repo, v => diff --git a/src/AasxPackageLogic/DispEditHelperSammModules.cs b/src/AasxPackageLogic/DispEditHelperSammModules.cs index ebee2e9c..9450777f 100644 --- a/src/AasxPackageLogic/DispEditHelperSammModules.cs +++ b/src/AasxPackageLogic/DispEditHelperSammModules.cs @@ -1714,7 +1714,7 @@ public void ImportCreateCDandIds( DispEditHelperSammModules.SammExtensionHelperUpdateJson(newSammExt, si.SammType, si.SammInst); // save CD - env?.ConceptDescriptions?.Add(newCD); + env?.Add(newCD); } public void ImportSammModelToConceptDescriptions( diff --git a/src/AasxPackageLogic/ExplorerMenuFactory.cs b/src/AasxPackageLogic/ExplorerMenuFactory.cs index abd9a244..67b8b96e 100644 --- a/src/AasxPackageLogic/ExplorerMenuFactory.cs +++ b/src/AasxPackageLogic/ExplorerMenuFactory.cs @@ -122,7 +122,9 @@ public static AasxMenu CreateMainMenu() .AddWpfBlazor(name: "ConnectExtended", header: "Connect (extended) …", args: new AasxMenuListOfArgDefs() .AddFromReflection(new PackageContainerHttpRepoSubset.ConnectExtendedRecord())) - .AddWpfBlazor(name: "ApiUploadAssistant", header: "Upload assistant …") + .AddWpfBlazor(name: "ApiUploadAssistant", header: "Upload assistant …", + args: new AasxMenuListOfArgDefs() + .AddFromReflection(new PackageContainerHttpRepoSubset.UploadAssistantJobRecord())) .AddWpf(name: "CreateRepoFromApi", header: "Create (local) file repository from API base …", args: new AasxMenuListOfArgDefs() .AddFromReflection(new PackageContainerHttpRepoSubset.ConnectExtendedRecord())) diff --git a/src/AasxPackageLogic/IExecuteMainCommand.cs b/src/AasxPackageLogic/IExecuteMainCommand.cs new file mode 100644 index 00000000..75ff7e6c --- /dev/null +++ b/src/AasxPackageLogic/IExecuteMainCommand.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace AasxPackageLogic +{ + public interface IExecuteMainCommand + { + Task ExecuteMainMenuCommand(string menuItemName, params object[] args); + } +} diff --git a/src/AasxPackageLogic/Options.cs b/src/AasxPackageLogic/Options.cs index b23c137f..d83a77e8 100644 --- a/src/AasxPackageLogic/Options.cs +++ b/src/AasxPackageLogic/Options.cs @@ -565,7 +565,13 @@ public AnyUiColor GetColor(ColorNames c) Cmd = "-cd-sort-order")] public string CdSortOrder = null; - [OptionDescription(Description = + [OptionDescription(Description = + "Only check the value (id) field of keys of semanticId for Submodels. That is, both" + + "GlobalReference and Submodel types match.", + Cmd = "-sm-only-id")] + public bool SubmodelCheckOnlyId = false; + + [OptionDescription(Description = "For such operations as query repository, do load a new AASX file without " + "prompting the user.", Cmd = "-load-without-prompt")] diff --git a/src/AasxPackageLogic/PackageCentral/PackageContainerFactory.cs b/src/AasxPackageLogic/PackageCentral/PackageContainerFactory.cs index 0a1e04d4..b9769c41 100644 --- a/src/AasxPackageLogic/PackageCentral/PackageContainerFactory.cs +++ b/src/AasxPackageLogic/PackageCentral/PackageContainerFactory.cs @@ -219,6 +219,11 @@ public static async Task GuessAndCreateForAsync( var extCntOpt = new PackageContainerHttpRepoSubsetOptions(containerOptions, new ConnectExtendedRecord()); + // in this situation (guess and load a "complete" ressource), make sure, + // that Submodels are loaded with it .. + extCntOpt.Record.AutoLoadSubmodels = true; + extCntOpt.Record.AutoLoadOnDemand = false; + // prepare runtime options var cnt = await PackageContainerHttpRepoSubset.CreateAndLoadAsync( packageCentral, location, fullItemLocation, diff --git a/src/AasxPackageLogic/PackageCentral/PackageContainerHttpRepoSubset.cs b/src/AasxPackageLogic/PackageCentral/PackageContainerHttpRepoSubset.cs index 58be58bb..c0664430 100644 --- a/src/AasxPackageLogic/PackageCentral/PackageContainerHttpRepoSubset.cs +++ b/src/AasxPackageLogic/PackageCentral/PackageContainerHttpRepoSubset.cs @@ -239,6 +239,9 @@ public static bool IsValidUriForRepoRegistryAasByAssetId(string location) public static bool IsValidUriAnyMatch(string location) { + if (location?.HasContent() != true) + return false; + return IsValidUriForRepoAllAAS(location) || IsValidUriForRepoSingleAAS(location) || IsValidUriForRepoAllSubmodel(location) @@ -1599,6 +1602,76 @@ await PackageHttpDownloadUtil.HttpGetToMemoryStream( }); }); + // start auto-load missing Submodels? + if (operationFound && (record?.AutoLoadCds ?? false)) + { + var lrs = env.FindAllReferencedSemanticIds().ToList(); + + await Parallel.ForEachAsync(lrs, + new ParallelOptions() { MaxDegreeOfParallelism = Options.Curr.MaxParallelOps }, + async (lr, token) => + { + var cdid = lr.Reference?.GetAsExactlyOneKey()?.Value; + if (cdid?.HasContent() != true) + return; + + if (record?.AutoLoadOnDemand ?? true) + { + // side info level 1 + lock (prepSM) + { + prepSM.AddIfNew(null, new AasIdentifiableSideInfo() + { + IsStub = true, + StubLevel = AasIdentifiableSideInfoLevel.IdWithEndpoint, + Id = lr.Reference.Keys[0].Value, + IdShort = "", + Endpoint = BuildUriForRepoSingleCD(baseUri, cdid) + }); + } + } + else + { + // no side info => full element + var sourceUri = BuildUriForRepoSingleCD(baseUri, cdid); + await PackageHttpDownloadUtil.HttpGetToMemoryStream( + null, + sourceUri: sourceUri, + allowFakeResponses: allowFakeResponses, + runtimeOptions: runtimeOptions, + lambdaDownloadDoneOrFail: (code, ms, contentFn) => + { + if (code != HttpStatusCode.OK) + return; + + try + { + var node = System.Text.Json.Nodes.JsonNode.Parse(ms); + var cd = Jsonization.Deserialize.ConceptDescriptionFrom(node); + lock (prepCD) + { + trackLoadedIdentifiables?.Add(cd); + if (prepCD.AddIfNew(cd, new AasIdentifiableSideInfo() + { + IsStub = false, + StubLevel = AasIdentifiableSideInfoLevel.IdWithEndpoint, + Id = cd.Id, + IdShort = cd.IdShort, + Endpoint = sourceUri + })) + { + trackNewIdentifiables?.Add(cd); + } + } + } + catch (Exception ex) + { + runtimeOptions?.Log?.Error(ex, "Parsing auto-loaded ConceptDescriptions"); + } + }); + } + }); + } } // @@ -1767,7 +1840,7 @@ public enum BaseTypeEnum { Repository, Registry } "identified by semanticIds as well. " + "Note: For this retrieveal, AutoLoadOnDemand may apply. " + "Note: This might significantly increase the number of retrievals.")] - public bool AutoLoadCds = true; + public bool AutoLoadCds = false; [AasxMenuArgument(help: "When a AAS is retrieved, try to retrieve the associated thumbnail as well.")] public bool AutoLoadThumbnails = true; @@ -2530,11 +2603,15 @@ public static List FindAllUsedFileElements( public class UploadAssistantJobRecord { + [AasxMenuArgument(help: "Specifies the part of the URI of the Repository/ Registry, which is " + + "common to all operations.")] + public string BaseAddress = ""; // public string BaseAddress = "https://cloudrepo.aas-voyager.com/"; - public string BaseAddress = "https://eis-data.aas-voyager.com/"; + // public string BaseAddress = "https://eis-data.aas-voyager.com/"; // public string BaseAddress = "http://smt-repo.admin-shell-io.com/api/v3.0"; // public string BaseAddress = "https://techday2-registry.admin-shell-io.com/"; + [AasxMenuArgument(help: "Either: Repository or Registry")] public ConnectExtendedRecord.BaseTypeEnum BaseType = ConnectExtendedRecord.BaseTypeEnum.Repository; // public ConnectExtendedRecord.BaseTypeEnum BaseType = ConnectExtendedRecord.BaseTypeEnum.Registry; @@ -2604,6 +2681,8 @@ public static async Task PerformUploadAssistant( // var recordJob = new UploadAssistantJobRecord(); + ticket?.ArgValue?.PopulateObjectFromArgs(recordJob); + var ucJob = new AnyUiDialogueDataModalPanel(caption); ucJob.ActivateRenderPanel(recordJob, disableScrollArea: false, diff --git a/src/AasxPackageLogic/Plugins.cs b/src/AasxPackageLogic/Plugins.cs index ecb61a6c..986b8cf7 100644 --- a/src/AasxPackageLogic/Plugins.cs +++ b/src/AasxPackageLogic/Plugins.cs @@ -189,6 +189,10 @@ public static PluginInstance FindPluginInstance(string pname) public static Dictionary TryActivatePlugins( IReadOnlyList pluginDll) { + // set some global options + AasxPluginsGlobal.SubmodelCheckOnlyId = Options.Curr.SubmodelCheckOnlyId; + + // try load var loadedPlugins = new Dictionary(); for (int index = 0; index < pluginDll.Count; index++) diff --git a/src/AasxPackageLogic/VisualAasxElements.cs b/src/AasxPackageLogic/VisualAasxElements.cs index e741dd98..c82252d6 100644 --- a/src/AasxPackageLogic/VisualAasxElements.cs +++ b/src/AasxPackageLogic/VisualAasxElements.cs @@ -1847,7 +1847,7 @@ private VisualElementConceptDescription GenerateVisualElementsForSingleCD( // remember, that this value pair CD hangs "below" an Submodel if (submodelForCDs != null) { - _cdToSm.Add(vrpCD, submodelForCDs); + _cdToSm.AddIfValueIsNew(vrpCD, submodelForCDs); } } } @@ -1889,8 +1889,8 @@ private VisualElementGeneric GenerateVisualElementsFromShellEnvAddElements( // bookkeeping if (tism.CachedCD != null) { - _cdReferred.Add(tism.CachedCD, tism); - _cdToSm.Add(tism.CachedCD, sm); + _cdReferred.AddIfValueIsNew(tism.CachedCD, tism); + _cdToSm.AddIfValueIsNew(tism.CachedCD, sm); } // nested cd? @@ -2421,6 +2421,37 @@ public void AddVisualElementsFromShellEnv( } } + // MIHO, 2024-12-22: new way to pre-fill _cdToSm + if (true) + { + _cdToSm.Clear(); + + Action lambdaIndex = (sm, semId) => + { + if (semId?.IsValid() != true) + return; + var cdid = semId.GetAsExactlyOneKey()?.Value; + if (cdid == null) + return; + if (!_idToReferable.ContainsKey(cdid)) + return; + var cd = _idToReferable[cdid]?.FirstOrDefault() as Aas.IConceptDescription; + if (cd == null) + return; + _cdToSm.AddIfValueIsNew(cd, sm); + }; + + foreach (var sm in env.AllSubmodels()) + { + lambdaIndex(sm, sm?.SemanticId); + sm?.RecurseOnSubmodelElements(null, (o, parents, sme) => + { + lambdaIndex(sm, sme?.SemanticId); + return true; + }); + } + } + // many operations try { @@ -2649,7 +2680,7 @@ public void AddVisualElementsFromShellEnv( { // single files var files = package.GetListOfSupplementaryFiles(); - foreach (var fi in files) + foreach (var fi in files.ForEachSafe()) tiFiles.Members.Add(new VisualElementSupplementalFile(tiFiles, cache, package, fi)); } } diff --git a/src/AasxWpfControlLibrary/PackageCentral/PackageContainerListOfListControl.xaml.cs b/src/AasxWpfControlLibrary/PackageCentral/PackageContainerListOfListControl.xaml.cs index c6f6e478..1fcc8ae0 100644 --- a/src/AasxWpfControlLibrary/PackageCentral/PackageContainerListOfListControl.xaml.cs +++ b/src/AasxWpfControlLibrary/PackageCentral/PackageContainerListOfListControl.xaml.cs @@ -39,6 +39,7 @@ public partial class PackageContainerListOfListControl : UserControl private AasxPackageLogic.PackageCentral.PackageCentral _packageCentral; private IFlyoutProvider _flyout; private IManageVisualAasxElements _manageVisuElems; + private IExecuteMainCommand _executeMainCommand; private PackageContainerListOfList _repoList; /// @@ -57,6 +58,11 @@ public partial class PackageContainerListOfListControl : UserControl /// public IManageVisualAasxElements ManageVisuElems { set { _manageVisuElems = value; } } + /// + /// Handler, which can provide the ability to execute main menu commands. + /// + public IExecuteMainCommand ExecuteMainCommand { set { _executeMainCommand = value; } } + /// /// AasxRepoList which is being managed by this control. Is expected to sit in the PackageCentral. /// Note: only setter, as direct access from outside shall be redirected to the original source. @@ -191,12 +197,30 @@ public async Task CommandBinding_FileRepoAll(Control senderList, PackageContaine // dialogue var uc = new AnyUiDialogueDataSelectFromRepository("Select from: " + fr.Header); uc.Items = fr.EnumerateItems().ToList(); - if (await _flyout?.GetDisplayContext()?.StartFlyoverModalAsync(uc) - && uc.ResultItem != null) + if (await _flyout?.GetDisplayContext()?.StartFlyoverModalAsync(uc)) { - var fi = uc.ResultItem; + // got an asset id only? + if (uc.ResultId != null) + { + var ri = await fr.FindByAssetId(uc.ResultId); + if (ri?.Location?.HasContent() == true) + try + { + // load + Log.Singleton.Info("Switching to repository location {0} ..", ri.Location); + FileDoubleClick?.Invoke(senderList, fr, ri); + } + catch (Exception ex) + { + Log.Singleton.Error( + ex, $"When loading item on repository location {ri.Location}."); + } + } + + // use an item directly + var fi = uc?.ResultItem; var fn = fi?.Location; - if (fn != null) + if (fn?.HasContent() == true) { // start animation fr.StartAnimation(fi, @@ -426,6 +450,13 @@ public async Task CommandBinding_FileRepoAll(Control senderList, PackageContaine } } + if (cmd == "filerepouploadtoapi" && fr is PackageContainerListHttpRestRepository frRepo) + { + await _executeMainCommand?.ExecuteMainMenuCommand( + "ApiUploadAssistant", + "BaseType", "Repository", + "BaseAddress", "" + frRepo.Endpoint?.ToString()); + } } } @@ -473,8 +504,11 @@ private async Task PackageContainerListControl_ButtonClick( if (!(fr is PackageContainerListLastRecentlyUsed)) { - menu.AddAction( - "FileRepoLoadAllResident", "Load all resident files ..", icon: "\U0001f503"); + if (!(fr is PackageContainerListHttpRestBase)) + { + menu.AddAction( + "FileRepoLoadAllResident", "Load all resident files ..", icon: "\U0001f503"); + } if (fr is PackageContainerListLocal) { @@ -482,11 +516,21 @@ private async Task PackageContainerListControl_ButtonClick( "FileRepoMakeRelative", "Make AASX filenames relative ..", icon: "\u2699"); } - menu.AddAction("FileRepoAddCurrent", "Add current AAS", icon: "\u2699") - .AddAction("FileRepoAddToServer", "Add AASX File to File Repository", icon: "\u2699") - .AddAction("FileRepoMultiAdd", "Add multiple AASX files ..", icon: "\u2699") - .AddAction("FileRepoAddFromServer", "Add from REST server ..", icon: "\u2699") - .AddAction("FileRepoPrint", "Print 2D code sheet ..", icon: "\u2699"); + if (fr is PackageContainerListLocalBase) + { + menu.AddAction("FileRepoAddCurrent", "Add current AAS", icon: "\u2699") + .AddAction("FileRepoAddToServer", "Add AASX File to File Repository", icon: "\u2699") + .AddAction("FileRepoMultiAdd", "Add multiple AASX files ..", icon: "\u2699") + .AddAction("FileRepoAddFromServer", "Add from REST server ..", icon: "\u2699") + .AddAction("FileRepoPrint", "Print 2D code sheet ..", icon: "\u2699"); + } + + if (fr is PackageContainerListHttpRestRepository + || fr is PackageContainerListHttpRestRegistry) + { + menu.AddAction( + "FileRepoUploadToApi", "Upload to API ..", icon: "\U0001f879"); + } } var cm2 = DynamicContextMenu.CreateNew(