@meshmakers/octo-ui 3.4.280 → 3.4.310
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/meshmakers-octo-ui-tree-navigation-settings.mjs +420 -0
- package/fesm2022/meshmakers-octo-ui-tree-navigation-settings.mjs.map +1 -0
- package/fesm2022/meshmakers-octo-ui.mjs +1166 -198
- package/fesm2022/meshmakers-octo-ui.mjs.map +1 -1
- package/lib/runtime-browser/styles/_styles.scss +5 -23
- package/package.json +5 -1
- package/types/meshmakers-octo-ui-tree-navigation-settings.d.ts +157 -0
- package/types/meshmakers-octo-ui.d.ts +291 -7
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
2
|
import { inject, ChangeDetectionStrategy, Component, Injectable, Input, EventEmitter, Output, ElementRef, forwardRef, ViewChild, signal, computed, input, model, output, effect, untracked, Directive, InjectionToken, HostListener, makeEnvironmentProviders } from '@angular/core';
|
|
3
3
|
import { provideAnimationsAsync } from '@angular/platform-browser/animations/async';
|
|
4
|
-
import { AttributeSelectorService, AttributeValueTypeDto as AttributeValueTypeDto$1, CkTypeSelectorService, CkTypeAttributeService, GetEntitiesByCkTypeDtoGQL, RuntimeEntitySelectDataSource, RuntimeEntityDialogDataSource, SearchFilterTypesDto, SortOrdersDto, FieldFilterOperatorsDto, GetCkTypesDtoGQL, GetCkModelByIdDtoGQL,
|
|
4
|
+
import { AttributeSelectorService, AttributeValueTypeDto as AttributeValueTypeDto$1, CkTypeSelectorService, CkTypeAttributeService, GetEntitiesByCkTypeDtoGQL, RuntimeEntitySelectDataSource, RuntimeEntityDialogDataSource, SearchFilterTypesDto, SortOrdersDto, FieldFilterOperatorsDto, GetCkTypesDtoGQL, GetCkModelByIdDtoGQL, CkTypeMetaData, GraphDirectionDto, AssociationModOptionsDto, GraphQL, DeleteStrategiesDto, CommunicationService, provideOctoServices } from '@meshmakers/octo-services';
|
|
5
5
|
import { Roles, provideMmSharedAuth } from '@meshmakers/shared-auth';
|
|
6
6
|
import { WindowStateService, EntitySelectInputComponent, DataSourceTyped, HierarchyDataSourceBase, NotificationDisplayService, TreeComponent, ListViewComponent, FetchResultTyped, DataSourceBase, InputService, BaseTreeDetailComponent, ConfirmationService, provideMmSharedUi } from '@meshmakers/shared-ui';
|
|
7
7
|
import * as i1$2 from '@angular/common';
|
|
@@ -19,12 +19,12 @@ import * as i5$1 from '@progress/kendo-angular-icons';
|
|
|
19
19
|
import { IconsModule, SVGIconModule, SVGIconComponent } from '@progress/kendo-angular-icons';
|
|
20
20
|
import * as i5 from '@progress/kendo-angular-inputs';
|
|
21
21
|
import { InputsModule, TextBoxModule, KENDO_INPUTS, SwitchModule } from '@progress/kendo-angular-inputs';
|
|
22
|
-
import { searchIcon, sortAscSmallIcon, sortDescSmallIcon, filterClearIcon, fileIcon, folderIcon, calendarIcon, checkboxCheckedIcon, listUnorderedIcon, chevronRightIcon, chevronDownIcon, downloadIcon, windowIcon, arrowRightIcon, arrowLeftIcon, chevronDoubleRightIcon, chevronDoubleLeftIcon, arrowUpIcon, arrowDownIcon, pencilIcon, trashIcon, copyIcon, folderMoreIcon,
|
|
22
|
+
import { searchIcon, sortAscSmallIcon, sortDescSmallIcon, filterClearIcon, fileIcon, folderIcon, calendarIcon, checkboxCheckedIcon, listUnorderedIcon, chevronRightIcon, chevronDownIcon, downloadIcon, windowIcon, arrowRightIcon, arrowLeftIcon, chevronDoubleRightIcon, chevronDoubleLeftIcon, arrowUpIcon, arrowDownIcon, pencilIcon, trashIcon, copyIcon, folderMoreIcon, gearIcon, folderOpenIcon, plusIcon, minusIcon, dollarIcon, hyperlinkOpenIcon, infoCircleIcon, eyeIcon, arrowRotateCcwIcon, locationsIcon, arrowRotateCwIcon, xIcon, checkCircleIcon, exclamationCircleIcon, xCircleIcon, warningCircleIcon, gridIcon, linkIcon } from '@progress/kendo-svg-icons';
|
|
23
23
|
import { Subject, firstValueFrom, Subscription, of, forkJoin, map as map$1, takeUntil as takeUntil$1, catchError as catchError$1, defer, from, finalize, switchMap as switchMap$1, startWith } from 'rxjs';
|
|
24
24
|
import { debounceTime, distinctUntilChanged, map, switchMap, tap, catchError, takeUntil } from 'rxjs/operators';
|
|
25
25
|
import { LoaderModule, BadgeModule } from '@progress/kendo-angular-indicators';
|
|
26
26
|
import * as i1$3 from 'apollo-angular';
|
|
27
|
-
import { gql } from 'apollo-angular';
|
|
27
|
+
import { gql, Apollo } from 'apollo-angular';
|
|
28
28
|
import { isCompositeFilterDescriptor } from '@progress/kendo-data-query';
|
|
29
29
|
import { TreeItemDataTyped } from '@meshmakers/shared-services';
|
|
30
30
|
import * as i7 from '@progress/kendo-angular-dateinputs';
|
|
@@ -5488,6 +5488,66 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
|
|
|
5488
5488
|
}]
|
|
5489
5489
|
}], ctorParameters: () => [{ type: i1$3.Apollo }] });
|
|
5490
5490
|
|
|
5491
|
+
const GetCkTypeAssociationRolesDocumentDto = gql `
|
|
5492
|
+
query getCkTypeAssociationRoles($ckTypeId: String!) {
|
|
5493
|
+
constructionKit {
|
|
5494
|
+
types(rtCkId: $ckTypeId, first: 1) {
|
|
5495
|
+
items {
|
|
5496
|
+
rtCkTypeId
|
|
5497
|
+
associations {
|
|
5498
|
+
in {
|
|
5499
|
+
all {
|
|
5500
|
+
roleId {
|
|
5501
|
+
fullName
|
|
5502
|
+
semanticVersionedFullName
|
|
5503
|
+
}
|
|
5504
|
+
rtRoleId
|
|
5505
|
+
navigationPropertyName
|
|
5506
|
+
multiplicity
|
|
5507
|
+
targetCkTypeId {
|
|
5508
|
+
fullName
|
|
5509
|
+
}
|
|
5510
|
+
rtTargetCkTypeId
|
|
5511
|
+
rtOriginCkTypeId
|
|
5512
|
+
}
|
|
5513
|
+
}
|
|
5514
|
+
out {
|
|
5515
|
+
all {
|
|
5516
|
+
roleId {
|
|
5517
|
+
fullName
|
|
5518
|
+
semanticVersionedFullName
|
|
5519
|
+
}
|
|
5520
|
+
rtRoleId
|
|
5521
|
+
navigationPropertyName
|
|
5522
|
+
multiplicity
|
|
5523
|
+
targetCkTypeId {
|
|
5524
|
+
fullName
|
|
5525
|
+
}
|
|
5526
|
+
rtTargetCkTypeId
|
|
5527
|
+
rtOriginCkTypeId
|
|
5528
|
+
}
|
|
5529
|
+
}
|
|
5530
|
+
}
|
|
5531
|
+
}
|
|
5532
|
+
}
|
|
5533
|
+
}
|
|
5534
|
+
}
|
|
5535
|
+
`;
|
|
5536
|
+
class GetCkTypeAssociationRolesDtoGQL extends i1$3.Query {
|
|
5537
|
+
document = GetCkTypeAssociationRolesDocumentDto;
|
|
5538
|
+
constructor(apollo) {
|
|
5539
|
+
super(apollo);
|
|
5540
|
+
}
|
|
5541
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: GetCkTypeAssociationRolesDtoGQL, deps: [{ token: i1$3.Apollo }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
5542
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: GetCkTypeAssociationRolesDtoGQL, providedIn: 'root' });
|
|
5543
|
+
}
|
|
5544
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: GetCkTypeAssociationRolesDtoGQL, decorators: [{
|
|
5545
|
+
type: Injectable,
|
|
5546
|
+
args: [{
|
|
5547
|
+
providedIn: 'root'
|
|
5548
|
+
}]
|
|
5549
|
+
}], ctorParameters: () => [{ type: i1$3.Apollo }] });
|
|
5550
|
+
|
|
5491
5551
|
const GetRuntimeEntityAssociationsByIdDocumentDto = gql `
|
|
5492
5552
|
query getRuntimeEntityAssociationsById($rtId: OctoObjectId!, $ckTypeId: String!, $direction: GraphDirection!, $after: String, $first: Int, $roleId: String, $relatedRtCkId: RtCkTypeId, $relatedRtId: OctoObjectId) {
|
|
5493
5553
|
runtime {
|
|
@@ -5534,39 +5594,32 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
|
|
|
5534
5594
|
}]
|
|
5535
5595
|
}], ctorParameters: () => [{ type: i1$3.Apollo }] });
|
|
5536
5596
|
|
|
5537
|
-
const
|
|
5538
|
-
query
|
|
5597
|
+
const GetTreeAssociationTargetsDocumentDto = gql `
|
|
5598
|
+
query getTreeAssociationTargets($rtId: OctoObjectId!, $ckTypeId: String!, $roleId: String!, $targetCkTypeId: String!, $direction: GraphDirection!, $first: Int) {
|
|
5539
5599
|
runtime {
|
|
5540
|
-
runtimeEntities(rtId: $rtId, ckId: $ckTypeId) {
|
|
5600
|
+
runtimeEntities(rtId: $rtId, ckId: $ckTypeId, first: 1) {
|
|
5541
5601
|
items {
|
|
5542
|
-
rtId
|
|
5543
|
-
ckTypeId
|
|
5544
|
-
attributes(attributeNames: ["name", "description"]) {
|
|
5545
|
-
items {
|
|
5546
|
-
attributeName
|
|
5547
|
-
value
|
|
5548
|
-
}
|
|
5549
|
-
}
|
|
5550
5602
|
associations {
|
|
5551
|
-
targets(
|
|
5603
|
+
targets(
|
|
5604
|
+
roleId: $roleId
|
|
5605
|
+
ckId: $targetCkTypeId
|
|
5606
|
+
direction: $direction
|
|
5607
|
+
first: $first
|
|
5608
|
+
) {
|
|
5609
|
+
totalCount
|
|
5552
5610
|
items {
|
|
5553
5611
|
rtId
|
|
5554
5612
|
ckTypeId
|
|
5555
|
-
|
|
5613
|
+
rtWellKnownName
|
|
5614
|
+
attributes(
|
|
5615
|
+
attributeNames: ["name", "displayName", "description"]
|
|
5616
|
+
resolveEnumValuesToNames: true
|
|
5617
|
+
) {
|
|
5556
5618
|
items {
|
|
5557
5619
|
attributeName
|
|
5558
5620
|
value
|
|
5559
5621
|
}
|
|
5560
5622
|
}
|
|
5561
|
-
associations {
|
|
5562
|
-
targets(
|
|
5563
|
-
roleId: $indirectRoleId
|
|
5564
|
-
ckId: $indirectTargetCkTypeId
|
|
5565
|
-
direction: INBOUND
|
|
5566
|
-
) {
|
|
5567
|
-
totalCount
|
|
5568
|
-
}
|
|
5569
|
-
}
|
|
5570
5623
|
}
|
|
5571
5624
|
}
|
|
5572
5625
|
}
|
|
@@ -5575,15 +5628,15 @@ const GetTreeNodesDocumentDto = gql `
|
|
|
5575
5628
|
}
|
|
5576
5629
|
}
|
|
5577
5630
|
`;
|
|
5578
|
-
class
|
|
5579
|
-
document =
|
|
5631
|
+
class GetTreeAssociationTargetsDtoGQL extends i1$3.Query {
|
|
5632
|
+
document = GetTreeAssociationTargetsDocumentDto;
|
|
5580
5633
|
constructor(apollo) {
|
|
5581
5634
|
super(apollo);
|
|
5582
5635
|
}
|
|
5583
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type:
|
|
5584
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type:
|
|
5636
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: GetTreeAssociationTargetsDtoGQL, deps: [{ token: i1$3.Apollo }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
5637
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: GetTreeAssociationTargetsDtoGQL, providedIn: 'root' });
|
|
5585
5638
|
}
|
|
5586
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type:
|
|
5639
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: GetTreeAssociationTargetsDtoGQL, decorators: [{
|
|
5587
5640
|
type: Injectable,
|
|
5588
5641
|
args: [{
|
|
5589
5642
|
providedIn: 'root'
|
|
@@ -5963,6 +6016,475 @@ const article = {
|
|
|
5963
6016
|
viewBox: '0 -960 960 960'
|
|
5964
6017
|
};
|
|
5965
6018
|
|
|
6019
|
+
/** Runtime CK type id of the per-tenant tree navigation configuration singleton. */
|
|
6020
|
+
const CONFIG_CK_TYPE_ID = 'System.UI/TreeNavigationConfiguration';
|
|
6021
|
+
/** rtWellKnownName of the singleton instance. */
|
|
6022
|
+
const CONFIG_WELL_KNOWN_NAME = 'TreeNavigation';
|
|
6023
|
+
/** Matches every source CK type. */
|
|
6024
|
+
const WILDCARD = '*';
|
|
6025
|
+
const CONFIG_TYPE_EXISTS_QUERY = gql `
|
|
6026
|
+
query treeNavigationConfigTypeExists {
|
|
6027
|
+
constructionKit {
|
|
6028
|
+
types(rtCkId: "System.UI/TreeNavigationConfiguration", first: 1) {
|
|
6029
|
+
items {
|
|
6030
|
+
rtCkTypeId
|
|
6031
|
+
}
|
|
6032
|
+
}
|
|
6033
|
+
}
|
|
6034
|
+
}
|
|
6035
|
+
`;
|
|
6036
|
+
const CONFIG_QUERY = gql `
|
|
6037
|
+
query getTreeNavigationConfiguration {
|
|
6038
|
+
runtime {
|
|
6039
|
+
systemUITreeNavigationConfiguration(
|
|
6040
|
+
first: 1
|
|
6041
|
+
fieldFilter: [
|
|
6042
|
+
{
|
|
6043
|
+
attributePath: "rtWellKnownName"
|
|
6044
|
+
operator: EQUALS
|
|
6045
|
+
comparisonValue: "TreeNavigation"
|
|
6046
|
+
}
|
|
6047
|
+
]
|
|
6048
|
+
) {
|
|
6049
|
+
items {
|
|
6050
|
+
rtId
|
|
6051
|
+
roles {
|
|
6052
|
+
sourceCkTypeId
|
|
6053
|
+
roleId
|
|
6054
|
+
visible
|
|
6055
|
+
displayName
|
|
6056
|
+
sortIndex
|
|
6057
|
+
grouped
|
|
6058
|
+
icon
|
|
6059
|
+
}
|
|
6060
|
+
}
|
|
6061
|
+
}
|
|
6062
|
+
}
|
|
6063
|
+
}
|
|
6064
|
+
`;
|
|
6065
|
+
/**
|
|
6066
|
+
* Loads the singleton's `perspectives` array (AB#4263). Kept SEPARATE from
|
|
6067
|
+
* CONFIG_QUERY on purpose: the `perspectives` field only exists in the tenant
|
|
6068
|
+
* schema when System.UI >= 2.3.0. On a tenant still on System.UI 2.2.0 the type
|
|
6069
|
+
* IS present (so the type-exists probe passes) but this field is not, which would
|
|
6070
|
+
* raise a GraphQL validation error for the whole operation. Isolating it here
|
|
6071
|
+
* lets `fetchPerspectives` swallow that error so the 2.2.0 roles feature keeps
|
|
6072
|
+
* working and perspectives simply come back empty.
|
|
6073
|
+
*/
|
|
6074
|
+
const CONFIG_PERSPECTIVES_QUERY = gql `
|
|
6075
|
+
query getTreeNavigationPerspectives {
|
|
6076
|
+
runtime {
|
|
6077
|
+
systemUITreeNavigationConfiguration(
|
|
6078
|
+
first: 1
|
|
6079
|
+
fieldFilter: [
|
|
6080
|
+
{
|
|
6081
|
+
attributePath: "rtWellKnownName"
|
|
6082
|
+
operator: EQUALS
|
|
6083
|
+
comparisonValue: "TreeNavigation"
|
|
6084
|
+
}
|
|
6085
|
+
]
|
|
6086
|
+
) {
|
|
6087
|
+
items {
|
|
6088
|
+
rtId
|
|
6089
|
+
perspectives {
|
|
6090
|
+
key
|
|
6091
|
+
displayName
|
|
6092
|
+
sortIndex
|
|
6093
|
+
icon
|
|
6094
|
+
rootMode
|
|
6095
|
+
rootCkTypeId
|
|
6096
|
+
primaryRoleId
|
|
6097
|
+
primaryDirection
|
|
6098
|
+
secondaryRoleIds
|
|
6099
|
+
}
|
|
6100
|
+
}
|
|
6101
|
+
}
|
|
6102
|
+
}
|
|
6103
|
+
}
|
|
6104
|
+
`;
|
|
6105
|
+
const ROLE_SUGGESTIONS_QUERY = gql `
|
|
6106
|
+
query treeNavigationRoleSuggestions($ckTypeId: String!) {
|
|
6107
|
+
constructionKit {
|
|
6108
|
+
types(rtCkId: $ckTypeId, first: 1) {
|
|
6109
|
+
items {
|
|
6110
|
+
associations {
|
|
6111
|
+
in {
|
|
6112
|
+
all {
|
|
6113
|
+
rtRoleId
|
|
6114
|
+
navigationPropertyName
|
|
6115
|
+
}
|
|
6116
|
+
}
|
|
6117
|
+
}
|
|
6118
|
+
}
|
|
6119
|
+
}
|
|
6120
|
+
}
|
|
6121
|
+
}
|
|
6122
|
+
`;
|
|
6123
|
+
const CREATE_CONFIG_MUTATION = gql `
|
|
6124
|
+
mutation createTreeNavigationConfiguration(
|
|
6125
|
+
$entities: [SystemUITreeNavigationConfigurationInput!]!
|
|
6126
|
+
) {
|
|
6127
|
+
runtime {
|
|
6128
|
+
systemUITreeNavigationConfigurations {
|
|
6129
|
+
create(entities: $entities) {
|
|
6130
|
+
rtId
|
|
6131
|
+
}
|
|
6132
|
+
}
|
|
6133
|
+
}
|
|
6134
|
+
}
|
|
6135
|
+
`;
|
|
6136
|
+
const UPDATE_CONFIG_MUTATION = gql `
|
|
6137
|
+
mutation updateTreeNavigationConfiguration(
|
|
6138
|
+
$entities: [SystemUITreeNavigationConfigurationInputUpdate!]!
|
|
6139
|
+
) {
|
|
6140
|
+
runtime {
|
|
6141
|
+
systemUITreeNavigationConfigurations {
|
|
6142
|
+
update(entities: $entities) {
|
|
6143
|
+
rtId
|
|
6144
|
+
}
|
|
6145
|
+
}
|
|
6146
|
+
}
|
|
6147
|
+
}
|
|
6148
|
+
`;
|
|
6149
|
+
/**
|
|
6150
|
+
* Loads the optional per-tenant `System.UI/TreeNavigationConfiguration` singleton
|
|
6151
|
+
* and resolves per-association overrides for the entity trees.
|
|
6152
|
+
*
|
|
6153
|
+
* Design notes:
|
|
6154
|
+
* - The config entity is OPTIONAL. When the CK type is not installed on the
|
|
6155
|
+
* tenant (System.UI < 2.2.0) or no instance exists, every lookup returns
|
|
6156
|
+
* undefined and the trees fall back to pure auto-discovery.
|
|
6157
|
+
* - The singleton field (`systemUITreeNavigationConfiguration`) only exists in
|
|
6158
|
+
* the tenant schema when the CK type is installed, so querying it blindly
|
|
6159
|
+
* would raise a GraphQL validation error (and a user-facing toast). We first
|
|
6160
|
+
* probe the CK schema with the always-valid `constructionKit.types` query and
|
|
6161
|
+
* only run the singleton query when the type is present.
|
|
6162
|
+
* - Uses inline `gql` (not codegen) so the feature is decoupled from a schema
|
|
6163
|
+
* re-introspection that includes the new CK type.
|
|
6164
|
+
*/
|
|
6165
|
+
class TreeNavigationConfigService {
|
|
6166
|
+
apollo = inject(Apollo);
|
|
6167
|
+
/** key `${sourceCkTypeId}::${roleId}` -> override; cached for the session. */
|
|
6168
|
+
overridesPromise;
|
|
6169
|
+
/** Configured extra perspectives; cached for the session. */
|
|
6170
|
+
perspectivesPromise;
|
|
6171
|
+
/**
|
|
6172
|
+
* Resolves the override for one (source type, role) pair, preferring an exact
|
|
6173
|
+
* source-type match over a wildcard (`*`) rule. Returns undefined when nothing
|
|
6174
|
+
* is configured.
|
|
6175
|
+
*/
|
|
6176
|
+
async resolve(sourceCkTypeId, roleId) {
|
|
6177
|
+
const overrides = await this.getOverrides();
|
|
6178
|
+
return (overrides.get(`${sourceCkTypeId}::${roleId}`) ??
|
|
6179
|
+
overrides.get(`${WILDCARD}::${roleId}`));
|
|
6180
|
+
}
|
|
6181
|
+
/** Forces a reload on next access (e.g. after a tenant switch). */
|
|
6182
|
+
reset() {
|
|
6183
|
+
this.overridesPromise = undefined;
|
|
6184
|
+
this.perspectivesPromise = undefined;
|
|
6185
|
+
}
|
|
6186
|
+
/**
|
|
6187
|
+
* Returns the configured extra tree perspectives (AB#4263), sorted by
|
|
6188
|
+
* sortIndex then displayName. Returns [] when the CK type is absent
|
|
6189
|
+
* (System.UI < 2.3.0) or none are configured. The built-in spatial
|
|
6190
|
+
* perspective is synthesized by the data source and is NOT included here.
|
|
6191
|
+
*/
|
|
6192
|
+
perspectives() {
|
|
6193
|
+
if (!this.perspectivesPromise) {
|
|
6194
|
+
this.perspectivesPromise = this.loadPerspectives().catch((error) => {
|
|
6195
|
+
console.error('Error loading tree navigation perspectives', error);
|
|
6196
|
+
this.perspectivesPromise = undefined;
|
|
6197
|
+
return [];
|
|
6198
|
+
});
|
|
6199
|
+
}
|
|
6200
|
+
return this.perspectivesPromise;
|
|
6201
|
+
}
|
|
6202
|
+
async loadPerspectives() {
|
|
6203
|
+
// Skip the singleton entirely when the CK type is not installed at all.
|
|
6204
|
+
if (!(await this.probeTypePresent())) {
|
|
6205
|
+
return [];
|
|
6206
|
+
}
|
|
6207
|
+
const rawPerspectives = await this.fetchPerspectivesRaw();
|
|
6208
|
+
return rawPerspectives
|
|
6209
|
+
.map((raw) => this.toPerspectiveDefinition(raw))
|
|
6210
|
+
.filter((p) => p !== null)
|
|
6211
|
+
.sort((a, b) => (a.sortIndex ?? Number.MAX_SAFE_INTEGER) -
|
|
6212
|
+
(b.sortIndex ?? Number.MAX_SAFE_INTEGER) ||
|
|
6213
|
+
a.displayName.localeCompare(b.displayName));
|
|
6214
|
+
}
|
|
6215
|
+
/** Maps a raw perspective record to a definition, dropping invalid rows. */
|
|
6216
|
+
toPerspectiveDefinition(raw) {
|
|
6217
|
+
const key = raw?.key?.trim();
|
|
6218
|
+
if (!key) {
|
|
6219
|
+
return null;
|
|
6220
|
+
}
|
|
6221
|
+
const rootMode = raw?.rootMode === 'Type' ? 'Type' : 'Spatial';
|
|
6222
|
+
const secondary = (raw?.secondaryRoleIds ?? [])
|
|
6223
|
+
.map((r) => (typeof r === 'string' ? r : ''))
|
|
6224
|
+
.filter((r) => r.length > 0);
|
|
6225
|
+
return {
|
|
6226
|
+
key,
|
|
6227
|
+
displayName: raw?.displayName?.trim() || key,
|
|
6228
|
+
sortIndex: raw?.sortIndex ?? undefined,
|
|
6229
|
+
icon: raw?.icon ?? undefined,
|
|
6230
|
+
rootMode,
|
|
6231
|
+
rootCkTypeId: raw?.rootCkTypeId ?? undefined,
|
|
6232
|
+
primaryRoleId: raw?.primaryRoleId ?? undefined,
|
|
6233
|
+
primaryDirection: raw?.primaryDirection === 'Outbound' ? 'Outbound' : undefined,
|
|
6234
|
+
secondaryRoleIds: secondary.length > 0 ? secondary : undefined,
|
|
6235
|
+
};
|
|
6236
|
+
}
|
|
6237
|
+
/**
|
|
6238
|
+
* Returns the inbound association roles declared on a CK type, for the role
|
|
6239
|
+
* autocomplete in the settings editor. Returns `{ roleId, label }` where the
|
|
6240
|
+
* label is the friendly inbound name plus the role id. Empty for `*` or an
|
|
6241
|
+
* unknown type (orphan roles can still be typed as custom values).
|
|
6242
|
+
*/
|
|
6243
|
+
async getRoleSuggestions(ckTypeId) {
|
|
6244
|
+
if (!ckTypeId || ckTypeId === WILDCARD) {
|
|
6245
|
+
return [];
|
|
6246
|
+
}
|
|
6247
|
+
try {
|
|
6248
|
+
const result = await firstValueFrom(this.apollo.query({
|
|
6249
|
+
query: ROLE_SUGGESTIONS_QUERY,
|
|
6250
|
+
variables: { ckTypeId },
|
|
6251
|
+
fetchPolicy: 'network-only',
|
|
6252
|
+
}));
|
|
6253
|
+
const all = result.data?.constructionKit?.types?.items?.[0]?.associations?.in
|
|
6254
|
+
?.all ?? [];
|
|
6255
|
+
const byRole = new Map();
|
|
6256
|
+
for (const role of all) {
|
|
6257
|
+
const roleId = String(role?.rtRoleId ?? '');
|
|
6258
|
+
if (!roleId || byRole.has(roleId)) {
|
|
6259
|
+
continue;
|
|
6260
|
+
}
|
|
6261
|
+
const nav = role?.navigationPropertyName ?? '';
|
|
6262
|
+
byRole.set(roleId, nav ? `${nav} (${roleId})` : roleId);
|
|
6263
|
+
}
|
|
6264
|
+
return [...byRole.entries()].map(([roleId, label]) => ({ roleId, label }));
|
|
6265
|
+
}
|
|
6266
|
+
catch (error) {
|
|
6267
|
+
console.error('Error loading role suggestions for', ckTypeId, error);
|
|
6268
|
+
return [];
|
|
6269
|
+
}
|
|
6270
|
+
}
|
|
6271
|
+
getOverrides() {
|
|
6272
|
+
if (!this.overridesPromise) {
|
|
6273
|
+
this.overridesPromise = this.load().catch((error) => {
|
|
6274
|
+
console.error('Error loading tree navigation configuration', error);
|
|
6275
|
+
// Drop the cache so a later expand can retry, fall back to no overrides.
|
|
6276
|
+
this.overridesPromise = undefined;
|
|
6277
|
+
return new Map();
|
|
6278
|
+
});
|
|
6279
|
+
}
|
|
6280
|
+
return this.overridesPromise;
|
|
6281
|
+
}
|
|
6282
|
+
async load() {
|
|
6283
|
+
const map = new Map();
|
|
6284
|
+
const { rawRoles } = await this.fetchSingleton();
|
|
6285
|
+
for (const raw of rawRoles) {
|
|
6286
|
+
if (!raw?.sourceCkTypeId || !raw?.roleId) {
|
|
6287
|
+
continue;
|
|
6288
|
+
}
|
|
6289
|
+
map.set(`${raw.sourceCkTypeId}::${raw.roleId}`, {
|
|
6290
|
+
visible: raw.visible ?? undefined,
|
|
6291
|
+
displayName: raw.displayName ?? undefined,
|
|
6292
|
+
sortIndex: raw.sortIndex ?? undefined,
|
|
6293
|
+
grouped: raw.grouped ?? undefined,
|
|
6294
|
+
icon: raw.icon ?? undefined,
|
|
6295
|
+
});
|
|
6296
|
+
}
|
|
6297
|
+
return map;
|
|
6298
|
+
}
|
|
6299
|
+
/**
|
|
6300
|
+
* Loads the full configuration for editing (settings page). Returns whether
|
|
6301
|
+
* the CK type is installed (so the page can show a clear "upgrade System.UI"
|
|
6302
|
+
* hint), the singleton rtId (null when not created yet), and the role rules.
|
|
6303
|
+
*/
|
|
6304
|
+
async loadConfig() {
|
|
6305
|
+
const { typePresent, rtId, rawRoles } = await this.fetchSingleton();
|
|
6306
|
+
const rawPerspectives = typePresent ? await this.fetchPerspectivesRaw() : [];
|
|
6307
|
+
const roles = [];
|
|
6308
|
+
for (const raw of rawRoles) {
|
|
6309
|
+
if (!raw?.sourceCkTypeId || !raw?.roleId) {
|
|
6310
|
+
continue;
|
|
6311
|
+
}
|
|
6312
|
+
roles.push({
|
|
6313
|
+
sourceCkTypeId: raw.sourceCkTypeId,
|
|
6314
|
+
roleId: raw.roleId,
|
|
6315
|
+
visible: raw.visible ?? undefined,
|
|
6316
|
+
displayName: raw.displayName ?? undefined,
|
|
6317
|
+
sortIndex: raw.sortIndex ?? undefined,
|
|
6318
|
+
grouped: raw.grouped ?? undefined,
|
|
6319
|
+
icon: raw.icon ?? undefined,
|
|
6320
|
+
});
|
|
6321
|
+
}
|
|
6322
|
+
const perspectives = rawPerspectives
|
|
6323
|
+
.map((raw) => this.toPerspectiveDefinition(raw))
|
|
6324
|
+
.filter((p) => p !== null);
|
|
6325
|
+
return { typePresent, rtId, roles, perspectives };
|
|
6326
|
+
}
|
|
6327
|
+
/**
|
|
6328
|
+
* Creates or updates the singleton with the given rules and perspectives, then
|
|
6329
|
+
* invalidates the resolve/perspective cache so the trees pick up the change on
|
|
6330
|
+
* the next expand. Returns the singleton rtId.
|
|
6331
|
+
*/
|
|
6332
|
+
async saveConfig(rtId, roles, perspectives = []) {
|
|
6333
|
+
const cleanRoles = roles
|
|
6334
|
+
.filter((r) => r.sourceCkTypeId && r.roleId)
|
|
6335
|
+
.map((r) => this.toRoleInput(r));
|
|
6336
|
+
const cleanPerspectives = perspectives
|
|
6337
|
+
.filter((p) => p.key)
|
|
6338
|
+
.map((p) => this.toPerspectiveInput(p));
|
|
6339
|
+
// Only send `perspectives` when non-empty: on a System.UI 2.2.0 tenant the
|
|
6340
|
+
// input type has no `perspectives` field, so including it (even as []) would
|
|
6341
|
+
// fail validation and break roles saving. Trade-off: clearing the last
|
|
6342
|
+
// perspective on 2.3.0 is not persisted via save (edge case).
|
|
6343
|
+
let savedRtId;
|
|
6344
|
+
if (rtId) {
|
|
6345
|
+
const item = { roles: cleanRoles };
|
|
6346
|
+
if (cleanPerspectives.length > 0) {
|
|
6347
|
+
item['perspectives'] = cleanPerspectives;
|
|
6348
|
+
}
|
|
6349
|
+
const result = await firstValueFrom(this.apollo.mutate({
|
|
6350
|
+
mutation: UPDATE_CONFIG_MUTATION,
|
|
6351
|
+
variables: {
|
|
6352
|
+
entities: [{ rtId, item }],
|
|
6353
|
+
},
|
|
6354
|
+
fetchPolicy: 'no-cache',
|
|
6355
|
+
}));
|
|
6356
|
+
savedRtId =
|
|
6357
|
+
result.data?.runtime?.systemUITreeNavigationConfigurations?.update?.[0]
|
|
6358
|
+
?.rtId ?? rtId;
|
|
6359
|
+
}
|
|
6360
|
+
else {
|
|
6361
|
+
const result = await firstValueFrom(this.apollo.mutate({
|
|
6362
|
+
mutation: CREATE_CONFIG_MUTATION,
|
|
6363
|
+
variables: {
|
|
6364
|
+
entities: [
|
|
6365
|
+
{
|
|
6366
|
+
rtWellKnownName: CONFIG_WELL_KNOWN_NAME,
|
|
6367
|
+
name: 'Tree Navigation',
|
|
6368
|
+
roles: cleanRoles,
|
|
6369
|
+
...(cleanPerspectives.length > 0
|
|
6370
|
+
? { perspectives: cleanPerspectives }
|
|
6371
|
+
: {}),
|
|
6372
|
+
},
|
|
6373
|
+
],
|
|
6374
|
+
},
|
|
6375
|
+
fetchPolicy: 'no-cache',
|
|
6376
|
+
}));
|
|
6377
|
+
const created = result.data?.runtime?.systemUITreeNavigationConfigurations?.create?.[0]
|
|
6378
|
+
?.rtId;
|
|
6379
|
+
if (!created) {
|
|
6380
|
+
throw new Error('createTreeNavigationConfiguration returned no entity');
|
|
6381
|
+
}
|
|
6382
|
+
savedRtId = created;
|
|
6383
|
+
}
|
|
6384
|
+
this.reset();
|
|
6385
|
+
return savedRtId;
|
|
6386
|
+
}
|
|
6387
|
+
/** Drops undefined fields so the record-array input only carries set values. */
|
|
6388
|
+
toRoleInput(role) {
|
|
6389
|
+
const input = {
|
|
6390
|
+
sourceCkTypeId: role.sourceCkTypeId,
|
|
6391
|
+
roleId: role.roleId,
|
|
6392
|
+
};
|
|
6393
|
+
if (role.visible !== undefined)
|
|
6394
|
+
input['visible'] = role.visible;
|
|
6395
|
+
if (role.displayName !== undefined && role.displayName !== '') {
|
|
6396
|
+
input['displayName'] = role.displayName;
|
|
6397
|
+
}
|
|
6398
|
+
if (role.sortIndex !== undefined && role.sortIndex !== null) {
|
|
6399
|
+
input['sortIndex'] = role.sortIndex;
|
|
6400
|
+
}
|
|
6401
|
+
if (role.grouped !== undefined)
|
|
6402
|
+
input['grouped'] = role.grouped;
|
|
6403
|
+
if (role.icon !== undefined && role.icon !== '')
|
|
6404
|
+
input['icon'] = role.icon;
|
|
6405
|
+
return input;
|
|
6406
|
+
}
|
|
6407
|
+
/** Drops undefined/empty fields so the perspective input only carries set values. */
|
|
6408
|
+
toPerspectiveInput(p) {
|
|
6409
|
+
const input = {
|
|
6410
|
+
key: p.key,
|
|
6411
|
+
displayName: p.displayName || p.key,
|
|
6412
|
+
rootMode: p.rootMode,
|
|
6413
|
+
};
|
|
6414
|
+
if (p.sortIndex !== undefined && p.sortIndex !== null) {
|
|
6415
|
+
input['sortIndex'] = p.sortIndex;
|
|
6416
|
+
}
|
|
6417
|
+
if (p.icon)
|
|
6418
|
+
input['icon'] = p.icon;
|
|
6419
|
+
if (p.rootCkTypeId)
|
|
6420
|
+
input['rootCkTypeId'] = p.rootCkTypeId;
|
|
6421
|
+
if (p.primaryRoleId)
|
|
6422
|
+
input['primaryRoleId'] = p.primaryRoleId;
|
|
6423
|
+
if (p.primaryDirection)
|
|
6424
|
+
input['primaryDirection'] = p.primaryDirection;
|
|
6425
|
+
if (p.secondaryRoleIds && p.secondaryRoleIds.length > 0) {
|
|
6426
|
+
input['secondaryRoleIds'] = p.secondaryRoleIds;
|
|
6427
|
+
}
|
|
6428
|
+
return input;
|
|
6429
|
+
}
|
|
6430
|
+
/**
|
|
6431
|
+
* Probes whether the `System.UI/TreeNavigationConfiguration` CK type is
|
|
6432
|
+
* installed on the tenant (System.UI >= 2.2.0). Uses the always-valid
|
|
6433
|
+
* `constructionKit.types` query so it never raises a schema validation error.
|
|
6434
|
+
*/
|
|
6435
|
+
async probeTypePresent() {
|
|
6436
|
+
const exists = await firstValueFrom(this.apollo.query({ query: CONFIG_TYPE_EXISTS_QUERY, fetchPolicy: 'network-only' }));
|
|
6437
|
+
return (exists.data?.constructionKit?.types?.items?.length ?? 0) > 0;
|
|
6438
|
+
}
|
|
6439
|
+
/**
|
|
6440
|
+
* Probes the CK schema and (when present) loads the singleton's raw roles.
|
|
6441
|
+
* Perspectives are loaded separately (see fetchPerspectivesRaw) so a System.UI
|
|
6442
|
+
* 2.2.0 tenant (type present but no `perspectives` field yet) keeps its roles.
|
|
6443
|
+
*/
|
|
6444
|
+
async fetchSingleton() {
|
|
6445
|
+
if (!(await this.probeTypePresent())) {
|
|
6446
|
+
return { typePresent: false, rtId: null, rawRoles: [] };
|
|
6447
|
+
}
|
|
6448
|
+
const result = await firstValueFrom(this.apollo.query({ query: CONFIG_QUERY, fetchPolicy: 'network-only' }));
|
|
6449
|
+
const item = result.data?.runtime?.systemUITreeNavigationConfiguration?.items?.[0];
|
|
6450
|
+
return {
|
|
6451
|
+
typePresent: true,
|
|
6452
|
+
rtId: item?.rtId ?? null,
|
|
6453
|
+
rawRoles: item?.roles ?? [],
|
|
6454
|
+
};
|
|
6455
|
+
}
|
|
6456
|
+
/**
|
|
6457
|
+
* Loads the singleton's raw perspectives, tolerating the System.UI 2.2.0 case
|
|
6458
|
+
* where the `perspectives` field does not yet exist (GraphQL validation error).
|
|
6459
|
+
* Any failure yields an empty list so roles loading is never affected.
|
|
6460
|
+
*/
|
|
6461
|
+
async fetchPerspectivesRaw() {
|
|
6462
|
+
try {
|
|
6463
|
+
const result = await firstValueFrom(this.apollo.query({ query: CONFIG_PERSPECTIVES_QUERY, fetchPolicy: 'network-only' }));
|
|
6464
|
+
return (result.data?.runtime?.systemUITreeNavigationConfiguration?.items?.[0]
|
|
6465
|
+
?.perspectives ?? []);
|
|
6466
|
+
}
|
|
6467
|
+
catch {
|
|
6468
|
+
// System.UI 2.2.0: `perspectives` field absent → validation error. Degrade
|
|
6469
|
+
// to no perspectives; the roles query above is unaffected.
|
|
6470
|
+
return [];
|
|
6471
|
+
}
|
|
6472
|
+
}
|
|
6473
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: TreeNavigationConfigService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
6474
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: TreeNavigationConfigService, providedIn: 'root' });
|
|
6475
|
+
}
|
|
6476
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: TreeNavigationConfigService, decorators: [{
|
|
6477
|
+
type: Injectable,
|
|
6478
|
+
args: [{
|
|
6479
|
+
providedIn: 'root',
|
|
6480
|
+
}]
|
|
6481
|
+
}] });
|
|
6482
|
+
const TREE_NAVIGATION_CONFIG_CONSTANTS = {
|
|
6483
|
+
CONFIG_CK_TYPE_ID,
|
|
6484
|
+
CONFIG_WELL_KNOWN_NAME,
|
|
6485
|
+
WILDCARD,
|
|
6486
|
+
};
|
|
6487
|
+
|
|
5966
6488
|
/**
|
|
5967
6489
|
* Performs helpful Octomesh Types operations, like checks, comparisons etc.
|
|
5968
6490
|
*/
|
|
@@ -5988,9 +6510,59 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
|
|
|
5988
6510
|
}]
|
|
5989
6511
|
}] });
|
|
5990
6512
|
|
|
6513
|
+
/** Well-known role id of the hierarchical parent-child association. */
|
|
6514
|
+
const PARENT_CHILD_ROLE_ID = 'System/ParentChild';
|
|
6515
|
+
/**
|
|
6516
|
+
* Target CK types that cannot be navigated in the tree. `System/Entity` is the
|
|
6517
|
+
* universal abstract base type and has no defining collection root, so the
|
|
6518
|
+
* generic `System/Related` association (target `System/Entity`, present as an
|
|
6519
|
+
* inbound role on every type) makes `targets(ckId: "System/Entity")` throw
|
|
6520
|
+
* server-side ("has no defining collection root"). Skipping it here keeps the
|
|
6521
|
+
* tree from firing a guaranteed-failing query for every entity.
|
|
6522
|
+
*/
|
|
6523
|
+
const NON_NAVIGABLE_TARGET_CK_TYPES = new Set(['System/Entity']);
|
|
6524
|
+
/** Key of the built-in spatial perspective (all Basic/Tree roots, as before). */
|
|
6525
|
+
const SPATIAL_PERSPECTIVE_KEY = 'Spatial';
|
|
6526
|
+
/**
|
|
6527
|
+
* The always-available built-in perspective. It reproduces the pre-AB#4263
|
|
6528
|
+
* behaviour (roots = all Basic/Tree entities) and is synthesized rather than
|
|
6529
|
+
* stored, so a zero-config tenant still has exactly one perspective.
|
|
6530
|
+
*/
|
|
6531
|
+
const BUILT_IN_SPATIAL_PERSPECTIVE = {
|
|
6532
|
+
key: SPATIAL_PERSPECTIVE_KEY,
|
|
6533
|
+
displayName: 'Spatial',
|
|
6534
|
+
rootMode: 'Spatial',
|
|
6535
|
+
sortIndex: 0,
|
|
6536
|
+
};
|
|
6537
|
+
/**
|
|
6538
|
+
* Loads all runtime instances of a CK type as the roots of a `Type` perspective
|
|
6539
|
+
* (AB#4263). Inline gql (like TreeNavigationConfigService) to stay decoupled
|
|
6540
|
+
* from a schema re-introspection; the selection mirrors getTrees so the existing
|
|
6541
|
+
* root-node rendering keeps working.
|
|
6542
|
+
*/
|
|
6543
|
+
const GET_ROOT_ENTITIES_BY_CK_TYPE = gql `
|
|
6544
|
+
query getRuntimeEntitiesByCkType($ckTypeId: String!, $first: Int!) {
|
|
6545
|
+
runtime {
|
|
6546
|
+
runtimeEntities(ckId: $ckTypeId, first: $first) {
|
|
6547
|
+
items {
|
|
6548
|
+
rtId
|
|
6549
|
+
ckTypeId
|
|
6550
|
+
rtWellKnownName
|
|
6551
|
+
attributes(attributeNames: ["name", "displayName", "description"]) {
|
|
6552
|
+
items {
|
|
6553
|
+
attributeName
|
|
6554
|
+
value
|
|
6555
|
+
}
|
|
6556
|
+
}
|
|
6557
|
+
}
|
|
6558
|
+
}
|
|
6559
|
+
}
|
|
6560
|
+
}
|
|
6561
|
+
`;
|
|
5991
6562
|
class RuntimeBrowserDataSource extends OctoGraphQlHierarchyDataSource {
|
|
5992
6563
|
getTreesDtoGQL = inject(GetTreesDtoGQL);
|
|
5993
|
-
|
|
6564
|
+
getCkTypeAssociationRolesDtoGQL = inject(GetCkTypeAssociationRolesDtoGQL);
|
|
6565
|
+
getTreeAssociationTargetsDtoGQL = inject(GetTreeAssociationTargetsDtoGQL);
|
|
5994
6566
|
getCkModelsGQL = inject(GetCkModelsDtoGQL);
|
|
5995
6567
|
getCkTypesGQL = inject(GetCkTypesDtoGQL);
|
|
5996
6568
|
getCkModelByIdDtoGQL = inject(GetCkModelByIdDtoGQL);
|
|
@@ -5999,6 +6571,94 @@ class RuntimeBrowserDataSource extends OctoGraphQlHierarchyDataSource {
|
|
|
5999
6571
|
updateRuntimeEntitiesDtoGQL = inject(UpdateRuntimeEntitiesDtoGQL);
|
|
6000
6572
|
updateTreeNodesDtoGQL = inject(UpdateTreeNodesDtoGQL);
|
|
6001
6573
|
typeHelperService = inject(TypeHelperService);
|
|
6574
|
+
treeNavConfig = inject(TreeNavigationConfigService);
|
|
6575
|
+
apollo = inject(Apollo);
|
|
6576
|
+
/** Key of the currently active tree perspective (AB#4263). */
|
|
6577
|
+
activePerspectiveKey = SPATIAL_PERSPECTIVE_KEY;
|
|
6578
|
+
/**
|
|
6579
|
+
* The perspective resolved during the last `fetchRootNodes()`. Used by
|
|
6580
|
+
* `fetchChildren()` to apply the root-level whitelist for `Type` perspectives.
|
|
6581
|
+
*/
|
|
6582
|
+
activePerspective = BUILT_IN_SPATIAL_PERSPECTIVE;
|
|
6583
|
+
/**
|
|
6584
|
+
* rtIds of the current perspective's root nodes. The primary/secondary role
|
|
6585
|
+
* whitelist is applied ONLY to the direct children of these roots — deeper
|
|
6586
|
+
* nodes keep full auto-discovery (whitelist-at-root-only).
|
|
6587
|
+
*/
|
|
6588
|
+
perspectiveRootRtIds = new Set();
|
|
6589
|
+
/**
|
|
6590
|
+
* Selects the active perspective by key. The host is responsible for reloading
|
|
6591
|
+
* the tree afterwards (e.g. `treeDetail.refreshTree()`), which re-runs
|
|
6592
|
+
* `fetchRootNodes()` and re-resolves the perspective.
|
|
6593
|
+
*/
|
|
6594
|
+
setActivePerspective(key) {
|
|
6595
|
+
this.activePerspectiveKey = key || SPATIAL_PERSPECTIVE_KEY;
|
|
6596
|
+
}
|
|
6597
|
+
/** The currently selected perspective key. */
|
|
6598
|
+
getActivePerspectiveKey() {
|
|
6599
|
+
return this.activePerspectiveKey;
|
|
6600
|
+
}
|
|
6601
|
+
/**
|
|
6602
|
+
* Returns all selectable perspectives: the built-in spatial one first, then the
|
|
6603
|
+
* per-tenant configured perspectives, de-duplicated by key (a configured
|
|
6604
|
+
* `Spatial` overrides the built-in). With no configuration this is a single
|
|
6605
|
+
* entry, so the host can hide the switcher.
|
|
6606
|
+
*/
|
|
6607
|
+
async getPerspectives() {
|
|
6608
|
+
let configured = [];
|
|
6609
|
+
try {
|
|
6610
|
+
configured = await this.treeNavConfig.perspectives();
|
|
6611
|
+
}
|
|
6612
|
+
catch (error) {
|
|
6613
|
+
console.error('Error loading perspectives', error);
|
|
6614
|
+
}
|
|
6615
|
+
const byKey = new Map();
|
|
6616
|
+
byKey.set(BUILT_IN_SPATIAL_PERSPECTIVE.key, BUILT_IN_SPATIAL_PERSPECTIVE);
|
|
6617
|
+
for (const p of configured) {
|
|
6618
|
+
byKey.set(p.key, p);
|
|
6619
|
+
}
|
|
6620
|
+
return [...byKey.values()].sort((a, b) => (a.sortIndex ?? Number.MAX_SAFE_INTEGER) -
|
|
6621
|
+
(b.sortIndex ?? Number.MAX_SAFE_INTEGER) ||
|
|
6622
|
+
a.displayName.localeCompare(b.displayName));
|
|
6623
|
+
}
|
|
6624
|
+
/**
|
|
6625
|
+
* The role-id whitelist of the active perspective (primary + secondary), or
|
|
6626
|
+
* null when the perspective is not a `Type` perspective or declares no roles.
|
|
6627
|
+
*/
|
|
6628
|
+
activePerspectiveWhitelist() {
|
|
6629
|
+
const p = this.activePerspective;
|
|
6630
|
+
if (p.rootMode !== 'Type') {
|
|
6631
|
+
return null;
|
|
6632
|
+
}
|
|
6633
|
+
const allowed = new Set();
|
|
6634
|
+
if (p.primaryRoleId) {
|
|
6635
|
+
allowed.add(p.primaryRoleId);
|
|
6636
|
+
}
|
|
6637
|
+
for (const roleId of p.secondaryRoleIds ?? []) {
|
|
6638
|
+
allowed.add(roleId);
|
|
6639
|
+
}
|
|
6640
|
+
return allowed.size > 0 ? allowed : null;
|
|
6641
|
+
}
|
|
6642
|
+
/**
|
|
6643
|
+
* The set of role ids the given entity's direct children are restricted to,
|
|
6644
|
+
* or null for full auto-discovery. Non-null only when the entity is a root of
|
|
6645
|
+
* the active `Type` perspective (whitelist-at-root-only).
|
|
6646
|
+
*/
|
|
6647
|
+
rootWhitelistFor(rtId) {
|
|
6648
|
+
return this.perspectiveRootRtIds.has(rtId)
|
|
6649
|
+
? this.activePerspectiveWhitelist()
|
|
6650
|
+
: null;
|
|
6651
|
+
}
|
|
6652
|
+
/**
|
|
6653
|
+
* Resolves the active perspective from the configured list, falling back to a
|
|
6654
|
+
* configured/built-in spatial one when the selected key is unknown.
|
|
6655
|
+
*/
|
|
6656
|
+
async resolveActivePerspective() {
|
|
6657
|
+
const perspectives = await this.getPerspectives();
|
|
6658
|
+
return (perspectives.find((p) => p.key === this.activePerspectiveKey) ??
|
|
6659
|
+
perspectives.find((p) => p.key === SPATIAL_PERSPECTIVE_KEY) ??
|
|
6660
|
+
BUILT_IN_SPATIAL_PERSPECTIVE);
|
|
6661
|
+
}
|
|
6002
6662
|
isCkModelsRoot(item) {
|
|
6003
6663
|
return !!item && 'isCkModelsRoot' in item;
|
|
6004
6664
|
}
|
|
@@ -6008,20 +6668,16 @@ class RuntimeBrowserDataSource extends OctoGraphQlHierarchyDataSource {
|
|
|
6008
6668
|
isCkType(item) {
|
|
6009
6669
|
return !!item && 'ckTypeId' in item && !('rtId' in item) && !('id' in item);
|
|
6010
6670
|
}
|
|
6011
|
-
|
|
6012
|
-
|
|
6013
|
-
|
|
6014
|
-
|
|
6015
|
-
|
|
6016
|
-
|
|
6017
|
-
|
|
6018
|
-
|
|
6019
|
-
|
|
6020
|
-
|
|
6021
|
-
new RtAssociationMetaData('System/ParentChild', 'Basic/TreeNode'),
|
|
6022
|
-
new RtAssociationMetaData('Basic/RelatedClassification', 'Basic/Asset'),
|
|
6023
|
-
]),
|
|
6024
|
-
];
|
|
6671
|
+
isAssociationGroup(item) {
|
|
6672
|
+
return !!item && 'isAssociationGroup' in item;
|
|
6673
|
+
}
|
|
6674
|
+
/**
|
|
6675
|
+
* Cache of inbound association roles per CK type id. Discovered lazily from
|
|
6676
|
+
* the CK schema and reused across tree expansions (and to decide whether a
|
|
6677
|
+
* child entity node is expandable). Lives on the instance because the tree is
|
|
6678
|
+
* created fresh per browser/picker mount.
|
|
6679
|
+
*/
|
|
6680
|
+
inboundRolesCache = new Map();
|
|
6025
6681
|
// Define visual metadata for different entity types
|
|
6026
6682
|
static ckTypeMetaData = [
|
|
6027
6683
|
new CkTypeMetaData('Basic/Tree', 'Tree', 'Tree Structure', folderMoreIcon),
|
|
@@ -6043,92 +6699,300 @@ class RuntimeBrowserDataSource extends OctoGraphQlHierarchyDataSource {
|
|
|
6043
6699
|
if (this.isCkType(item.item)) {
|
|
6044
6700
|
return [];
|
|
6045
6701
|
}
|
|
6702
|
+
// Handle association group node - lazily load its target entities
|
|
6703
|
+
if (this.isAssociationGroup(item.item)) {
|
|
6704
|
+
const group = item.item;
|
|
6705
|
+
const targets = await this.fetchAssociationTargets(group.parentRtId, group.parentCkTypeId, group.roleId, group.targetCkTypeId, group.direction);
|
|
6706
|
+
return this.buildEntityTreeItems(targets);
|
|
6707
|
+
}
|
|
6046
6708
|
// Handle regular runtime entity
|
|
6047
6709
|
const rtEntity = item.item;
|
|
6048
6710
|
if (!rtEntity.rtId || !rtEntity.ckTypeId) {
|
|
6049
6711
|
return [];
|
|
6050
6712
|
}
|
|
6051
|
-
//
|
|
6052
|
-
|
|
6053
|
-
|
|
6054
|
-
|
|
6713
|
+
// Discover the inbound association roles from the entity's ACTUAL inbound
|
|
6714
|
+
// edges (associations.definitions), not the CK type schema. This mirrors the
|
|
6715
|
+
// entity detail "Associations" tab and also surfaces roles that exist as
|
|
6716
|
+
// runtime edges but are no longer declared on the type in the installed CK
|
|
6717
|
+
// model (orphan roles after model evolution). Each group carries its concrete
|
|
6718
|
+
// origin CK type (the ckId used to load its targets) and an exact count.
|
|
6719
|
+
const discoveredGroups = await this.discoverEntityInboundRoleGroups(rtEntity.rtId, rtEntity.ckTypeId);
|
|
6720
|
+
// AB#4263: when this entity is a root of the active `Type` perspective,
|
|
6721
|
+
// restrict its direct children to the perspective's primary + secondary
|
|
6722
|
+
// roles (whitelist-at-root-only). Deeper nodes are not in
|
|
6723
|
+
// perspectiveRootRtIds, so they keep full auto-discovery.
|
|
6724
|
+
const whitelist = this.rootWhitelistFor(rtEntity.rtId);
|
|
6725
|
+
const primaryRoleId = whitelist ? this.activePerspective.primaryRoleId : undefined;
|
|
6726
|
+
const roleGroups = whitelist
|
|
6727
|
+
? discoveredGroups.filter((g) => whitelist.has(g.roleId))
|
|
6728
|
+
: discoveredGroups;
|
|
6729
|
+
// Apply the optional per-tenant TreeNavigationConfiguration overrides on top
|
|
6730
|
+
// of auto-discovery: hide (visible), relabel (displayName), reorder
|
|
6731
|
+
// (sortIndex), flatten vs group (grouped), icon. Defaults reproduce Phase 1:
|
|
6732
|
+
// System/ParentChild flat, every other role grouped. In a perspective root
|
|
6733
|
+
// the perspective's primary role is flattened at the top instead.
|
|
6734
|
+
const annotated = await Promise.all(roleGroups.map(async (group) => {
|
|
6735
|
+
const override = await this.treeNavConfig.resolve(rtEntity.ckTypeId, group.roleId);
|
|
6736
|
+
const defaultGrouped = primaryRoleId
|
|
6737
|
+
? group.roleId !== primaryRoleId
|
|
6738
|
+
: group.roleId !== PARENT_CHILD_ROLE_ID;
|
|
6739
|
+
return {
|
|
6740
|
+
group,
|
|
6741
|
+
visible: override?.visible !== false,
|
|
6742
|
+
grouped: override?.grouped ?? defaultGrouped,
|
|
6743
|
+
displayName: override?.displayName,
|
|
6744
|
+
sortIndex: override?.sortIndex,
|
|
6745
|
+
icon: override?.icon,
|
|
6746
|
+
};
|
|
6747
|
+
}));
|
|
6748
|
+
const visibleRoles = annotated.filter((a) => a.visible);
|
|
6749
|
+
const result = [];
|
|
6750
|
+
// 1. Flattened roles (default: System/ParentChild) — their targets appear
|
|
6751
|
+
// directly under the node to preserve the familiar hierarchy navigation.
|
|
6752
|
+
const flattenedTargetLists = await Promise.all(visibleRoles
|
|
6753
|
+
.filter((a) => !a.grouped)
|
|
6754
|
+
.map((a) => this.fetchAssociationTargets(rtEntity.rtId, rtEntity.ckTypeId, a.group.roleId, a.group.targetCkTypeId, GraphDirectionDto.InboundDto)));
|
|
6755
|
+
result.push(...(await this.buildEntityTreeItems(flattenedTargetLists.flat())));
|
|
6756
|
+
// 2. Grouped roles become expandable group nodes (counts already known from
|
|
6757
|
+
// the discovered edges). Ordered by configured sortIndex.
|
|
6758
|
+
const groupNodes = visibleRoles
|
|
6759
|
+
.filter((a) => a.grouped && a.group.count > 0)
|
|
6760
|
+
.sort((x, y) => this.compareGroupOrder(x, y));
|
|
6761
|
+
for (const a of groupNodes) {
|
|
6762
|
+
const group = a.group;
|
|
6763
|
+
const groupNode = {
|
|
6764
|
+
isAssociationGroup: true,
|
|
6765
|
+
parentRtId: rtEntity.rtId,
|
|
6766
|
+
parentCkTypeId: rtEntity.ckTypeId,
|
|
6767
|
+
roleId: group.roleId,
|
|
6768
|
+
targetCkTypeId: group.targetCkTypeId,
|
|
6769
|
+
direction: GraphDirectionDto.InboundDto,
|
|
6770
|
+
};
|
|
6771
|
+
const label = `${a.displayName ?? group.navigationPropertyName} (${group.count})`;
|
|
6772
|
+
result.push(new TreeItemDataTyped(this.buildGroupNodeId(rtEntity.rtId, rtEntity.ckTypeId, group), label, `${group.roleId} → ${group.targetCkTypeId}`, groupNode, this.resolveGroupIcon(a.icon), true));
|
|
6055
6773
|
}
|
|
6056
|
-
|
|
6774
|
+
return result;
|
|
6775
|
+
}
|
|
6776
|
+
/**
|
|
6777
|
+
* Discovers the navigable inbound role groups of an entity from its ACTUAL
|
|
6778
|
+
* inbound edges (associations.definitions), grouped by (roleId, origin CK
|
|
6779
|
+
* type) with exact counts. Labels are enriched from the CK type schema
|
|
6780
|
+
* (friendly inbound navigation property name) when the role is declared on the
|
|
6781
|
+
* type, and otherwise derived from the role id (so orphan roles still get a
|
|
6782
|
+
* readable label).
|
|
6783
|
+
*/
|
|
6784
|
+
async discoverEntityInboundRoleGroups(rtId, ckTypeId) {
|
|
6785
|
+
let definitions = [];
|
|
6786
|
+
try {
|
|
6787
|
+
const response = await firstValueFrom(this.getRuntimeEntityAssociationsByIdDtoGQL.fetch({
|
|
6788
|
+
variables: {
|
|
6789
|
+
rtId,
|
|
6790
|
+
ckTypeId,
|
|
6791
|
+
direction: GraphDirectionDto.InboundDto,
|
|
6792
|
+
first: 2000,
|
|
6793
|
+
},
|
|
6794
|
+
fetchPolicy: 'network-only',
|
|
6795
|
+
}));
|
|
6796
|
+
definitions =
|
|
6797
|
+
response.data?.runtime?.runtimeEntities?.items?.[0]?.associations
|
|
6798
|
+
?.definitions?.items ?? [];
|
|
6799
|
+
}
|
|
6800
|
+
catch (error) {
|
|
6801
|
+
console.error('Error discovering inbound association edges', { ckTypeId, rtId }, error);
|
|
6057
6802
|
return [];
|
|
6058
6803
|
}
|
|
6059
|
-
|
|
6060
|
-
//
|
|
6061
|
-
|
|
6062
|
-
|
|
6063
|
-
|
|
6064
|
-
|
|
6065
|
-
|
|
6066
|
-
|
|
6067
|
-
|
|
6068
|
-
|
|
6069
|
-
|
|
6070
|
-
|
|
6071
|
-
|
|
6072
|
-
|
|
6073
|
-
|
|
6074
|
-
|
|
6075
|
-
|
|
6076
|
-
|
|
6077
|
-
|
|
6078
|
-
|
|
6079
|
-
|
|
6080
|
-
|
|
6081
|
-
|
|
6082
|
-
|
|
6083
|
-
|
|
6804
|
+
// Count edges per role and remember a representative concrete origin type
|
|
6805
|
+
// (used as a fallback ckId for orphan roles not declared on the type).
|
|
6806
|
+
const edgeCount = new Map();
|
|
6807
|
+
const edgeOrigin = new Map();
|
|
6808
|
+
for (const def of definitions) {
|
|
6809
|
+
const roleId = String(def?.ckAssociationRoleId ?? '');
|
|
6810
|
+
const origin = String(def?.originCkTypeId ?? '');
|
|
6811
|
+
if (!roleId || !origin || NON_NAVIGABLE_TARGET_CK_TYPES.has(origin)) {
|
|
6812
|
+
continue;
|
|
6813
|
+
}
|
|
6814
|
+
edgeCount.set(roleId, (edgeCount.get(roleId) ?? 0) + 1);
|
|
6815
|
+
if (!edgeOrigin.has(roleId)) {
|
|
6816
|
+
edgeOrigin.set(roleId, origin);
|
|
6817
|
+
}
|
|
6818
|
+
}
|
|
6819
|
+
// Declared roles from the CK type schema give the friendly inbound name and,
|
|
6820
|
+
// crucially, the origin BASE type — using it as the ckId aggregates all
|
|
6821
|
+
// concrete subtypes into a single group (e.g. one "Sensoren (5)" instead of
|
|
6822
|
+
// one group per concrete sensor type).
|
|
6823
|
+
const schemaRoles = await this.getInboundRoles(ckTypeId);
|
|
6824
|
+
const schemaByRole = new Map();
|
|
6825
|
+
for (const r of schemaRoles) {
|
|
6826
|
+
if (!schemaByRole.has(r.roleId)) {
|
|
6827
|
+
schemaByRole.set(r.roleId, {
|
|
6828
|
+
origin: r.targetCkTypeId,
|
|
6829
|
+
nav: r.navigationPropertyName,
|
|
6830
|
+
});
|
|
6084
6831
|
}
|
|
6085
|
-
|
|
6086
|
-
|
|
6087
|
-
|
|
6832
|
+
}
|
|
6833
|
+
// One group per role actually present on the entity. Declared roles use the
|
|
6834
|
+
// schema base type as ckId; orphan roles (edge exists but role not declared
|
|
6835
|
+
// on the type in the installed model, e.g. EnergyIQ/StoreyElements) fall back
|
|
6836
|
+
// to the concrete edge origin type and a derived label.
|
|
6837
|
+
const groups = [];
|
|
6838
|
+
for (const [roleId, count] of edgeCount) {
|
|
6839
|
+
const schema = schemaByRole.get(roleId);
|
|
6840
|
+
groups.push({
|
|
6841
|
+
roleId,
|
|
6842
|
+
targetCkTypeId: schema?.origin ?? edgeOrigin.get(roleId) ?? '',
|
|
6843
|
+
navigationPropertyName: schema?.nav ?? this.deriveRoleLabel(roleId),
|
|
6844
|
+
count,
|
|
6845
|
+
});
|
|
6846
|
+
}
|
|
6847
|
+
return groups;
|
|
6848
|
+
}
|
|
6849
|
+
/** Readable fallback label for a role id without a schema navigation name. */
|
|
6850
|
+
deriveRoleLabel(roleId) {
|
|
6851
|
+
const slash = roleId.lastIndexOf('/');
|
|
6852
|
+
return slash >= 0 ? roleId.slice(slash + 1) : roleId;
|
|
6853
|
+
}
|
|
6854
|
+
/**
|
|
6855
|
+
* Orders group nodes by configured sortIndex (ascending, unconfigured last),
|
|
6856
|
+
* then by navigation property name for a stable, readable order.
|
|
6857
|
+
*/
|
|
6858
|
+
compareGroupOrder(x, y) {
|
|
6859
|
+
const xi = x.sortIndex ?? Number.MAX_SAFE_INTEGER;
|
|
6860
|
+
const yi = y.sortIndex ?? Number.MAX_SAFE_INTEGER;
|
|
6861
|
+
if (xi !== yi) {
|
|
6862
|
+
return xi - yi;
|
|
6863
|
+
}
|
|
6864
|
+
return x.group.navigationPropertyName.localeCompare(y.group.navigationPropertyName);
|
|
6865
|
+
}
|
|
6866
|
+
/** Resolves a configured group icon name to an SVG icon (folder by default). */
|
|
6867
|
+
resolveGroupIcon(name) {
|
|
6868
|
+
switch (name) {
|
|
6869
|
+
case 'file':
|
|
6870
|
+
return fileIcon;
|
|
6871
|
+
case 'gear':
|
|
6872
|
+
return gearIcon;
|
|
6873
|
+
case 'database':
|
|
6874
|
+
return storage;
|
|
6875
|
+
case 'code':
|
|
6876
|
+
return code;
|
|
6877
|
+
case 'folder':
|
|
6878
|
+
default:
|
|
6879
|
+
return folderMoreIcon;
|
|
6880
|
+
}
|
|
6881
|
+
}
|
|
6882
|
+
/**
|
|
6883
|
+
* Returns the inbound association roles of a CK type, discovered from the CK
|
|
6884
|
+
* schema and cached per type id for the lifetime of this data source.
|
|
6885
|
+
*/
|
|
6886
|
+
getInboundRoles(ckTypeId) {
|
|
6887
|
+
const cached = this.inboundRolesCache.get(ckTypeId);
|
|
6888
|
+
if (cached) {
|
|
6889
|
+
return cached;
|
|
6890
|
+
}
|
|
6891
|
+
const promise = firstValueFrom(this.getCkTypeAssociationRolesDtoGQL.fetch({ variables: { ckTypeId } }))
|
|
6892
|
+
.then((response) => {
|
|
6893
|
+
const all = response.data?.constructionKit?.types?.items?.[0]?.associations?.in
|
|
6894
|
+
?.all ?? [];
|
|
6895
|
+
const roles = [];
|
|
6896
|
+
for (const role of all) {
|
|
6897
|
+
if (!role) {
|
|
6088
6898
|
continue;
|
|
6089
6899
|
}
|
|
6090
|
-
|
|
6091
|
-
|
|
6092
|
-
|
|
6093
|
-
|
|
6094
|
-
|
|
6095
|
-
|
|
6096
|
-
|
|
6097
|
-
|
|
6098
|
-
|
|
6099
|
-
|
|
6100
|
-
}
|
|
6101
|
-
// Extract display name and description from attributes
|
|
6102
|
-
const nameValue = child.attributes?.items?.find((x) => x?.attributeName === 'name')?.value;
|
|
6103
|
-
const displayNameValue = child.attributes?.items?.find((x) => x?.attributeName === 'displayName')?.value;
|
|
6104
|
-
// Debug logging
|
|
6105
|
-
if (typeof nameValue === 'object') {
|
|
6106
|
-
console.warn('Child name value is an object:', nameValue);
|
|
6107
|
-
}
|
|
6108
|
-
const text = (typeof nameValue === 'string'
|
|
6109
|
-
? nameValue
|
|
6110
|
-
: typeof nameValue === 'object' && nameValue !== null
|
|
6111
|
-
? JSON.stringify(nameValue)
|
|
6112
|
-
: null) ||
|
|
6113
|
-
(typeof displayNameValue === 'string'
|
|
6114
|
-
? displayNameValue
|
|
6115
|
-
: null) ||
|
|
6116
|
-
child.ckTypeId ||
|
|
6117
|
-
'Unknown';
|
|
6118
|
-
const descValue = child.attributes?.items?.find((x) => x?.attributeName === 'description')?.value;
|
|
6119
|
-
const tooltip = (typeof descValue === 'string' ? descValue : null) ||
|
|
6120
|
-
`${child.ckTypeId} - ${child.rtId}`;
|
|
6121
|
-
mergedResultsMap[rtId] = new TreeItemDataTyped(rtId, text, tooltip, child, childMetaData.svgIcon, (child?.associations?.targets?.totalCount ?? 0) > 0);
|
|
6122
|
-
}
|
|
6123
|
-
else {
|
|
6124
|
-
// Update expandable status if object already exists
|
|
6125
|
-
mergedResultsMap[rtId].expandable ||=
|
|
6126
|
-
(child?.associations?.targets?.totalCount ?? 0) > 0;
|
|
6127
|
-
}
|
|
6900
|
+
// Use the RUNTIME ids from the backend, never the versioned fullName.
|
|
6901
|
+
// For an INBOUND role this entity is the association's TARGET side, so the
|
|
6902
|
+
// related entities to navigate to are on the ORIGIN side: query
|
|
6903
|
+
// targets(direction: INBOUND, ckId: rtOriginCkTypeId). rtTargetCkTypeId
|
|
6904
|
+
// here is this entity's own (target) type and would return nothing.
|
|
6905
|
+
// The runtime form must come from the backend (rtOriginCkTypeId) — it
|
|
6906
|
+
// follows a resolution logic that simply stripping the version does not.
|
|
6907
|
+
const targetCkTypeId = String(role.rtOriginCkTypeId ?? '');
|
|
6908
|
+
if (!targetCkTypeId || NON_NAVIGABLE_TARGET_CK_TYPES.has(targetCkTypeId)) {
|
|
6909
|
+
continue;
|
|
6128
6910
|
}
|
|
6911
|
+
roles.push({
|
|
6912
|
+
roleId: String(role.rtRoleId ?? ''),
|
|
6913
|
+
navigationPropertyName: role.navigationPropertyName,
|
|
6914
|
+
targetCkTypeId,
|
|
6915
|
+
multiplicity: role.multiplicity,
|
|
6916
|
+
});
|
|
6129
6917
|
}
|
|
6918
|
+
return roles;
|
|
6919
|
+
})
|
|
6920
|
+
.catch((error) => {
|
|
6921
|
+
console.error('Error fetching association roles for type', ckTypeId, error);
|
|
6922
|
+
// Drop the failed promise from the cache so a later expand can retry.
|
|
6923
|
+
this.inboundRolesCache.delete(ckTypeId);
|
|
6924
|
+
return [];
|
|
6925
|
+
});
|
|
6926
|
+
this.inboundRolesCache.set(ckTypeId, promise);
|
|
6927
|
+
return promise;
|
|
6928
|
+
}
|
|
6929
|
+
/** Loads the target entities reachable from an entity through one role. */
|
|
6930
|
+
async fetchAssociationTargets(rtId, ckTypeId, roleId, targetCkTypeId, direction) {
|
|
6931
|
+
try {
|
|
6932
|
+
const response = await firstValueFrom(this.getTreeAssociationTargetsDtoGQL.fetch({
|
|
6933
|
+
variables: { rtId, ckTypeId, roleId, targetCkTypeId, direction },
|
|
6934
|
+
}));
|
|
6935
|
+
const items = response.data?.runtime?.runtimeEntities?.items?.[0]?.associations
|
|
6936
|
+
?.targets?.items ?? [];
|
|
6937
|
+
return items.filter((i) => !!i);
|
|
6938
|
+
}
|
|
6939
|
+
catch (error) {
|
|
6940
|
+
console.error('Error fetching association targets', { ckTypeId, roleId, targetCkTypeId }, error);
|
|
6941
|
+
return [];
|
|
6942
|
+
}
|
|
6943
|
+
}
|
|
6944
|
+
/**
|
|
6945
|
+
* Builds tree items for runtime entities, de-duplicating by rtId and marking
|
|
6946
|
+
* an entity expandable when its CK type defines at least one inbound
|
|
6947
|
+
* association role.
|
|
6948
|
+
*/
|
|
6949
|
+
async buildEntityTreeItems(entities) {
|
|
6950
|
+
const unique = new Map();
|
|
6951
|
+
for (const entity of entities) {
|
|
6952
|
+
if (entity?.rtId && entity?.ckTypeId && !unique.has(entity.rtId)) {
|
|
6953
|
+
unique.set(entity.rtId, entity);
|
|
6954
|
+
}
|
|
6955
|
+
}
|
|
6956
|
+
// Warm the role cache for every distinct child type in parallel so the
|
|
6957
|
+
// expandable flag can be resolved without a per-entity round trip.
|
|
6958
|
+
const distinctTypes = [
|
|
6959
|
+
...new Set([...unique.values()].map((e) => e.ckTypeId)),
|
|
6960
|
+
];
|
|
6961
|
+
await Promise.all(distinctTypes.map((t) => this.getInboundRoles(t)));
|
|
6962
|
+
const result = [];
|
|
6963
|
+
for (const entity of unique.values()) {
|
|
6964
|
+
const roles = await this.getInboundRoles(entity.ckTypeId);
|
|
6965
|
+
result.push(new TreeItemDataTyped(entity.rtId, this.extractDisplayName(entity), this.extractTooltip(entity), entity, this.resolveIcon(entity.ckTypeId), roles.length > 0));
|
|
6130
6966
|
}
|
|
6131
|
-
return
|
|
6967
|
+
return result;
|
|
6968
|
+
}
|
|
6969
|
+
/** Stable tree-node id for an association group node. */
|
|
6970
|
+
buildGroupNodeId(parentRtId, parentCkTypeId, role) {
|
|
6971
|
+
return `assoc:${parentCkTypeId}@${parentRtId}:${role.roleId}:${role.targetCkTypeId}`;
|
|
6972
|
+
}
|
|
6973
|
+
/** Resolves the display label of an entity from its name/displayName attributes. */
|
|
6974
|
+
extractDisplayName(entity) {
|
|
6975
|
+
const nameValue = entity.attributes?.items?.find((x) => x?.attributeName === 'name')?.value;
|
|
6976
|
+
const displayNameValue = entity.attributes?.items?.find((x) => x?.attributeName === 'displayName')?.value;
|
|
6977
|
+
return ((typeof nameValue === 'string'
|
|
6978
|
+
? nameValue
|
|
6979
|
+
: typeof nameValue === 'object' && nameValue !== null
|
|
6980
|
+
? JSON.stringify(nameValue)
|
|
6981
|
+
: null) ||
|
|
6982
|
+
(typeof displayNameValue === 'string' ? displayNameValue : null) ||
|
|
6983
|
+
entity.rtWellKnownName ||
|
|
6984
|
+
entity.ckTypeId ||
|
|
6985
|
+
'Unknown');
|
|
6986
|
+
}
|
|
6987
|
+
/** Resolves the tooltip of an entity from its description attribute. */
|
|
6988
|
+
extractTooltip(entity) {
|
|
6989
|
+
const descValue = entity.attributes?.items?.find((x) => x?.attributeName === 'description')?.value;
|
|
6990
|
+
return ((typeof descValue === 'string' ? descValue : null) ||
|
|
6991
|
+
`${entity.ckTypeId} - ${entity.rtId}`);
|
|
6992
|
+
}
|
|
6993
|
+
/** Resolves the icon for a CK type, falling back to a generic entity icon. */
|
|
6994
|
+
resolveIcon(ckTypeId) {
|
|
6995
|
+
return (RuntimeBrowserDataSource.ckTypeMetaData.find((x) => x.ckTypeId === ckTypeId)?.svgIcon ?? code);
|
|
6132
6996
|
}
|
|
6133
6997
|
async fetchRootNodes() {
|
|
6134
6998
|
try {
|
|
@@ -6136,6 +7000,17 @@ class RuntimeBrowserDataSource extends OctoGraphQlHierarchyDataSource {
|
|
|
6136
7000
|
// Add CK Models root node
|
|
6137
7001
|
const ckModelsRoot = { isCkModelsRoot: true };
|
|
6138
7002
|
result.push(new TreeItemDataTyped('ck-models-root', 'CK Models', 'Construction Kit Models', ckModelsRoot, folderOpenIcon, true));
|
|
7003
|
+
// AB#4263: resolve the active perspective and reset the root-id set that
|
|
7004
|
+
// scopes the whitelist to the direct children of these roots.
|
|
7005
|
+
this.perspectiveRootRtIds.clear();
|
|
7006
|
+
this.activePerspective = await this.resolveActivePerspective();
|
|
7007
|
+
// `Type` perspective: roots are all instances of the configured CK type.
|
|
7008
|
+
if (this.activePerspective.rootMode === 'Type' &&
|
|
7009
|
+
this.activePerspective.rootCkTypeId) {
|
|
7010
|
+
result.push(...(await this.fetchTypePerspectiveRoots(this.activePerspective.rootCkTypeId)));
|
|
7011
|
+
return result;
|
|
7012
|
+
}
|
|
7013
|
+
// Spatial perspective (default): all Basic/Tree entities, exactly as before.
|
|
6139
7014
|
// Check if Basic construction kit is available before trying to fetch Tree entities
|
|
6140
7015
|
const isBasicCkAvailable = await this.checkBasicConstructionKitAvailable();
|
|
6141
7016
|
if (isBasicCkAvailable) {
|
|
@@ -6182,6 +7057,39 @@ class RuntimeBrowserDataSource extends OctoGraphQlHierarchyDataSource {
|
|
|
6182
7057
|
return [];
|
|
6183
7058
|
}
|
|
6184
7059
|
}
|
|
7060
|
+
/**
|
|
7061
|
+
* Loads all runtime instances of a CK type as the roots of a `Type`
|
|
7062
|
+
* perspective (AB#4263), registering their rtIds so the whitelist applies to
|
|
7063
|
+
* their direct children only. Expandability is schema-based (does the type
|
|
7064
|
+
* declare an inbound role, restricted to the whitelist when set).
|
|
7065
|
+
*/
|
|
7066
|
+
async fetchTypePerspectiveRoots(ckTypeId) {
|
|
7067
|
+
try {
|
|
7068
|
+
const response = await firstValueFrom(this.apollo.query({
|
|
7069
|
+
query: GET_ROOT_ENTITIES_BY_CK_TYPE,
|
|
7070
|
+
variables: { ckTypeId, first: 2000 },
|
|
7071
|
+
fetchPolicy: 'network-only',
|
|
7072
|
+
}));
|
|
7073
|
+
const items = (response.data?.runtime?.runtimeEntities?.items ?? []).filter((i) => !!i && !!i.rtId && !!i.ckTypeId);
|
|
7074
|
+
// Expandable when the root type declares at least one inbound role that
|
|
7075
|
+
// survives the whitelist (avoids always-empty expand arrows).
|
|
7076
|
+
const whitelist = this.activePerspectiveWhitelist();
|
|
7077
|
+
const roles = items.length > 0 ? await this.getInboundRoles(items[0].ckTypeId) : [];
|
|
7078
|
+
const expandable = whitelist
|
|
7079
|
+
? roles.some((r) => whitelist.has(r.roleId))
|
|
7080
|
+
: roles.length > 0;
|
|
7081
|
+
const result = [];
|
|
7082
|
+
for (const item of items) {
|
|
7083
|
+
this.perspectiveRootRtIds.add(item.rtId);
|
|
7084
|
+
result.push(new TreeItemDataTyped(`${item.ckTypeId}@${item.rtId}`, this.extractDisplayName(item), this.extractTooltip(item), item, this.resolveIcon(item.ckTypeId), expandable));
|
|
7085
|
+
}
|
|
7086
|
+
return result;
|
|
7087
|
+
}
|
|
7088
|
+
catch (error) {
|
|
7089
|
+
console.error('Error fetching type-perspective roots for', ckTypeId, error);
|
|
7090
|
+
return [];
|
|
7091
|
+
}
|
|
7092
|
+
}
|
|
6185
7093
|
/**
|
|
6186
7094
|
* Gets ParentChild association of given Runtime Entity.
|
|
6187
7095
|
*
|
|
@@ -6475,11 +7383,86 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
|
|
|
6475
7383
|
}]
|
|
6476
7384
|
}] });
|
|
6477
7385
|
|
|
7386
|
+
/**
|
|
7387
|
+
* Small toolbar control that lets the user switch the active tree perspective
|
|
7388
|
+
* (AB#4263). Theme-neutral (Kendo CSS variables only). Renders nothing when
|
|
7389
|
+
* there is a single perspective, so a zero-config tenant sees no switcher.
|
|
7390
|
+
*/
|
|
7391
|
+
class PerspectiveSwitcherComponent {
|
|
7392
|
+
/** All selectable perspectives (built-in spatial first). */
|
|
7393
|
+
perspectives = input([], /* @ts-ignore */
|
|
7394
|
+
...(ngDevMode ? [{ debugName: "perspectives" }] : /* istanbul ignore next */ []));
|
|
7395
|
+
/** Currently active perspective key. */
|
|
7396
|
+
activeKey = input('Spatial', /* @ts-ignore */
|
|
7397
|
+
...(ngDevMode ? [{ debugName: "activeKey" }] : /* istanbul ignore next */ []));
|
|
7398
|
+
/** Label shown before the dropdown. */
|
|
7399
|
+
label = input('Perspective', /* @ts-ignore */
|
|
7400
|
+
...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
|
|
7401
|
+
/** Emits the selected perspective key. */
|
|
7402
|
+
perspectiveChange = output();
|
|
7403
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: PerspectiveSwitcherComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
7404
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.2", type: PerspectiveSwitcherComponent, isStandalone: true, selector: "mm-perspective-switcher", inputs: { perspectives: { classPropertyName: "perspectives", publicName: "perspectives", isSignal: true, isRequired: false, transformFunction: null }, activeKey: { classPropertyName: "activeKey", publicName: "activeKey", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { perspectiveChange: "perspectiveChange" }, ngImport: i0, template: `
|
|
7405
|
+
@if (perspectives().length > 1) {
|
|
7406
|
+
<div class="perspective-switcher">
|
|
7407
|
+
<span class="switcher-label">{{ label() }}</span>
|
|
7408
|
+
<kendo-dropdownlist
|
|
7409
|
+
[data]="perspectives()"
|
|
7410
|
+
[textField]="'displayName'"
|
|
7411
|
+
[valueField]="'key'"
|
|
7412
|
+
[valuePrimitive]="true"
|
|
7413
|
+
[value]="activeKey()"
|
|
7414
|
+
(valueChange)="perspectiveChange.emit($event)"
|
|
7415
|
+
></kendo-dropdownlist>
|
|
7416
|
+
</div>
|
|
7417
|
+
}
|
|
7418
|
+
`, isInline: true, styles: [".perspective-switcher{display:flex;align-items:center;gap:8px;padding:4px 8px}.switcher-label{font-size:.85rem;font-weight:600;color:var(--kendo-color-subtle, #6c757d);white-space:nowrap}\n"], dependencies: [{ kind: "ngmodule", type: DropDownListModule }, { kind: "component", type: i3$1.DropDownListComponent, selector: "kendo-dropdownlist", inputs: ["customIconClass", "showStickyHeader", "icon", "svgIcon", "loading", "data", "value", "textField", "valueField", "adaptiveMode", "adaptiveTitle", "adaptiveSubtitle", "popupSettings", "listHeight", "defaultItem", "disabled", "itemDisabled", "readonly", "filterable", "virtual", "ignoreCase", "delay", "valuePrimitive", "tabindex", "tabIndex", "size", "rounded", "fillMode", "leftRightArrowsNavigation", "id"], outputs: ["valueChange", "filterChange", "selectionChange", "open", "opened", "close", "closed", "focus", "blur"], exportAs: ["kendoDropDownList"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
7419
|
+
}
|
|
7420
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: PerspectiveSwitcherComponent, decorators: [{
|
|
7421
|
+
type: Component,
|
|
7422
|
+
args: [{ selector: 'mm-perspective-switcher', standalone: true, imports: [DropDownListModule], template: `
|
|
7423
|
+
@if (perspectives().length > 1) {
|
|
7424
|
+
<div class="perspective-switcher">
|
|
7425
|
+
<span class="switcher-label">{{ label() }}</span>
|
|
7426
|
+
<kendo-dropdownlist
|
|
7427
|
+
[data]="perspectives()"
|
|
7428
|
+
[textField]="'displayName'"
|
|
7429
|
+
[valueField]="'key'"
|
|
7430
|
+
[valuePrimitive]="true"
|
|
7431
|
+
[value]="activeKey()"
|
|
7432
|
+
(valueChange)="perspectiveChange.emit($event)"
|
|
7433
|
+
></kendo-dropdownlist>
|
|
7434
|
+
</div>
|
|
7435
|
+
}
|
|
7436
|
+
`, changeDetection: ChangeDetectionStrategy.OnPush, styles: [".perspective-switcher{display:flex;align-items:center;gap:8px;padding:4px 8px}.switcher-label{font-size:.85rem;font-weight:600;color:var(--kendo-color-subtle, #6c757d);white-space:nowrap}\n"] }]
|
|
7437
|
+
}], propDecorators: { perspectives: [{ type: i0.Input, args: [{ isSignal: true, alias: "perspectives", required: false }] }], activeKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeKey", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], perspectiveChange: [{ type: i0.Output, args: ["perspectiveChange"] }] } });
|
|
7438
|
+
|
|
6478
7439
|
class EntitySelectorDialogComponent {
|
|
6479
7440
|
windowRef = inject(WindowRef);
|
|
6480
7441
|
treeDataSource = inject(RuntimeBrowserDataSource);
|
|
7442
|
+
tree;
|
|
7443
|
+
/** Selectable tree perspectives (AB#4263); switcher hides itself when <= 1. */
|
|
7444
|
+
perspectives = signal([], /* @ts-ignore */
|
|
7445
|
+
...(ngDevMode ? [{ debugName: "perspectives" }] : /* istanbul ignore next */ []));
|
|
7446
|
+
activePerspectiveKey = signal(this.treeDataSource.getActivePerspectiveKey(), /* @ts-ignore */
|
|
7447
|
+
...(ngDevMode ? [{ debugName: "activePerspectiveKey" }] : /* istanbul ignore next */ []));
|
|
6481
7448
|
data = {};
|
|
6482
7449
|
selectedEntity = null;
|
|
7450
|
+
async ngOnInit() {
|
|
7451
|
+
try {
|
|
7452
|
+
this.perspectives.set(await this.treeDataSource.getPerspectives());
|
|
7453
|
+
this.activePerspectiveKey.set(this.treeDataSource.getActivePerspectiveKey());
|
|
7454
|
+
}
|
|
7455
|
+
catch (error) {
|
|
7456
|
+
console.error('Error loading perspectives', error);
|
|
7457
|
+
}
|
|
7458
|
+
}
|
|
7459
|
+
/** Switches the active perspective and reloads the picker tree. */
|
|
7460
|
+
async onPerspectiveChange(key) {
|
|
7461
|
+
this.treeDataSource.setActivePerspective(key);
|
|
7462
|
+
this.activePerspectiveKey.set(key);
|
|
7463
|
+
this.selectedEntity = null;
|
|
7464
|
+
await this.tree?.refreshTree();
|
|
7465
|
+
}
|
|
6483
7466
|
onNodeSelected(node) {
|
|
6484
7467
|
const item = node.item;
|
|
6485
7468
|
if (item && typeof item === 'object' && 'rtId' in item && 'ckTypeId' in item) {
|
|
@@ -6509,11 +7492,17 @@ class EntitySelectorDialogComponent {
|
|
|
6509
7492
|
this.windowRef.close();
|
|
6510
7493
|
}
|
|
6511
7494
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: EntitySelectorDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
6512
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.2", type: EntitySelectorDialogComponent, isStandalone: true, selector: "mm-entity-selector-dialog", providers: [RuntimeBrowserDataSource], ngImport: i0, template: `
|
|
7495
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.2", type: EntitySelectorDialogComponent, isStandalone: true, selector: "mm-entity-selector-dialog", providers: [RuntimeBrowserDataSource], viewQueries: [{ propertyName: "tree", first: true, predicate: ["tree"], descendants: true }], ngImport: i0, template: `
|
|
6513
7496
|
<div class="entity-selector">
|
|
6514
7497
|
<div class="entity-selector-body">
|
|
7498
|
+
<mm-perspective-switcher
|
|
7499
|
+
[perspectives]="perspectives()"
|
|
7500
|
+
[activeKey]="activePerspectiveKey()"
|
|
7501
|
+
(perspectiveChange)="onPerspectiveChange($event)"
|
|
7502
|
+
></mm-perspective-switcher>
|
|
6515
7503
|
<div class="tree-section">
|
|
6516
7504
|
<mm-tree-view
|
|
7505
|
+
#tree
|
|
6517
7506
|
[dataSource]="treeDataSource"
|
|
6518
7507
|
(nodeSelected)="onNodeSelected($event)"
|
|
6519
7508
|
></mm-tree-view>
|
|
@@ -6548,7 +7537,7 @@ class EntitySelectorDialogComponent {
|
|
|
6548
7537
|
</button>
|
|
6549
7538
|
</div>
|
|
6550
7539
|
</div>
|
|
6551
|
-
`, isInline: true, styles: [":host{display:flex;flex-direction:column;height:100%;min-height:0}.entity-selector{display:flex;flex-direction:column;flex:1 1 auto;min-height:0;box-sizing:border-box}.entity-selector-body{flex:1 1 auto;min-height:0;overflow-y:auto;padding:12px;display:flex;flex-direction:column;gap:12px}.tree-section{flex:1;min-height:0;overflow:auto;border:1px solid var(--kendo-color-border, #dee2e6);border-radius:4px;background:var(--kendo-color-surface, #ffffff)}.selection-preview{padding:10px 12px;border:1px solid var(--kendo-color-border, #dee2e6);border-radius:4px;background:var(--kendo-color-surface-alt, #f8f9fa);display:flex;flex-direction:column;gap:4px;flex-shrink:0}.preview-row{display:flex;gap:8px}.preview-row .preview-label{font-weight:600;min-width:45px;color:var(--kendo-color-subtle, #6c757d);font-size:.85rem}.preview-row .preview-value{font-size:.85rem}.preview-row .monospace{font-family:monospace}.selection-hint{text-align:center;padding:8px;color:var(--kendo-color-subtle, #6c757d);font-size:.85rem;flex-shrink:0}.dialog-actions{flex:0 0 auto;display:flex;gap:8px;justify-content:flex-end;padding:10px 14px;border-top:1px solid var(--kendo-color-border, #dee2e6);background:var(--kendo-color-surface, transparent)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$1.ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconPosition", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }, { kind: "component", type: TreeComponent, selector: "mm-tree-view", inputs: ["dataSource"], outputs: ["nodeSelected", "nodeClick", "nodeDoubleClick", "nodeDrop", "expand", "collapse"] }], changeDetection: i0.ChangeDetectionStrategy.Eager });
|
|
7540
|
+
`, isInline: true, styles: [":host{display:flex;flex-direction:column;height:100%;min-height:0}.entity-selector{display:flex;flex-direction:column;flex:1 1 auto;min-height:0;box-sizing:border-box}.entity-selector-body{flex:1 1 auto;min-height:0;overflow-y:auto;padding:12px;display:flex;flex-direction:column;gap:12px}.tree-section{flex:1;min-height:0;overflow:auto;border:1px solid var(--kendo-color-border, #dee2e6);border-radius:4px;background:var(--kendo-color-surface, #ffffff)}.selection-preview{padding:10px 12px;border:1px solid var(--kendo-color-border, #dee2e6);border-radius:4px;background:var(--kendo-color-surface-alt, #f8f9fa);display:flex;flex-direction:column;gap:4px;flex-shrink:0}.preview-row{display:flex;gap:8px}.preview-row .preview-label{font-weight:600;min-width:45px;color:var(--kendo-color-subtle, #6c757d);font-size:.85rem}.preview-row .preview-value{font-size:.85rem}.preview-row .monospace{font-family:monospace}.selection-hint{text-align:center;padding:8px;color:var(--kendo-color-subtle, #6c757d);font-size:.85rem;flex-shrink:0}.dialog-actions{flex:0 0 auto;display:flex;gap:8px;justify-content:flex-end;padding:10px 14px;border-top:1px solid var(--kendo-color-border, #dee2e6);background:var(--kendo-color-surface, transparent)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$1.ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconPosition", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }, { kind: "component", type: TreeComponent, selector: "mm-tree-view", inputs: ["dataSource"], outputs: ["nodeSelected", "nodeClick", "nodeDoubleClick", "nodeDrop", "expand", "collapse"] }, { kind: "component", type: PerspectiveSwitcherComponent, selector: "mm-perspective-switcher", inputs: ["perspectives", "activeKey", "label"], outputs: ["perspectiveChange"] }], changeDetection: i0.ChangeDetectionStrategy.Eager });
|
|
6552
7541
|
}
|
|
6553
7542
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: EntitySelectorDialogComponent, decorators: [{
|
|
6554
7543
|
type: Component,
|
|
@@ -6556,11 +7545,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
|
|
|
6556
7545
|
CommonModule,
|
|
6557
7546
|
ButtonModule,
|
|
6558
7547
|
TreeComponent,
|
|
7548
|
+
PerspectiveSwitcherComponent,
|
|
6559
7549
|
], providers: [RuntimeBrowserDataSource], template: `
|
|
6560
7550
|
<div class="entity-selector">
|
|
6561
7551
|
<div class="entity-selector-body">
|
|
7552
|
+
<mm-perspective-switcher
|
|
7553
|
+
[perspectives]="perspectives()"
|
|
7554
|
+
[activeKey]="activePerspectiveKey()"
|
|
7555
|
+
(perspectiveChange)="onPerspectiveChange($event)"
|
|
7556
|
+
></mm-perspective-switcher>
|
|
6562
7557
|
<div class="tree-section">
|
|
6563
7558
|
<mm-tree-view
|
|
7559
|
+
#tree
|
|
6564
7560
|
[dataSource]="treeDataSource"
|
|
6565
7561
|
(nodeSelected)="onNodeSelected($event)"
|
|
6566
7562
|
></mm-tree-view>
|
|
@@ -6596,7 +7592,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
|
|
|
6596
7592
|
</div>
|
|
6597
7593
|
</div>
|
|
6598
7594
|
`, changeDetection: ChangeDetectionStrategy.Eager, styles: [":host{display:flex;flex-direction:column;height:100%;min-height:0}.entity-selector{display:flex;flex-direction:column;flex:1 1 auto;min-height:0;box-sizing:border-box}.entity-selector-body{flex:1 1 auto;min-height:0;overflow-y:auto;padding:12px;display:flex;flex-direction:column;gap:12px}.tree-section{flex:1;min-height:0;overflow:auto;border:1px solid var(--kendo-color-border, #dee2e6);border-radius:4px;background:var(--kendo-color-surface, #ffffff)}.selection-preview{padding:10px 12px;border:1px solid var(--kendo-color-border, #dee2e6);border-radius:4px;background:var(--kendo-color-surface-alt, #f8f9fa);display:flex;flex-direction:column;gap:4px;flex-shrink:0}.preview-row{display:flex;gap:8px}.preview-row .preview-label{font-weight:600;min-width:45px;color:var(--kendo-color-subtle, #6c757d);font-size:.85rem}.preview-row .preview-value{font-size:.85rem}.preview-row .monospace{font-family:monospace}.selection-hint{text-align:center;padding:8px;color:var(--kendo-color-subtle, #6c757d);font-size:.85rem;flex-shrink:0}.dialog-actions{flex:0 0 auto;display:flex;gap:8px;justify-content:flex-end;padding:10px 14px;border-top:1px solid var(--kendo-color-border, #dee2e6);background:var(--kendo-color-surface, transparent)}\n"] }]
|
|
6599
|
-
}]
|
|
7595
|
+
}], propDecorators: { tree: [{
|
|
7596
|
+
type: ViewChild,
|
|
7597
|
+
args: ['tree']
|
|
7598
|
+
}] } });
|
|
6600
7599
|
|
|
6601
7600
|
const DIALOG_KEY$1 = 'entity-selector';
|
|
6602
7601
|
const DEFAULT_SIZE$1 = { width: 600, height: 680 };
|
|
@@ -8256,6 +9255,7 @@ const DEFAULT_RUNTIME_BROWSER_MESSAGES = {
|
|
|
8256
9255
|
mappingNotSet: '(not set)',
|
|
8257
9256
|
mappingSelect: 'Select...',
|
|
8258
9257
|
mappingNoneConfigured: 'No data point mappings configured yet.',
|
|
9258
|
+
perspective: 'Perspective',
|
|
8259
9259
|
};
|
|
8260
9260
|
|
|
8261
9261
|
class DataMappingListComponent {
|
|
@@ -9907,64 +10907,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
|
|
|
9907
10907
|
type: Input
|
|
9908
10908
|
}] } });
|
|
9909
10909
|
|
|
9910
|
-
const GetCkTypeAssociationRolesDocumentDto = gql `
|
|
9911
|
-
query getCkTypeAssociationRoles($ckTypeId: String!) {
|
|
9912
|
-
constructionKit {
|
|
9913
|
-
types(rtCkId: $ckTypeId, first: 1) {
|
|
9914
|
-
items {
|
|
9915
|
-
rtCkTypeId
|
|
9916
|
-
associations {
|
|
9917
|
-
in {
|
|
9918
|
-
all {
|
|
9919
|
-
roleId {
|
|
9920
|
-
fullName
|
|
9921
|
-
semanticVersionedFullName
|
|
9922
|
-
}
|
|
9923
|
-
rtRoleId
|
|
9924
|
-
navigationPropertyName
|
|
9925
|
-
multiplicity
|
|
9926
|
-
targetCkTypeId {
|
|
9927
|
-
fullName
|
|
9928
|
-
}
|
|
9929
|
-
rtTargetCkTypeId
|
|
9930
|
-
}
|
|
9931
|
-
}
|
|
9932
|
-
out {
|
|
9933
|
-
all {
|
|
9934
|
-
roleId {
|
|
9935
|
-
fullName
|
|
9936
|
-
semanticVersionedFullName
|
|
9937
|
-
}
|
|
9938
|
-
rtRoleId
|
|
9939
|
-
navigationPropertyName
|
|
9940
|
-
multiplicity
|
|
9941
|
-
targetCkTypeId {
|
|
9942
|
-
fullName
|
|
9943
|
-
}
|
|
9944
|
-
rtTargetCkTypeId
|
|
9945
|
-
}
|
|
9946
|
-
}
|
|
9947
|
-
}
|
|
9948
|
-
}
|
|
9949
|
-
}
|
|
9950
|
-
}
|
|
9951
|
-
}
|
|
9952
|
-
`;
|
|
9953
|
-
class GetCkTypeAssociationRolesDtoGQL extends i1$3.Query {
|
|
9954
|
-
document = GetCkTypeAssociationRolesDocumentDto;
|
|
9955
|
-
constructor(apollo) {
|
|
9956
|
-
super(apollo);
|
|
9957
|
-
}
|
|
9958
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: GetCkTypeAssociationRolesDtoGQL, deps: [{ token: i1$3.Apollo }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
9959
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: GetCkTypeAssociationRolesDtoGQL, providedIn: 'root' });
|
|
9960
|
-
}
|
|
9961
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: GetCkTypeAssociationRolesDtoGQL, decorators: [{
|
|
9962
|
-
type: Injectable,
|
|
9963
|
-
args: [{
|
|
9964
|
-
providedIn: 'root'
|
|
9965
|
-
}]
|
|
9966
|
-
}], ctorParameters: () => [{ type: i1$3.Apollo }] });
|
|
9967
|
-
|
|
9968
10910
|
/**
|
|
9969
10911
|
* Validates whether a drag-and-drop move (reparenting) is allowed by the CK model.
|
|
9970
10912
|
*
|
|
@@ -14251,6 +15193,26 @@ class RuntimeBrowserComponent {
|
|
|
14251
15193
|
...this.messages(),
|
|
14252
15194
|
}), /* @ts-ignore */
|
|
14253
15195
|
...(ngDevMode ? [{ debugName: "resolvedMessages" }] : /* istanbul ignore next */ []));
|
|
15196
|
+
/** Selectable tree perspectives (AB#4263); switcher hides itself when <= 1. */
|
|
15197
|
+
perspectives = signal([], /* @ts-ignore */
|
|
15198
|
+
...(ngDevMode ? [{ debugName: "perspectives" }] : /* istanbul ignore next */ []));
|
|
15199
|
+
activePerspectiveKey = signal(this.dataSource.getActivePerspectiveKey(), /* @ts-ignore */
|
|
15200
|
+
...(ngDevMode ? [{ debugName: "activePerspectiveKey" }] : /* istanbul ignore next */ []));
|
|
15201
|
+
/** Switches the active perspective and reloads the tree from its new roots. */
|
|
15202
|
+
async onPerspectiveChange(key) {
|
|
15203
|
+
this.dataSource.setActivePerspective(key);
|
|
15204
|
+
this.activePerspectiveKey.set(key);
|
|
15205
|
+
await this.treeDetail?.refreshTree();
|
|
15206
|
+
}
|
|
15207
|
+
async loadPerspectives() {
|
|
15208
|
+
try {
|
|
15209
|
+
this.perspectives.set(await this.dataSource.getPerspectives());
|
|
15210
|
+
this.activePerspectiveKey.set(this.dataSource.getActivePerspectiveKey());
|
|
15211
|
+
}
|
|
15212
|
+
catch (error) {
|
|
15213
|
+
console.error('Error loading perspectives', error);
|
|
15214
|
+
}
|
|
15215
|
+
}
|
|
14254
15216
|
treeDetail;
|
|
14255
15217
|
detailsPanel;
|
|
14256
15218
|
// Define toolbar actions
|
|
@@ -14330,6 +15292,8 @@ class RuntimeBrowserComponent {
|
|
|
14330
15292
|
return !this.isLoading && this.isSelectedItemAnRtEntity && !this.isEditing;
|
|
14331
15293
|
}
|
|
14332
15294
|
ngAfterViewInit() {
|
|
15295
|
+
// Load the selectable perspectives for the switcher (AB#4263).
|
|
15296
|
+
void this.loadPerspectives();
|
|
14333
15297
|
// Restore tree state after the tree has been initialized
|
|
14334
15298
|
this.waitForTreeComponent().then((isReady) => {
|
|
14335
15299
|
if (isReady) {
|
|
@@ -14835,6 +15799,12 @@ class RuntimeBrowserComponent {
|
|
|
14835
15799
|
<!-- Main Content -->
|
|
14836
15800
|
<div class="lcars-content-panel">
|
|
14837
15801
|
<div class="panel-accent-top"></div>
|
|
15802
|
+
<mm-perspective-switcher
|
|
15803
|
+
[perspectives]="perspectives()"
|
|
15804
|
+
[activeKey]="activePerspectiveKey()"
|
|
15805
|
+
[label]="resolvedMessages().perspective ?? 'Perspective'"
|
|
15806
|
+
(perspectiveChange)="onPerspectiveChange($event)"
|
|
15807
|
+
></mm-perspective-switcher>
|
|
14838
15808
|
<mm-base-tree-detail
|
|
14839
15809
|
#treeDetail
|
|
14840
15810
|
[treeDataSource]="dataSource"
|
|
@@ -14870,11 +15840,15 @@ class RuntimeBrowserComponent {
|
|
|
14870
15840
|
</div>
|
|
14871
15841
|
</div>
|
|
14872
15842
|
</div>
|
|
14873
|
-
`, isInline: true, styles: [".runtime-browser-container{display:flex;flex-direction:column;height:100%;padding:16px;gap:16px}::ng-deep mm-base-tree-detail .k-splitter{background:transparent;border:none}::ng-deep mm-base-tree-detail .k-splitter .k-splitbar{background:linear-gradient(180deg,var(--octo-mint-30),transparent);width:4px!important}::ng-deep mm-base-tree-detail .k-splitter .k-splitbar:hover{background:linear-gradient(180deg,var(--octo-mint-50),var(--octo-mint-20))}::ng-deep mm-base-tree-detail kendo-treeview .k-treeview-item .k-treeview-leaf{font-family:Roboto,sans-serif;transition:all .2s ease;border-radius:4px}::ng-deep mm-base-tree-detail kendo-treeview .k-treeview-item .k-treeview-leaf:hover{background:var(--octo-mint-10);color:var(--octo-mint)}::ng-deep mm-base-tree-detail kendo-treeview .k-treeview-item .k-treeview-leaf.k-selected{background:linear-gradient(90deg,var(--octo-mint-20),transparent);color:var(--octo-mint);border-left:3px solid var(--octo-mint)}::ng-deep mm-base-tree-detail kendo-treeview .k-treeview-item .k-treeview-leaf.k-selected:hover{background:linear-gradient(90deg,var(--octo-mint-25),transparent)}::ng-deep mm-base-tree-detail .toolbar{background:linear-gradient(90deg,var(--octo-mint-05),transparent);border-bottom:1px solid var(--octo-mint-20)}::ng-deep mm-base-tree-detail .base-tree-detail-container{height:100%;display:flex;flex-direction:column}::ng-deep mm-base-tree-detail .base-tree-detail-container .k-splitter{flex:1;min-height:0}::ng-deep mm-base-tree-detail kendo-splitter-pane.detail-pane{display:flex!important;flex-direction:column!important;height:100%!important}::ng-deep mm-base-tree-detail kendo-splitter-pane.detail-pane>mm-runtime-browser-details{display:flex!important;flex:1!important;min-height:0!important;height:100%!important}::ng-deep mm-base-tree-detail kendo-splitter-pane.detail-pane>mm-runtime-browser-details>.runtime-browser-details{flex:1;display:flex;flex-direction:column;min-height:0}@media(max-width:1024px){.runtime-browser-container{padding:12px;gap:12px}}@media(max-width:768px){.runtime-browser-container{padding:8px;gap:10px}}\n"], dependencies: [{ kind: "component", type: BaseTreeDetailComponent, selector: "mm-base-tree-detail", inputs: ["treeDataSource", "leftPaneSize", "leftToolbarActions", "rightToolbarActions"], outputs: ["nodeSelected", "nodeDropped"] }, { kind: "component", type: RuntimeBrowserDetailsComponent, selector: "mm-runtime-browser-details", inputs: ["selectedItem", "showDataMapping", "messages", "expressionValidator"], outputs: ["entitySaved"] }], changeDetection: i0.ChangeDetectionStrategy.Eager });
|
|
15843
|
+
`, isInline: true, styles: [":host{display:flex;flex-direction:column;height:100%;width:100%}.runtime-browser-container{display:flex;flex-direction:column;height:100%;padding:16px;gap:16px}::ng-deep mm-base-tree-detail .k-splitter{background:transparent;border:none}::ng-deep mm-base-tree-detail .k-splitter .k-splitbar{background:linear-gradient(180deg,var(--octo-mint-30),transparent);width:4px!important}::ng-deep mm-base-tree-detail .k-splitter .k-splitbar:hover{background:linear-gradient(180deg,var(--octo-mint-50),var(--octo-mint-20))}::ng-deep mm-base-tree-detail kendo-treeview .k-treeview-item .k-treeview-leaf{font-family:Roboto,sans-serif;transition:all .2s ease;border-radius:4px}::ng-deep mm-base-tree-detail kendo-treeview .k-treeview-item .k-treeview-leaf:hover{background:var(--octo-mint-10);color:var(--octo-mint)}::ng-deep mm-base-tree-detail kendo-treeview .k-treeview-item .k-treeview-leaf.k-selected{background:linear-gradient(90deg,var(--octo-mint-20),transparent);color:var(--octo-mint);border-left:3px solid var(--octo-mint)}::ng-deep mm-base-tree-detail kendo-treeview .k-treeview-item .k-treeview-leaf.k-selected:hover{background:linear-gradient(90deg,var(--octo-mint-25),transparent)}::ng-deep mm-base-tree-detail .toolbar{background:linear-gradient(90deg,var(--octo-mint-05),transparent);border-bottom:1px solid var(--octo-mint-20)}::ng-deep mm-base-tree-detail .base-tree-detail-container{height:100%;display:flex;flex-direction:column}::ng-deep mm-base-tree-detail .base-tree-detail-container .k-splitter{flex:1;min-height:0}::ng-deep mm-base-tree-detail kendo-splitter-pane.detail-pane{display:flex!important;flex-direction:column!important;height:100%!important}::ng-deep mm-base-tree-detail kendo-splitter-pane.detail-pane>mm-runtime-browser-details{display:flex!important;flex:1!important;min-height:0!important;height:100%!important}::ng-deep mm-base-tree-detail kendo-splitter-pane.detail-pane>mm-runtime-browser-details>.runtime-browser-details{flex:1;display:flex;flex-direction:column;min-height:0}@media(max-width:1024px){.runtime-browser-container{padding:12px;gap:12px}}@media(max-width:768px){.runtime-browser-container{padding:8px;gap:10px}}\n"], dependencies: [{ kind: "component", type: BaseTreeDetailComponent, selector: "mm-base-tree-detail", inputs: ["treeDataSource", "leftPaneSize", "leftToolbarActions", "rightToolbarActions"], outputs: ["nodeSelected", "nodeDropped"] }, { kind: "component", type: RuntimeBrowserDetailsComponent, selector: "mm-runtime-browser-details", inputs: ["selectedItem", "showDataMapping", "messages", "expressionValidator"], outputs: ["entitySaved"] }, { kind: "component", type: PerspectiveSwitcherComponent, selector: "mm-perspective-switcher", inputs: ["perspectives", "activeKey", "label"], outputs: ["perspectiveChange"] }], changeDetection: i0.ChangeDetectionStrategy.Eager });
|
|
14874
15844
|
}
|
|
14875
15845
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: RuntimeBrowserComponent, decorators: [{
|
|
14876
15846
|
type: Component,
|
|
14877
|
-
args: [{ selector: 'mm-runtime-browser', imports: [
|
|
15847
|
+
args: [{ selector: 'mm-runtime-browser', imports: [
|
|
15848
|
+
BaseTreeDetailComponent,
|
|
15849
|
+
RuntimeBrowserDetailsComponent,
|
|
15850
|
+
PerspectiveSwitcherComponent,
|
|
15851
|
+
], template: `
|
|
14878
15852
|
<div class="runtime-browser-container kendo-theme-provider">
|
|
14879
15853
|
<!-- LCARS Header -->
|
|
14880
15854
|
<div class="lcars-page-header">
|
|
@@ -14901,6 +15875,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
|
|
|
14901
15875
|
<!-- Main Content -->
|
|
14902
15876
|
<div class="lcars-content-panel">
|
|
14903
15877
|
<div class="panel-accent-top"></div>
|
|
15878
|
+
<mm-perspective-switcher
|
|
15879
|
+
[perspectives]="perspectives()"
|
|
15880
|
+
[activeKey]="activePerspectiveKey()"
|
|
15881
|
+
[label]="resolvedMessages().perspective ?? 'Perspective'"
|
|
15882
|
+
(perspectiveChange)="onPerspectiveChange($event)"
|
|
15883
|
+
></mm-perspective-switcher>
|
|
14904
15884
|
<mm-base-tree-detail
|
|
14905
15885
|
#treeDetail
|
|
14906
15886
|
[treeDataSource]="dataSource"
|
|
@@ -14936,7 +15916,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
|
|
|
14936
15916
|
</div>
|
|
14937
15917
|
</div>
|
|
14938
15918
|
</div>
|
|
14939
|
-
`, changeDetection: ChangeDetectionStrategy.Eager, styles: [".runtime-browser-container{display:flex;flex-direction:column;height:100%;padding:16px;gap:16px}::ng-deep mm-base-tree-detail .k-splitter{background:transparent;border:none}::ng-deep mm-base-tree-detail .k-splitter .k-splitbar{background:linear-gradient(180deg,var(--octo-mint-30),transparent);width:4px!important}::ng-deep mm-base-tree-detail .k-splitter .k-splitbar:hover{background:linear-gradient(180deg,var(--octo-mint-50),var(--octo-mint-20))}::ng-deep mm-base-tree-detail kendo-treeview .k-treeview-item .k-treeview-leaf{font-family:Roboto,sans-serif;transition:all .2s ease;border-radius:4px}::ng-deep mm-base-tree-detail kendo-treeview .k-treeview-item .k-treeview-leaf:hover{background:var(--octo-mint-10);color:var(--octo-mint)}::ng-deep mm-base-tree-detail kendo-treeview .k-treeview-item .k-treeview-leaf.k-selected{background:linear-gradient(90deg,var(--octo-mint-20),transparent);color:var(--octo-mint);border-left:3px solid var(--octo-mint)}::ng-deep mm-base-tree-detail kendo-treeview .k-treeview-item .k-treeview-leaf.k-selected:hover{background:linear-gradient(90deg,var(--octo-mint-25),transparent)}::ng-deep mm-base-tree-detail .toolbar{background:linear-gradient(90deg,var(--octo-mint-05),transparent);border-bottom:1px solid var(--octo-mint-20)}::ng-deep mm-base-tree-detail .base-tree-detail-container{height:100%;display:flex;flex-direction:column}::ng-deep mm-base-tree-detail .base-tree-detail-container .k-splitter{flex:1;min-height:0}::ng-deep mm-base-tree-detail kendo-splitter-pane.detail-pane{display:flex!important;flex-direction:column!important;height:100%!important}::ng-deep mm-base-tree-detail kendo-splitter-pane.detail-pane>mm-runtime-browser-details{display:flex!important;flex:1!important;min-height:0!important;height:100%!important}::ng-deep mm-base-tree-detail kendo-splitter-pane.detail-pane>mm-runtime-browser-details>.runtime-browser-details{flex:1;display:flex;flex-direction:column;min-height:0}@media(max-width:1024px){.runtime-browser-container{padding:12px;gap:12px}}@media(max-width:768px){.runtime-browser-container{padding:8px;gap:10px}}\n"] }]
|
|
15919
|
+
`, changeDetection: ChangeDetectionStrategy.Eager, styles: [":host{display:flex;flex-direction:column;height:100%;width:100%}.runtime-browser-container{display:flex;flex-direction:column;height:100%;padding:16px;gap:16px}::ng-deep mm-base-tree-detail .k-splitter{background:transparent;border:none}::ng-deep mm-base-tree-detail .k-splitter .k-splitbar{background:linear-gradient(180deg,var(--octo-mint-30),transparent);width:4px!important}::ng-deep mm-base-tree-detail .k-splitter .k-splitbar:hover{background:linear-gradient(180deg,var(--octo-mint-50),var(--octo-mint-20))}::ng-deep mm-base-tree-detail kendo-treeview .k-treeview-item .k-treeview-leaf{font-family:Roboto,sans-serif;transition:all .2s ease;border-radius:4px}::ng-deep mm-base-tree-detail kendo-treeview .k-treeview-item .k-treeview-leaf:hover{background:var(--octo-mint-10);color:var(--octo-mint)}::ng-deep mm-base-tree-detail kendo-treeview .k-treeview-item .k-treeview-leaf.k-selected{background:linear-gradient(90deg,var(--octo-mint-20),transparent);color:var(--octo-mint);border-left:3px solid var(--octo-mint)}::ng-deep mm-base-tree-detail kendo-treeview .k-treeview-item .k-treeview-leaf.k-selected:hover{background:linear-gradient(90deg,var(--octo-mint-25),transparent)}::ng-deep mm-base-tree-detail .toolbar{background:linear-gradient(90deg,var(--octo-mint-05),transparent);border-bottom:1px solid var(--octo-mint-20)}::ng-deep mm-base-tree-detail .base-tree-detail-container{height:100%;display:flex;flex-direction:column}::ng-deep mm-base-tree-detail .base-tree-detail-container .k-splitter{flex:1;min-height:0}::ng-deep mm-base-tree-detail kendo-splitter-pane.detail-pane{display:flex!important;flex-direction:column!important;height:100%!important}::ng-deep mm-base-tree-detail kendo-splitter-pane.detail-pane>mm-runtime-browser-details{display:flex!important;flex:1!important;min-height:0!important;height:100%!important}::ng-deep mm-base-tree-detail kendo-splitter-pane.detail-pane>mm-runtime-browser-details>.runtime-browser-details{flex:1;display:flex;flex-direction:column;min-height:0}@media(max-width:1024px){.runtime-browser-container{padding:12px;gap:12px}}@media(max-width:768px){.runtime-browser-container{padding:8px;gap:10px}}\n"] }]
|
|
14940
15920
|
}], propDecorators: { messages: [{ type: i0.Input, args: [{ isSignal: true, alias: "messages", required: false }] }], showDataMapping: [{ type: i0.Input, args: [{ isSignal: true, alias: "showDataMapping", required: false }] }], expressionValidator: [{ type: i0.Input, args: [{ isSignal: true, alias: "expressionValidator", required: false }] }], treeDetail: [{
|
|
14941
15921
|
type: ViewChild,
|
|
14942
15922
|
args: ['treeDetail', { static: false }]
|
|
@@ -14951,17 +15931,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
|
|
|
14951
15931
|
*/
|
|
14952
15932
|
class RuntimeBrowserOutletComponent {
|
|
14953
15933
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: RuntimeBrowserOutletComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
14954
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.0.2", type: RuntimeBrowserOutletComponent, isStandalone: true, selector: "mm-runtime-browser-outlet", ngImport: i0, template: `<router-outlet />`, isInline: true, dependencies: [{ kind: "directive", type: RouterOutlet, selector: "router-outlet", inputs: ["name", "routerOutletData"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }], changeDetection: i0.ChangeDetectionStrategy.Eager });
|
|
15934
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.0.2", type: RuntimeBrowserOutletComponent, isStandalone: true, selector: "mm-runtime-browser-outlet", ngImport: i0, template: `<router-outlet />`, isInline: true, styles: [":host{display:flex;flex-direction:column;height:100%;width:100%}\n"], dependencies: [{ kind: "directive", type: RouterOutlet, selector: "router-outlet", inputs: ["name", "routerOutletData"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }], changeDetection: i0.ChangeDetectionStrategy.Eager });
|
|
14955
15935
|
}
|
|
14956
15936
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: RuntimeBrowserOutletComponent, decorators: [{
|
|
14957
15937
|
type: Component,
|
|
14958
|
-
args: [{
|
|
14959
|
-
selector: 'mm-runtime-browser-outlet',
|
|
14960
|
-
standalone: true,
|
|
14961
|
-
imports: [RouterOutlet],
|
|
14962
|
-
changeDetection: ChangeDetectionStrategy.Eager,
|
|
14963
|
-
template: `<router-outlet />`,
|
|
14964
|
-
}]
|
|
15938
|
+
args: [{ selector: 'mm-runtime-browser-outlet', standalone: true, imports: [RouterOutlet], changeDetection: ChangeDetectionStrategy.Eager, template: `<router-outlet />`, styles: [":host{display:flex;flex-direction:column;height:100%;width:100%}\n"] }]
|
|
14965
15939
|
}] });
|
|
14966
15940
|
|
|
14967
15941
|
/**
|
|
@@ -14982,17 +15956,11 @@ class RuntimeBrowserPageComponent {
|
|
|
14982
15956
|
? this.injectedMessages
|
|
14983
15957
|
: DEFAULT_RUNTIME_BROWSER_MESSAGES;
|
|
14984
15958
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: RuntimeBrowserPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
14985
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.0.2", type: RuntimeBrowserPageComponent, isStandalone: true, selector: "mm-runtime-browser-page", ngImport: i0, template: `<mm-runtime-browser [messages]="messages" />`, isInline: true, dependencies: [{ kind: "component", type: RuntimeBrowserComponent, selector: "mm-runtime-browser", inputs: ["messages", "showDataMapping", "expressionValidator"] }], changeDetection: i0.ChangeDetectionStrategy.Eager });
|
|
15959
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.0.2", type: RuntimeBrowserPageComponent, isStandalone: true, selector: "mm-runtime-browser-page", ngImport: i0, template: `<mm-runtime-browser [messages]="messages" />`, isInline: true, styles: [":host{display:flex;flex-direction:column;height:100%;width:100%}\n"], dependencies: [{ kind: "component", type: RuntimeBrowserComponent, selector: "mm-runtime-browser", inputs: ["messages", "showDataMapping", "expressionValidator"] }], changeDetection: i0.ChangeDetectionStrategy.Eager });
|
|
14986
15960
|
}
|
|
14987
15961
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: RuntimeBrowserPageComponent, decorators: [{
|
|
14988
15962
|
type: Component,
|
|
14989
|
-
args: [{
|
|
14990
|
-
selector: 'mm-runtime-browser-page',
|
|
14991
|
-
standalone: true,
|
|
14992
|
-
imports: [RuntimeBrowserComponent],
|
|
14993
|
-
changeDetection: ChangeDetectionStrategy.Eager,
|
|
14994
|
-
template: `<mm-runtime-browser [messages]="messages" />`,
|
|
14995
|
-
}]
|
|
15963
|
+
args: [{ selector: 'mm-runtime-browser-page', standalone: true, imports: [RuntimeBrowserComponent], changeDetection: ChangeDetectionStrategy.Eager, template: `<mm-runtime-browser [messages]="messages" />`, styles: [":host{display:flex;flex-direction:column;height:100%;width:100%}\n"] }]
|
|
14996
15964
|
}] });
|
|
14997
15965
|
|
|
14998
15966
|
/**
|
|
@@ -18018,5 +18986,5 @@ function provideOctoUi() {
|
|
|
18018
18986
|
* Generated bundle index. Do not edit.
|
|
18019
18987
|
*/
|
|
18020
18988
|
|
|
18021
|
-
export { AssociationValidationService, AttributeSelectorDialogComponent, AttributeSelectorDialogService, AttributeSortSelectorDialogComponent, AttributeSortSelectorDialogService, AttributeValueTypeDto, CkTypeSelectorDialogComponent, CkTypeSelectorDialogService, CkTypeSelectorInputComponent, DEFAULT_CK_TYPE_SELECTOR_DIALOG_MESSAGES, DEFAULT_CK_TYPE_SELECTOR_INPUT_MESSAGES, DEFAULT_DATA_POINT, DEFAULT_MAPPING_COVERAGE_TREE_CONFIG, DEFAULT_PROPERTY_GRID_MESSAGES, DEFAULT_RUNTIME_BROWSER_MESSAGES, DataMappingOverviewComponent, DataPointPickerComponent, DataPointResolverService, DefaultPropertyCategory, EntityDetailComponent, EntityIdInfoComponent, EntitySelectorDialogComponent, EntitySelectorDialogService, FieldFilterEditorComponent, MappingCoverageTreeComponent, MappingCoverageTreeDataSource, MappingEditDialogComponent, MappingEditDialogService, OctoGraphQlDataSource, OctoGraphQlHierarchyDataSource, OctoLoaderComponent, PropertyConverterService, PropertyDisplayMode, PropertyGridComponent, PropertyValueDisplayComponent, RUNTIME_BROWSER_MESSAGES, RecordDetailDialogComponent, RtEntityIdHelper, RuntimeBrowserComponent, RuntimeBrowserOutletComponent, RuntimeBrowserPageComponent, RuntimeBrowserStateService, RuntimeEntityVariableDialogComponent, RuntimeEntityVariableDialogService, TenantSwitcherComponent, account_tree, add, analytics, app_registration, article, botService, category, chat, checklist, code, component_exchange, computer, createRuntimeBrowserRoutes, customer, dashboard, event_list, extractDataPointNames, graphic_eq, group, identityService, insert_link, manage_accounts, more_time, notifications, page_info, pages, person_search, playlist_add_check, pool, power, provideOctoUi, publicIcon, query_builder, schedule_send, settings, sort, storage, swagger, swagger_asset, swagger_bot, swagger_communication, swagger_identity, team_dashboard, tenancy, text_snippet, travel_explore, user_diagnostics, webhook, work };
|
|
18989
|
+
export { AssociationValidationService, AttributeSelectorDialogComponent, AttributeSelectorDialogService, AttributeSortSelectorDialogComponent, AttributeSortSelectorDialogService, AttributeValueTypeDto, CkTypeSelectorDialogComponent, CkTypeSelectorDialogService, CkTypeSelectorInputComponent, DEFAULT_CK_TYPE_SELECTOR_DIALOG_MESSAGES, DEFAULT_CK_TYPE_SELECTOR_INPUT_MESSAGES, DEFAULT_DATA_POINT, DEFAULT_MAPPING_COVERAGE_TREE_CONFIG, DEFAULT_PROPERTY_GRID_MESSAGES, DEFAULT_RUNTIME_BROWSER_MESSAGES, DataMappingOverviewComponent, DataPointPickerComponent, DataPointResolverService, DefaultPropertyCategory, EntityDetailComponent, EntityIdInfoComponent, EntitySelectorDialogComponent, EntitySelectorDialogService, FieldFilterEditorComponent, MappingCoverageTreeComponent, MappingCoverageTreeDataSource, MappingEditDialogComponent, MappingEditDialogService, OctoGraphQlDataSource, OctoGraphQlHierarchyDataSource, OctoLoaderComponent, PropertyConverterService, PropertyDisplayMode, PropertyGridComponent, PropertyValueDisplayComponent, RUNTIME_BROWSER_MESSAGES, RecordDetailDialogComponent, RtEntityIdHelper, RuntimeBrowserComponent, RuntimeBrowserOutletComponent, RuntimeBrowserPageComponent, RuntimeBrowserStateService, RuntimeEntityVariableDialogComponent, RuntimeEntityVariableDialogService, TREE_NAVIGATION_CONFIG_CONSTANTS, TenantSwitcherComponent, TreeNavigationConfigService, account_tree, add, analytics, app_registration, article, botService, category, chat, checklist, code, component_exchange, computer, createRuntimeBrowserRoutes, customer, dashboard, event_list, extractDataPointNames, graphic_eq, group, identityService, insert_link, manage_accounts, more_time, notifications, page_info, pages, person_search, playlist_add_check, pool, power, provideOctoUi, publicIcon, query_builder, schedule_send, settings, sort, storage, swagger, swagger_asset, swagger_bot, swagger_communication, swagger_identity, team_dashboard, tenancy, text_snippet, travel_explore, user_diagnostics, webhook, work };
|
|
18022
18990
|
//# sourceMappingURL=meshmakers-octo-ui.mjs.map
|