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

HicServices / RDMP / 16417034308

21 Jul 2025 12:31PM UTC coverage: 57.423% (+0.1%) from 57.301%
16417034308

push

github

web-flow
Merge pull request #2205 from HicServices/test-multi-project

Multi-Project Catalogues

11427 of 21435 branches covered (53.31%)

Branch coverage included in aggregate %.

101 of 145 new or added lines in 16 files covered. (69.66%)

32 existing lines in 4 files now uncovered.

32393 of 54876 relevant lines covered (59.03%)

17564.0 hits per line

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

51.91
/Rdmp.Core/CommandExecution/GoToCommandFactory.cs
1
// Copyright (c) The University of Dundee 2018-2024
2
// This file is part of the Research Data Management Platform (RDMP).
3
// RDMP is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
4
// RDMP is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
5
// You should have received a copy of the GNU General Public License along with RDMP. If not, see <https://www.gnu.org/licenses/>.
6

7
using System;
8
using System.Collections.Generic;
9
using System.Linq;
10
using Rdmp.Core.CommandExecution.AtomicCommands;
11
using Rdmp.Core.Curation.Data;
12
using Rdmp.Core.Curation.Data.Aggregation;
13
using Rdmp.Core.Curation.Data.Cohort;
14
using Rdmp.Core.Curation.Data.Dashboarding;
15
using Rdmp.Core.Curation.Data.DataLoad;
16
using Rdmp.Core.Curation.Data.Governance;
17
using Rdmp.Core.Curation.Data.ImportExport;
18
using Rdmp.Core.DataExport.Data;
19
using Rdmp.Core.Icons.IconProvision;
20
using Rdmp.Core.MapsDirectlyToDatabaseTable;
21
using Rdmp.Core.MapsDirectlyToDatabaseTable.Injection;
22
using Rdmp.Core.Providers;
23
using SixLabors.ImageSharp;
24
using SixLabors.ImageSharp.PixelFormats;
25

26
namespace Rdmp.Core.CommandExecution;
27

