mirror of https://github.com/apache/nifi.git
NIFI-12795: (#8416)
- Including embedded help documentation. - Support linking to specific help documentation from the canvas and component listings.
This commit is contained in:
parent
bd11031725
commit
6f6ddf8960
|
@ -28,6 +28,12 @@ const routes: Routes = [
|
|||
path: 'error',
|
||||
loadChildren: () => import('./pages/error/feature/error.module').then((m) => m.ErrorModule)
|
||||
},
|
||||
{
|
||||
path: 'documentation',
|
||||
canMatch: [authenticationGuard],
|
||||
loadChildren: () =>
|
||||
import('./pages/documentation/feature/documentation.module').then((m) => m.DocumentationModule)
|
||||
},
|
||||
{
|
||||
path: 'settings',
|
||||
canMatch: [authenticationGuard],
|
||||
|
|
|
@ -45,6 +45,7 @@ import { ComponentStateEffects } from './state/component-state/component-state.e
|
|||
import { ErrorEffects } from './state/error/error.effects';
|
||||
import { MatSnackBarModule } from '@angular/material/snack-bar';
|
||||
import { PipesModule } from './pipes/pipes.module';
|
||||
import { DocumentationEffects } from './state/documentation/documentation.effects';
|
||||
|
||||
@NgModule({
|
||||
declarations: [AppComponent],
|
||||
|
@ -71,7 +72,8 @@ import { PipesModule } from './pipes/pipes.module';
|
|||
StatusHistoryEffects,
|
||||
ControllerServiceStateEffects,
|
||||
SystemDiagnosticsEffects,
|
||||
ComponentStateEffects
|
||||
ComponentStateEffects,
|
||||
DocumentationEffects
|
||||
),
|
||||
StoreDevtoolsModule.instrument({
|
||||
maxAge: 25,
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* 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 { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
import { Documentation } from './documentation.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
component: Documentation
|
||||
}
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class DocumentationRoutingModule {}
|
|
@ -0,0 +1,27 @@
|
|||
<!--
|
||||
~ 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="pb-5 flex flex-col h-screen justify-between">
|
||||
<header class="nifi-header">
|
||||
<navigation></navigation>
|
||||
</header>
|
||||
@if (frameSource) {
|
||||
<iframe class="flex-1" [src]="frameSource"></iframe>
|
||||
} @else {
|
||||
<iframe class="flex-1" src="../nifi-docs/documentation"></iframe>
|
||||
}
|
||||
</div>
|
|
@ -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.
|
||||
*/
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* 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 { Documentation } from './documentation.component';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { Component } from '@angular/core';
|
||||
import { provideMockStore } from '@ngrx/store/testing';
|
||||
import { initialState } from '../../../state/documentation/documentation.reducer';
|
||||
|
||||
describe('Documentation', () => {
|
||||
let component: Documentation;
|
||||
let fixture: ComponentFixture<Documentation>;
|
||||
|
||||
@Component({
|
||||
selector: 'navigation',
|
||||
standalone: true,
|
||||
template: ''
|
||||
})
|
||||
class MockNavigation {}
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [Documentation],
|
||||
imports: [RouterModule, RouterTestingModule, MockNavigation],
|
||||
providers: [provideMockStore({ initialState })]
|
||||
});
|
||||
fixture = TestBed.createComponent(Documentation);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* 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, OnDestroy, SecurityContext } from '@angular/core';
|
||||
import { NiFiState } from '../../../state';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser';
|
||||
import { HttpParams } from '@angular/common/http';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
import { selectDocumentationParameters } from '../../../state/documentation/documentation.selectors';
|
||||
import { DocumentationParameters } from '../../../state/documentation';
|
||||
import { clearDocumentationParameters } from '../../../state/documentation/documentation.actions';
|
||||
|
||||
@Component({
|
||||
selector: 'documentation',
|
||||
templateUrl: './documentation.component.html',
|
||||
styleUrls: ['./documentation.component.scss']
|
||||
})
|
||||
export class Documentation implements OnDestroy {
|
||||
frameSource!: SafeResourceUrl | null;
|
||||
|
||||
constructor(
|
||||
private store: Store<NiFiState>,
|
||||
private domSanitizer: DomSanitizer
|
||||
) {
|
||||
this.store
|
||||
.select(selectDocumentationParameters)
|
||||
.pipe(takeUntilDestroyed())
|
||||
.subscribe((params) => {
|
||||
this.frameSource = this.getFrameSource(params);
|
||||
});
|
||||
}
|
||||
|
||||
private getFrameSource(params: DocumentationParameters | null): SafeResourceUrl | null {
|
||||
let url = '../nifi-docs/documentation';
|
||||
|
||||
if (params) {
|
||||
if (Object.keys(params).length > 0) {
|
||||
const queryParams: string = new HttpParams({ fromObject: params }).toString();
|
||||
url = `${url}?${queryParams}`;
|
||||
}
|
||||
|
||||
const sanitizedUrl = this.domSanitizer.sanitize(SecurityContext.URL, url);
|
||||
|
||||
if (sanitizedUrl) {
|
||||
return this.domSanitizer.bypassSecurityTrustResourceUrl(sanitizedUrl);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.store.dispatch(clearDocumentationParameters());
|
||||
}
|
||||
}
|
|
@ -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 { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { Documentation } from './documentation.component';
|
||||
import { DocumentationRoutingModule } from './documentation-routing.module';
|
||||
import { MatDialogModule } from '@angular/material/dialog';
|
||||
import { Navigation } from '../../../ui/common/navigation/navigation.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [Documentation],
|
||||
exports: [Documentation],
|
||||
imports: [CommonModule, MatDialogModule, DocumentationRoutingModule, Navigation]
|
||||
})
|
||||
export class DocumentationModule {}
|
|
@ -57,6 +57,7 @@ import {
|
|||
} from '../../../ui/common/context-menu/context-menu.component';
|
||||
import { promptEmptyQueueRequest, promptEmptyQueuesRequest } from '../state/queue/queue.actions';
|
||||
import { getComponentStateAndOpenDialog } from '../../../state/component-state/component-state.actions';
|
||||
import { navigateToComponentDocumentation } from '../../../state/documentation/documentation.actions';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class CanvasContextMenu implements ContextMenuDefinitionProvider {
|
||||
|
@ -717,13 +718,26 @@ export class CanvasContextMenu implements ContextMenuDefinitionProvider {
|
|||
},
|
||||
{
|
||||
condition: (selection: any) => {
|
||||
// TODO - hasUsage
|
||||
return false;
|
||||
return (
|
||||
this.canvasUtils.canRead(selection) &&
|
||||
selection.size() === 1 &&
|
||||
this.canvasUtils.isProcessor(selection)
|
||||
);
|
||||
},
|
||||
clazz: 'fa fa-book',
|
||||
text: 'View usage',
|
||||
action: () => {
|
||||
// TODO - showUsage
|
||||
text: 'View documentation',
|
||||
action: (selection: any) => {
|
||||
const selectionData = selection.datum();
|
||||
this.store.dispatch(
|
||||
navigateToComponentDocumentation({
|
||||
params: {
|
||||
select: selectionData.component.type,
|
||||
group: selectionData.component.bundle.group,
|
||||
artifact: selectionData.component.bundle.artifact,
|
||||
version: selectionData.component.bundle.version
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
[flowConfiguration]="flowConfiguration"
|
||||
[canModifyParent]="canModifyParent(serviceState.breadcrumb)"
|
||||
(selectControllerService)="selectControllerService($event)"
|
||||
(viewControllerServiceDocumentation)="viewControllerServiceDocumentation($event)"
|
||||
(configureControllerService)="configureControllerService($event)"
|
||||
(enableControllerService)="enableControllerService($event)"
|
||||
(disableControllerService)="disableControllerService($event)"
|
||||
|
|
|
@ -46,6 +46,7 @@ import { selectFlowConfiguration } from '../../../../state/flow-configuration/fl
|
|||
import { NiFiState } from '../../../../state';
|
||||
import { loadFlowConfiguration } from '../../../../state/flow-configuration/flow-configuration.actions';
|
||||
import { getComponentStateAndOpenDialog } from '../../../../state/component-state/component-state.actions';
|
||||
import { navigateToComponentDocumentation } from '../../../../state/documentation/documentation.actions';
|
||||
|
||||
@Component({
|
||||
selector: 'controller-services',
|
||||
|
@ -160,6 +161,19 @@ export class ControllerServices implements OnInit, OnDestroy {
|
|||
};
|
||||
}
|
||||
|
||||
viewControllerServiceDocumentation(entity: ControllerServiceEntity): void {
|
||||
this.store.dispatch(
|
||||
navigateToComponentDocumentation({
|
||||
params: {
|
||||
select: entity.component.type,
|
||||
group: entity.component.bundle.group,
|
||||
artifact: entity.component.bundle.artifact,
|
||||
version: entity.component.bundle.version
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
configureControllerService(entity: ControllerServiceEntity): void {
|
||||
this.store.dispatch(
|
||||
navigateToEditService({
|
||||
|
|
|
@ -31,7 +31,10 @@
|
|||
<td mat-cell *matCellDef="let item">
|
||||
@if (canRead(item)) {
|
||||
<div class="flex items-center gap-x-3">
|
||||
<div class="pointer fa fa-book" title="Usage"></div>
|
||||
<div
|
||||
class="pointer fa fa-book"
|
||||
(click)="viewDocumentationClicked(item, $event)"
|
||||
title="View Documentation"></div>
|
||||
<!-- TODO - handle read only in configure component? -->
|
||||
@if (hasComments(item)) {
|
||||
<div>
|
||||
|
|
|
@ -51,10 +51,13 @@ export class FlowAnalysisRuleTable {
|
|||
@Input() set flowAnalysisRules(flowAnalysisRuleEntities: FlowAnalysisRuleEntity[]) {
|
||||
this.dataSource.data = this.sortFlowAnalysisRules(flowAnalysisRuleEntities, this.sort);
|
||||
}
|
||||
|
||||
@Input() selectedFlowAnalysisRuleId!: string;
|
||||
@Input() currentUser!: CurrentUser;
|
||||
|
||||
@Output() selectFlowAnalysisRule: EventEmitter<FlowAnalysisRuleEntity> = new EventEmitter<FlowAnalysisRuleEntity>();
|
||||
@Output() viewFlowAnalysisRuleDocumentation: EventEmitter<FlowAnalysisRuleEntity> =
|
||||
new EventEmitter<FlowAnalysisRuleEntity>();
|
||||
@Output() deleteFlowAnalysisRule: EventEmitter<FlowAnalysisRuleEntity> = new EventEmitter<FlowAnalysisRuleEntity>();
|
||||
@Output() configureFlowAnalysisRule: EventEmitter<FlowAnalysisRuleEntity> =
|
||||
new EventEmitter<FlowAnalysisRuleEntity>();
|
||||
|
@ -123,6 +126,11 @@ export class FlowAnalysisRuleTable {
|
|||
return !!entity.operatePermissions?.canWrite;
|
||||
}
|
||||
|
||||
viewDocumentationClicked(entity: FlowAnalysisRuleEntity, event: MouseEvent): void {
|
||||
event.stopPropagation();
|
||||
this.viewFlowAnalysisRuleDocumentation.next(entity);
|
||||
}
|
||||
|
||||
hasComments(entity: FlowAnalysisRuleEntity): boolean {
|
||||
return !this.nifiCommon.isBlank(entity.component.comments);
|
||||
}
|
||||
|
@ -236,7 +244,7 @@ export class FlowAnalysisRuleTable {
|
|||
this.isDisabled(entity) &&
|
||||
this.canRead(entity) &&
|
||||
this.canWrite(entity) &&
|
||||
entity.component.multipleVersionsAvailable === true
|
||||
entity.component.multipleVersionsAvailable
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
[flowAnalysisRules]="flowAnalysisRuleState.flowAnalysisRules"
|
||||
(configureFlowAnalysisRule)="configureFlowAnalysisRule($event)"
|
||||
(selectFlowAnalysisRule)="selectFlowAnalysisRule($event)"
|
||||
(viewFlowAnalysisRuleDocumentation)="viewFlowAnalysisRuleDocumentation($event)"
|
||||
(enableFlowAnalysisRule)="enableFlowAnalysisRule($event)"
|
||||
(disableFlowAnalysisRule)="disableFlowAnalysisRule($event)"
|
||||
(viewStateFlowAnalysisRule)="viewStateFlowAnalysisRule($event)"
|
||||
|
|
|
@ -41,6 +41,7 @@ import { selectCurrentUser } from '../../../../state/current-user/current-user.s
|
|||
import { NiFiState } from '../../../../state';
|
||||
import { FlowAnalysisRuleEntity, FlowAnalysisRulesState } from '../../state/flow-analysis-rules';
|
||||
import { getComponentStateAndOpenDialog } from '../../../../state/component-state/component-state.actions';
|
||||
import { navigateToComponentDocumentation } from '../../../../state/documentation/documentation.actions';
|
||||
|
||||
@Component({
|
||||
selector: 'flow-analysis-rules',
|
||||
|
@ -106,6 +107,19 @@ export class FlowAnalysisRules implements OnInit, OnDestroy {
|
|||
);
|
||||
}
|
||||
|
||||
viewFlowAnalysisRuleDocumentation(entity: FlowAnalysisRuleEntity): void {
|
||||
this.store.dispatch(
|
||||
navigateToComponentDocumentation({
|
||||
params: {
|
||||
select: entity.component.type,
|
||||
group: entity.component.bundle.group,
|
||||
artifact: entity.component.bundle.artifact,
|
||||
version: entity.component.bundle.version
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
enableFlowAnalysisRule(entity: FlowAnalysisRuleEntity): void {
|
||||
this.store.dispatch(
|
||||
enableFlowAnalysisRule({
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
[canModifyParent]="canModifyParent(currentUser)"
|
||||
[flowConfiguration]="(flowConfiguration$ | async)!"
|
||||
(selectControllerService)="selectControllerService($event)"
|
||||
(viewControllerServiceDocumentation)="viewControllerServiceDocumentation($event)"
|
||||
(configureControllerService)="configureControllerService($event)"
|
||||
(enableControllerService)="enableControllerService($event)"
|
||||
(disableControllerService)="disableControllerService($event)"
|
||||
|
|
|
@ -45,6 +45,7 @@ import { selectFlowConfiguration } from '../../../../state/flow-configuration/fl
|
|||
import { loadFlowConfiguration } from '../../../../state/flow-configuration/flow-configuration.actions';
|
||||
import { CurrentUser } from '../../../../state/current-user';
|
||||
import { getComponentStateAndOpenDialog } from '../../../../state/component-state/component-state.actions';
|
||||
import { navigateToComponentDocumentation } from '../../../../state/documentation/documentation.actions';
|
||||
|
||||
@Component({
|
||||
selector: 'management-controller-services',
|
||||
|
@ -110,6 +111,19 @@ export class ManagementControllerServices implements OnInit, OnDestroy {
|
|||
return true;
|
||||
}
|
||||
|
||||
viewControllerServiceDocumentation(entity: ControllerServiceEntity): void {
|
||||
this.store.dispatch(
|
||||
navigateToComponentDocumentation({
|
||||
params: {
|
||||
select: entity.component.type,
|
||||
group: entity.component.bundle.group,
|
||||
artifact: entity.component.bundle.artifact,
|
||||
version: entity.component.bundle.version
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
configureControllerService(entity: ControllerServiceEntity): void {
|
||||
this.store.dispatch(
|
||||
navigateToEditService({
|
||||
|
|
|
@ -31,25 +31,29 @@
|
|||
<ng-container matColumnDef="moreDetails">
|
||||
<th mat-header-cell *matHeaderCellDef></th>
|
||||
<td mat-cell *matCellDef="let item">
|
||||
<div class="flex items-center gap-x-3">
|
||||
<!-- TODO: open details -->
|
||||
<div class="pointer fa fa-info-circle" title="View details"></div>
|
||||
@if (canRead(item)) {
|
||||
<div class="flex items-center gap-x-3">
|
||||
<!-- TODO: open details -->
|
||||
<div class="pointer fa fa-info-circle" title="View details"></div>
|
||||
|
||||
<!-- TODO: open documentation -->
|
||||
<div class="pointer fa fa-book" title="View Documentation"></div>
|
||||
<div
|
||||
class="pointer fa fa-book"
|
||||
(click)="viewDocumentationClicked(item, $event)"
|
||||
title="View Documentation"></div>
|
||||
|
||||
<!-- Validation Errors -->
|
||||
@if (hasErrors(item)) {
|
||||
<div>
|
||||
<div
|
||||
class="pointer fa fa-warning has-errors"
|
||||
nifiTooltip
|
||||
[delayClose]="false"
|
||||
[tooltipComponentType]="ValidationErrorsTip"
|
||||
[tooltipInputData]="getValidationErrorsTipData(item)"></div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<!-- Validation Errors -->
|
||||
@if (hasErrors(item)) {
|
||||
<div>
|
||||
<div
|
||||
class="pointer fa fa-warning has-errors"
|
||||
nifiTooltip
|
||||
[delayClose]="false"
|
||||
[tooltipComponentType]="ValidationErrorsTip"
|
||||
[tooltipInputData]="getValidationErrorsTipData(item)"></div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
|
|
|
@ -72,6 +72,8 @@ export class ParameterProvidersTable {
|
|||
|
||||
@Output() selectParameterProvider: EventEmitter<ParameterProviderEntity> =
|
||||
new EventEmitter<ParameterProviderEntity>();
|
||||
@Output() viewParameterProviderDocumentation: EventEmitter<ParameterProviderEntity> =
|
||||
new EventEmitter<ParameterProviderEntity>();
|
||||
@Output() configureParameterProvider: EventEmitter<ParameterProviderEntity> =
|
||||
new EventEmitter<ParameterProviderEntity>();
|
||||
@Output() deleteParameterProvider: EventEmitter<ParameterProviderEntity> =
|
||||
|
@ -129,6 +131,11 @@ export class ParameterProvidersTable {
|
|||
return false;
|
||||
}
|
||||
|
||||
viewDocumentationClicked(entity: ParameterProviderEntity, event: MouseEvent): void {
|
||||
event.stopPropagation();
|
||||
this.viewParameterProviderDocumentation.next(entity);
|
||||
}
|
||||
|
||||
formatName(entity: ParameterProviderEntity): string {
|
||||
return this.canRead(entity) ? entity.component.name : entity.id;
|
||||
}
|
||||
|
@ -142,7 +149,7 @@ export class ParameterProvidersTable {
|
|||
}
|
||||
|
||||
hasErrors(entity: ParameterProviderEntity): boolean {
|
||||
return this.canRead(entity) && !this.nifiCommon.isEmpty(entity.component.validationErrors);
|
||||
return !this.nifiCommon.isEmpty(entity.component.validationErrors);
|
||||
}
|
||||
|
||||
getValidationErrorsTipData(entity: ParameterProviderEntity): ValidationErrorsTipInput | null {
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
(deleteParameterProvider)="deleteParameterProvider($event)"
|
||||
(configureParameterProvider)="openConfigureParameterProviderDialog($event)"
|
||||
(fetchParameterProvider)="fetchParameterProviderParameters($event)"
|
||||
(viewParameterProviderDocumentation)="viewParameterProviderDocumentation($event)"
|
||||
(selectParameterProvider)="selectParameterProvider($event)"></parameter-providers-table>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
|
|
|
@ -34,6 +34,7 @@ import { initialParameterProvidersState } from '../../state/parameter-providers/
|
|||
import { switchMap, take } from 'rxjs';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
import { isDefinedAndNotNull } from '../../../../state/shared';
|
||||
import { navigateToComponentDocumentation } from '../../../../state/documentation/documentation.actions';
|
||||
|
||||
@Component({
|
||||
selector: 'parameter-providers',
|
||||
|
@ -130,6 +131,19 @@ export class ParameterProviders implements OnInit, OnDestroy {
|
|||
);
|
||||
}
|
||||
|
||||
viewParameterProviderDocumentation(parameterProvider: ParameterProviderEntity): void {
|
||||
this.store.dispatch(
|
||||
navigateToComponentDocumentation({
|
||||
params: {
|
||||
select: parameterProvider.component.type,
|
||||
group: parameterProvider.component.bundle.group,
|
||||
artifact: parameterProvider.component.bundle.artifact,
|
||||
version: parameterProvider.component.bundle.version
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
deleteParameterProvider(parameterProvider: ParameterProviderEntity) {
|
||||
this.store.dispatch(
|
||||
ParameterProviderActions.promptParameterProviderDeletion({
|
||||
|
|
|
@ -31,7 +31,10 @@
|
|||
<td mat-cell *matCellDef="let item">
|
||||
@if (canRead(item)) {
|
||||
<div class="flex items-center gap-x-3">
|
||||
<div class="pointer fa fa-book" title="Usage"></div>
|
||||
<div
|
||||
class="pointer fa fa-book"
|
||||
(click)="viewDocumentationClicked(item, $event)"
|
||||
title="View Documentation"></div>
|
||||
<!-- TODO - handle read only in configure component? -->
|
||||
@if (hasComments(item)) {
|
||||
<div>
|
||||
|
|
|
@ -49,6 +49,8 @@ export class ReportingTaskTable {
|
|||
@Input() currentUser!: CurrentUser;
|
||||
|
||||
@Output() selectReportingTask: EventEmitter<ReportingTaskEntity> = new EventEmitter<ReportingTaskEntity>();
|
||||
@Output() viewReportingTaskDocumentation: EventEmitter<ReportingTaskEntity> =
|
||||
new EventEmitter<ReportingTaskEntity>();
|
||||
@Output() deleteReportingTask: EventEmitter<ReportingTaskEntity> = new EventEmitter<ReportingTaskEntity>();
|
||||
@Output() startReportingTask: EventEmitter<ReportingTaskEntity> = new EventEmitter<ReportingTaskEntity>();
|
||||
@Output() configureReportingTask: EventEmitter<ReportingTaskEntity> = new EventEmitter<ReportingTaskEntity>();
|
||||
|
@ -79,6 +81,11 @@ export class ReportingTaskTable {
|
|||
return !!entity.operatePermissions?.canWrite;
|
||||
}
|
||||
|
||||
viewDocumentationClicked(entity: ReportingTaskEntity, event: MouseEvent): void {
|
||||
event.stopPropagation();
|
||||
this.viewReportingTaskDocumentation.next(entity);
|
||||
}
|
||||
|
||||
hasComments(entity: ReportingTaskEntity): boolean {
|
||||
return !this.nifiCommon.isBlank(entity.component.comments);
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
(configureReportingTask)="configureReportingTask($event)"
|
||||
(viewStateReportingTask)="viewStateReportingTask($event)"
|
||||
(selectReportingTask)="selectReportingTask($event)"
|
||||
(viewReportingTaskDocumentation)="viewReportingTaskDocumentation($event)"
|
||||
(deleteReportingTask)="deleteReportingTask($event)"
|
||||
(stopReportingTask)="stopReportingTask($event)"
|
||||
(startReportingTask)="startReportingTask($event)"></reporting-task-table>
|
||||
|
|
|
@ -43,6 +43,7 @@ import { NiFiState } from '../../../../state';
|
|||
import { loadFlowConfiguration } from '../../../../state/flow-configuration/flow-configuration.actions';
|
||||
import { selectFlowConfiguration } from '../../../../state/flow-configuration/flow-configuration.selectors';
|
||||
import { getComponentStateAndOpenDialog } from '../../../../state/component-state/component-state.actions';
|
||||
import { navigateToComponentDocumentation } from '../../../../state/documentation/documentation.actions';
|
||||
|
||||
@Component({
|
||||
selector: 'reporting-tasks',
|
||||
|
@ -110,6 +111,19 @@ export class ReportingTasks implements OnInit, OnDestroy {
|
|||
);
|
||||
}
|
||||
|
||||
viewReportingTaskDocumentation(entity: ReportingTaskEntity): void {
|
||||
this.store.dispatch(
|
||||
navigateToComponentDocumentation({
|
||||
params: {
|
||||
select: entity.component.type,
|
||||
group: entity.component.bundle.group,
|
||||
artifact: entity.component.bundle.artifact,
|
||||
version: entity.component.bundle.version
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
deleteReportingTask(entity: ReportingTaskEntity): void {
|
||||
this.store.dispatch(
|
||||
promptReportingTaskDeletion({
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* 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 { createAction, props } from '@ngrx/store';
|
||||
import { DocumentationParameters } from './index';
|
||||
|
||||
export const navigateToComponentDocumentation = createAction(
|
||||
'[Documentation] Navigate To Component Documentation',
|
||||
props<{
|
||||
params: DocumentationParameters;
|
||||
}>()
|
||||
);
|
||||
|
||||
export const clearDocumentationParameters = createAction('[Documentation] Clear Documentation Parameters');
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* 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 { Injectable } from '@angular/core';
|
||||
import { Actions, createEffect, ofType } from '@ngrx/effects';
|
||||
import * as DocumentationActions from './documentation.actions';
|
||||
import { tap } from 'rxjs';
|
||||
import { Router } from '@angular/router';
|
||||
|
||||
@Injectable()
|
||||
export class DocumentationEffects {
|
||||
constructor(
|
||||
private actions$: Actions,
|
||||
private router: Router
|
||||
) {}
|
||||
|
||||
navigateToComponentDocumentation$ = createEffect(
|
||||
() =>
|
||||
this.actions$.pipe(
|
||||
ofType(DocumentationActions.navigateToComponentDocumentation),
|
||||
tap(() => {
|
||||
this.router.navigate(['/documentation']);
|
||||
})
|
||||
),
|
||||
{ dispatch: false }
|
||||
);
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* 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 { createReducer, on } from '@ngrx/store';
|
||||
import { DocumentationState } from './index';
|
||||
import { clearDocumentationParameters, navigateToComponentDocumentation } from './documentation.actions';
|
||||
|
||||
export const initialState: DocumentationState = {
|
||||
documentationParameters: null
|
||||
};
|
||||
|
||||
export const documentationReducer = createReducer(
|
||||
initialState,
|
||||
on(navigateToComponentDocumentation, (state, { params }) => ({
|
||||
...state,
|
||||
documentationParameters: params
|
||||
})),
|
||||
on(clearDocumentationParameters, (state) => ({
|
||||
...state,
|
||||
documentationParameters: null
|
||||
}))
|
||||
);
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* 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 { createFeatureSelector, createSelector } from '@ngrx/store';
|
||||
import { documentationFeatureKey, DocumentationState } from './index';
|
||||
|
||||
export const selectDocumentationState = createFeatureSelector<DocumentationState>(documentationFeatureKey);
|
||||
|
||||
export const selectDocumentationParameters = createSelector(
|
||||
selectDocumentationState,
|
||||
(state: DocumentationState) => state.documentationParameters
|
||||
);
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export const documentationFeatureKey = 'documentation';
|
||||
|
||||
export interface DocumentationParameters {
|
||||
[key: string]: string;
|
||||
}
|
||||
|
||||
export interface DocumentationState {
|
||||
documentationParameters: DocumentationParameters | null;
|
||||
}
|
|
@ -35,6 +35,8 @@ import { componentStateFeatureKey, ComponentStateState } from './component-state
|
|||
import { componentStateReducer } from './component-state/component-state.reducer';
|
||||
import { errorFeatureKey, ErrorState } from './error';
|
||||
import { errorReducer } from './error/error.reducer';
|
||||
import { documentationFeatureKey, DocumentationState } from './documentation';
|
||||
import { documentationReducer } from './documentation/documentation.reducer';
|
||||
|
||||
export interface NiFiState {
|
||||
router: RouterReducerState;
|
||||
|
@ -47,6 +49,7 @@ export interface NiFiState {
|
|||
[controllerServiceStateFeatureKey]: ControllerServiceState;
|
||||
[systemDiagnosticsFeatureKey]: SystemDiagnosticsState;
|
||||
[componentStateFeatureKey]: ComponentStateState;
|
||||
[documentationFeatureKey]: DocumentationState;
|
||||
}
|
||||
|
||||
export const rootReducers: ActionReducerMap<NiFiState> = {
|
||||
|
@ -59,5 +62,6 @@ export const rootReducers: ActionReducerMap<NiFiState> = {
|
|||
[statusHistoryFeatureKey]: statusHistoryReducer,
|
||||
[controllerServiceStateFeatureKey]: controllerServiceStateReducer,
|
||||
[systemDiagnosticsFeatureKey]: systemDiagnosticsReducer,
|
||||
[componentStateFeatureKey]: componentStateReducer
|
||||
[componentStateFeatureKey]: componentStateReducer,
|
||||
[documentationFeatureKey]: documentationReducer
|
||||
};
|
||||
|
|
|
@ -31,13 +31,11 @@
|
|||
<td mat-cell *matCellDef="let item">
|
||||
@if (canRead(item)) {
|
||||
<div class="flex items-center gap-x-3">
|
||||
<div class="pointer fa fa-book" title="Usage"></div>
|
||||
<!--
|
||||
nifiTooltip dynamically inserts the tooltip component
|
||||
into the dom. the dom placement caused shifting of icons
|
||||
because of the gap between items. simple solution is to
|
||||
just wrap the target.
|
||||
-->
|
||||
<div
|
||||
class="pointer fa fa-book"
|
||||
(click)="viewDocumentationClicked(item, $event)"
|
||||
title="View Documentation"></div>
|
||||
|
||||
@if (hasComments(item)) {
|
||||
<div>
|
||||
<div
|
||||
|
|
|
@ -72,6 +72,8 @@ export class ControllerServiceTable {
|
|||
|
||||
@Output() selectControllerService: EventEmitter<ControllerServiceEntity> =
|
||||
new EventEmitter<ControllerServiceEntity>();
|
||||
@Output() viewControllerServiceDocumentation: EventEmitter<ControllerServiceEntity> =
|
||||
new EventEmitter<ControllerServiceEntity>();
|
||||
@Output() deleteControllerService: EventEmitter<ControllerServiceEntity> =
|
||||
new EventEmitter<ControllerServiceEntity>();
|
||||
@Output() configureControllerService: EventEmitter<ControllerServiceEntity> =
|
||||
|
@ -117,6 +119,11 @@ export class ControllerServiceTable {
|
|||
};
|
||||
}
|
||||
|
||||
viewDocumentationClicked(entity: ControllerServiceEntity, event: MouseEvent): void {
|
||||
event.stopPropagation();
|
||||
this.viewControllerServiceDocumentation.next(entity);
|
||||
}
|
||||
|
||||
hasErrors(entity: ControllerServiceEntity): boolean {
|
||||
return !this.nifiCommon.isEmpty(entity.component.validationErrors);
|
||||
}
|
||||
|
@ -236,7 +243,7 @@ export class ControllerServiceTable {
|
|||
this.isDisabled(entity) &&
|
||||
this.canRead(entity) &&
|
||||
this.canWrite(entity) &&
|
||||
entity.component.multipleVersionsAvailable === true
|
||||
entity.component.multipleVersionsAvailable
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -136,7 +136,7 @@
|
|||
<mat-divider></mat-divider>
|
||||
}
|
||||
}
|
||||
<button mat-menu-item class="global-menu-item">
|
||||
<button mat-menu-item class="global-menu-item" [routerLink]="['/documentation']">
|
||||
<i class="fa fa-fw fa-question-circle mr-2"></i>
|
||||
Help
|
||||
</button>
|
||||
|
@ -144,7 +144,10 @@
|
|||
<i class="fa fa-fw fa-info-circle mr-2"></i>
|
||||
About
|
||||
</button>
|
||||
<button mat-menu-item [matMenuTriggerFor]="theming">Appearance</button>
|
||||
<button mat-menu-item [matMenuTriggerFor]="theming">
|
||||
<i class="fa fa-fw mr-2"></i>
|
||||
Appearance
|
||||
</button>
|
||||
</mat-menu>
|
||||
<mat-menu #theming="matMenu" xPosition="before">
|
||||
<button mat-menu-item class="global-menu-item" (click)="toggleTheme(LIGHT_THEME)">
|
||||
|
|
Loading…
Reference in New Issue