NIFI-13112: (#8711)

- Fixing linking to non canvas items.
- Adding a tooltip to render search match details.

This closes #8711
This commit is contained in:
Matt Gilman 2024-05-01 12:00:02 -04:00 committed by GitHub
parent 0e373e9c21
commit 2c43a706f8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 195 additions and 23 deletions

View File

@ -128,7 +128,6 @@
}
"></ng-container>
}
<!-- TODO - Handling linking to Controller Services, Parameter Providers, Parameter Contexts, and Parameters -->
@if (controllerServiceNodeResults.length > 0) {
<ng-container
*ngTemplateOutlet="
@ -186,31 +185,81 @@
#searchInput="cdkOverlayOrigin"
formControlName="searchBar" />
<ng-template #renderResults let-results let-header="header" let-icon="icon" let-path="path">
<li class="flex items-center">
<span class="icon mr-1" [class]="icon"></span>
<span class="font-medium">{{ header }}</span>
</li>
<!-- TODO - Consider showing more context of match like existing UI -->
@for (result of results; track result) {
<li class="ml-2 py-1">
@if (!result.parentGroup) {
<a [routerLink]="['/process-groups', result.id]">
{{ result.name }}
</a>
} @else {
@if (result.parentGroup.id == currentProcessGroupId) {
@if (results.length > 0) {
<li class="flex items-center">
<span class="icon mr-1 accent-color" [class]="icon"></span>
<span class="font-medium">{{ header }}</span>
</li>
@for (result of results; track result) {
<li class="ml-4 py-1 flex gap-x-2 items-center">
<i
class="fa fa-info-circle on-surface-medium"
nifiTooltip
[tooltipComponentType]="SearchMatchTip"
[tooltipInputData]="getSearchMatchTipInput(result)"
[delayClose]="false"></i>
@if (header === 'Parameters') {
<a
(click)="componentLinkClicked(path, result.id)"
[routerLink]="['/process-groups', result.parentGroup.id, path, result.id]">
class="w-full overflow-ellipsis overflow-hidden whitespace-nowrap"
[title]="result.name"
[routerLink]="['/parameter-contexts', result.parentGroup.id]">
{{ result.name }}
</a>
} @else if (header === 'Parameter Contexts') {
<a
class="w-full overflow-ellipsis overflow-hidden whitespace-nowrap"
[title]="result.name"
[routerLink]="['/parameter-contexts', result.id]">
{{ result.name }}
</a>
} @else if (header === 'Parameter Providers') {
<a
class="w-full overflow-ellipsis overflow-hidden whitespace-nowrap"
[title]="result.name"
[routerLink]="['/settings', 'parameter-providers', result.parentGroup.id]">
{{ result.name }}
</a>
} @else if (header === 'Controller Services') {
<a
class="w-full overflow-ellipsis overflow-hidden whitespace-nowrap"
[title]="result.name"
[routerLink]="[
'/process-groups',
result.parentGroup.id,
'controller-services',
result.id
]">
{{ result.name ? result.name : result.id }}
</a>
} @else {
<a [routerLink]="['/process-groups', result.parentGroup.id, path, result.id]">
{{ result.name ? result.name : result.id }}
</a>
@if (!result.parentGroup) {
<a
class="w-full overflow-ellipsis overflow-hidden whitespace-nowrap"
[title]="result.name"
[routerLink]="['/process-groups', result.id]">
{{ result.name }}
</a>
} @else {
@if (result.parentGroup.id == currentProcessGroupId) {
<a
class="w-full overflow-ellipsis overflow-hidden whitespace-nowrap"
(click)="componentLinkClicked(path, result.id)"
[title]="result.name"
[routerLink]="['/process-groups', result.parentGroup.id, path, result.id]">
{{ result.name ? result.name : result.id }}
</a>
} @else {
<a
class="w-full overflow-ellipsis overflow-hidden whitespace-nowrap"
[title]="result.name"
[routerLink]="['/process-groups', result.parentGroup.id, path, result.id]">
{{ result.name ? result.name : result.id }}
</a>
}
}
}
}
</li>
</li>
}
}
</ng-template>
</form>

View File

@ -27,7 +27,7 @@ import {
OriginConnectionPosition,
OverlayConnectionPosition
} from '@angular/cdk/overlay';
import { ComponentType } from '../../../../../../state/shared';
import { ComponentType, SearchMatchTipInput } from '../../../../../../state/shared';
import { NgTemplateOutlet } from '@angular/common';
import { RouterLink } from '@angular/router';
import { MatFormFieldModule } from '@angular/material/form-field';
@ -37,6 +37,8 @@ import { Store } from '@ngrx/store';
import { centerSelectedComponents, setAllowTransition } from '../../../../state/flow/flow.actions';
import { selectCurrentRoute } from '../../../../../../state/router/router.selectors';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { NifiTooltipDirective } from '../../../../../../ui/common/tooltips/nifi-tooltip.directive';
import { SearchMatchTip } from '../../../../../../ui/common/tooltips/search-match-tip/search-match-tip.component';
@Component({
selector: 'search',
@ -50,11 +52,13 @@ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
NgTemplateOutlet,
RouterLink,
MatFormFieldModule,
MatInputModule
MatInputModule,
NifiTooltipDirective
]
})
export class Search implements OnInit {
protected readonly ComponentType = ComponentType;
protected readonly SearchMatchTip = SearchMatchTip;
@Input() currentProcessGroupId: string = initialState.id;
@ViewChild('searchInput') searchInput!: CdkOverlayOrigin;
@ -190,6 +194,12 @@ export class Search implements OnInit {
this.parameterResults = [];
}
getSearchMatchTipInput(result: ComponentSearchResult): SearchMatchTipInput {
return {
matches: result.matches
};
}
componentLinkClicked(componentType: ComponentType, id: string): void {
if (componentType == this.selectedComponentType && id == this.selectedComponentId) {
this.store.dispatch(centerSelectedComponents({ request: { allowTransition: true } }));

View File

@ -229,6 +229,10 @@ export interface UnorderedListTipInput {
items: string[];
}
export interface SearchMatchTipInput {
matches: string[];
}
export interface ControllerServiceApi {
type: string;
bundle: Bundle;

View File

@ -0,0 +1,25 @@
<!--
~ Licensed to the Apache Software Foundation (ASF) under one or more
~ contributor license agreements. See the NOTICE file distributed with
~ this work for additional information regarding copyright ownership.
~ The ASF licenses this file to You under the Apache License, Version 2.0
~ (the "License"); you may not use this file except in compliance with
~ the License. You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<div class="tooltip">
Search matched:
<ul>
@for (match of data?.matches; track match) {
<li>{{ match }}</li>
}
</ul>
</div>

View File

@ -0,0 +1,16 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

View File

@ -0,0 +1,38 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { SearchMatchTip } from './search-match-tip.component';
describe('SearchMatchTip', () => {
let component: SearchMatchTip;
let fixture: ComponentFixture<SearchMatchTip>;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [SearchMatchTip]
});
fixture = TestBed.createComponent(SearchMatchTip);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,30 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Component, Input } from '@angular/core';
import { SearchMatchTipInput } from '../../../../state/shared';
@Component({
selector: 'search-match-tip',
standalone: true,
templateUrl: './search-match-tip.component.html',
imports: [],
styleUrls: ['./search-match-tip.component.scss']
})
export class SearchMatchTip {
@Input() data: SearchMatchTipInput | undefined;
}