28
/// <summary>
29
/// Builds the "Go To" submenu for travelling between objects in an RDMP database (e.g. Catalogue to extractions using the Catalogue)
30
/// </summary>
31
public class GoToCommandFactory : CommandFactoryBase
32
{
33
    private readonly IBasicActivateItems _activator;
34
    public const string GoTo = "Go To";
35

36
    public GoToCommandFactory(IBasicActivateItems activator)
198✔
37
    {
38
        _activator = activator;
198✔
39
    }
198✔
40

41
    public IEnumerable<IAtomicCommand> GetCommands(object forObject)
42
    {
43
        //forget old values, get them up to the minute
44
        if (Is(forObject, out IInjectKnown ii))
198✔
45
            ii.ClearAllInjections();
90✔
46

47
        if (Is(forObject, out IMapsDirectlyToDatabaseTable mt))
198✔
48
        {
49
            // Go to import / export definitions
50
            var export = _activator.RepositoryLocator.CatalogueRepository.GetReferencesTo<ObjectExport>(mt)
192✔
51
                .FirstOrDefault();
192✔
52

53
            if (export != null)
192!
54
                yield return new ExecuteCommandShow(_activator, export, 0, true)
×
55
                { OverrideCommandName = "Show Export Definition" };
×
56

57
            var import = _activator.RepositoryLocator.CatalogueRepository.GetReferencesTo<ObjectImport>(mt)
192✔
58
                .FirstOrDefault();
192✔
59
            if (import != null)
192!
60
                yield return new ExecuteCommandShow(_activator, import, 0)
×
61
                { OverrideCommandName = "Show Import Definition" };
×
62

63
            if (SupportsReplacement(forObject))
192✔
64
                yield return new ExecuteCommandShow(_activator, () => GetReplacementIfAny(mt))
190✔
65
                { OverrideCommandName = "Replacement" };
190✔
66

67

68
            yield return new ExecuteCommandSimilar(_activator, mt, false) { GoTo = true };
192✔
69
        }
70

71
        // cic => associated projects
72
        if (Is(forObject, out CohortIdentificationConfiguration cic))
198✔
73
            yield return new ExecuteCommandShow(_activator, () =>
2✔
74
            {
2✔
75
                return _activator.CoreChildProvider is DataExportChildProvider { AllProjectAssociatedCics: not null } dx
×
76
                    ? dx.AllProjectAssociatedCics.Where(a => a.CohortIdentificationConfiguration_ID == cic.ID)
×
77
                        .Select(a => a.Project).Distinct()
×
78
                    : Array.Empty<CohortIdentificationConfiguration>();
×
79
            })
2✔
80
            {
2✔
81
                OverrideCommandName = "Project(s)",
2✔
82
                OverrideIcon = GetImage(RDMPConcept.Project)
2✔
83
            };
2✔
84

85
        if (Is(forObject, out ColumnInfo columnInfo))
198✔
86
        {
87
            yield return new ExecuteCommandSimilar(_activator, columnInfo, true)
4✔
88
            {
4✔
89
                OverrideCommandName = "Different",
4✔
90
                GoTo = true,
4✔
91
                OverrideIcon = GetImage(RDMPConcept.ColumnInfo)
4✔
92
            };
4✔
93

94
            yield return new ExecuteCommandShow(_activator, columnInfo.TableInfo_ID, typeof(TableInfo))
4✔
95
            {
4✔
96
                OverrideCommandName = "Table Info",
4✔
97
                OverrideIcon = GetImage(RDMPConcept.TableInfo)
4✔
98
            };
4✔
99
            yield return new ExecuteCommandShow(_activator,
4✔
100
                () => _activator.CoreChildProvider.AllCatalogueItems.Where(catItem =>
×
101
                    catItem.ColumnInfo_ID == columnInfo.ID))
×
102
            {
4✔
103
                OverrideCommandName = "Catalogue Item(s)",
4✔
104
                OverrideIcon = GetImage(RDMPConcept.CatalogueItem)
4✔
105
            };
4✔
106

107
            yield return new ExecuteCommandShow(_activator, columnInfo.ANOTable_ID, typeof(ANOTable))
4✔
108
            {
4✔
109
                OverrideCommandName = "ANO Table",
4✔
110
                OverrideIcon = GetImage(RDMPConcept.ANOTable)
4✔
111
            };
4✔
112
        }
113

114
        if (Is(forObject, out ExtractionInformation ei))
198✔
115
        {
116
            yield return new ExecuteCommandShow(_activator, ei.CatalogueItem?.Catalogue_ID, typeof(Catalogue))
2!
117
            {
2✔
118
                OverrideCommandName = "Catalogue",
2✔
119
                OverrideIcon = GetImage(RDMPConcept.Catalogue)
2✔
120
            };
2✔
121
            yield return new ExecuteCommandShow(_activator, ei.CatalogueItem_ID, typeof(CatalogueItem))
2✔
122
            {
2✔
123
                OverrideCommandName = "Catalogue Item",
2✔
124
                OverrideIcon = GetImage(RDMPConcept.CatalogueItem)
2✔
125
            };
2✔
126
            yield return new ExecuteCommandShow(_activator, ei.ColumnInfo, 0, true)
2✔
127
            {
2✔
128
                OverrideCommandName = "Column Info",
2✔
129
                OverrideIcon = GetImage(RDMPConcept.ColumnInfo)
2✔
130
            };
2✔
131
        }
132

133
        if (Is(forObject, out CatalogueItem ci))
198✔
134
        {
135
            yield return new ExecuteCommandShow(_activator, ci.Catalogue_ID, typeof(Catalogue))
14✔
136
            {
14✔
137
                OverrideCommandName = "Catalogue",
14✔
138
                OverrideIcon = GetImage(RDMPConcept.Catalogue)
14✔
139
            };
14✔
140
            yield return new ExecuteCommandShow(_activator, ci.ExtractionInformation, 0, true)
14✔
141
            {
14✔
142
                OverrideCommandName = "Extraction Information",
14✔
143
                OverrideIcon = GetImage(RDMPConcept.ExtractionInformation)
14✔
144
            };
14✔
145
            yield return new ExecuteCommandShow(_activator, ci.ColumnInfo, 0, true)
14✔
146
            {
14✔
147
                OverrideCommandName = "Column Info",
14✔
148
                OverrideIcon = GetImage(RDMPConcept.ColumnInfo)
14✔
149
            };
14✔
150
        }
151

152
        if (Is(forObject, out ExtractableDataSet eds))
198!
153
        {
154
            yield return new ExecuteCommandShow(_activator, eds.Catalogue_ID, typeof(Catalogue))
×
155
            {
×
156
                OverrideCommandName = "Catalogue",
×
157
                OverrideIcon = GetImage(RDMPConcept.Catalogue)
×
158
            };
×
159

160
            yield return new ExecuteCommandShow(_activator, () =>
×
161
            {
×
162
                return _activator.CoreChildProvider is DataExportChildProvider dx
×
163
                    ? dx.SelectedDataSets.Where(s => s.ExtractableDataSet_ID == eds.ID)
×
164
                        .Select(s => s.ExtractionConfiguration)
×
165
                    : Array.Empty<SelectedDataSets>();
×
166
            })
×
167
            {
×
168
                OverrideCommandName = "Extraction Configuration(s)",
×
169
                OverrideIcon = GetImage(RDMPConcept.ExtractionConfiguration)
×
170
            };
×
171
        }
172

173
        if (Is(forObject, out GovernancePeriod period))
198✔
174
            yield return new ExecuteCommandShow(_activator, () => period.GovernedCatalogues)
2✔
175
            { OverrideCommandName = "Catalogue(s)", OverrideIcon = GetImage(RDMPConcept.Catalogue) };
2✔
176

177
        if (Is(forObject, out JoinInfo j))
198!
178
            yield return new ExecuteCommandShow(_activator, j.ForeignKey_ID, typeof(ColumnInfo))
×
179
            { OverrideCommandName = "Foreign Key", OverrideIcon = GetImage(RDMPConcept.ColumnInfo) };
×
180

181
        if (Is(forObject, out Lookup lookup))
198✔
182
        {
183
            yield return new ExecuteCommandShow(_activator, lookup.Description.TableInfo_ID, typeof(TableInfo));
6✔
184
            yield return new ExecuteCommandShow(_activator, lookup.ForeignKey_ID, typeof(ColumnInfo))
6✔
185
            { OverrideCommandName = "Foreign Key", OverrideIcon = GetImage(RDMPConcept.ColumnInfo) };
6✔
186
        }
187

188
        if (Is(forObject, out ExtractionFilter masterFilter))
198!
189
        {
190
            yield return new ExecuteCommandShow(_activator, () =>
×
191
                _activator.RepositoryLocator.CatalogueRepository
×
192
                    .GetAllObjectsWhere<AggregateFilter>("ClonedFromExtractionFilter_ID", masterFilter.ID)
×
193
                    .Select(f => f.GetAggregate())
×
194
                    .Where(a => a != null).Distinct()
×
195
            )
×
196
            { OverrideCommandName = "Usages (in Cohort Builder)" };
×
197

198

199
            yield return new ExecuteCommandShow(_activator, () =>
×
200
                _activator.RepositoryLocator.DataExportRepository
×
201
                    .GetAllObjectsWhere<DeployedExtractionFilter>("ClonedFromExtractionFilter_ID", masterFilter.ID)
×
202
                    .Select(f => f.GetDataset()?.ExtractionConfiguration)
×
203
                    .Where(c => c != null).Distinct()
×
204
            )
×
205
            { OverrideCommandName = "Usages (in Extractions)" };
×
206
        }
207

208
        if (Is(forObject, out IFilter filter) && filter.ClonedFromExtractionFilter_ID.HasValue)
198!
209
        {
210
            ExtractionFilter parent = null;
×
211

212
            try
213
            {
214
                parent = _activator.RepositoryLocator.CatalogueRepository.GetObjectByID<ExtractionFilter>(
×
215
                    filter.ClonedFromExtractionFilter_ID.Value);
×
216
            }
×
217
            catch (KeyNotFoundException)
×
218
            {
219
                // new ImpossibleCommand("Parent filter has been deleted") { OverrideCommandName = "Parent Filter" };
220
            }
×
221

222
            if (parent != null)
×
223
                yield return new ExecuteCommandShow(_activator, parent, 0)
×
224
                { OverrideCommandName = "Parent Filter", OverrideIcon = GetImage(RDMPConcept.Filter) };
×
225
        }
226

227
        if (Is(forObject, out SelectedDataSets selectedDataSet))
198✔
228
        {
229
            yield return new ExecuteCommandShow(_activator, selectedDataSet.ExtractableDataSet.Catalogue_ID,
14✔
230
                typeof(Catalogue))
14✔
231
            {
14✔
232
                OverrideCommandName = "Catalogue",
14✔
233
                OverrideIcon = GetImage(RDMPConcept.Catalogue)
14✔
234
            };
14✔
235

236
            var ep = selectedDataSet.ExtractionProgressIfAny;
14✔
237
            if (ep != null) yield return new ExecuteCommandShow(_activator, ep, 0, true);
14!
238
        }
239

240
        if (Is(forObject, out TableInfo tableInfo))
198✔
241
            yield return new ExecuteCommandShow(_activator,
4✔
242
                () => tableInfo.ColumnInfos.SelectMany(c =>
×
243
                    _activator.CoreChildProvider.AllCatalogueItems.Where(catItem => catItem.ColumnInfo_ID == c.ID)
×
244
                        .Select(catItem => catItem.Catalogue)).Distinct())
×
245
            {
4✔
246
                OverrideCommandName = "Catalogue(s)",
4✔
247
                OverrideIcon = GetImage(RDMPConcept.Catalogue)
4✔
248
            };
4✔
249

250
        if (Is(forObject, out AggregateConfiguration aggregate))
198✔
251
        {
252
            yield return new ExecuteCommandShow(_activator, aggregate.GetCohortIdentificationConfigurationIfAny()?.ID,
14!
253
                typeof(CohortIdentificationConfiguration))
14✔
254
            {
14✔
255
                OverrideCommandName = "Cohort Identification Configuration",
14✔
256
                OverrideIcon = GetImage(RDMPConcept.CohortIdentificationConfiguration)
14✔
257
            };
14✔
258
            yield return new ExecuteCommandShow(_activator, aggregate.Catalogue_ID, typeof(Catalogue))
14✔
259
            {
14✔
260
                OverrideCommandName = "Catalogue",
14✔
261
                OverrideIcon = GetImage(RDMPConcept.Catalogue)
14✔
262
            };
14✔
263
        }
264

265
        if (Is(forObject, out Catalogue catalogue))
198✔
266
        {
267
            foreach (var lmd in catalogue.LoadMetadatas())
72!
268
            {
269
                yield return new ExecuteCommandShow(_activator, lmd.ID, typeof(LoadMetadata))
×
270
                { OverrideCommandName = $"Data Load ({lmd.Name})", OverrideIcon = GetImage(RDMPConcept.LoadMetadata) };
×
271
            }
272
            if (catalogue.LoadMetadatas().Length == 0)
36✔
273
            {
274
                yield return new ExecuteCommandShow(_activator, null, typeof(LoadMetadata))
36✔
275
                { OverrideCommandName = "No Data Load", OverrideIcon = GetImage(RDMPConcept.LoadMetadata) };
36✔
276
            }
277

278

279
            if (_activator.CoreChildProvider is DataExportChildProvider exp)
36✔
280
            {
281
                var cataEds = exp.ExtractableDataSets.Where(d => d.Catalogue_ID == catalogue.ID);
36✔
282

283
                if (cataEds != null)
36!
284
                {
285
                    yield return new ExecuteCommandShow(_activator,
36✔
NEW
286
                         () => (cataEds.SelectMany(c => c.Projects.Select(p => p.ID)).Select(p => _activator.RepositoryLocator.DataExportRepository.GetObjectByID<Project>(p))))
×
287
                    {
36✔
288
                        OverrideCommandName = "Associated Projects",
36✔
289
                        OverrideIcon = GetImage(RDMPConcept.Project)
36✔
290
                    };
36✔
291
                    yield return new ExecuteCommandShow(_activator,
36✔
NEW
292
                          () => (cataEds.SelectMany(c => c.ExtractionConfigurations.Select(e => e.Project))))
×
293
                    {
36✔
294
                        OverrideCommandName = "Extracted In (Project)",
36✔
295
                        OverrideIcon = GetImage(RDMPConcept.Project)
36✔
296
                    };
36✔
297
                    yield return new ExecuteCommandShow(_activator, () => cataEds.SelectMany(c => c.ExtractionConfigurations))
36✔
298
                    {
36✔
299
                        OverrideCommandName = $"Extracted In (Extraction Configuration)",
36✔
300
                        OverrideIcon = GetImage(RDMPConcept.ExtractionConfiguration)
36✔
301
                    };
36✔
302
                }
303
                else
304
                {
305
                    //no values, show disabled options
UNCOV
306
                    yield return new ExecuteCommandShow(_activator,
×
UNCOV
307
                          () =>
×
UNCOV
308
                          {
×
309
                              return new Project[] { };
×
UNCOV
310
                          }
×
UNCOV
311
                      )
×
UNCOV
312
                    {
×
UNCOV
313
                        OverrideCommandName = "No Associated Project",
×
UNCOV
314
                        OverrideIcon = GetImage(RDMPConcept.Project)
×
UNCOV
315
                    };
×
UNCOV
316
                    yield return new ExecuteCommandShow(_activator,
×
UNCOV
317
                                             () =>
×
UNCOV
318
                                             {
×
319
                                                 return new Project[] { };
×
UNCOV
320
                                             }
×
UNCOV
321
                                         )
×
UNCOV
322
                    {
×
UNCOV
323
                        OverrideCommandName = "Not Extracted In (Project)",
×
UNCOV
324
                        OverrideIcon = GetImage(RDMPConcept.Project)
×
UNCOV
325
                    };
×
UNCOV
326
                    yield return new ExecuteCommandShow(_activator,
×
UNCOV
327
                        () =>
×
UNCOV
328
                        {
×
329
                            return new ExtractionConfiguration[] { };
×
UNCOV
330
                        }
×
UNCOV
331
                    )
×
UNCOV
332
                    {
×
UNCOV
333
                        OverrideCommandName = "Not Extracted In (Extraction Configuration)",
×
UNCOV
334
                        OverrideIcon = GetImage(RDMPConcept.ExtractionConfiguration)
×
UNCOV
335
                    };
×
336
                }
337
            }
36✔
338

339
            yield return new ExecuteCommandShow(_activator, () => catalogue.GetTableInfoList(true))
36✔
340
            { OverrideCommandName = "Table(s)", OverrideIcon = GetImage(RDMPConcept.TableInfo) };
36✔
341

342
            yield return new ExecuteCommandShow(_activator,
36✔
343
                () =>
36✔
344
                    _activator
×
345
                        .CoreChildProvider
×
346
                        .AllAggregateConfigurations.Where(ac =>
×
347
                            ac.IsCohortIdentificationAggregate && ac.Catalogue_ID == catalogue.ID)
×
348
                        .Select(ac => ac.GetCohortIdentificationConfigurationIfAny())
×
349
                        .Where(cataCic => cataCic != null)
×
350
                        .Distinct())
×
351
            {
36✔
352
                OverrideCommandName = "Cohort Identification Configuration(s)",
36✔
353
                OverrideIcon = GetImage(RDMPConcept.CohortIdentificationConfiguration)
36✔
354
            };
36✔
355

356

357
            yield return new ExecuteCommandShow(_activator,
36✔
358
                () => _activator.CoreChildProvider.AllGovernancePeriods.Where(p =>
×
359
                    p.GovernedCatalogues.Contains(catalogue)))
×
360
            {
36✔
361
                OverrideCommandName = "Governance",
36✔
362
                OverrideIcon = GetImage(RDMPConcept.GovernancePeriod)
36✔
363
            };
36✔
364
        }
365

366
        if (Is(forObject, out ExtractableCohort cohort))
198!
367
        {
368
            yield return new ExecuteCommandShow(_activator, () =>
×
369
            {
×
370
                return _activator.CoreChildProvider is DataExportChildProvider dx
×
371
                    ? dx.ExtractionConfigurations.Where(ec => ec.Cohort_ID == cohort.ID)
×
372
                    : (IEnumerable<IMapsDirectlyToDatabaseTable>)Array.Empty<ExtractionConfiguration>();
×
373
            })
×
374
            {
×
375
                OverrideCommandName = "Extraction Configuration(s)",
×
376
                OverrideIcon = GetImage(RDMPConcept.ExtractionConfiguration)
×
377
            };
×
378

379
            yield return new ExecuteCommandShow(_activator, () =>
×
380
            {
×
381
                return _activator.CoreChildProvider is DataExportChildProvider dx
×
382
                    ? dx.Projects.Where(p => p.ProjectNumber == cohort.ExternalProjectNumber)
×
383
                    : (IEnumerable<IMapsDirectlyToDatabaseTable>)Array.Empty<Project>();
×
384
            })
×
385
            {
×
386
                OverrideCommandName = "Project(s)",
×
387
                OverrideIcon = GetImage(RDMPConcept.Project)
×
388
            };
×
389

390
            var obj = ExtractableCohortAuditLogBuilder.GetObjectIfAny(cohort, _activator.RepositoryLocator);
×
391
            if (obj is not null && obj is CohortIdentificationConfiguration configuration)
×
392
            {
393
                yield return new ExecuteCommandShow(_activator, () =>
×
394
                {
×
395
                    return [configuration];
×
396
                })
×
397
                {
×
398
                    OverrideCommandName = "Cohort Identification Configuration(s)",
×
399
                    OverrideIcon = GetImage(RDMPConcept.CohortIdentificationConfiguration)
×
400
                };
×
401
            }
402

403
        }
×
404

405
        //if it is a masquerader and masquerading as a DatabaseEntity then add a goto the object
406
        if (forObject is IMasqueradeAs masqueraderIfAny)
198!
407
            if (masqueraderIfAny.MasqueradingAs() is DatabaseEntity m)
×
408
                yield return new ExecuteCommandShow(_activator, m, 0, true)
×
409
                { OverrideIcon = _activator.CoreIconProvider.GetImage(m) };
×
410
    }
198✔
411

412
    private static bool SupportsReplacement(object o) => o is not DashboardLayout;
192✔
413

414
    private IEnumerable<IMapsDirectlyToDatabaseTable> GetReplacementIfAny(IMapsDirectlyToDatabaseTable mt)
415
    {
416
        var replacement = _activator.RepositoryLocator.CatalogueRepository
×
417
            .GetAllObjectsWhere<ExtendedProperty>("Name", ExtendedProperty.ReplacedBy)
×
418
            .FirstOrDefault(r => r.IsReferenceTo(mt));
×
419

420
        return replacement == null
×
421
            ? Enumerable.Empty<IMapsDirectlyToDatabaseTable>()
×
422
            : new[] { mt.Repository.GetObjectByID(mt.GetType(), int.Parse(replacement.Value)) };
×
423
    }
424

425
    private Image<Rgba32> GetImage(RDMPConcept concept) => _activator.CoreIconProvider.GetImage(concept);
372✔
426
}
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