mirror of https://github.com/apache/nifi.git
NIFI-12967: Introducing Back action (#8859)
* NIFI-12967: - Adding support for navigating back to the users previous location in certain circumstances like going to a Controller Service, managing access policies, going to parameters, viewing documentation, opening advanced UIs, and viewing data provenance. - Cleaning unnecessary instances of postUpdateNavigation. * NIFI-12967: - Updating the implementation to leverage router events and router state to simplify needed changes. * NIFI-12967: - Conditionally resetting or popping back navigation history because on routing context. * NIFI-12967: - Adding support for navigating back from queue listing and provenance. * NIFI-12967: - Conditionally applying the back navigation following a component update. * NIFI-12967: - Adding back from CS service listing. * NIFI-12967: - Adding back from Go To CS. - Restoring some space in the context menu. * NIFI-12967: - Prevent duplicate entries in the back navigation stack. * NIFI-12967: - Not executing pop through navigation extras because it can result in multiple pops if the user uses their back/forward browser buttons. Instead, always popping until we encounter a back navigation that is still within a route boundary.
This commit is contained in:
parent
68630b64c1
commit
f0e1cdcb22
|
@ -19,12 +19,22 @@ import { TestBed } from '@angular/core/testing';
|
|||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { AppComponent } from './app.component';
|
||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||
import { provideMockStore } from '@ngrx/store/testing';
|
||||
import { navigationFeatureKey } from './state/navigation';
|
||||
import * as fromNavigation from './state/navigation/navigation.reducer';
|
||||
|
||||
describe('AppComponent', () => {
|
||||
beforeEach(() =>
|
||||
TestBed.configureTestingModule({
|
||||
imports: [RouterTestingModule, MatProgressSpinnerModule],
|
||||
declarations: [AppComponent]
|
||||
declarations: [AppComponent],
|
||||
providers: [
|
||||
provideMockStore({
|
||||
initialState: {
|
||||
[navigationFeatureKey]: fromNavigation.initialState
|
||||
}
|
||||
})
|
||||
]
|
||||
})
|
||||
);
|
||||
|
||||
|
|
|
@ -16,11 +16,18 @@
|
|||
*/
|
||||
|
||||
import { Component } from '@angular/core';
|
||||
import { GuardsCheckEnd, GuardsCheckStart, NavigationCancel, NavigationStart, Router } from '@angular/router';
|
||||
import { GuardsCheckEnd, GuardsCheckStart, NavigationCancel, NavigationStart, NavigationEnd, Router } from '@angular/router';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
import { Storage } from './service/storage.service';
|
||||
import { ThemingService } from './service/theming.service';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { NiFiState } from './state';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { BackNavigation } from './state/navigation';
|
||||
import { popBackNavigation, pushBackNavigation } from './state/navigation/navigation.actions';
|
||||
import { filter, map, tap } from 'rxjs';
|
||||
import { concatLatestFrom } from '@ngrx/operators';
|
||||
import { selectBackNavigation } from './state/navigation/navigation.selectors';
|
||||
|
||||
@Component({
|
||||
selector: 'nifi',
|
||||
|
@ -35,19 +42,44 @@ export class AppComponent {
|
|||
private router: Router,
|
||||
private storage: Storage,
|
||||
private themingService: ThemingService,
|
||||
private dialog: MatDialog
|
||||
private dialog: MatDialog,
|
||||
private store: Store<NiFiState>
|
||||
) {
|
||||
this.router.events.pipe(takeUntilDestroyed()).subscribe((event) => {
|
||||
if (event instanceof NavigationStart) {
|
||||
this.dialog.openDialogs.forEach((dialog) => dialog.close('ROUTED'));
|
||||
}
|
||||
if (event instanceof GuardsCheckStart) {
|
||||
this.guardLoading = true;
|
||||
}
|
||||
if (event instanceof GuardsCheckEnd || event instanceof NavigationCancel) {
|
||||
this.guardLoading = false;
|
||||
}
|
||||
});
|
||||
this.router.events
|
||||
.pipe(
|
||||
takeUntilDestroyed(),
|
||||
tap((event) => {
|
||||
if (event instanceof NavigationStart) {
|
||||
this.dialog.openDialogs.forEach((dialog) => dialog.close('ROUTED'));
|
||||
}
|
||||
if (event instanceof GuardsCheckStart) {
|
||||
this.guardLoading = true;
|
||||
}
|
||||
if (event instanceof GuardsCheckEnd || event instanceof NavigationCancel) {
|
||||
this.guardLoading = false;
|
||||
}
|
||||
}),
|
||||
filter((e) => e instanceof NavigationEnd),
|
||||
map((e) => e as NavigationEnd),
|
||||
concatLatestFrom(() => this.store.select(selectBackNavigation))
|
||||
)
|
||||
.subscribe(([event, previousBackNavigation]) => {
|
||||
const extras = this.router.getCurrentNavigation()?.extras;
|
||||
if (extras?.state?.['backNavigation']) {
|
||||
const backNavigation: BackNavigation = extras?.state?.['backNavigation'];
|
||||
this.store.dispatch(
|
||||
pushBackNavigation({
|
||||
backNavigation
|
||||
})
|
||||
);
|
||||
} else if (previousBackNavigation) {
|
||||
this.store.dispatch(
|
||||
popBackNavigation({
|
||||
url: event.url
|
||||
})
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
let theme = this.storage.getItem('theme');
|
||||
|
||||
|
|
|
@ -331,6 +331,7 @@ export class ComponentAccessPolicies implements OnInit, OnDestroy {
|
|||
return 'icon-group-remote';
|
||||
case 'parameter-providers':
|
||||
case 'parameter-contexts':
|
||||
case 'reporting-tasks':
|
||||
return 'icon-drop';
|
||||
}
|
||||
|
||||
|
@ -353,6 +354,8 @@ export class ComponentAccessPolicies implements OnInit, OnDestroy {
|
|||
return ComponentType.RemoteProcessGroup;
|
||||
case 'parameter-contexts':
|
||||
return 'Parameter Context';
|
||||
case 'reporting-tasks':
|
||||
return 'Reporting Task';
|
||||
case 'parameter-providers':
|
||||
return ComponentType.ParameterProvider;
|
||||
}
|
||||
|
|
|
@ -229,7 +229,8 @@ export class CanvasActionsService {
|
|||
navigateToManageComponentPolicies({
|
||||
request: {
|
||||
resource: 'process-groups',
|
||||
id: extraArgs.processGroupId
|
||||
id: extraArgs.processGroupId,
|
||||
backNavigationContext: 'Process Group'
|
||||
}
|
||||
})
|
||||
);
|
||||
|
@ -239,24 +240,31 @@ export class CanvasActionsService {
|
|||
const componentType: ComponentType = selectionData.type;
|
||||
|
||||
let resource = 'process-groups';
|
||||
let backNavigationContext = 'Process Group';
|
||||
switch (componentType) {
|
||||
case ComponentType.Processor:
|
||||
resource = 'processors';
|
||||
backNavigationContext = 'Processor';
|
||||
break;
|
||||
case ComponentType.InputPort:
|
||||
resource = 'input-ports';
|
||||
backNavigationContext = 'Input Port';
|
||||
break;
|
||||
case ComponentType.OutputPort:
|
||||
resource = 'output-ports';
|
||||
backNavigationContext = 'Output Port';
|
||||
break;
|
||||
case ComponentType.Funnel:
|
||||
resource = 'funnels';
|
||||
backNavigationContext = 'Funnel';
|
||||
break;
|
||||
case ComponentType.Label:
|
||||
resource = 'labels';
|
||||
backNavigationContext = 'Label';
|
||||
break;
|
||||
case ComponentType.RemoteProcessGroup:
|
||||
resource = 'remote-process-groups';
|
||||
backNavigationContext = 'Remote Process Group';
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -264,7 +272,8 @@ export class CanvasActionsService {
|
|||
navigateToManageComponentPolicies({
|
||||
request: {
|
||||
resource,
|
||||
id: selectionData.id
|
||||
id: selectionData.id,
|
||||
backNavigationContext
|
||||
}
|
||||
})
|
||||
);
|
||||
|
|
|
@ -72,6 +72,7 @@ import { CanvasView } from './canvas-view.service';
|
|||
import { CanvasActionsService } from './canvas-actions.service';
|
||||
import * as FlowActions from '../state/flow/flow.actions';
|
||||
import { DraggableBehavior } from './behavior/draggable-behavior.service';
|
||||
import { BackNavigation } from '../../../state/navigation';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class CanvasContextMenu implements ContextMenuDefinitionProvider {
|
||||
|
@ -660,18 +661,37 @@ export class CanvasContextMenu implements ContextMenuDefinitionProvider {
|
|||
text: 'Parameters',
|
||||
action: (selection: d3.Selection<any, any, any, any>) => {
|
||||
let id;
|
||||
let backNavigation;
|
||||
if (selection.empty()) {
|
||||
id = this.canvasUtils.getParameterContextId();
|
||||
|
||||
backNavigation = {
|
||||
route: ['/process-groups', this.canvasUtils.getProcessGroupId()],
|
||||
routeBoundary: ['/parameter-contexts'],
|
||||
context: 'Process Group'
|
||||
} as BackNavigation;
|
||||
} else {
|
||||
const selectionData = selection.datum();
|
||||
id = selectionData.parameterContext.id;
|
||||
|
||||
backNavigation = {
|
||||
route: [
|
||||
'/process-groups',
|
||||
this.canvasUtils.getProcessGroupId(),
|
||||
ComponentType.ProcessGroup,
|
||||
selectionData.id
|
||||
],
|
||||
routeBoundary: ['/parameter-contexts'],
|
||||
context: 'Process Group'
|
||||
} as BackNavigation;
|
||||
}
|
||||
|
||||
if (id) {
|
||||
this.store.dispatch(
|
||||
navigateToParameterContext({
|
||||
request: {
|
||||
id
|
||||
id,
|
||||
backNavigation
|
||||
}
|
||||
})
|
||||
);
|
||||
|
@ -941,14 +961,27 @@ export class CanvasContextMenu implements ContextMenuDefinitionProvider {
|
|||
clazz: 'fa fa-book',
|
||||
text: 'View Documentation',
|
||||
action: (selection: any) => {
|
||||
const processGroupId = this.canvasUtils.getProcessGroupId();
|
||||
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
|
||||
request: {
|
||||
backNavigation: {
|
||||
route: [
|
||||
'/process-groups',
|
||||
processGroupId,
|
||||
ComponentType.Processor,
|
||||
selectionData.id
|
||||
],
|
||||
routeBoundary: ['/documentation'],
|
||||
context: 'Processor'
|
||||
} as BackNavigation,
|
||||
parameters: {
|
||||
select: selectionData.component.type,
|
||||
group: selectionData.component.bundle.group,
|
||||
artifact: selectionData.component.bundle.artifact,
|
||||
version: selectionData.component.bundle.version
|
||||
}
|
||||
}
|
||||
})
|
||||
);
|
||||
|
|
|
@ -68,6 +68,11 @@ export const inlineCreateControllerServiceSuccess = createAction(
|
|||
props<{ response: CreateControllerServiceSuccess }>()
|
||||
);
|
||||
|
||||
export const navigateToService = createAction(
|
||||
'[Controller Services] Navigate To Service',
|
||||
props<{ request: SelectControllerServiceRequest }>()
|
||||
);
|
||||
|
||||
export const navigateToEditService = createAction(
|
||||
'[Controller Services] Navigate To Edit Service',
|
||||
props<{ id: string }>()
|
||||
|
@ -78,6 +83,11 @@ export const navigateToAdvancedServiceUi = createAction(
|
|||
props<{ id: string }>()
|
||||
);
|
||||
|
||||
export const navigateToManageComponentPolicies = createAction(
|
||||
'[Controller Services] Navigate To Manage Component Policies',
|
||||
props<{ id: string }>()
|
||||
);
|
||||
|
||||
export const openConfigureControllerServiceDialog = createAction(
|
||||
'[Controller Services] Open Configure Controller Service Dialog',
|
||||
props<{ request: EditControllerServiceDialogRequest }>()
|
||||
|
|
|
@ -63,6 +63,7 @@ import {
|
|||
selectPropertyVerificationStatus
|
||||
} from '../../../../state/property-verification/property-verification.selectors';
|
||||
import { VerifyPropertiesRequestContext } from '../../../../state/property-verification';
|
||||
import { BackNavigation } from '../../../../state/navigation';
|
||||
|
||||
@Injectable()
|
||||
export class ControllerServicesEffects {
|
||||
|
@ -204,7 +205,66 @@ export class ControllerServicesEffects {
|
|||
map((action) => action.id),
|
||||
concatLatestFrom(() => this.store.select(selectCurrentProcessGroupId)),
|
||||
tap(([id, processGroupId]) => {
|
||||
this.router.navigate(['/process-groups', processGroupId, 'controller-services', id, 'advanced']);
|
||||
const routeBoundary: string[] = [
|
||||
'/process-groups',
|
||||
processGroupId,
|
||||
'controller-services',
|
||||
id,
|
||||
'advanced'
|
||||
];
|
||||
this.router.navigate([...routeBoundary], {
|
||||
state: {
|
||||
backNavigation: {
|
||||
route: ['/process-groups', processGroupId, 'controller-services', id],
|
||||
routeBoundary,
|
||||
context: 'Controller Service'
|
||||
} as BackNavigation
|
||||
}
|
||||
});
|
||||
})
|
||||
),
|
||||
{ dispatch: false }
|
||||
);
|
||||
|
||||
navigateToManageComponentPolicies$ = createEffect(
|
||||
() =>
|
||||
this.actions$.pipe(
|
||||
ofType(ControllerServicesActions.navigateToManageComponentPolicies),
|
||||
map((action) => action.id),
|
||||
concatLatestFrom(() => this.store.select(selectCurrentProcessGroupId)),
|
||||
tap(([id, processGroupId]) => {
|
||||
const routeBoundary: string[] = ['/access-policies'];
|
||||
this.router.navigate([...routeBoundary, 'read', 'component', 'controller-services', id], {
|
||||
state: {
|
||||
backNavigation: {
|
||||
route: ['/process-groups', processGroupId, 'controller-services', id],
|
||||
routeBoundary,
|
||||
context: 'Controller Service'
|
||||
} as BackNavigation
|
||||
}
|
||||
});
|
||||
})
|
||||
),
|
||||
{ dispatch: false }
|
||||
);
|
||||
|
||||
navigateToService$ = createEffect(
|
||||
() =>
|
||||
this.actions$.pipe(
|
||||
ofType(ControllerServicesActions.navigateToService),
|
||||
map((action) => action.request),
|
||||
concatLatestFrom(() => this.store.select(selectCurrentProcessGroupId)),
|
||||
tap(([request, processGroupId]) => {
|
||||
const routeBoundary: string[] = ['/process-groups', request.processGroupId, 'controller-services'];
|
||||
this.router.navigate([...routeBoundary, request.id], {
|
||||
state: {
|
||||
backNavigation: {
|
||||
route: ['/process-groups', processGroupId, 'controller-services', request.id],
|
||||
routeBoundary,
|
||||
context: 'Controller Service'
|
||||
} as BackNavigation
|
||||
}
|
||||
});
|
||||
})
|
||||
),
|
||||
{ dispatch: false }
|
||||
|
@ -306,7 +366,7 @@ export class ControllerServicesEffects {
|
|||
selectPropertyVerificationStatus
|
||||
);
|
||||
|
||||
const goTo = (commands: string[], destination: string): void => {
|
||||
const goTo = (commands: string[], destination: string, commandBoundary?: string[]): void => {
|
||||
if (editDialogReference.componentInstance.editControllerServiceForm.dirty) {
|
||||
const saveChangesDialogReference = this.dialog.open(YesNoDialog, {
|
||||
...SMALL_DIALOG,
|
||||
|
@ -317,14 +377,50 @@ export class ControllerServicesEffects {
|
|||
});
|
||||
|
||||
saveChangesDialogReference.componentInstance.yes.pipe(take(1)).subscribe(() => {
|
||||
editDialogReference.componentInstance.submitForm(commands);
|
||||
editDialogReference.componentInstance.submitForm(commands, commandBoundary);
|
||||
});
|
||||
|
||||
saveChangesDialogReference.componentInstance.no.pipe(take(1)).subscribe(() => {
|
||||
this.router.navigate(commands);
|
||||
if (commandBoundary) {
|
||||
this.router.navigate(commands, {
|
||||
state: {
|
||||
backNavigation: {
|
||||
route: [
|
||||
'/process-groups',
|
||||
processGroupId,
|
||||
'controller-services',
|
||||
serviceId,
|
||||
'edit'
|
||||
],
|
||||
routeBoundary: commandBoundary,
|
||||
context: 'Controller Service'
|
||||
} as BackNavigation
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.router.navigate(commands);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.router.navigate(commands);
|
||||
if (commandBoundary) {
|
||||
this.router.navigate(commands, {
|
||||
state: {
|
||||
backNavigation: {
|
||||
route: [
|
||||
'/process-groups',
|
||||
processGroupId,
|
||||
'controller-services',
|
||||
serviceId,
|
||||
'edit'
|
||||
],
|
||||
routeBoundary: commandBoundary,
|
||||
context: 'Controller Service'
|
||||
} as BackNavigation
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.router.navigate(commands);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -338,8 +434,9 @@ export class ControllerServicesEffects {
|
|||
if (parameterContext != null) {
|
||||
editDialogReference.componentInstance.parameterContext = parameterContext;
|
||||
editDialogReference.componentInstance.goToParameter = () => {
|
||||
const commands: string[] = ['/parameter-contexts', parameterContext.id];
|
||||
goTo(commands, 'Parameter');
|
||||
const commandBoundary: string[] = ['/parameter-contexts'];
|
||||
const commands: string[] = [...commandBoundary, parameterContext.id, 'edit'];
|
||||
goTo(commands, 'Parameter', commandBoundary);
|
||||
};
|
||||
|
||||
editDialogReference.componentInstance.convertToParameter =
|
||||
|
@ -349,13 +446,13 @@ export class ControllerServicesEffects {
|
|||
editDialogReference.componentInstance.goToService = (serviceId: string) => {
|
||||
this.controllerServiceService.getControllerService(serviceId).subscribe({
|
||||
next: (serviceEntity) => {
|
||||
const commands: string[] = [
|
||||
const commandBoundary: string[] = [
|
||||
'/process-groups',
|
||||
serviceEntity.component.parentGroupId,
|
||||
'controller-services',
|
||||
serviceEntity.id
|
||||
'controller-services'
|
||||
];
|
||||
goTo(commands, 'Controller Service');
|
||||
const commands: string[] = [...commandBoundary, serviceEntity.id];
|
||||
goTo(commands, 'Controller Service', commandBoundary);
|
||||
},
|
||||
error: (errorResponse: HttpErrorResponse) => {
|
||||
this.store.dispatch(
|
||||
|
@ -392,7 +489,9 @@ export class ControllerServicesEffects {
|
|||
id: request.controllerService.id,
|
||||
uri: request.controllerService.uri,
|
||||
payload: updateControllerServiceRequest.payload,
|
||||
postUpdateNavigation: updateControllerServiceRequest.postUpdateNavigation
|
||||
postUpdateNavigation: updateControllerServiceRequest.postUpdateNavigation,
|
||||
postUpdateNavigationBoundary:
|
||||
updateControllerServiceRequest.postUpdateNavigationBoundary
|
||||
}
|
||||
})
|
||||
);
|
||||
|
@ -429,7 +528,8 @@ export class ControllerServicesEffects {
|
|||
response: {
|
||||
id: request.id,
|
||||
controllerService: response,
|
||||
postUpdateNavigation: request.postUpdateNavigation
|
||||
postUpdateNavigation: request.postUpdateNavigation,
|
||||
postUpdateNavigationBoundary: request.postUpdateNavigationBoundary
|
||||
}
|
||||
})
|
||||
),
|
||||
|
@ -462,9 +562,28 @@ export class ControllerServicesEffects {
|
|||
this.actions$.pipe(
|
||||
ofType(ControllerServicesActions.configureControllerServiceSuccess),
|
||||
map((action) => action.response),
|
||||
tap((response) => {
|
||||
concatLatestFrom(() => this.store.select(selectCurrentProcessGroupId)),
|
||||
tap(([response, processGroupId]) => {
|
||||
if (response.postUpdateNavigation) {
|
||||
this.router.navigate(response.postUpdateNavigation);
|
||||
if (response.postUpdateNavigationBoundary) {
|
||||
this.router.navigate(response.postUpdateNavigation, {
|
||||
state: {
|
||||
backNavigation: {
|
||||
route: [
|
||||
'/process-groups',
|
||||
processGroupId,
|
||||
'controller-services',
|
||||
response.id,
|
||||
'edit'
|
||||
],
|
||||
routeBoundary: response.postUpdateNavigationBoundary,
|
||||
context: 'Controller Service'
|
||||
} as BackNavigation
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.router.navigate(response.postUpdateNavigation);
|
||||
}
|
||||
} else {
|
||||
this.dialog.closeAll();
|
||||
}
|
||||
|
|
|
@ -41,12 +41,14 @@ export interface ConfigureControllerServiceRequest {
|
|||
uri: string;
|
||||
payload: any;
|
||||
postUpdateNavigation?: string[];
|
||||
postUpdateNavigationBoundary?: string[];
|
||||
}
|
||||
|
||||
export interface ConfigureControllerServiceSuccess {
|
||||
id: string;
|
||||
controllerService: ControllerServiceEntity;
|
||||
postUpdateNavigation?: string[];
|
||||
postUpdateNavigationBoundary?: string[];
|
||||
}
|
||||
|
||||
export interface DeleteControllerServiceRequest {
|
||||
|
|
|
@ -106,6 +106,8 @@ import {
|
|||
UpdateConnectionRequest,
|
||||
UpdateConnectionSuccess,
|
||||
UpdatePositionsRequest,
|
||||
UpdateProcessorRequest,
|
||||
UpdateProcessorResponse,
|
||||
UploadProcessGroupRequest,
|
||||
VersionControlInformationEntity
|
||||
} from './index';
|
||||
|
@ -460,12 +462,12 @@ export const updateComponentFailure = createAction(
|
|||
|
||||
export const updateProcessor = createAction(
|
||||
`${CANVAS_PREFIX} Update Processor`,
|
||||
props<{ request: UpdateComponentRequest }>()
|
||||
props<{ request: UpdateProcessorRequest }>()
|
||||
);
|
||||
|
||||
export const updateProcessorSuccess = createAction(
|
||||
`${CANVAS_PREFIX} Update Processor Success`,
|
||||
props<{ response: UpdateComponentResponse }>()
|
||||
props<{ response: UpdateProcessorResponse }>()
|
||||
);
|
||||
|
||||
export const updateConnection = createAction(
|
||||
|
|
|
@ -60,6 +60,7 @@ import {
|
|||
UpdateComponentResponse,
|
||||
UpdateConnectionSuccess,
|
||||
UpdateProcessorRequest,
|
||||
UpdateProcessorResponse,
|
||||
VersionControlInformationEntity
|
||||
} from './index';
|
||||
import { Action, Store } from '@ngrx/store';
|
||||
|
@ -145,6 +146,7 @@ import {
|
|||
selectPropertyVerificationStatus
|
||||
} from '../../../../state/property-verification/property-verification.selectors';
|
||||
import { VerifyPropertiesRequestContext } from '../../../../state/property-verification';
|
||||
import { BackNavigation } from '../../../../state/navigation';
|
||||
|
||||
@Injectable()
|
||||
export class FlowEffects {
|
||||
|
@ -1008,7 +1010,16 @@ export class FlowEffects {
|
|||
map((action) => action.id),
|
||||
concatLatestFrom(() => this.store.select(selectCurrentProcessGroupId)),
|
||||
tap(([id, processGroupId]) => {
|
||||
this.router.navigate(['/process-groups', processGroupId, ComponentType.Processor, id, 'advanced']);
|
||||
const routeBoundary = ['/process-groups', processGroupId, ComponentType.Processor, id, 'advanced'];
|
||||
this.router.navigate([...routeBoundary], {
|
||||
state: {
|
||||
backNavigation: {
|
||||
route: ['/process-groups', processGroupId, ComponentType.Processor, id],
|
||||
routeBoundary,
|
||||
context: 'Processor'
|
||||
} as BackNavigation
|
||||
}
|
||||
});
|
||||
})
|
||||
),
|
||||
{ dispatch: false }
|
||||
|
@ -1020,7 +1031,11 @@ export class FlowEffects {
|
|||
ofType(FlowActions.navigateToParameterContext),
|
||||
map((action) => action.request),
|
||||
tap((request) => {
|
||||
this.router.navigate(['/parameter-contexts', request.id]);
|
||||
this.router.navigate(['/parameter-contexts', request.id], {
|
||||
state: {
|
||||
backNavigation: request.backNavigation
|
||||
}
|
||||
});
|
||||
})
|
||||
),
|
||||
{ dispatch: false }
|
||||
|
@ -1043,8 +1058,18 @@ export class FlowEffects {
|
|||
this.actions$.pipe(
|
||||
ofType(FlowActions.navigateToManageComponentPolicies),
|
||||
map((action) => action.request),
|
||||
tap((request) => {
|
||||
this.router.navigate(['/access-policies', 'read', 'component', request.resource, request.id]);
|
||||
concatLatestFrom(() => this.store.select(selectCurrentProcessGroupId)),
|
||||
tap(([request, processGroupId]) => {
|
||||
const routeBoundary: string[] = ['/access-policies'];
|
||||
this.router.navigate([...routeBoundary, 'read', 'component', request.resource, request.id], {
|
||||
state: {
|
||||
backNavigation: {
|
||||
route: ['/process-groups', processGroupId, request.resource, request.id],
|
||||
routeBoundary,
|
||||
context: request.backNavigationContext
|
||||
} as BackNavigation
|
||||
}
|
||||
});
|
||||
})
|
||||
),
|
||||
{ dispatch: false }
|
||||
|
@ -1055,8 +1080,23 @@ export class FlowEffects {
|
|||
this.actions$.pipe(
|
||||
ofType(FlowActions.navigateToQueueListing),
|
||||
map((action) => action.request),
|
||||
tap((request) => {
|
||||
this.router.navigate(['/queue', request.connectionId]);
|
||||
concatLatestFrom(() => this.store.select(selectCurrentProcessGroupId)),
|
||||
tap(([request, processGroupId]) => {
|
||||
const routeBoundary: string[] = ['/queue', request.connectionId];
|
||||
this.router.navigate([...routeBoundary], {
|
||||
state: {
|
||||
backNavigation: {
|
||||
route: [
|
||||
'/process-groups',
|
||||
processGroupId,
|
||||
ComponentType.Connection,
|
||||
request.connectionId
|
||||
],
|
||||
routeBoundary,
|
||||
context: 'Connection'
|
||||
} as BackNavigation
|
||||
}
|
||||
});
|
||||
})
|
||||
),
|
||||
{ dispatch: false }
|
||||
|
@ -1110,8 +1150,25 @@ export class FlowEffects {
|
|||
this.actions$.pipe(
|
||||
ofType(FlowActions.navigateToControllerServicesForProcessGroup),
|
||||
map((action) => action.request),
|
||||
tap((request) => {
|
||||
this.router.navigate(['/process-groups', request.id, 'controller-services']);
|
||||
concatLatestFrom(() => this.store.select(selectCurrentProcessGroupId)),
|
||||
tap(([request, processGroupId]) => {
|
||||
let route: string[];
|
||||
if (processGroupId == request.id) {
|
||||
route = ['/process-groups', processGroupId];
|
||||
} else {
|
||||
route = ['/process-groups', processGroupId, ComponentType.ProcessGroup, request.id];
|
||||
}
|
||||
|
||||
const routeBoundary: string[] = ['/process-groups', request.id, 'controller-services'];
|
||||
this.router.navigate([...routeBoundary], {
|
||||
state: {
|
||||
backNavigation: {
|
||||
route,
|
||||
routeBoundary,
|
||||
context: 'Process Group'
|
||||
} as BackNavigation
|
||||
}
|
||||
});
|
||||
})
|
||||
),
|
||||
{ dispatch: false }
|
||||
|
@ -1327,7 +1384,7 @@ export class FlowEffects {
|
|||
selectPropertyVerificationStatus
|
||||
);
|
||||
|
||||
const goTo = (commands: string[], destination: string): void => {
|
||||
const goTo = (commands: string[], commandBoundary: string[], destination: string): void => {
|
||||
if (editDialogReference.componentInstance.editProcessorForm.dirty) {
|
||||
const saveChangesDialogReference = this.dialog.open(YesNoDialog, {
|
||||
...SMALL_DIALOG,
|
||||
|
@ -1338,22 +1395,51 @@ export class FlowEffects {
|
|||
});
|
||||
|
||||
saveChangesDialogReference.componentInstance.yes.pipe(take(1)).subscribe(() => {
|
||||
editDialogReference.componentInstance.submitForm(commands);
|
||||
editDialogReference.componentInstance.submitForm(commands, commandBoundary);
|
||||
});
|
||||
|
||||
saveChangesDialogReference.componentInstance.no.pipe(take(1)).subscribe(() => {
|
||||
this.router.navigate(commands);
|
||||
this.router.navigate(commands, {
|
||||
state: {
|
||||
backNavigation: {
|
||||
route: [
|
||||
'/process-groups',
|
||||
processGroupId,
|
||||
ComponentType.Processor,
|
||||
processorId,
|
||||
'edit'
|
||||
],
|
||||
routeBoundary: commandBoundary,
|
||||
context: 'Processor'
|
||||
} as BackNavigation
|
||||
}
|
||||
});
|
||||
});
|
||||
} else {
|
||||
this.router.navigate(commands);
|
||||
this.router.navigate(commands, {
|
||||
state: {
|
||||
backNavigation: {
|
||||
route: [
|
||||
'/process-groups',
|
||||
processGroupId,
|
||||
ComponentType.Processor,
|
||||
processorId,
|
||||
'edit'
|
||||
],
|
||||
routeBoundary: commandBoundary,
|
||||
context: 'Processor'
|
||||
} as BackNavigation
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
if (parameterContext != null) {
|
||||
editDialogReference.componentInstance.parameterContext = parameterContext;
|
||||
editDialogReference.componentInstance.goToParameter = () => {
|
||||
const commands: string[] = ['/parameter-contexts', parameterContext.id];
|
||||
goTo(commands, 'Parameter');
|
||||
const commandBoundary: string[] = ['/parameter-contexts'];
|
||||
const commands: string[] = [...commandBoundary, parameterContext.id, 'edit'];
|
||||
goTo(commands, commandBoundary, 'Parameter');
|
||||
};
|
||||
|
||||
editDialogReference.componentInstance.convertToParameter =
|
||||
|
@ -1363,13 +1449,13 @@ export class FlowEffects {
|
|||
editDialogReference.componentInstance.goToService = (serviceId: string) => {
|
||||
this.controllerServiceService.getControllerService(serviceId).subscribe({
|
||||
next: (serviceEntity) => {
|
||||
const commands: string[] = [
|
||||
const commandBoundary: string[] = [
|
||||
'/process-groups',
|
||||
serviceEntity.component.parentGroupId,
|
||||
'controller-services',
|
||||
serviceEntity.id
|
||||
'controller-services'
|
||||
];
|
||||
goTo(commands, 'Controller Service');
|
||||
const commands: string[] = [...commandBoundary, serviceEntity.id];
|
||||
goTo(commands, commandBoundary, 'Controller Service');
|
||||
},
|
||||
error: (errorResponse: HttpErrorResponse) => {
|
||||
this.store.dispatch(this.snackBarOrFullScreenError(errorResponse));
|
||||
|
@ -1390,14 +1476,7 @@ export class FlowEffects {
|
|||
.subscribe((updateProcessorRequest: UpdateProcessorRequest) => {
|
||||
this.store.dispatch(
|
||||
FlowActions.updateProcessor({
|
||||
request: {
|
||||
id: processorId,
|
||||
uri: request.uri,
|
||||
type: request.type,
|
||||
payload: updateProcessorRequest.payload,
|
||||
errorStrategy: 'banner',
|
||||
postUpdateNavigation: updateProcessorRequest.postUpdateNavigation
|
||||
}
|
||||
request: updateProcessorRequest
|
||||
})
|
||||
);
|
||||
});
|
||||
|
@ -1636,7 +1715,6 @@ export class FlowEffects {
|
|||
requestId: request.requestId,
|
||||
id: request.id,
|
||||
type: request.type,
|
||||
postUpdateNavigation: request.postUpdateNavigation,
|
||||
response
|
||||
};
|
||||
return FlowActions.updateComponentSuccess({ response: updateComponentResponse });
|
||||
|
@ -1661,12 +1739,8 @@ export class FlowEffects {
|
|||
this.actions$.pipe(
|
||||
ofType(FlowActions.updateComponentSuccess),
|
||||
map((action) => action.response),
|
||||
tap((response) => {
|
||||
if (response.postUpdateNavigation) {
|
||||
this.router.navigate(response.postUpdateNavigation);
|
||||
} else {
|
||||
this.dialog.closeAll();
|
||||
}
|
||||
tap(() => {
|
||||
this.dialog.closeAll();
|
||||
})
|
||||
),
|
||||
{ dispatch: false }
|
||||
|
@ -1693,14 +1767,15 @@ export class FlowEffects {
|
|||
mergeMap((request) =>
|
||||
from(this.flowService.updateComponent(request)).pipe(
|
||||
map((response) => {
|
||||
const updateComponentResponse: UpdateComponentResponse = {
|
||||
const updateProcessorResponse: UpdateProcessorResponse = {
|
||||
requestId: request.requestId,
|
||||
id: request.id,
|
||||
type: request.type,
|
||||
postUpdateNavigation: request.postUpdateNavigation,
|
||||
postUpdateNavigationBoundary: request.postUpdateNavigationBoundary,
|
||||
response
|
||||
};
|
||||
return FlowActions.updateProcessorSuccess({ response: updateComponentResponse });
|
||||
return FlowActions.updateProcessorSuccess({ response: updateProcessorResponse });
|
||||
}),
|
||||
catchError((errorResponse: HttpErrorResponse) => {
|
||||
const updateComponentFailure: UpdateComponentFailure = {
|
||||
|
@ -1721,15 +1796,34 @@ export class FlowEffects {
|
|||
this.actions$.pipe(
|
||||
ofType(FlowActions.updateProcessorSuccess),
|
||||
map((action) => action.response),
|
||||
tap((response) => {
|
||||
concatLatestFrom(() => this.store.select(selectCurrentProcessGroupId)),
|
||||
tap(([response, processGroupId]) => {
|
||||
if (response.postUpdateNavigation) {
|
||||
this.router.navigate(response.postUpdateNavigation);
|
||||
if (response.postUpdateNavigationBoundary) {
|
||||
this.router.navigate(response.postUpdateNavigation, {
|
||||
state: {
|
||||
backNavigation: {
|
||||
route: [
|
||||
'/process-groups',
|
||||
processGroupId,
|
||||
ComponentType.Processor,
|
||||
response.id,
|
||||
'edit'
|
||||
],
|
||||
routeBoundary: response.postUpdateNavigationBoundary,
|
||||
context: 'Processor'
|
||||
} as BackNavigation
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.router.navigate(response.postUpdateNavigation);
|
||||
}
|
||||
} else {
|
||||
this.dialog.closeAll();
|
||||
}
|
||||
}),
|
||||
filter((response) => response.postUpdateNavigation == null),
|
||||
switchMap((response) => of(FlowActions.loadConnectionsForComponent({ id: response.id })))
|
||||
filter(([response]) => response.postUpdateNavigation == null),
|
||||
switchMap(([response]) => of(FlowActions.loadConnectionsForComponent({ id: response.id })))
|
||||
)
|
||||
);
|
||||
|
||||
|
@ -2466,8 +2560,18 @@ export class FlowEffects {
|
|||
this.actions$.pipe(
|
||||
ofType(FlowActions.navigateToProvenanceForComponent),
|
||||
map((action) => action.id),
|
||||
tap((componentId) => {
|
||||
this.router.navigate(['/provenance'], { queryParams: { componentId } });
|
||||
concatLatestFrom(() => this.store.select(selectCurrentProcessGroupId)),
|
||||
tap(([componentId, processGroupId]) => {
|
||||
this.router.navigate(['/provenance'], {
|
||||
queryParams: { componentId },
|
||||
state: {
|
||||
backNavigation: {
|
||||
route: ['/process-groups', processGroupId, ComponentType.Processor, componentId],
|
||||
routeBoundary: ['/provenance'],
|
||||
context: 'Processor'
|
||||
} as BackNavigation
|
||||
}
|
||||
});
|
||||
})
|
||||
),
|
||||
{ dispatch: false }
|
||||
|
|
|
@ -32,6 +32,7 @@ import {
|
|||
VersionedFlowSnapshotMetadataEntity
|
||||
} from '../../../../state/shared';
|
||||
import { HttpErrorResponse } from '@angular/common/http';
|
||||
import { BackNavigation } from '../../../../state/navigation';
|
||||
|
||||
export const flowFeatureKey = 'flowState';
|
||||
|
||||
|
@ -346,6 +347,7 @@ export interface OpenComponentDialogRequest {
|
|||
export interface NavigateToManageComponentPoliciesRequest {
|
||||
resource: string;
|
||||
id: string;
|
||||
backNavigationContext: string;
|
||||
}
|
||||
|
||||
export interface EditComponentDialogRequest {
|
||||
|
@ -373,6 +375,7 @@ export interface NavigateToQueueListing {
|
|||
|
||||
export interface NavigateToParameterContext {
|
||||
id: string;
|
||||
backNavigation: BackNavigation;
|
||||
}
|
||||
|
||||
export interface EditCurrentProcessGroupRequest {
|
||||
|
@ -388,9 +391,9 @@ export interface EditConnectionDialogRequest extends EditComponentDialogRequest
|
|||
};
|
||||
}
|
||||
|
||||
export interface UpdateProcessorRequest {
|
||||
payload: any;
|
||||
export interface UpdateProcessorRequest extends UpdateComponentRequest {
|
||||
postUpdateNavigation?: string[];
|
||||
postUpdateNavigationBoundary?: string[];
|
||||
}
|
||||
|
||||
export interface UpdateComponentRequest {
|
||||
|
@ -401,7 +404,6 @@ export interface UpdateComponentRequest {
|
|||
payload: any;
|
||||
errorStrategy: 'snackbar' | 'banner';
|
||||
restoreOnFailure?: any;
|
||||
postUpdateNavigation?: string[];
|
||||
}
|
||||
|
||||
export interface UpdateComponentResponse {
|
||||
|
@ -409,7 +411,11 @@ export interface UpdateComponentResponse {
|
|||
id: string;
|
||||
type: ComponentType;
|
||||
response: any;
|
||||
}
|
||||
|
||||
export interface UpdateProcessorResponse extends UpdateComponentResponse {
|
||||
postUpdateNavigation?: string[];
|
||||
postUpdateNavigationBoundary?: string[];
|
||||
}
|
||||
|
||||
export interface UpdateComponentFailure {
|
||||
|
|
|
@ -19,13 +19,12 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|||
|
||||
import { HeaderComponent } from './header.component';
|
||||
import { provideMockStore } from '@ngrx/store/testing';
|
||||
import { initialState } from '../../../state/flow/flow.reducer';
|
||||
import { HttpClientTestingModule } from '@angular/common/http/testing';
|
||||
import { NewCanvasItem } from './new-canvas-item/new-canvas-item.component';
|
||||
import { MatMenuModule } from '@angular/material/menu';
|
||||
import { MatDividerModule } from '@angular/material/divider';
|
||||
import { selectControllerBulletins, selectControllerStatus } from '../../../state/flow/flow.selectors';
|
||||
import { ControllerStatus } from '../../../state/flow';
|
||||
import { ControllerStatus, flowFeatureKey } from '../../../state/flow';
|
||||
import { CdkConnectedOverlay, CdkOverlayOrigin } from '@angular/cdk/overlay';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { Component } from '@angular/core';
|
||||
|
@ -34,10 +33,13 @@ import { ClusterSummary } from '../../../../../state/cluster-summary';
|
|||
import { selectClusterSummary } from '../../../../../state/cluster-summary/cluster-summary.selectors';
|
||||
import { selectCurrentUser } from '../../../../../state/current-user/current-user.selectors';
|
||||
import * as fromUser from '../../../../../state/current-user/current-user.reducer';
|
||||
import * as fromNavigation from '../../../../../state/navigation/navigation.reducer';
|
||||
import * as fromFlow from '../../../state/flow/flow.reducer';
|
||||
import { selectFlowConfiguration } from '../../../../../state/flow-configuration/flow-configuration.selectors';
|
||||
import * as fromFlowConfiguration from '../../../../../state/flow-configuration/flow-configuration.reducer';
|
||||
import { selectLoginConfiguration } from '../../../../../state/login-configuration/login-configuration.selectors';
|
||||
import * as fromLoginConfiguration from '../../../../../state/login-configuration/login-configuration.reducer';
|
||||
import { navigationFeatureKey } from '../../../../../state/navigation';
|
||||
|
||||
describe('HeaderComponent', () => {
|
||||
let component: HeaderComponent;
|
||||
|
@ -101,7 +103,10 @@ describe('HeaderComponent', () => {
|
|||
],
|
||||
providers: [
|
||||
provideMockStore({
|
||||
initialState,
|
||||
initialState: {
|
||||
[flowFeatureKey]: fromFlow.initialState,
|
||||
[navigationFeatureKey]: fromNavigation.initialState
|
||||
},
|
||||
selectors: [
|
||||
{
|
||||
selector: selectClusterSummary,
|
||||
|
|
|
@ -27,6 +27,7 @@ import { MatOptionModule } from '@angular/material/core';
|
|||
import { MatSelectModule } from '@angular/material/select';
|
||||
import { Observable, of } from 'rxjs';
|
||||
import {
|
||||
ComponentType,
|
||||
InlineServiceCreationRequest,
|
||||
InlineServiceCreationResponse,
|
||||
ParameterContextEntity,
|
||||
|
@ -300,7 +301,7 @@ export class EditProcessor extends TabbedDialog {
|
|||
);
|
||||
}
|
||||
|
||||
submitForm(postUpdateNavigation?: string[]) {
|
||||
submitForm(postUpdateNavigation?: string[], postUpdateNavigationBoundary?: string[]) {
|
||||
const relationshipConfiguration: RelationshipConfiguration =
|
||||
this.editProcessorForm.get('relationshipConfiguration')?.value;
|
||||
const autoTerminated: string[] = relationshipConfiguration.relationships
|
||||
|
@ -351,7 +352,12 @@ export class EditProcessor extends TabbedDialog {
|
|||
}
|
||||
|
||||
this.editProcessor.next({
|
||||
id: this.request.entity.id,
|
||||
uri: this.request.entity.uri,
|
||||
type: ComponentType.Processor,
|
||||
errorStrategy: 'banner',
|
||||
postUpdateNavigation,
|
||||
postUpdateNavigationBoundary,
|
||||
payload
|
||||
});
|
||||
}
|
||||
|
|
|
@ -50,10 +50,12 @@
|
|||
(viewControllerServiceDocumentation)="viewControllerServiceDocumentation($event)"
|
||||
(configureControllerService)="configureControllerService($event)"
|
||||
(openAdvancedUi)="openAdvancedUi($event)"
|
||||
(manageAccessPolicies)="navigateToManageComponentPolicies($event)"
|
||||
(enableControllerService)="enableControllerService($event)"
|
||||
(disableControllerService)="disableControllerService($event)"
|
||||
(viewStateControllerService)="viewStateControllerService($event)"
|
||||
(changeControllerServiceVersion)="changeControllerServiceVersion($event)"
|
||||
(goToControllerService)="navigateToControllerService($event)"
|
||||
(deleteControllerService)="deleteControllerService($event)"></controller-service-table>
|
||||
</div>
|
||||
}
|
||||
|
|
|
@ -31,6 +31,8 @@ import {
|
|||
loadControllerServices,
|
||||
navigateToAdvancedServiceUi,
|
||||
navigateToEditService,
|
||||
navigateToManageComponentPolicies,
|
||||
navigateToService,
|
||||
openChangeControllerServiceVersionDialog,
|
||||
openConfigureControllerServiceDialog,
|
||||
openDisableControllerServiceDialog,
|
||||
|
@ -49,6 +51,7 @@ import { NiFiState } from '../../../../state';
|
|||
import { getComponentStateAndOpenDialog } from '../../../../state/component-state/component-state.actions';
|
||||
import { navigateToComponentDocumentation } from '../../../../state/documentation/documentation.actions';
|
||||
import { FlowConfiguration } from '../../../../state/flow-configuration';
|
||||
import { DocumentationRequest } from '../../../../state/documentation';
|
||||
|
||||
@Component({
|
||||
selector: 'controller-services',
|
||||
|
@ -162,14 +165,26 @@ export class ControllerServices implements OnDestroy {
|
|||
}
|
||||
|
||||
viewControllerServiceDocumentation(entity: ControllerServiceEntity): void {
|
||||
const request: DocumentationRequest = {
|
||||
parameters: {
|
||||
select: entity.component.type,
|
||||
group: entity.component.bundle.group,
|
||||
artifact: entity.component.bundle.artifact,
|
||||
version: entity.component.bundle.version
|
||||
}
|
||||
};
|
||||
|
||||
if (entity.parentGroupId) {
|
||||
request.backNavigation = {
|
||||
route: ['/process-groups', entity.parentGroupId, 'controller-services', entity.id],
|
||||
routeBoundary: ['/documentation'],
|
||||
context: 'Controller Service'
|
||||
};
|
||||
}
|
||||
|
||||
this.store.dispatch(
|
||||
navigateToComponentDocumentation({
|
||||
params: {
|
||||
select: entity.component.type,
|
||||
group: entity.component.bundle.group,
|
||||
artifact: entity.component.bundle.artifact,
|
||||
version: entity.component.bundle.version
|
||||
}
|
||||
request
|
||||
})
|
||||
);
|
||||
}
|
||||
|
@ -190,6 +205,27 @@ export class ControllerServices implements OnDestroy {
|
|||
);
|
||||
}
|
||||
|
||||
navigateToControllerService(entity: ControllerServiceEntity): void {
|
||||
if (entity.parentGroupId) {
|
||||
this.store.dispatch(
|
||||
navigateToService({
|
||||
request: {
|
||||
id: entity.id,
|
||||
processGroupId: entity.parentGroupId
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
navigateToManageComponentPolicies(entity: ControllerServiceEntity): void {
|
||||
this.store.dispatch(
|
||||
navigateToManageComponentPolicies({
|
||||
id: entity.id
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
enableControllerService(entity: ControllerServiceEntity): void {
|
||||
this.store.dispatch(
|
||||
openEnableControllerServiceDialog({
|
||||
|
|
|
@ -64,6 +64,11 @@ export const navigateToEditParameterContext = createAction(
|
|||
props<{ id: string }>()
|
||||
);
|
||||
|
||||
export const navigateToManageComponentPolicies = createAction(
|
||||
'[Parameter Context Listing] Navigate To Manage Component Policies',
|
||||
props<{ id: string }>()
|
||||
);
|
||||
|
||||
export const getEffectiveParameterContextAndOpenDialog = createAction(
|
||||
'[Parameter Context Listing] Get Effective Parameter Context Open Dialog',
|
||||
props<{ request: GetEffectiveParameterContext }>()
|
||||
|
|
|
@ -59,6 +59,7 @@ import { OkDialog } from '../../../../ui/common/ok-dialog/ok-dialog.component';
|
|||
import { ErrorHelper } from '../../../../service/error-helper.service';
|
||||
import { HttpErrorResponse } from '@angular/common/http';
|
||||
import { MEDIUM_DIALOG, SMALL_DIALOG, XL_DIALOG } from '../../../../index';
|
||||
import { BackNavigation } from '../../../../state/navigation';
|
||||
|
||||
@Injectable()
|
||||
export class ParameterContextListingEffects {
|
||||
|
@ -201,6 +202,27 @@ export class ParameterContextListingEffects {
|
|||
)
|
||||
);
|
||||
|
||||
navigateToManageComponentPolicies$ = createEffect(
|
||||
() =>
|
||||
this.actions$.pipe(
|
||||
ofType(ParameterContextListingActions.navigateToManageComponentPolicies),
|
||||
map((action) => action.id),
|
||||
tap((id) => {
|
||||
const routeBoundary: string[] = ['/access-policies'];
|
||||
this.router.navigate([...routeBoundary, 'read', 'component', 'parameter-contexts', id], {
|
||||
state: {
|
||||
backNavigation: {
|
||||
route: ['/parameter-contexts', id],
|
||||
routeBoundary,
|
||||
context: 'Parameter Context'
|
||||
} as BackNavigation
|
||||
}
|
||||
});
|
||||
})
|
||||
),
|
||||
{ dispatch: false }
|
||||
);
|
||||
|
||||
navigateToEditService$ = createEffect(
|
||||
() =>
|
||||
this.actions$.pipe(
|
||||
|
|
|
@ -35,7 +35,8 @@
|
|||
[flowConfiguration]="(flowConfiguration$ | async)!"
|
||||
(selectParameterContext)="selectParameterContext($event)"
|
||||
(editParameterContext)="editParameterContext($event)"
|
||||
(deleteParameterContext)="deleteParameterContext($event)"></parameter-context-table>
|
||||
(deleteParameterContext)="deleteParameterContext($event)"
|
||||
(manageAccessPolicies)="navigateToManageComponentPolicies($event)"></parameter-context-table>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<div class="refresh-container flex items-center gap-x-2">
|
||||
|
|
|
@ -28,6 +28,7 @@ import {
|
|||
getEffectiveParameterContextAndOpenDialog,
|
||||
loadParameterContexts,
|
||||
navigateToEditParameterContext,
|
||||
navigateToManageComponentPolicies,
|
||||
openNewParameterContextDialog,
|
||||
promptParameterContextDeletion,
|
||||
selectParameterContext
|
||||
|
@ -120,4 +121,12 @@ export class ParameterContextListing implements OnInit {
|
|||
})
|
||||
);
|
||||
}
|
||||
|
||||
navigateToManageComponentPolicies(entity: ParameterContextEntity): void {
|
||||
this.store.dispatch(
|
||||
navigateToManageComponentPolicies({
|
||||
id: entity.id
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -86,10 +86,7 @@
|
|||
</button>
|
||||
}
|
||||
@if (canManageAccessPolicies()) {
|
||||
<button
|
||||
mat-menu-item
|
||||
(click)="$event.stopPropagation()"
|
||||
[routerLink]="getPolicyLink(item)">
|
||||
<button mat-menu-item (click)="manageAccessPoliciesClicked(item)">
|
||||
<i class="fa fa-key primary-color mr-2"></i>
|
||||
Manage Access Policies
|
||||
</button>
|
||||
|
|
|
@ -47,6 +47,7 @@ export class ParameterContextTable {
|
|||
@Output() selectParameterContext: EventEmitter<ParameterContextEntity> = new EventEmitter<ParameterContextEntity>();
|
||||
@Output() editParameterContext: EventEmitter<ParameterContextEntity> = new EventEmitter<ParameterContextEntity>();
|
||||
@Output() deleteParameterContext: EventEmitter<ParameterContextEntity> = new EventEmitter<ParameterContextEntity>();
|
||||
@Output() manageAccessPolicies: EventEmitter<ParameterContextEntity> = new EventEmitter<ParameterContextEntity>();
|
||||
|
||||
displayedColumns: string[] = ['name', 'provider', 'description', 'actions'];
|
||||
dataSource: MatTableDataSource<ParameterContextEntity> = new MatTableDataSource<ParameterContextEntity>();
|
||||
|
@ -99,6 +100,10 @@ export class ParameterContextTable {
|
|||
return this.flowConfiguration?.supportsManagedAuthorizer && this.currentUser.tenantsPermissions.canRead;
|
||||
}
|
||||
|
||||
manageAccessPoliciesClicked(entity: ParameterContextEntity): void {
|
||||
this.manageAccessPolicies.next(entity);
|
||||
}
|
||||
|
||||
canGoToParameterProvider(entity: ParameterContextEntity): boolean {
|
||||
if (!this.canRead(entity)) {
|
||||
return false;
|
||||
|
@ -113,10 +118,6 @@ export class ParameterContextTable {
|
|||
return ['/settings', 'parameter-providers', entity.component.parameterProviderConfiguration.id];
|
||||
}
|
||||
|
||||
getPolicyLink(entity: ParameterContextEntity): string[] {
|
||||
return ['/access-policies', 'read', 'component', 'parameter-contexts', entity.id];
|
||||
}
|
||||
|
||||
select(entity: ParameterContextEntity): void {
|
||||
this.selectParameterContext.next(entity);
|
||||
}
|
||||
|
|
|
@ -73,6 +73,7 @@ export interface LoadConnectionLabelRequest {
|
|||
}
|
||||
|
||||
export interface LoadConnectionLabelResponse {
|
||||
connectionId: string;
|
||||
connectionLabel: string;
|
||||
}
|
||||
|
||||
|
@ -103,10 +104,15 @@ export interface FlowFileDialogRequest {
|
|||
clusterNodeId?: string;
|
||||
}
|
||||
|
||||
export interface SelectedConnection {
|
||||
id: string;
|
||||
label: string;
|
||||
}
|
||||
|
||||
export interface QueueListingState {
|
||||
activeListingRequest: ListingRequest | null;
|
||||
completedListingRequest: ListingRequest;
|
||||
connectionLabel: string;
|
||||
selectedConnection: SelectedConnection | null;
|
||||
loadedTimestamp: string;
|
||||
status: 'pending' | 'loading' | 'error' | 'success';
|
||||
}
|
||||
|
|
|
@ -66,6 +66,7 @@ export class QueueListingEffects {
|
|||
|
||||
return QueueListingActions.loadConnectionLabelSuccess({
|
||||
response: {
|
||||
connectionId: request.connectionId,
|
||||
connectionLabel
|
||||
}
|
||||
});
|
||||
|
@ -74,6 +75,7 @@ export class QueueListingEffects {
|
|||
of(
|
||||
QueueListingActions.loadConnectionLabelSuccess({
|
||||
response: {
|
||||
connectionId: request.connectionId,
|
||||
connectionLabel: 'Connection'
|
||||
}
|
||||
})
|
||||
|
|
|
@ -48,7 +48,7 @@ export const initialState: QueueListingState = {
|
|||
},
|
||||
flowFileSummaries: []
|
||||
},
|
||||
connectionLabel: 'Connection',
|
||||
selectedConnection: null,
|
||||
loadedTimestamp: 'N/A',
|
||||
status: 'pending'
|
||||
};
|
||||
|
@ -57,7 +57,10 @@ export const queueListingReducer = createReducer(
|
|||
initialState,
|
||||
on(loadConnectionLabelSuccess, (state, { response }) => ({
|
||||
...state,
|
||||
connectionLabel: response.connectionLabel
|
||||
selectedConnection: {
|
||||
id: response.connectionId,
|
||||
label: response.connectionLabel
|
||||
}
|
||||
})),
|
||||
on(submitQueueListingRequest, (state) => ({
|
||||
...state,
|
||||
|
|
|
@ -37,9 +37,9 @@ export const selectCompletedListingRequest = createSelector(
|
|||
|
||||
export const selectStatus = createSelector(selectQueueListingState, (state: QueueListingState) => state.status);
|
||||
|
||||
export const selectConnectionLabel = createSelector(
|
||||
export const selectSelectedConnection = createSelector(
|
||||
selectQueueListingState,
|
||||
(state: QueueListingState) => state.connectionLabel
|
||||
(state: QueueListingState) => state.selectedConnection
|
||||
);
|
||||
|
||||
export const selectLoadedTimestamp = createSelector(
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
-->
|
||||
|
||||
<div class="flowfile-table h-full flex flex-col">
|
||||
<h3 class="queue-listing-header primary-color">{{ connectionLabel }}</h3>
|
||||
<h3 class="queue-listing-header primary-color">{{ selectedConnection?.label }}</h3>
|
||||
<error-banner></error-banner>
|
||||
<div class="flex justify-between mb-2">
|
||||
<div class="accent-color font-medium">
|
||||
|
@ -151,11 +151,18 @@
|
|||
View content
|
||||
</button>
|
||||
}
|
||||
@if (currentUser.provenancePermissions.canRead) {
|
||||
@if (selectedConnection && currentUser.provenancePermissions.canRead) {
|
||||
<button
|
||||
mat-menu-item
|
||||
[routerLink]="['/provenance']"
|
||||
[queryParams]="{ flowFileUuid: item.uuid }">
|
||||
[queryParams]="{ flowFileUuid: item.uuid }"
|
||||
[state]="{
|
||||
backNavigation: {
|
||||
route: ['/queue', selectedConnection.id],
|
||||
routeBoundary: ['/provenance'],
|
||||
context: 'Queue'
|
||||
}
|
||||
}">
|
||||
<i class="icon icon-provenance primary-color mr-2"></i>
|
||||
Provenance
|
||||
</button>
|
||||
|
|
|
@ -23,7 +23,7 @@ import { ValidationErrorsTip } from '../../../../../ui/common/tooltips/validatio
|
|||
import { NiFiCommon } from '../../../../../service/nifi-common.service';
|
||||
|
||||
import { RouterLink } from '@angular/router';
|
||||
import { FlowFileSummary, ListingRequest } from '../../../state/queue-listing';
|
||||
import { FlowFileSummary, ListingRequest, SelectedConnection } from '../../../state/queue-listing';
|
||||
import { CurrentUser } from '../../../../../state/current-user';
|
||||
import { ErrorBanner } from '../../../../../ui/common/error-banner/error-banner.component';
|
||||
import { ClusterSummary } from '../../../../../state/cluster-summary';
|
||||
|
@ -38,7 +38,7 @@ import { MatMenu, MatMenuItem, MatMenuTrigger } from '@angular/material/menu';
|
|||
styleUrls: ['./flowfile-table.component.scss']
|
||||
})
|
||||
export class FlowFileTable {
|
||||
@Input() connectionLabel!: string;
|
||||
@Input() selectedConnection: SelectedConnection | null = null;
|
||||
|
||||
@Input() set listingRequest(listingRequest: ListingRequest) {
|
||||
if (listingRequest.flowFileSummaries) {
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
@if (listingRequest$ | async; as listingRequest) {
|
||||
@if (about$ | async; as about) {
|
||||
<flowfile-table
|
||||
[connectionLabel]="(connectionLabel$ | async)!"
|
||||
[selectedConnection]="(selectedConnection$ | async)!"
|
||||
[listingRequest]="listingRequest"
|
||||
[currentUser]="(currentUser$ | async)!"
|
||||
[clusterSummary]="(clusterSummary$ | async)!"
|
||||
|
|
|
@ -20,7 +20,7 @@ import { Store } from '@ngrx/store';
|
|||
import { distinctUntilChanged, filter } from 'rxjs';
|
||||
import {
|
||||
selectConnectionIdFromRoute,
|
||||
selectConnectionLabel,
|
||||
selectSelectedConnection,
|
||||
selectCompletedListingRequest,
|
||||
selectLoadedTimestamp,
|
||||
selectStatus
|
||||
|
@ -51,7 +51,7 @@ import { loadClusterSummary } from '../../../../state/cluster-summary/cluster-su
|
|||
})
|
||||
export class QueueListing implements OnInit, OnDestroy {
|
||||
status$ = this.store.select(selectStatus);
|
||||
connectionLabel$ = this.store.select(selectConnectionLabel);
|
||||
selectedConnection$ = this.store.select(selectSelectedConnection);
|
||||
loadedTimestamp$ = this.store.select(selectLoadedTimestamp);
|
||||
listingRequest$ = this.store.select(selectCompletedListingRequest);
|
||||
currentUser$ = this.store.select(selectCurrentUser);
|
||||
|
|
|
@ -30,9 +30,13 @@ import { ManagementControllerServiceService } from '../../service/management-con
|
|||
import { CreateFlowAnalysisRule } from '../../ui/flow-analysis-rules/create-flow-analysis-rule/create-flow-analysis-rule.component';
|
||||
import { Router } from '@angular/router';
|
||||
import { selectSaving } from '../management-controller-services/management-controller-services.selectors';
|
||||
import { OpenChangeComponentVersionDialogRequest, UpdateControllerServiceRequest } from '../../../../state/shared';
|
||||
import { OpenChangeComponentVersionDialogRequest } from '../../../../state/shared';
|
||||
import { EditFlowAnalysisRule } from '../../ui/flow-analysis-rules/edit-flow-analysis-rule/edit-flow-analysis-rule.component';
|
||||
import { CreateFlowAnalysisRuleSuccess, EditFlowAnalysisRuleDialogRequest } from './index';
|
||||
import {
|
||||
CreateFlowAnalysisRuleSuccess,
|
||||
EditFlowAnalysisRuleDialogRequest,
|
||||
UpdateFlowAnalysisRuleRequest
|
||||
} from './index';
|
||||
import { PropertyTableHelperService } from '../../../../service/property-table-helper.service';
|
||||
import * as ErrorActions from '../../../../state/error/error.actions';
|
||||
import { ErrorHelper } from '../../../../service/error-helper.service';
|
||||
|
@ -50,6 +54,7 @@ import {
|
|||
selectPropertyVerificationStatus
|
||||
} from '../../../../state/property-verification/property-verification.selectors';
|
||||
import { VerifyPropertiesRequestContext } from '../../../../state/property-verification';
|
||||
import { BackNavigation } from '../../../../state/navigation';
|
||||
|
||||
@Injectable()
|
||||
export class FlowAnalysisRulesEffects {
|
||||
|
@ -290,7 +295,7 @@ export class FlowAnalysisRulesEffects {
|
|||
selectPropertyVerificationStatus
|
||||
);
|
||||
|
||||
const goTo = (commands: string[], destination: string): void => {
|
||||
const goTo = (commands: string[], destination: string, commandBoundary: string[]): void => {
|
||||
if (editDialogReference.componentInstance.editFlowAnalysisRuleForm.dirty) {
|
||||
const saveChangesDialogReference = this.dialog.open(YesNoDialog, {
|
||||
...SMALL_DIALOG,
|
||||
|
@ -301,20 +306,37 @@ export class FlowAnalysisRulesEffects {
|
|||
});
|
||||
|
||||
saveChangesDialogReference.componentInstance.yes.pipe(take(1)).subscribe(() => {
|
||||
editDialogReference.componentInstance.submitForm(commands);
|
||||
editDialogReference.componentInstance.submitForm(commands, commandBoundary);
|
||||
});
|
||||
|
||||
saveChangesDialogReference.componentInstance.no.pipe(take(1)).subscribe(() => {
|
||||
this.router.navigate(commands);
|
||||
this.router.navigate(commands, {
|
||||
state: {
|
||||
backNavigation: {
|
||||
route: ['/settings', 'flow-analysis-rules', ruleId, 'edit'],
|
||||
routeBoundary: commandBoundary,
|
||||
context: 'Flow Analysis Rule'
|
||||
} as BackNavigation
|
||||
}
|
||||
});
|
||||
});
|
||||
} else {
|
||||
this.router.navigate(commands);
|
||||
this.router.navigate(commands, {
|
||||
state: {
|
||||
backNavigation: {
|
||||
route: ['/settings', 'flow-analysis-rules', ruleId, 'edit'],
|
||||
routeBoundary: commandBoundary,
|
||||
context: 'Flow Analysis Rule'
|
||||
} as BackNavigation
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
editDialogReference.componentInstance.goToService = (serviceId: string) => {
|
||||
const commands: string[] = ['/settings', 'management-controller-services', serviceId];
|
||||
goTo(commands, 'Controller Service');
|
||||
const commandBoundary: string[] = ['/settings', 'management-controller-services'];
|
||||
const commands: string[] = [...commandBoundary, serviceId];
|
||||
goTo(commands, 'Controller Service', commandBoundary);
|
||||
};
|
||||
|
||||
editDialogReference.componentInstance.createNewService =
|
||||
|
@ -326,14 +348,16 @@ export class FlowAnalysisRulesEffects {
|
|||
|
||||
editDialogReference.componentInstance.editFlowAnalysisRule
|
||||
.pipe(takeUntil(editDialogReference.afterClosed()))
|
||||
.subscribe((updateControllerServiceRequest: UpdateControllerServiceRequest) => {
|
||||
.subscribe((updateFlowAnalysisRuleRequest: UpdateFlowAnalysisRuleRequest) => {
|
||||
this.store.dispatch(
|
||||
FlowAnalysisRuleActions.configureFlowAnalysisRule({
|
||||
request: {
|
||||
id: request.flowAnalysisRule.id,
|
||||
uri: request.flowAnalysisRule.uri,
|
||||
payload: updateControllerServiceRequest.payload,
|
||||
postUpdateNavigation: updateControllerServiceRequest.postUpdateNavigation
|
||||
payload: updateFlowAnalysisRuleRequest.payload,
|
||||
postUpdateNavigation: updateFlowAnalysisRuleRequest.postUpdateNavigation,
|
||||
postUpdateNavigationBoundary:
|
||||
updateFlowAnalysisRuleRequest.postUpdateNavigationBoundary
|
||||
}
|
||||
})
|
||||
);
|
||||
|
@ -369,7 +393,8 @@ export class FlowAnalysisRulesEffects {
|
|||
response: {
|
||||
id: request.id,
|
||||
flowAnalysisRule: response,
|
||||
postUpdateNavigation: request.postUpdateNavigation
|
||||
postUpdateNavigation: request.postUpdateNavigation,
|
||||
postUpdateNavigationBoundary: request.postUpdateNavigationBoundary
|
||||
}
|
||||
})
|
||||
),
|
||||
|
@ -392,7 +417,19 @@ export class FlowAnalysisRulesEffects {
|
|||
map((action) => action.response),
|
||||
tap((response) => {
|
||||
if (response.postUpdateNavigation) {
|
||||
this.router.navigate(response.postUpdateNavigation);
|
||||
if (response.postUpdateNavigationBoundary) {
|
||||
this.router.navigate(response.postUpdateNavigation, {
|
||||
state: {
|
||||
backNavigation: {
|
||||
route: ['/settings', 'flow-analysis-rules', response.id, 'edit'],
|
||||
routeBoundary: response.postUpdateNavigationBoundary,
|
||||
context: 'Flow Analysis Rule'
|
||||
} as BackNavigation
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.router.navigate(response.postUpdateNavigation);
|
||||
}
|
||||
} else {
|
||||
this.dialog.closeAll();
|
||||
}
|
||||
|
@ -423,8 +460,7 @@ export class FlowAnalysisRulesEffects {
|
|||
FlowAnalysisRuleActions.enableFlowAnalysisRuleSuccess({
|
||||
response: {
|
||||
id: request.id,
|
||||
flowAnalysisRule: response,
|
||||
postUpdateNavigation: response.postUpdateNavigation
|
||||
flowAnalysisRule: response
|
||||
}
|
||||
})
|
||||
),
|
||||
|
@ -440,20 +476,6 @@ export class FlowAnalysisRulesEffects {
|
|||
)
|
||||
);
|
||||
|
||||
enableFlowAnalysisRuleSuccess$ = createEffect(
|
||||
() =>
|
||||
this.actions$.pipe(
|
||||
ofType(FlowAnalysisRuleActions.enableFlowAnalysisRuleSuccess),
|
||||
map((action) => action.response),
|
||||
tap((response) => {
|
||||
if (response.postUpdateNavigation) {
|
||||
this.router.navigate(response.postUpdateNavigation);
|
||||
}
|
||||
})
|
||||
),
|
||||
{ dispatch: false }
|
||||
);
|
||||
|
||||
disableFlowAnalysisRule$ = createEffect(() =>
|
||||
this.actions$.pipe(
|
||||
ofType(FlowAnalysisRuleActions.disableFlowAnalysisRule),
|
||||
|
@ -464,8 +486,7 @@ export class FlowAnalysisRulesEffects {
|
|||
FlowAnalysisRuleActions.disableFlowAnalysisRuleSuccess({
|
||||
response: {
|
||||
id: request.id,
|
||||
flowAnalysisRule: response,
|
||||
postUpdateNavigation: response.postUpdateNavigation
|
||||
flowAnalysisRule: response
|
||||
}
|
||||
})
|
||||
),
|
||||
|
@ -481,20 +502,6 @@ export class FlowAnalysisRulesEffects {
|
|||
)
|
||||
);
|
||||
|
||||
disableFlowAnalysisRuleSuccess$ = createEffect(
|
||||
() =>
|
||||
this.actions$.pipe(
|
||||
ofType(FlowAnalysisRuleActions.disableFlowAnalysisRuleSuccess),
|
||||
map((action) => action.response),
|
||||
tap((response) => {
|
||||
if (response.postUpdateNavigation) {
|
||||
this.router.navigate(response.postUpdateNavigation);
|
||||
}
|
||||
})
|
||||
),
|
||||
{ dispatch: false }
|
||||
);
|
||||
|
||||
openChangeFlowAnalysisRuleVersionDialog$ = createEffect(
|
||||
() =>
|
||||
this.actions$.pipe(
|
||||
|
|
|
@ -50,29 +50,30 @@ export interface ConfigureFlowAnalysisRuleRequest {
|
|||
uri: string;
|
||||
payload: any;
|
||||
postUpdateNavigation?: string[];
|
||||
postUpdateNavigationBoundary?: string[];
|
||||
}
|
||||
|
||||
export interface ConfigureFlowAnalysisRuleSuccess {
|
||||
id: string;
|
||||
flowAnalysisRule: FlowAnalysisRuleEntity;
|
||||
postUpdateNavigation?: string[];
|
||||
postUpdateNavigationBoundary?: string[];
|
||||
}
|
||||
|
||||
export interface UpdateFlowAnalysisRuleRequest {
|
||||
payload: any;
|
||||
postUpdateNavigation?: string[];
|
||||
postUpdateNavigationBoundary?: string[];
|
||||
}
|
||||
|
||||
export interface EnableFlowAnalysisRuleSuccess {
|
||||
id: string;
|
||||
flowAnalysisRule: FlowAnalysisRuleEntity;
|
||||
postUpdateNavigation?: string[];
|
||||
}
|
||||
|
||||
export interface DisableFlowAnalysisRuleSuccess {
|
||||
id: string;
|
||||
flowAnalysisRule: FlowAnalysisRuleEntity;
|
||||
postUpdateNavigation?: string[];
|
||||
}
|
||||
|
||||
export interface EnableFlowAnalysisRuleRequest {
|
||||
|
|
|
@ -33,12 +33,14 @@ export interface ConfigureControllerServiceRequest {
|
|||
uri: string;
|
||||
payload: any;
|
||||
postUpdateNavigation?: string[];
|
||||
postUpdateNavigationBoundary?: string[];
|
||||
}
|
||||
|
||||
export interface ConfigureControllerServiceSuccess {
|
||||
id: string;
|
||||
controllerService: ControllerServiceEntity;
|
||||
postUpdateNavigation?: string[];
|
||||
postUpdateNavigationBoundary?: string[];
|
||||
}
|
||||
|
||||
export interface DeleteControllerServiceRequest {
|
||||
|
|
|
@ -81,7 +81,12 @@ export const navigateToEditService = createAction(
|
|||
);
|
||||
|
||||
export const navigateToAdvancedServiceUi = createAction(
|
||||
'[Controller Services] Navigate To Advanced Service UI',
|
||||
'[Management Controller Services] Navigate To Advanced Service UI',
|
||||
props<{ id: string }>()
|
||||
);
|
||||
|
||||
export const navigateToManageComponentPolicies = createAction(
|
||||
'[Management Controller Services] Navigate To Manage Component Policies',
|
||||
props<{ id: string }>()
|
||||
);
|
||||
|
||||
|
|
|
@ -56,6 +56,7 @@ import {
|
|||
selectPropertyVerificationStatus
|
||||
} from '../../../../state/property-verification/property-verification.selectors';
|
||||
import { VerifyPropertiesRequestContext } from '../../../../state/property-verification';
|
||||
import { BackNavigation } from '../../../../state/navigation';
|
||||
|
||||
@Injectable()
|
||||
export class ManagementControllerServicesEffects {
|
||||
|
@ -191,7 +192,37 @@ export class ManagementControllerServicesEffects {
|
|||
ofType(ManagementControllerServicesActions.navigateToAdvancedServiceUi),
|
||||
map((action) => action.id),
|
||||
tap((id) => {
|
||||
this.router.navigate(['/settings', 'management-controller-services', id, 'advanced']);
|
||||
const routeBoundary: string[] = ['/settings', 'management-controller-services', id, 'advanced'];
|
||||
this.router.navigate([...routeBoundary], {
|
||||
state: {
|
||||
backNavigation: {
|
||||
route: ['/settings', 'management-controller-services', id],
|
||||
routeBoundary,
|
||||
context: 'Controller Service'
|
||||
} as BackNavigation
|
||||
}
|
||||
});
|
||||
})
|
||||
),
|
||||
{ dispatch: false }
|
||||
);
|
||||
|
||||
navigateToManageComponentPolicies$ = createEffect(
|
||||
() =>
|
||||
this.actions$.pipe(
|
||||
ofType(ManagementControllerServicesActions.navigateToManageComponentPolicies),
|
||||
map((action) => action.id),
|
||||
tap((id) => {
|
||||
const routeBoundary: string[] = ['/access-policies'];
|
||||
this.router.navigate([...routeBoundary, 'read', 'component', 'controller-services', id], {
|
||||
state: {
|
||||
backNavigation: {
|
||||
route: ['/settings', 'management-controller-services', id],
|
||||
routeBoundary,
|
||||
context: 'Controller Service'
|
||||
} as BackNavigation
|
||||
}
|
||||
});
|
||||
})
|
||||
),
|
||||
{ dispatch: false }
|
||||
|
@ -263,7 +294,7 @@ export class ManagementControllerServicesEffects {
|
|||
selectPropertyVerificationStatus
|
||||
);
|
||||
|
||||
const goTo = (commands: string[], destination: string): void => {
|
||||
const goTo = (commands: string[], destination: string, commandBoundary?: string[]): void => {
|
||||
if (editDialogReference.componentInstance.editControllerServiceForm.dirty) {
|
||||
const saveChangesDialogReference = this.dialog.open(YesNoDialog, {
|
||||
...SMALL_DIALOG,
|
||||
|
@ -274,20 +305,50 @@ export class ManagementControllerServicesEffects {
|
|||
});
|
||||
|
||||
saveChangesDialogReference.componentInstance.yes.pipe(take(1)).subscribe(() => {
|
||||
editDialogReference.componentInstance.submitForm(commands);
|
||||
editDialogReference.componentInstance.submitForm(commands, commandBoundary);
|
||||
});
|
||||
|
||||
saveChangesDialogReference.componentInstance.no.pipe(take(1)).subscribe(() => {
|
||||
this.router.navigate(commands);
|
||||
if (commandBoundary) {
|
||||
this.router.navigate(commands, {
|
||||
state: {
|
||||
backNavigation: {
|
||||
route: [
|
||||
'/settings',
|
||||
'management-controller-services',
|
||||
serviceId,
|
||||
'edit'
|
||||
],
|
||||
routeBoundary: commandBoundary,
|
||||
context: 'Controller Service'
|
||||
} as BackNavigation
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.router.navigate(commands);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.router.navigate(commands);
|
||||
if (commandBoundary) {
|
||||
this.router.navigate(commands, {
|
||||
state: {
|
||||
backNavigation: {
|
||||
route: ['/settings', 'management-controller-services', serviceId, 'edit'],
|
||||
routeBoundary: commandBoundary,
|
||||
context: 'Controller Service'
|
||||
} as BackNavigation
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.router.navigate(commands);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
editDialogReference.componentInstance.goToService = (serviceId: string) => {
|
||||
const commands: string[] = ['/settings', 'management-controller-services', serviceId];
|
||||
goTo(commands, 'Controller Service');
|
||||
const commandBoundary: string[] = ['/settings', 'management-controller-services'];
|
||||
const commands: string[] = [...commandBoundary, serviceId];
|
||||
goTo(commands, 'Controller Service', commandBoundary);
|
||||
};
|
||||
|
||||
editDialogReference.componentInstance.goToReferencingComponent = (
|
||||
|
@ -322,7 +383,9 @@ export class ManagementControllerServicesEffects {
|
|||
id: request.controllerService.id,
|
||||
uri: request.controllerService.uri,
|
||||
payload: updateControllerServiceRequest.payload,
|
||||
postUpdateNavigation: updateControllerServiceRequest.postUpdateNavigation
|
||||
postUpdateNavigation: updateControllerServiceRequest.postUpdateNavigation,
|
||||
postUpdateNavigationBoundary:
|
||||
updateControllerServiceRequest.postUpdateNavigationBoundary
|
||||
}
|
||||
})
|
||||
);
|
||||
|
@ -358,7 +421,8 @@ export class ManagementControllerServicesEffects {
|
|||
response: {
|
||||
id: request.id,
|
||||
controllerService: response,
|
||||
postUpdateNavigation: request.postUpdateNavigation
|
||||
postUpdateNavigation: request.postUpdateNavigation,
|
||||
postUpdateNavigationBoundary: request.postUpdateNavigationBoundary
|
||||
}
|
||||
})
|
||||
),
|
||||
|
@ -401,7 +465,19 @@ export class ManagementControllerServicesEffects {
|
|||
map((action) => action.response),
|
||||
tap((response) => {
|
||||
if (response.postUpdateNavigation) {
|
||||
this.router.navigate(response.postUpdateNavigation);
|
||||
if (response.postUpdateNavigationBoundary) {
|
||||
this.router.navigate(response.postUpdateNavigation, {
|
||||
state: {
|
||||
backNavigation: {
|
||||
route: ['/settings', 'management-controller-services', response.id, 'edit'],
|
||||
routeBoundary: response.postUpdateNavigationBoundary,
|
||||
context: 'Controller Service'
|
||||
} as BackNavigation
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.router.navigate(response.postUpdateNavigation);
|
||||
}
|
||||
} else {
|
||||
this.dialog.closeAll();
|
||||
}
|
||||
|
|
|
@ -167,17 +167,20 @@ export interface ConfigureParameterProviderRequest {
|
|||
uri: string;
|
||||
payload: any;
|
||||
postUpdateNavigation?: string[];
|
||||
postUpdateNavigationBoundary?: string[];
|
||||
}
|
||||
|
||||
export interface ConfigureParameterProviderSuccess {
|
||||
id: string;
|
||||
parameterProvider: ParameterProviderEntity;
|
||||
postUpdateNavigation?: string[];
|
||||
postUpdateNavigationBoundary?: string[];
|
||||
}
|
||||
|
||||
export interface UpdateParameterProviderRequest {
|
||||
payload: any;
|
||||
postUpdateNavigation?: string[];
|
||||
postUpdateNavigationBoundary?: string[];
|
||||
}
|
||||
|
||||
export interface FetchParameterProviderParametersRequest {
|
||||
|
|
|
@ -92,6 +92,11 @@ export const navigateToAdvancedParameterProviderUi = createAction(
|
|||
props<{ id: string }>()
|
||||
);
|
||||
|
||||
export const navigateToManageAccessPolicies = createAction(
|
||||
`${PARAMETER_PROVIDERS_PREFIX} Navigate To Manage Access Policies`,
|
||||
props<{ id: string }>()
|
||||
);
|
||||
|
||||
export const navigateToFetchParameterProvider = createAction(
|
||||
`${PARAMETER_PROVIDERS_PREFIX} Navigate To Fetch Parameter Provider`,
|
||||
props<{ id: string }>()
|
||||
|
|
|
@ -66,6 +66,7 @@ import {
|
|||
selectPropertyVerificationStatus
|
||||
} from '../../../../state/property-verification/property-verification.selectors';
|
||||
import { VerifyPropertiesRequestContext } from '../../../../state/property-verification';
|
||||
import { BackNavigation } from '../../../../state/navigation';
|
||||
|
||||
@Injectable()
|
||||
export class ParameterProvidersEffects {
|
||||
|
@ -257,7 +258,37 @@ export class ParameterProvidersEffects {
|
|||
ofType(ParameterProviderActions.navigateToAdvancedParameterProviderUi),
|
||||
map((action) => action.id),
|
||||
tap((id) => {
|
||||
this.router.navigate(['settings', 'parameter-providers', id, 'advanced']);
|
||||
const routeBoundary: string[] = ['/settings', 'parameter-providers', id, 'advanced'];
|
||||
this.router.navigate([...routeBoundary], {
|
||||
state: {
|
||||
backNavigation: {
|
||||
route: ['/settings', 'parameter-providers', id],
|
||||
routeBoundary,
|
||||
context: 'Parameter Provider'
|
||||
} as BackNavigation
|
||||
}
|
||||
});
|
||||
})
|
||||
),
|
||||
{ dispatch: false }
|
||||
);
|
||||
|
||||
navigateToManageAccessPolicies$ = createEffect(
|
||||
() =>
|
||||
this.actions$.pipe(
|
||||
ofType(ParameterProviderActions.navigateToManageAccessPolicies),
|
||||
map((action) => action.id),
|
||||
tap((id) => {
|
||||
const routeBoundary: string[] = ['/access-policies'];
|
||||
this.router.navigate([...routeBoundary, 'read', 'component', 'parameter-providers', id], {
|
||||
state: {
|
||||
backNavigation: {
|
||||
route: ['/settings', 'parameter-providers', id],
|
||||
routeBoundary,
|
||||
context: 'Parameter Provider'
|
||||
} as BackNavigation
|
||||
}
|
||||
});
|
||||
})
|
||||
),
|
||||
{ dispatch: false }
|
||||
|
@ -333,7 +364,7 @@ export class ParameterProvidersEffects {
|
|||
selectPropertyVerificationStatus
|
||||
);
|
||||
|
||||
const goTo = (commands: string[], destination: string) => {
|
||||
const goTo = (commands: string[], destination: string, commandBoundary: string[]) => {
|
||||
// confirm navigating away while changes are unsaved
|
||||
if (editDialogReference.componentInstance.editParameterProviderForm.dirty) {
|
||||
const promptSaveDialogRef = this.dialog.open(YesNoDialog, {
|
||||
|
@ -345,25 +376,43 @@ export class ParameterProvidersEffects {
|
|||
});
|
||||
|
||||
promptSaveDialogRef.componentInstance.yes.pipe(take(1)).subscribe(() => {
|
||||
editDialogReference.componentInstance.submitForm(commands);
|
||||
editDialogReference.componentInstance.submitForm(commands, commandBoundary);
|
||||
});
|
||||
|
||||
promptSaveDialogRef.componentInstance.no.pipe(take(1)).subscribe(() => {
|
||||
this.router.navigate(commands);
|
||||
this.router.navigate(commands, {
|
||||
state: {
|
||||
backNavigation: {
|
||||
route: ['/settings', 'parameter-providers', id, 'edit'],
|
||||
routeBoundary: commandBoundary,
|
||||
context: 'Parameter Provider'
|
||||
} as BackNavigation
|
||||
}
|
||||
});
|
||||
});
|
||||
} else {
|
||||
this.router.navigate(commands);
|
||||
this.router.navigate(commands, {
|
||||
state: {
|
||||
backNavigation: {
|
||||
route: ['/settings', 'parameter-providers', id, 'edit'],
|
||||
routeBoundary: commandBoundary,
|
||||
context: 'Parameter Provider'
|
||||
} as BackNavigation
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
editDialogReference.componentInstance.goToReferencingParameterContext = (id: string) => {
|
||||
const commands: string[] = ['parameter-contexts', id];
|
||||
goTo(commands, 'Parameter Context');
|
||||
const commandBoundary: string[] = ['/parameter-contexts'];
|
||||
const commands: string[] = [...commandBoundary, id];
|
||||
goTo(commands, 'Parameter Context', commandBoundary);
|
||||
};
|
||||
|
||||
editDialogReference.componentInstance.goToService = (serviceId: string) => {
|
||||
const commands: string[] = ['/settings', 'management-controller-services', serviceId];
|
||||
goTo(commands, 'Controller Service');
|
||||
const commandBoundary: string[] = ['/settings', 'management-controller-services'];
|
||||
const commands: string[] = [...commandBoundary, serviceId];
|
||||
goTo(commands, 'Controller Service', commandBoundary);
|
||||
};
|
||||
|
||||
editDialogReference.componentInstance.createNewProperty =
|
||||
|
@ -385,7 +434,8 @@ export class ParameterProvidersEffects {
|
|||
id: request.parameterProvider.id,
|
||||
uri: request.parameterProvider.uri,
|
||||
payload: updateRequest.payload,
|
||||
postUpdateNavigation: updateRequest.postUpdateNavigation
|
||||
postUpdateNavigation: updateRequest.postUpdateNavigation,
|
||||
postUpdateNavigationBoundary: updateRequest.postUpdateNavigationBoundary
|
||||
}
|
||||
})
|
||||
);
|
||||
|
@ -421,7 +471,8 @@ export class ParameterProvidersEffects {
|
|||
response: {
|
||||
id: request.id,
|
||||
parameterProvider: response,
|
||||
postUpdateNavigation: request.postUpdateNavigation
|
||||
postUpdateNavigation: request.postUpdateNavigation,
|
||||
postUpdateNavigationBoundary: request.postUpdateNavigationBoundary
|
||||
}
|
||||
})
|
||||
),
|
||||
|
@ -448,7 +499,19 @@ export class ParameterProvidersEffects {
|
|||
map((action) => action.response),
|
||||
tap((response) => {
|
||||
if (response.postUpdateNavigation) {
|
||||
this.router.navigate(response.postUpdateNavigation);
|
||||
if (response.postUpdateNavigationBoundary) {
|
||||
this.router.navigate(response.postUpdateNavigation, {
|
||||
state: {
|
||||
backNavigation: {
|
||||
route: ['/settings', 'parameter-providers', response.id, 'edit'],
|
||||
routeBoundary: response.postUpdateNavigationBoundary,
|
||||
context: 'Parameter Provider'
|
||||
} as BackNavigation
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.router.navigate(response.postUpdateNavigation);
|
||||
}
|
||||
} else {
|
||||
this.dialog.closeAll();
|
||||
}
|
||||
|
|
|
@ -51,12 +51,14 @@ export interface EditRegistryClientRequest {
|
|||
uri: string;
|
||||
payload: any;
|
||||
postUpdateNavigation?: string[];
|
||||
postUpdateNavigationBoundary?: string[];
|
||||
}
|
||||
|
||||
export interface EditRegistryClientRequestSuccess {
|
||||
id: string;
|
||||
registryClient: RegistryClientEntity;
|
||||
postUpdateNavigation?: string[];
|
||||
postUpdateNavigationBoundary?: string[];
|
||||
}
|
||||
|
||||
export interface DeleteRegistryClientRequest {
|
||||
|
|
|
@ -37,6 +37,7 @@ import * as ErrorActions from '../../../../state/error/error.actions';
|
|||
import { ErrorHelper } from '../../../../service/error-helper.service';
|
||||
import { HttpErrorResponse } from '@angular/common/http';
|
||||
import { LARGE_DIALOG, MEDIUM_DIALOG, SMALL_DIALOG } from '../../../../index';
|
||||
import { BackNavigation } from '../../../../state/navigation';
|
||||
|
||||
@Injectable()
|
||||
export class RegistryClientsEffects {
|
||||
|
@ -193,7 +194,8 @@ export class RegistryClientsEffects {
|
|||
this.propertyTableHelperService.createNewProperty(registryClientId, this.registryClientService);
|
||||
|
||||
editDialogReference.componentInstance.goToService = (serviceId: string) => {
|
||||
const commands: string[] = ['/settings', 'management-controller-services', serviceId];
|
||||
const commandBoundary: string[] = ['/settings', 'management-controller-services'];
|
||||
const commands: string[] = [...commandBoundary, serviceId];
|
||||
|
||||
if (editDialogReference.componentInstance.editRegistryClientForm.dirty) {
|
||||
const saveChangesDialogReference = this.dialog.open(YesNoDialog, {
|
||||
|
@ -205,14 +207,30 @@ export class RegistryClientsEffects {
|
|||
});
|
||||
|
||||
saveChangesDialogReference.componentInstance.yes.pipe(take(1)).subscribe(() => {
|
||||
editDialogReference.componentInstance.submitForm(commands);
|
||||
editDialogReference.componentInstance.submitForm(commands, commandBoundary);
|
||||
});
|
||||
|
||||
saveChangesDialogReference.componentInstance.no.pipe(take(1)).subscribe(() => {
|
||||
this.router.navigate(commands);
|
||||
this.router.navigate(commands, {
|
||||
state: {
|
||||
backNavigation: {
|
||||
route: ['/settings', 'registry-clients', registryClientId, 'edit'],
|
||||
routeBoundary: commandBoundary,
|
||||
context: 'Registry Client'
|
||||
} as BackNavigation
|
||||
}
|
||||
});
|
||||
});
|
||||
} else {
|
||||
this.router.navigate(commands);
|
||||
this.router.navigate(commands, {
|
||||
state: {
|
||||
backNavigation: {
|
||||
route: ['/settings', 'registry-clients', registryClientId, 'edit'],
|
||||
routeBoundary: commandBoundary,
|
||||
context: 'Registry Client'
|
||||
} as BackNavigation
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -262,7 +280,8 @@ export class RegistryClientsEffects {
|
|||
response: {
|
||||
id: request.id,
|
||||
registryClient: response,
|
||||
postUpdateNavigation: request.postUpdateNavigation
|
||||
postUpdateNavigation: request.postUpdateNavigation,
|
||||
postUpdateNavigationBoundary: request.postUpdateNavigationBoundary
|
||||
}
|
||||
})
|
||||
),
|
||||
|
@ -285,7 +304,19 @@ export class RegistryClientsEffects {
|
|||
map((action) => action.response),
|
||||
tap((response) => {
|
||||
if (response.postUpdateNavigation) {
|
||||
this.router.navigate(response.postUpdateNavigation);
|
||||
if (response.postUpdateNavigationBoundary) {
|
||||
this.router.navigate(response.postUpdateNavigation, {
|
||||
state: {
|
||||
backNavigation: {
|
||||
route: ['/settings', 'registry-clients', response.id, 'edit'],
|
||||
routeBoundary: response.postUpdateNavigationBoundary,
|
||||
context: 'Registry Client'
|
||||
} as BackNavigation
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.router.navigate(response.postUpdateNavigation);
|
||||
}
|
||||
} else {
|
||||
this.dialog.closeAll();
|
||||
}
|
||||
|
|
|
@ -50,24 +50,20 @@ export interface ConfigureReportingTaskRequest {
|
|||
uri: string;
|
||||
payload: any;
|
||||
postUpdateNavigation?: string[];
|
||||
postUpdateNavigationBoundary?: string[];
|
||||
}
|
||||
|
||||
export interface ConfigureReportingTaskSuccess {
|
||||
id: string;
|
||||
reportingTask: ReportingTaskEntity;
|
||||
postUpdateNavigation?: string[];
|
||||
}
|
||||
|
||||
export interface ConfigureReportingTaskRequest {
|
||||
id: string;
|
||||
uri: string;
|
||||
payload: any;
|
||||
postUpdateNavigation?: string[];
|
||||
postUpdateNavigationBoundary?: string[];
|
||||
}
|
||||
|
||||
export interface UpdateReportingTaskRequest {
|
||||
payload: any;
|
||||
postUpdateNavigation?: string[];
|
||||
postUpdateNavigationBoundary?: string[];
|
||||
}
|
||||
|
||||
export interface EditReportingTaskDialogRequest {
|
||||
|
|
|
@ -89,6 +89,11 @@ export const navigateToAdvancedReportingTaskUi = createAction(
|
|||
props<{ id: string }>()
|
||||
);
|
||||
|
||||
export const navigateToManageAccessPolicies = createAction(
|
||||
'[Reporting Tasks] Navigate To Manage Access Policies',
|
||||
props<{ id: string }>()
|
||||
);
|
||||
|
||||
export const startReportingTask = createAction(
|
||||
'[Reporting Tasks] Start Reporting Task',
|
||||
props<{ request: StartReportingTaskRequest }>()
|
||||
|
|
|
@ -29,9 +29,9 @@ import { ReportingTaskService } from '../../service/reporting-task.service';
|
|||
import { CreateReportingTask } from '../../ui/reporting-tasks/create-reporting-task/create-reporting-task.component';
|
||||
import { Router } from '@angular/router';
|
||||
import { selectSaving } from '../management-controller-services/management-controller-services.selectors';
|
||||
import { OpenChangeComponentVersionDialogRequest, UpdateControllerServiceRequest } from '../../../../state/shared';
|
||||
import { OpenChangeComponentVersionDialogRequest } from '../../../../state/shared';
|
||||
import { EditReportingTask } from '../../ui/reporting-tasks/edit-reporting-task/edit-reporting-task.component';
|
||||
import { CreateReportingTaskSuccess, EditReportingTaskDialogRequest } from './index';
|
||||
import { CreateReportingTaskSuccess, EditReportingTaskDialogRequest, UpdateReportingTaskRequest } from './index';
|
||||
import { ManagementControllerServiceService } from '../../service/management-controller-service.service';
|
||||
import { PropertyTableHelperService } from '../../../../service/property-table-helper.service';
|
||||
import * as ErrorActions from '../../../../state/error/error.actions';
|
||||
|
@ -50,6 +50,7 @@ import {
|
|||
selectPropertyVerificationStatus
|
||||
} from '../../../../state/property-verification/property-verification.selectors';
|
||||
import { VerifyPropertiesRequestContext } from '../../../../state/property-verification';
|
||||
import { BackNavigation } from '../../../../state/navigation';
|
||||
|
||||
@Injectable()
|
||||
export class ReportingTasksEffects {
|
||||
|
@ -234,7 +235,37 @@ export class ReportingTasksEffects {
|
|||
ofType(ReportingTaskActions.navigateToAdvancedReportingTaskUi),
|
||||
map((action) => action.id),
|
||||
tap((id) => {
|
||||
this.router.navigate(['/settings', 'reporting-tasks', id, 'advanced']);
|
||||
const routeBoundary: string[] = ['/settings', 'reporting-tasks', id, 'advanced'];
|
||||
this.router.navigate([...routeBoundary], {
|
||||
state: {
|
||||
backNavigation: {
|
||||
route: ['/settings', 'reporting-tasks', id],
|
||||
routeBoundary,
|
||||
context: 'Reporting Task'
|
||||
} as BackNavigation
|
||||
}
|
||||
});
|
||||
})
|
||||
),
|
||||
{ dispatch: false }
|
||||
);
|
||||
|
||||
navigateToManageAccessPolicies$ = createEffect(
|
||||
() =>
|
||||
this.actions$.pipe(
|
||||
ofType(ReportingTaskActions.navigateToManageAccessPolicies),
|
||||
map((action) => action.id),
|
||||
tap((id) => {
|
||||
const routeBoundary = ['/access-policies'];
|
||||
this.router.navigate([...routeBoundary, 'read', 'component', 'reporting-tasks', id], {
|
||||
state: {
|
||||
backNavigation: {
|
||||
route: ['/settings', 'reporting-tasks', id],
|
||||
routeBoundary,
|
||||
context: 'Reporting Task'
|
||||
} as BackNavigation
|
||||
}
|
||||
});
|
||||
})
|
||||
),
|
||||
{ dispatch: false }
|
||||
|
@ -302,7 +333,7 @@ export class ReportingTasksEffects {
|
|||
selectPropertyVerificationStatus
|
||||
);
|
||||
|
||||
const goTo = (commands: string[], destination: string): void => {
|
||||
const goTo = (commands: string[], destination: string, commandBoundary: string[]): void => {
|
||||
if (editDialogReference.componentInstance.editReportingTaskForm.dirty) {
|
||||
const saveChangesDialogReference = this.dialog.open(YesNoDialog, {
|
||||
...SMALL_DIALOG,
|
||||
|
@ -313,20 +344,37 @@ export class ReportingTasksEffects {
|
|||
});
|
||||
|
||||
saveChangesDialogReference.componentInstance.yes.pipe(take(1)).subscribe(() => {
|
||||
editDialogReference.componentInstance.submitForm(commands);
|
||||
editDialogReference.componentInstance.submitForm(commands, commandBoundary);
|
||||
});
|
||||
|
||||
saveChangesDialogReference.componentInstance.no.pipe(take(1)).subscribe(() => {
|
||||
this.router.navigate(commands);
|
||||
this.router.navigate(commands, {
|
||||
state: {
|
||||
backNavigation: {
|
||||
route: ['/settings', 'reporting-tasks', taskId, 'edit'],
|
||||
routeBoundary: commandBoundary,
|
||||
context: 'Reporting Task'
|
||||
} as BackNavigation
|
||||
}
|
||||
});
|
||||
});
|
||||
} else {
|
||||
this.router.navigate(commands);
|
||||
this.router.navigate(commands, {
|
||||
state: {
|
||||
backNavigation: {
|
||||
route: ['/settings', 'reporting-tasks', taskId, 'edit'],
|
||||
routeBoundary: commandBoundary,
|
||||
context: 'Reporting Task'
|
||||
} as BackNavigation
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
editDialogReference.componentInstance.goToService = (serviceId: string) => {
|
||||
const commands: string[] = ['/settings', 'management-controller-services', serviceId];
|
||||
goTo(commands, 'Controller Service');
|
||||
const commandBoundary: string[] = ['/settings', 'management-controller-services'];
|
||||
const commands: string[] = [...commandBoundary, serviceId];
|
||||
goTo(commands, 'Controller Service', commandBoundary);
|
||||
};
|
||||
|
||||
editDialogReference.componentInstance.createNewService =
|
||||
|
@ -338,14 +386,16 @@ export class ReportingTasksEffects {
|
|||
|
||||
editDialogReference.componentInstance.editReportingTask
|
||||
.pipe(takeUntil(editDialogReference.afterClosed()))
|
||||
.subscribe((updateControllerServiceRequest: UpdateControllerServiceRequest) => {
|
||||
.subscribe((updateReportingTaskRequest: UpdateReportingTaskRequest) => {
|
||||
this.store.dispatch(
|
||||
ReportingTaskActions.configureReportingTask({
|
||||
request: {
|
||||
id: request.reportingTask.id,
|
||||
uri: request.reportingTask.uri,
|
||||
payload: updateControllerServiceRequest.payload,
|
||||
postUpdateNavigation: updateControllerServiceRequest.postUpdateNavigation
|
||||
payload: updateReportingTaskRequest.payload,
|
||||
postUpdateNavigation: updateReportingTaskRequest.postUpdateNavigation,
|
||||
postUpdateNavigationBoundary:
|
||||
updateReportingTaskRequest.postUpdateNavigationBoundary
|
||||
}
|
||||
})
|
||||
);
|
||||
|
@ -381,7 +431,8 @@ export class ReportingTasksEffects {
|
|||
response: {
|
||||
id: request.id,
|
||||
reportingTask: response,
|
||||
postUpdateNavigation: request.postUpdateNavigation
|
||||
postUpdateNavigation: request.postUpdateNavigation,
|
||||
postUpdateNavigationBoundary: request.postUpdateNavigationBoundary
|
||||
}
|
||||
})
|
||||
),
|
||||
|
@ -404,7 +455,19 @@ export class ReportingTasksEffects {
|
|||
map((action) => action.response),
|
||||
tap((response) => {
|
||||
if (response.postUpdateNavigation) {
|
||||
this.router.navigate(response.postUpdateNavigation);
|
||||
if (response.postUpdateNavigationBoundary) {
|
||||
this.router.navigate(response.postUpdateNavigation, {
|
||||
state: {
|
||||
backNavigation: {
|
||||
route: ['/settings', 'reporting-tasks', response.id, 'edit'],
|
||||
routeBoundary: response.postUpdateNavigationBoundary,
|
||||
context: 'Reporting Task'
|
||||
} as BackNavigation
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.router.navigate(response.postUpdateNavigation);
|
||||
}
|
||||
} else {
|
||||
this.dialog.closeAll();
|
||||
}
|
||||
|
|
|
@ -140,7 +140,7 @@ export class EditFlowAnalysisRule extends TabbedDialog {
|
|||
return this.nifiCommon.formatBundle(entity.component.bundle);
|
||||
}
|
||||
|
||||
submitForm(postUpdateNavigation?: string[]) {
|
||||
submitForm(postUpdateNavigation?: string[], postUpdateNavigationBoundary?: string[]) {
|
||||
const payload: any = {
|
||||
revision: this.client.getRevision(this.request.flowAnalysisRule),
|
||||
disconnectedNodeAcknowledged: this.clusterConnectionService.isDisconnectionAcknowledged(),
|
||||
|
@ -164,7 +164,8 @@ export class EditFlowAnalysisRule extends TabbedDialog {
|
|||
|
||||
this.editFlowAnalysisRule.next({
|
||||
payload,
|
||||
postUpdateNavigation
|
||||
postUpdateNavigation,
|
||||
postUpdateNavigationBoundary
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -111,11 +111,18 @@ 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
|
||||
request: {
|
||||
backNavigation: {
|
||||
route: ['/settings', 'flow-analysis-rules', entity.id],
|
||||
routeBoundary: ['/documentation'],
|
||||
context: 'Flow Analysis Rule'
|
||||
},
|
||||
parameters: {
|
||||
select: entity.component.type,
|
||||
group: entity.component.bundle.group,
|
||||
artifact: entity.component.bundle.artifact,
|
||||
version: entity.component.bundle.version
|
||||
}
|
||||
}
|
||||
})
|
||||
);
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
(selectControllerService)="selectControllerService($event)"
|
||||
(viewControllerServiceDocumentation)="viewControllerServiceDocumentation($event)"
|
||||
(configureControllerService)="configureControllerService($event)"
|
||||
(manageAccessPolicies)="navigateToManageComponentPolicies($event)"
|
||||
(openAdvancedUi)="openAdvancedUi($event)"
|
||||
(enableControllerService)="enableControllerService($event)"
|
||||
(disableControllerService)="disableControllerService($event)"
|
||||
|
|
|
@ -28,6 +28,7 @@ import {
|
|||
loadManagementControllerServices,
|
||||
navigateToAdvancedServiceUi,
|
||||
navigateToEditService,
|
||||
navigateToManageComponentPolicies,
|
||||
openChangeMgtControllerServiceVersionDialog,
|
||||
openConfigureControllerServiceDialog,
|
||||
openDisableControllerServiceDialog,
|
||||
|
@ -114,11 +115,18 @@ export class ManagementControllerServices 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
|
||||
request: {
|
||||
backNavigation: {
|
||||
route: ['/settings', 'management-controller-services', entity.id],
|
||||
routeBoundary: ['/documentation'],
|
||||
context: 'Controller Service'
|
||||
},
|
||||
parameters: {
|
||||
select: entity.component.type,
|
||||
group: entity.component.bundle.group,
|
||||
artifact: entity.component.bundle.artifact,
|
||||
version: entity.component.bundle.version
|
||||
}
|
||||
}
|
||||
})
|
||||
);
|
||||
|
@ -132,6 +140,14 @@ export class ManagementControllerServices implements OnInit, OnDestroy {
|
|||
);
|
||||
}
|
||||
|
||||
navigateToManageComponentPolicies(entity: ControllerServiceEntity): void {
|
||||
this.store.dispatch(
|
||||
navigateToManageComponentPolicies({
|
||||
id: entity.id
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
openAdvancedUi(entity: ControllerServiceEntity): void {
|
||||
this.store.dispatch(
|
||||
navigateToAdvancedServiceUi({
|
||||
|
|
|
@ -129,7 +129,7 @@ export class EditParameterProvider extends TabbedDialog {
|
|||
return this.nifiCommon.formatBundle(entity.component.bundle);
|
||||
}
|
||||
|
||||
submitForm(postUpdateNavigation?: string[]) {
|
||||
submitForm(postUpdateNavigation?: string[], postUpdateNavigationBoundary?: string[]) {
|
||||
const payload: any = {
|
||||
revision: this.client.getRevision(this.request.parameterProvider),
|
||||
disconnectedNodeAcknowledged: this.clusterConnectionService.isDisconnectionAcknowledged(),
|
||||
|
@ -151,7 +151,8 @@ export class EditParameterProvider extends TabbedDialog {
|
|||
|
||||
this.editParameterProvider.next({
|
||||
payload,
|
||||
postUpdateNavigation
|
||||
postUpdateNavigation,
|
||||
postUpdateNavigationBoundary
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -134,10 +134,7 @@
|
|||
</button>
|
||||
}
|
||||
@if (canManageAccessPolicies()) {
|
||||
<button
|
||||
mat-menu-item
|
||||
(click)="$event.stopPropagation()"
|
||||
[routerLink]="getPolicyLink(item)">
|
||||
<button mat-menu-item (click)="manageAccessPoliciesClicked(item)">
|
||||
<i class="fa fa-key primary-color mr-2"></i>
|
||||
Manage Access Policies
|
||||
</button>
|
||||
|
|
|
@ -212,7 +212,7 @@ export class ParameterProvidersTable {
|
|||
this.deleteParameterProvider.next(entity);
|
||||
}
|
||||
|
||||
getPolicyLink(entity: ParameterProviderEntity): string[] {
|
||||
return ['/access-policies', 'read', 'component', 'parameter-providers', entity.id];
|
||||
manageAccessPoliciesClicked(entity: ParameterProviderEntity) {
|
||||
this.manageAccessPolicies.next(entity);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
(deleteParameterProvider)="deleteParameterProvider($event)"
|
||||
(configureParameterProvider)="openConfigureParameterProviderDialog($event)"
|
||||
(openAdvancedUi)="openAdvancedUi($event)"
|
||||
(manageAccessPolicies)="navigateToManageAccessPolicies($event)"
|
||||
(fetchParameterProvider)="fetchParameterProviderParameters($event)"
|
||||
(viewParameterProviderDocumentation)="viewParameterProviderDocumentation($event)"
|
||||
(selectParameterProvider)="selectParameterProvider($event)"></parameter-providers-table>
|
||||
|
|
|
@ -137,14 +137,29 @@ export class ParameterProviders implements OnInit, OnDestroy {
|
|||
);
|
||||
}
|
||||
|
||||
navigateToManageAccessPolicies(parameterProvider: ParameterProviderEntity) {
|
||||
this.store.dispatch(
|
||||
ParameterProviderActions.navigateToManageAccessPolicies({
|
||||
id: parameterProvider.id
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
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
|
||||
request: {
|
||||
backNavigation: {
|
||||
route: ['/settings', 'parameter-providers', parameterProvider.id],
|
||||
routeBoundary: ['/documentation'],
|
||||
context: 'Parameter Provider'
|
||||
},
|
||||
parameters: {
|
||||
select: parameterProvider.component.type,
|
||||
group: parameterProvider.component.bundle.group,
|
||||
artifact: parameterProvider.component.bundle.artifact,
|
||||
version: parameterProvider.component.bundle.version
|
||||
}
|
||||
}
|
||||
})
|
||||
);
|
||||
|
|
|
@ -105,7 +105,7 @@ export class EditRegistryClient extends TabbedDialog {
|
|||
return this.nifiCommon.formatType(entity.component);
|
||||
}
|
||||
|
||||
submitForm(postUpdateNavigation?: string[]) {
|
||||
submitForm(postUpdateNavigation?: string[], postUpdateNavigationBoundary?: string[]) {
|
||||
const payload: any = {
|
||||
revision: this.client.getRevision(this.request.registryClient),
|
||||
disconnectedNodeAcknowledged: this.clusterConnectionService.isDisconnectionAcknowledged(),
|
||||
|
@ -132,7 +132,8 @@ export class EditRegistryClient extends TabbedDialog {
|
|||
id: this.request.registryClient.id,
|
||||
uri: this.request.registryClient.uri,
|
||||
payload,
|
||||
postUpdateNavigation
|
||||
postUpdateNavigation,
|
||||
postUpdateNavigationBoundary
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -179,7 +179,7 @@ export class EditReportingTask extends TabbedDialog {
|
|||
return this.nifiCommon.formatBundle(entity.component.bundle);
|
||||
}
|
||||
|
||||
submitForm(postUpdateNavigation?: string[]) {
|
||||
submitForm(postUpdateNavigation?: string[], postUpdateNavigationBoundary?: string[]) {
|
||||
const payload: any = {
|
||||
revision: this.client.getRevision(this.request.reportingTask),
|
||||
disconnectedNodeAcknowledged: this.clusterConnectionService.isDisconnectionAcknowledged(),
|
||||
|
@ -204,7 +204,8 @@ export class EditReportingTask extends TabbedDialog {
|
|||
|
||||
this.editReportingTask.next({
|
||||
payload,
|
||||
postUpdateNavigation
|
||||
postUpdateNavigation,
|
||||
postUpdateNavigationBoundary
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -160,10 +160,7 @@
|
|||
</button>
|
||||
}
|
||||
@if (canManageAccessPolicies()) {
|
||||
<button
|
||||
mat-menu-item
|
||||
(click)="$event.stopPropagation()"
|
||||
[routerLink]="getPolicyLink(item)">
|
||||
<button mat-menu-item (click)="managedAccessPoliciesClicked(item)">
|
||||
<i class="fa fa-key primary-color mr-2"></i>
|
||||
Manage Access Policies
|
||||
</button>
|
||||
|
|
|
@ -55,6 +55,7 @@ export class ReportingTaskTable {
|
|||
@Output() startReportingTask: EventEmitter<ReportingTaskEntity> = new EventEmitter<ReportingTaskEntity>();
|
||||
@Output() configureReportingTask: EventEmitter<ReportingTaskEntity> = new EventEmitter<ReportingTaskEntity>();
|
||||
@Output() openAdvancedUi: EventEmitter<ReportingTaskEntity> = new EventEmitter<ReportingTaskEntity>();
|
||||
@Output() manageAccessPolicies: EventEmitter<ReportingTaskEntity> = new EventEmitter<ReportingTaskEntity>();
|
||||
@Output() viewStateReportingTask: EventEmitter<ReportingTaskEntity> = new EventEmitter<ReportingTaskEntity>();
|
||||
@Output() stopReportingTask: EventEmitter<ReportingTaskEntity> = new EventEmitter<ReportingTaskEntity>();
|
||||
@Output() changeReportingTaskVersion: EventEmitter<ReportingTaskEntity> = new EventEmitter<ReportingTaskEntity>();
|
||||
|
@ -253,8 +254,8 @@ export class ReportingTaskTable {
|
|||
return this.flowConfiguration.supportsManagedAuthorizer && this.currentUser.tenantsPermissions.canRead;
|
||||
}
|
||||
|
||||
getPolicyLink(entity: ReportingTaskEntity): string[] {
|
||||
return ['/access-policies', 'read', 'component', 'reporting-tasks', entity.id];
|
||||
managedAccessPoliciesClicked(entity: ReportingTaskEntity): void {
|
||||
this.manageAccessPolicies.next(entity);
|
||||
}
|
||||
|
||||
select(entity: ReportingTaskEntity): void {
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
[flowConfiguration]="(flowConfiguration$ | async)!"
|
||||
(configureReportingTask)="configureReportingTask($event)"
|
||||
(openAdvancedUi)="openAdvancedUi($event)"
|
||||
(manageAccessPolicies)="navigateToManageAccessPolicies($event)"
|
||||
(viewStateReportingTask)="viewStateReportingTask($event)"
|
||||
(selectReportingTask)="selectReportingTask($event)"
|
||||
(viewReportingTaskDocumentation)="viewReportingTaskDocumentation($event)"
|
||||
|
|
|
@ -30,6 +30,7 @@ import {
|
|||
loadReportingTasks,
|
||||
navigateToAdvancedReportingTaskUi,
|
||||
navigateToEditReportingTask,
|
||||
navigateToManageAccessPolicies,
|
||||
openChangeReportingTaskVersionDialog,
|
||||
openConfigureReportingTaskDialog,
|
||||
openNewReportingTaskDialog,
|
||||
|
@ -119,14 +120,29 @@ export class ReportingTasks implements OnInit, OnDestroy {
|
|||
);
|
||||
}
|
||||
|
||||
navigateToManageAccessPolicies(entity: ReportingTaskEntity): void {
|
||||
this.store.dispatch(
|
||||
navigateToManageAccessPolicies({
|
||||
id: entity.id
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
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
|
||||
request: {
|
||||
backNavigation: {
|
||||
route: ['/settings', 'reporting-tasks', entity.id],
|
||||
routeBoundary: ['/documentation'],
|
||||
context: 'Reporting Task'
|
||||
},
|
||||
parameters: {
|
||||
select: entity.component.type,
|
||||
group: entity.component.bundle.group,
|
||||
artifact: entity.component.bundle.artifact,
|
||||
version: entity.component.bundle.version
|
||||
}
|
||||
}
|
||||
})
|
||||
);
|
||||
|
|
|
@ -16,12 +16,12 @@
|
|||
*/
|
||||
|
||||
import { createAction, props } from '@ngrx/store';
|
||||
import { DocumentationParameters } from './index';
|
||||
import { DocumentationRequest } from './index';
|
||||
|
||||
export const navigateToComponentDocumentation = createAction(
|
||||
'[Documentation] Navigate To Component Documentation',
|
||||
props<{
|
||||
params: DocumentationParameters;
|
||||
request: DocumentationRequest;
|
||||
}>()
|
||||
);
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { Actions, createEffect, ofType } from '@ngrx/effects';
|
||||
import * as DocumentationActions from './documentation.actions';
|
||||
import { tap } from 'rxjs';
|
||||
import { map, tap } from 'rxjs';
|
||||
import { Router } from '@angular/router';
|
||||
|
||||
@Injectable()
|
||||
|
@ -32,8 +32,13 @@ export class DocumentationEffects {
|
|||
() =>
|
||||
this.actions$.pipe(
|
||||
ofType(DocumentationActions.navigateToComponentDocumentation),
|
||||
tap(() => {
|
||||
this.router.navigate(['/documentation']);
|
||||
map((action) => action.request),
|
||||
tap((request) => {
|
||||
this.router.navigate(['/documentation'], {
|
||||
state: {
|
||||
backNavigation: request.backNavigation
|
||||
}
|
||||
});
|
||||
})
|
||||
),
|
||||
{ dispatch: false }
|
||||
|
|
|
@ -25,9 +25,9 @@ export const initialState: DocumentationState = {
|
|||
|
||||
export const documentationReducer = createReducer(
|
||||
initialState,
|
||||
on(navigateToComponentDocumentation, (state, { params }) => ({
|
||||
on(navigateToComponentDocumentation, (state, { request }) => ({
|
||||
...state,
|
||||
documentationParameters: params
|
||||
documentationParameters: request.parameters
|
||||
})),
|
||||
on(clearDocumentationParameters, (state) => ({
|
||||
...state,
|
||||
|
|
|
@ -15,8 +15,15 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { BackNavigation } from '../navigation';
|
||||
|
||||
export const documentationFeatureKey = 'documentation';
|
||||
|
||||
export interface DocumentationRequest {
|
||||
backNavigation?: BackNavigation;
|
||||
parameters: DocumentationParameters;
|
||||
}
|
||||
|
||||
export interface DocumentationParameters {
|
||||
[key: string]: string;
|
||||
}
|
||||
|
|
|
@ -43,6 +43,8 @@ import { loginConfigurationFeatureKey, LoginConfigurationState } from './login-c
|
|||
import { loginConfigurationReducer } from './login-configuration/login-configuration.reducer';
|
||||
import { propertyVerificationFeatureKey, PropertyVerificationState } from './property-verification';
|
||||
import { propertyVerificationReducer } from './property-verification/property-verification.reducer';
|
||||
import { navigationFeatureKey, NavigationState } from './navigation';
|
||||
import { navigationReducer } from './navigation/navigation.reducer';
|
||||
|
||||
export interface NiFiState {
|
||||
[DEFAULT_ROUTER_FEATURENAME]: RouterReducerState;
|
||||
|
@ -50,6 +52,7 @@ export interface NiFiState {
|
|||
[currentUserFeatureKey]: CurrentUserState;
|
||||
[extensionTypesFeatureKey]: ExtensionTypesState;
|
||||
[aboutFeatureKey]: AboutState;
|
||||
[navigationFeatureKey]: NavigationState;
|
||||
[flowConfigurationFeatureKey]: FlowConfigurationState;
|
||||
[loginConfigurationFeatureKey]: LoginConfigurationState;
|
||||
[statusHistoryFeatureKey]: StatusHistoryState;
|
||||
|
@ -67,6 +70,7 @@ export const rootReducers: ActionReducerMap<NiFiState> = {
|
|||
[currentUserFeatureKey]: currentUserReducer,
|
||||
[extensionTypesFeatureKey]: extensionTypesReducer,
|
||||
[aboutFeatureKey]: aboutReducer,
|
||||
[navigationFeatureKey]: navigationReducer,
|
||||
[flowConfigurationFeatureKey]: flowConfigurationReducer,
|
||||
[loginConfigurationFeatureKey]: loginConfigurationReducer,
|
||||
[statusHistoryFeatureKey]: statusHistoryReducer,
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
||||
export const navigationFeatureKey = 'navigation';
|
||||
|
||||
export interface BackNavigation {
|
||||
route: string[];
|
||||
routeBoundary: string[];
|
||||
context: string;
|
||||
}
|
||||
|
||||
export interface NavigationState {
|
||||
backNavigations: BackNavigation[];
|
||||
}
|
|
@ -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 { createAction, props } from '@ngrx/store';
|
||||
import { BackNavigation } from './index';
|
||||
|
||||
export const pushBackNavigation = createAction(
|
||||
'[Navigation] Push Back Navigation',
|
||||
props<{ backNavigation: BackNavigation }>()
|
||||
);
|
||||
|
||||
export const popBackNavigation = createAction('[Navigation] Pop Back Navigation', props<{ url: string }>());
|
|
@ -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 { createReducer, on } from '@ngrx/store';
|
||||
import { NavigationState } from './index';
|
||||
import { popBackNavigation, pushBackNavigation } from './navigation.actions';
|
||||
import { produce } from 'immer';
|
||||
|
||||
export const initialState: NavigationState = {
|
||||
backNavigations: []
|
||||
};
|
||||
|
||||
export const navigationReducer = createReducer(
|
||||
initialState,
|
||||
on(pushBackNavigation, (state, { backNavigation }) => {
|
||||
return produce(state, (draftState) => {
|
||||
if (draftState.backNavigations.length > 0) {
|
||||
const currentBackNavigation = draftState.backNavigations[draftState.backNavigations.length - 1];
|
||||
|
||||
// don't push multiple back navigations going to the same route
|
||||
if (routesNotEqual(currentBackNavigation.route, backNavigation.route)) {
|
||||
draftState.backNavigations.push(backNavigation);
|
||||
}
|
||||
} else {
|
||||
draftState.backNavigations.push(backNavigation);
|
||||
}
|
||||
});
|
||||
}),
|
||||
on(popBackNavigation, (state, { url }) => {
|
||||
return produce(state, (draftState) => {
|
||||
// pop any back navigation that is outside the bounds of the current url
|
||||
while (draftState.backNavigations.length > 0) {
|
||||
const lastBackNavigation = draftState.backNavigations[draftState.backNavigations.length - 1];
|
||||
if (!url.startsWith(lastBackNavigation.routeBoundary.join('/'))) {
|
||||
draftState.backNavigations.pop();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
function routesNotEqual(route1: string[], route2: string[]) {
|
||||
if (route1.length !== route2.length) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (let i = 0; i < route1.length; i++) {
|
||||
if (route1[i] !== route2[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* 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 { navigationFeatureKey, NavigationState } from './index';
|
||||
|
||||
export const selectNavigationState = createFeatureSelector<NavigationState>(navigationFeatureKey);
|
||||
|
||||
export const selectBackNavigation = createSelector(selectNavigationState, (state: NavigationState) => {
|
||||
if (state.backNavigations.length > 0) {
|
||||
return state.backNavigations[state.backNavigations.length - 1];
|
||||
}
|
||||
|
||||
return null;
|
||||
});
|
|
@ -135,6 +135,7 @@ export interface EditControllerServiceDialogRequest {
|
|||
export interface UpdateControllerServiceRequest {
|
||||
payload: any;
|
||||
postUpdateNavigation?: string[];
|
||||
postUpdateNavigationBoundary?: string[];
|
||||
}
|
||||
|
||||
export interface SetEnableControllerServiceDialogRequest {
|
||||
|
|
|
@ -21,16 +21,18 @@ import { AdvancedUi } from './advanced-ui.component';
|
|||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { Component } from '@angular/core';
|
||||
import { provideMockStore } from '@ngrx/store/testing';
|
||||
import { initialState } from '../../../state/documentation/documentation.reducer';
|
||||
import { HttpClientTestingModule } from '@angular/common/http/testing';
|
||||
import { selectCurrentUser } from '../../../state/current-user/current-user.selectors';
|
||||
import * as fromUser from '../../../state/current-user/current-user.reducer';
|
||||
import * as fromNavigation from '../../../state/navigation/navigation.reducer';
|
||||
import { selectClusterSummary } from '../../../state/cluster-summary/cluster-summary.selectors';
|
||||
import * as fromClusterSummary from '../../../state/cluster-summary/cluster-summary.reducer';
|
||||
import { selectFlowConfiguration } from '../../../state/flow-configuration/flow-configuration.selectors';
|
||||
import * as fromFlowConfiguration from '../../../state/flow-configuration/flow-configuration.reducer';
|
||||
import { selectLoginConfiguration } from '../../../state/login-configuration/login-configuration.selectors';
|
||||
import * as fromLoginConfiguration from '../../../state/login-configuration/login-configuration.reducer';
|
||||
import { currentUserFeatureKey } from '../../../state/current-user';
|
||||
import { navigationFeatureKey } from '../../../state/navigation';
|
||||
|
||||
describe('AdvancedUi', () => {
|
||||
let component: AdvancedUi;
|
||||
|
@ -48,7 +50,10 @@ describe('AdvancedUi', () => {
|
|||
imports: [AdvancedUi, HttpClientTestingModule, RouterTestingModule, MockNavigation],
|
||||
providers: [
|
||||
provideMockStore({
|
||||
initialState,
|
||||
initialState: {
|
||||
[currentUserFeatureKey]: fromUser.initialState,
|
||||
[navigationFeatureKey]: fromNavigation.initialState
|
||||
},
|
||||
selectors: [
|
||||
{
|
||||
selector: selectCurrentUser,
|
||||
|
|
|
@ -28,8 +28,10 @@
|
|||
@if (hasSubMenu(item)) {
|
||||
@if (menuComponent.menu; as subMenu) {
|
||||
<button class="context-menu-item pl-1 pr-1 pt-2 pb-2" cdkMenuItem [cdkMenuTriggerFor]="subMenu">
|
||||
<div class="context-menu-item-img" [class]="item.clazz"></div>
|
||||
<div class="context-menu-item-text surface-contrast">{{ item.text }}</div>
|
||||
<div class="flex gap-x-1">
|
||||
<div class="context-menu-item-img" [class]="item.clazz"></div>
|
||||
<div class="context-menu-item-text surface-contrast">{{ item.text }}</div>
|
||||
</div>
|
||||
<div class="context-menu-group-item-img fa fa-caret-right"></div>
|
||||
</button>
|
||||
}
|
||||
|
@ -42,7 +44,7 @@
|
|||
class="context-menu-item pl-1 pr-1 pt-2 pb-2 flex justify-between"
|
||||
(click)="menuItemClicked(item, $event)"
|
||||
cdkMenuItem>
|
||||
<div class="flex">
|
||||
<div class="flex gap-x-1">
|
||||
<div class="context-menu-item-img" [class]="item.clazz"></div>
|
||||
<div class="context-menu-item-text surface-contrast">{{ item.text }}</div>
|
||||
</div>
|
||||
|
|
|
@ -167,16 +167,13 @@
|
|||
</button>
|
||||
}
|
||||
@if (canManageAccessPolicies()) {
|
||||
<button
|
||||
mat-menu-item
|
||||
(click)="$event.stopPropagation()"
|
||||
[routerLink]="getPolicyLink(item)">
|
||||
<button mat-menu-item (click)="manageAccessPoliciesClicked(item)">
|
||||
<i class="fa fa-key primary-color mr-2"></i>
|
||||
Manage Access Policies
|
||||
</button>
|
||||
}
|
||||
} @else {
|
||||
<button mat-menu-item [routerLink]="getServiceLink(item)">
|
||||
<button mat-menu-item (click)="goToControllerServiceClicked(item)">
|
||||
<i class="fa fa-long-arrow-right primary-color mr-2"></i>
|
||||
Go To
|
||||
</button>
|
||||
|
|
|
@ -77,6 +77,7 @@ export class ControllerServiceTable {
|
|||
new EventEmitter<ControllerServiceEntity>();
|
||||
@Output() configureControllerService: EventEmitter<ControllerServiceEntity> =
|
||||
new EventEmitter<ControllerServiceEntity>();
|
||||
@Output() manageAccessPolicies: EventEmitter<ControllerServiceEntity> = new EventEmitter<ControllerServiceEntity>();
|
||||
@Output() openAdvancedUi: EventEmitter<ControllerServiceEntity> = new EventEmitter<ControllerServiceEntity>();
|
||||
@Output() enableControllerService: EventEmitter<ControllerServiceEntity> =
|
||||
new EventEmitter<ControllerServiceEntity>();
|
||||
|
@ -86,6 +87,8 @@ export class ControllerServiceTable {
|
|||
new EventEmitter<ControllerServiceEntity>();
|
||||
@Output() changeControllerServiceVersion: EventEmitter<ControllerServiceEntity> =
|
||||
new EventEmitter<ControllerServiceEntity>();
|
||||
@Output() goToControllerService: EventEmitter<ControllerServiceEntity> =
|
||||
new EventEmitter<ControllerServiceEntity>();
|
||||
|
||||
protected readonly TextTip = TextTip;
|
||||
protected readonly BulletinsTip = BulletinsTip;
|
||||
|
@ -191,12 +194,8 @@ export class ControllerServiceTable {
|
|||
return this.canRead(entity) ? this.nifiCommon.formatBundle(entity.component.bundle) : '';
|
||||
}
|
||||
|
||||
getServiceLink(entity: ControllerServiceEntity): string[] {
|
||||
if (entity.parentGroupId == null) {
|
||||
return ['/settings', 'management-controller-services', entity.id];
|
||||
} else {
|
||||
return ['/process-groups', entity.parentGroupId, 'controller-services', entity.id];
|
||||
}
|
||||
goToControllerServiceClicked(entity: ControllerServiceEntity): void {
|
||||
this.goToControllerService.next(entity);
|
||||
}
|
||||
|
||||
isDisabled(entity: ControllerServiceEntity): boolean {
|
||||
|
@ -259,6 +258,10 @@ export class ControllerServiceTable {
|
|||
this.deleteControllerService.next(entity);
|
||||
}
|
||||
|
||||
manageAccessPoliciesClicked(entity: ControllerServiceEntity): void {
|
||||
this.manageAccessPolicies.next(entity);
|
||||
}
|
||||
|
||||
changeVersionClicked(entity: ControllerServiceEntity) {
|
||||
this.changeControllerServiceVersion.next(entity);
|
||||
}
|
||||
|
@ -275,10 +278,6 @@ export class ControllerServiceTable {
|
|||
return this.flowConfiguration.supportsManagedAuthorizer && this.currentUser.tenantsPermissions.canRead;
|
||||
}
|
||||
|
||||
getPolicyLink(entity: ControllerServiceEntity): string[] {
|
||||
return ['/access-policies', 'read', 'component', 'controller-services', entity.id];
|
||||
}
|
||||
|
||||
select(entity: ControllerServiceEntity): void {
|
||||
this.selectControllerService.next(entity);
|
||||
}
|
||||
|
|
|
@ -166,7 +166,7 @@ export class EditControllerService extends TabbedDialog {
|
|||
return this.nifiCommon.formatBundle(entity.component.bundle);
|
||||
}
|
||||
|
||||
submitForm(postUpdateNavigation?: string[]) {
|
||||
submitForm(postUpdateNavigation?: string[], postUpdateNavigationBoundary?: string[]) {
|
||||
const payload: any = {
|
||||
revision: this.client.getRevision(this.request.controllerService),
|
||||
disconnectedNodeAcknowledged: this.clusterConnectionService.isDisconnectionAcknowledged(),
|
||||
|
@ -188,7 +188,8 @@ export class EditControllerService extends TabbedDialog {
|
|||
|
||||
this.editControllerService.next({
|
||||
payload,
|
||||
postUpdateNavigation
|
||||
postUpdateNavigation,
|
||||
postUpdateNavigationBoundary
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -15,178 +15,188 @@
|
|||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<nav class="nifi-navigation select-none">
|
||||
<div class="flex justify-between items-center h-16 pl-4">
|
||||
<div class="flex">
|
||||
<div class="h-16 w-28 mr-6 relative">
|
||||
<img
|
||||
ngSrc="assets/icons/nifi-logo.svg"
|
||||
fill
|
||||
priority
|
||||
alt="NiFi Logo"
|
||||
class="pointer"
|
||||
[routerLink]="getCanvasLink()" />
|
||||
</div>
|
||||
<ng-content></ng-content>
|
||||
</div>
|
||||
@if (currentUser(); as user) {
|
||||
<div class="flex justify-between items-center gap-x-1">
|
||||
<div class="flex flex-col justify-between items-end gap-y-1">
|
||||
@if (!user.anonymous) {
|
||||
<div class="current-user">{{ user.identity }}</div>
|
||||
}
|
||||
@if (allowLogin(user)) {
|
||||
<a href="#">log in</a>
|
||||
}
|
||||
@if (user.logoutSupported) {
|
||||
<a (click)="logout()">log out</a>
|
||||
}
|
||||
<div class="flex flex-col">
|
||||
<nav class="nifi-navigation select-none">
|
||||
<div class="flex justify-between items-center h-16 pl-4">
|
||||
<div class="flex">
|
||||
<div class="h-16 w-28 mr-6 relative">
|
||||
<img
|
||||
ngSrc="assets/icons/nifi-logo.svg"
|
||||
fill
|
||||
priority
|
||||
alt="NiFi Logo"
|
||||
class="pointer"
|
||||
[routerLink]="getCanvasLink()" />
|
||||
</div>
|
||||
<button
|
||||
mat-button
|
||||
[matMenuTriggerFor]="globalMenu"
|
||||
class="h-16 w-16 flex items-center justify-center icon global-menu">
|
||||
<i class="fa fa-navicon"></i>
|
||||
</button>
|
||||
<mat-menu #globalMenu="matMenu" xPosition="before">
|
||||
<button mat-menu-item class="global-menu-item" [routerLink]="getCanvasLink()">
|
||||
<i class="icon icon-drop primary-color mr-2"></i>
|
||||
Canvas
|
||||
</button>
|
||||
<mat-divider></mat-divider>
|
||||
<button mat-menu-item class="global-menu-item" [routerLink]="['/summary']">
|
||||
<i class="fa fa-table primary-color mr-2"></i>
|
||||
Summary
|
||||
</button>
|
||||
<ng-content></ng-content>
|
||||
</div>
|
||||
@if (currentUser(); as user) {
|
||||
<div class="flex justify-between items-center gap-x-1">
|
||||
<div class="flex flex-col justify-between items-end gap-y-1">
|
||||
@if (!user.anonymous) {
|
||||
<div class="current-user">{{ user.identity }}</div>
|
||||
}
|
||||
@if (allowLogin(user)) {
|
||||
<a href="#">log in</a>
|
||||
}
|
||||
@if (user.logoutSupported) {
|
||||
<a (click)="logout()">log out</a>
|
||||
}
|
||||
</div>
|
||||
<button
|
||||
mat-menu-item
|
||||
class="global-menu-item"
|
||||
[routerLink]="['/counters']"
|
||||
[disabled]="!user.countersPermissions.canRead">
|
||||
<i class="icon icon-counter primary-color mr-2"></i>
|
||||
Counter
|
||||
mat-button
|
||||
[matMenuTriggerFor]="globalMenu"
|
||||
class="h-16 w-16 flex items-center justify-center icon global-menu">
|
||||
<i class="fa fa-navicon"></i>
|
||||
</button>
|
||||
<button mat-menu-item class="global-menu-item" [routerLink]="['/bulletins']">
|
||||
<i class="fa fa-sticky-note-o primary-color mr-2"></i>
|
||||
Bulletin Board
|
||||
</button>
|
||||
<mat-divider></mat-divider>
|
||||
<button
|
||||
mat-menu-item
|
||||
class="global-menu-item"
|
||||
[routerLink]="['/provenance']"
|
||||
[disabled]="!user.provenancePermissions.canRead">
|
||||
<i class="icon icon-provenance primary-color mr-2"></i>
|
||||
Data Provenance
|
||||
</button>
|
||||
<mat-divider></mat-divider>
|
||||
<button
|
||||
mat-menu-item
|
||||
class="global-menu-item"
|
||||
[routerLink]="['/settings']"
|
||||
[disabled]="!user.controllerPermissions.canRead">
|
||||
<i class="fa fa-wrench primary-color mr-2"></i>
|
||||
Controller Settings
|
||||
</button>
|
||||
<button mat-menu-item class="global-menu-item" [routerLink]="['/parameter-contexts']">
|
||||
<i class="fa mr-2"></i>
|
||||
Parameter Contexts
|
||||
</button>
|
||||
@if (clusterSummary()?.clustered) {
|
||||
<mat-menu #globalMenu="matMenu" xPosition="before">
|
||||
<button mat-menu-item class="global-menu-item" [routerLink]="getCanvasLink()">
|
||||
<i class="icon icon-drop primary-color mr-2"></i>
|
||||
Canvas
|
||||
</button>
|
||||
<mat-divider></mat-divider>
|
||||
<button mat-menu-item class="global-menu-item" [routerLink]="['/summary']">
|
||||
<i class="fa fa-table primary-color mr-2"></i>
|
||||
Summary
|
||||
</button>
|
||||
<button
|
||||
mat-menu-item
|
||||
class="global-menu-item"
|
||||
[disabled]="!user.controllerPermissions.canRead"
|
||||
[routerLink]="['/cluster']">
|
||||
<i class="fa fa-cubes primary-color mr-2"></i>
|
||||
Cluster
|
||||
[routerLink]="['/counters']"
|
||||
[disabled]="!user.countersPermissions.canRead">
|
||||
<i class="icon icon-counter primary-color mr-2"></i>
|
||||
Counter
|
||||
</button>
|
||||
}
|
||||
<button mat-menu-item class="global-menu-item" [routerLink]="['/flow-configuration-history']">
|
||||
<i class="fa fa-history primary-color mr-2"></i>
|
||||
Flow Configuration History
|
||||
</button>
|
||||
<button mat-menu-item class="global-menu-item" (click)="viewNodeStatusHistory()">
|
||||
<i class="fa fa-area-chart primary-color mr-2"></i>
|
||||
Node Status History
|
||||
</button>
|
||||
<button
|
||||
mat-menu-item
|
||||
class="global-menu-item"
|
||||
[disabled]="!user.systemPermissions.canRead"
|
||||
(click)="viewSystemDiagnostics()">
|
||||
<i class="fa mr-2"></i>
|
||||
System Diagnostics
|
||||
</button>
|
||||
@if (flowConfiguration(); as flowConfig) {
|
||||
@if (flowConfig.supportsManagedAuthorizer) {
|
||||
<mat-divider></mat-divider>
|
||||
<button mat-menu-item class="global-menu-item" [routerLink]="['/bulletins']">
|
||||
<i class="fa fa-sticky-note-o primary-color mr-2"></i>
|
||||
Bulletin Board
|
||||
</button>
|
||||
<mat-divider></mat-divider>
|
||||
<button
|
||||
mat-menu-item
|
||||
class="global-menu-item"
|
||||
[routerLink]="['/provenance']"
|
||||
[disabled]="!user.provenancePermissions.canRead">
|
||||
<i class="icon icon-provenance primary-color mr-2"></i>
|
||||
Data Provenance
|
||||
</button>
|
||||
<mat-divider></mat-divider>
|
||||
<button
|
||||
mat-menu-item
|
||||
class="global-menu-item"
|
||||
[routerLink]="['/settings']"
|
||||
[disabled]="!user.controllerPermissions.canRead">
|
||||
<i class="fa fa-wrench primary-color mr-2"></i>
|
||||
Controller Settings
|
||||
</button>
|
||||
<button mat-menu-item class="global-menu-item" [routerLink]="['/parameter-contexts']">
|
||||
<i class="fa mr-2"></i>
|
||||
Parameter Contexts
|
||||
</button>
|
||||
@if (clusterSummary()?.clustered) {
|
||||
<button
|
||||
mat-menu-item
|
||||
class="global-menu-item"
|
||||
[routerLink]="['/users']"
|
||||
[disabled]="!user.tenantsPermissions.canRead">
|
||||
<i class="fa fa-users primary-color mr-2"></i>
|
||||
Users
|
||||
[disabled]="!user.controllerPermissions.canRead"
|
||||
[routerLink]="['/cluster']">
|
||||
<i class="fa fa-cubes primary-color mr-2"></i>
|
||||
Cluster
|
||||
</button>
|
||||
<button
|
||||
mat-menu-item
|
||||
class="global-menu-item"
|
||||
[routerLink]="['/access-policies', 'global']"
|
||||
[disabled]="
|
||||
!user.tenantsPermissions.canRead ||
|
||||
!user.policiesPermissions.canRead ||
|
||||
!user.policiesPermissions.canWrite
|
||||
">
|
||||
<i class="fa fa-key primary-color mr-2"></i>
|
||||
Policies
|
||||
</button>
|
||||
<mat-divider></mat-divider>
|
||||
}
|
||||
}
|
||||
<button mat-menu-item class="global-menu-item" [routerLink]="['/documentation']">
|
||||
<i class="fa fa-question-circle primary-color mr-2"></i>
|
||||
Help
|
||||
</button>
|
||||
<button mat-menu-item class="global-menu-item" (click)="viewAbout()">
|
||||
<i class="fa fa-info-circle primary-color mr-2"></i>
|
||||
About
|
||||
</button>
|
||||
<button mat-menu-item [matMenuTriggerFor]="theming">
|
||||
<i class="fa 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)">
|
||||
@if (theme === LIGHT_THEME) {
|
||||
<i class="fa fa-check primary-color mr-2"></i>
|
||||
}
|
||||
@if (theme !== LIGHT_THEME) {
|
||||
<button mat-menu-item class="global-menu-item" [routerLink]="['/flow-configuration-history']">
|
||||
<i class="fa fa-history primary-color mr-2"></i>
|
||||
Flow Configuration History
|
||||
</button>
|
||||
<button mat-menu-item class="global-menu-item" (click)="viewNodeStatusHistory()">
|
||||
<i class="fa fa-area-chart primary-color mr-2"></i>
|
||||
Node Status History
|
||||
</button>
|
||||
<button
|
||||
mat-menu-item
|
||||
class="global-menu-item"
|
||||
[disabled]="!user.systemPermissions.canRead"
|
||||
(click)="viewSystemDiagnostics()">
|
||||
<i class="fa mr-2"></i>
|
||||
System Diagnostics
|
||||
</button>
|
||||
@if (flowConfiguration(); as flowConfig) {
|
||||
@if (flowConfig.supportsManagedAuthorizer) {
|
||||
<mat-divider></mat-divider>
|
||||
<button
|
||||
mat-menu-item
|
||||
class="global-menu-item"
|
||||
[routerLink]="['/users']"
|
||||
[disabled]="!user.tenantsPermissions.canRead">
|
||||
<i class="fa fa-users primary-color mr-2"></i>
|
||||
Users
|
||||
</button>
|
||||
<button
|
||||
mat-menu-item
|
||||
class="global-menu-item"
|
||||
[routerLink]="['/access-policies', 'global']"
|
||||
[disabled]="
|
||||
!user.tenantsPermissions.canRead ||
|
||||
!user.policiesPermissions.canRead ||
|
||||
!user.policiesPermissions.canWrite
|
||||
">
|
||||
<i class="fa fa-key primary-color mr-2"></i>
|
||||
Policies
|
||||
</button>
|
||||
<mat-divider></mat-divider>
|
||||
}
|
||||
}
|
||||
Light
|
||||
</button>
|
||||
<button mat-menu-item class="global-menu-item" (click)="toggleTheme(DARK_THEME)">
|
||||
@if (theme === DARK_THEME) {
|
||||
<i class="fa fa-check primary-color mr-2"></i>
|
||||
}
|
||||
@if (theme !== DARK_THEME) {
|
||||
<button mat-menu-item class="global-menu-item" [routerLink]="['/documentation']">
|
||||
<i class="fa fa-question-circle primary-color mr-2"></i>
|
||||
Help
|
||||
</button>
|
||||
<button mat-menu-item class="global-menu-item" (click)="viewAbout()">
|
||||
<i class="fa fa-info-circle primary-color mr-2"></i>
|
||||
About
|
||||
</button>
|
||||
<button mat-menu-item [matMenuTriggerFor]="theming">
|
||||
<i class="fa mr-2"></i>
|
||||
}
|
||||
Dark
|
||||
</button>
|
||||
<button mat-menu-item class="global-menu-item" (click)="toggleTheme(OS_SETTING)">
|
||||
@if (theme === OS_SETTING || theme === null) {
|
||||
<i class="fa fa-check primary-color mr-2"></i>
|
||||
}
|
||||
@if (theme !== OS_SETTING && theme !== null) {
|
||||
<i class="fa mr-2"></i>
|
||||
}
|
||||
Device
|
||||
</button>
|
||||
</mat-menu>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</nav>
|
||||
Appearance
|
||||
</button>
|
||||
</mat-menu>
|
||||
<mat-menu #theming="matMenu" xPosition="before">
|
||||
<button mat-menu-item class="global-menu-item" (click)="toggleTheme(LIGHT_THEME)">
|
||||
@if (theme === LIGHT_THEME) {
|
||||
<i class="fa fa-check primary-color mr-2"></i>
|
||||
}
|
||||
@if (theme !== LIGHT_THEME) {
|
||||
<i class="fa mr-2"></i>
|
||||
}
|
||||
Light
|
||||
</button>
|
||||
<button mat-menu-item class="global-menu-item" (click)="toggleTheme(DARK_THEME)">
|
||||
@if (theme === DARK_THEME) {
|
||||
<i class="fa fa-check primary-color mr-2"></i>
|
||||
}
|
||||
@if (theme !== DARK_THEME) {
|
||||
<i class="fa mr-2"></i>
|
||||
}
|
||||
Dark
|
||||
</button>
|
||||
<button mat-menu-item class="global-menu-item" (click)="toggleTheme(OS_SETTING)">
|
||||
@if (theme === OS_SETTING || theme === null) {
|
||||
<i class="fa fa-check primary-color mr-2"></i>
|
||||
}
|
||||
@if (theme !== OS_SETTING && theme !== null) {
|
||||
<i class="fa mr-2"></i>
|
||||
}
|
||||
Device
|
||||
</button>
|
||||
</mat-menu>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</nav>
|
||||
@if (backNavigation(); as navigation) {
|
||||
<div class="pl-2 py-2">
|
||||
<a [routerLink]="navigation.route">
|
||||
<i class="fa fa-arrow-left primary-color mr-2"></i>
|
||||
Back to {{ navigation.context }}
|
||||
</a>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
|
|
@ -19,17 +19,19 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|||
|
||||
import { Navigation } from './navigation.component';
|
||||
import { provideMockStore } from '@ngrx/store/testing';
|
||||
import { initialState } from '../../../state/current-user/current-user.reducer';
|
||||
import { HttpClientTestingModule } from '@angular/common/http/testing';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { selectCurrentUser } from '../../../state/current-user/current-user.selectors';
|
||||
import * as fromUser from '../../../state/current-user/current-user.reducer';
|
||||
import * as fromNavigation from '../../../state/navigation/navigation.reducer';
|
||||
import { selectClusterSummary } from '../../../state/cluster-summary/cluster-summary.selectors';
|
||||
import * as fromClusterSummary from '../../../state/cluster-summary/cluster-summary.reducer';
|
||||
import { selectFlowConfiguration } from '../../../state/flow-configuration/flow-configuration.selectors';
|
||||
import * as fromFlowConfiguration from '../../../state/flow-configuration/flow-configuration.reducer';
|
||||
import { selectLoginConfiguration } from '../../../state/login-configuration/login-configuration.selectors';
|
||||
import * as fromLoginConfiguration from '../../../state/login-configuration/login-configuration.reducer';
|
||||
import { currentUserFeatureKey } from '../../../state/current-user';
|
||||
import { navigationFeatureKey } from '../../../state/navigation';
|
||||
|
||||
describe('Navigation', () => {
|
||||
let component: Navigation;
|
||||
|
@ -40,7 +42,10 @@ describe('Navigation', () => {
|
|||
imports: [Navigation, HttpClientTestingModule, RouterTestingModule],
|
||||
providers: [
|
||||
provideMockStore({
|
||||
initialState,
|
||||
initialState: {
|
||||
[currentUserFeatureKey]: fromUser.initialState,
|
||||
[navigationFeatureKey]: fromNavigation.initialState
|
||||
},
|
||||
selectors: [
|
||||
{
|
||||
selector: selectCurrentUser,
|
||||
|
|
|
@ -46,6 +46,7 @@ import {
|
|||
} from '../../../state/cluster-summary/cluster-summary.actions';
|
||||
import { selectClusterSummary } from '../../../state/cluster-summary/cluster-summary.selectors';
|
||||
import { selectLoginConfiguration } from '../../../state/login-configuration/login-configuration.selectors';
|
||||
import { selectBackNavigation } from '../../../state/navigation/navigation.selectors';
|
||||
|
||||
@Component({
|
||||
selector: 'navigation',
|
||||
|
@ -70,10 +71,12 @@ export class Navigation implements OnInit, OnDestroy {
|
|||
LIGHT_THEME: string = LIGHT_THEME;
|
||||
DARK_THEME: string = DARK_THEME;
|
||||
OS_SETTING: string = OS_SETTING;
|
||||
|
||||
currentUser = this.store.selectSignal(selectCurrentUser);
|
||||
flowConfiguration = this.store.selectSignal(selectFlowConfiguration);
|
||||
loginConfiguration = this.store.selectSignal(selectLoginConfiguration);
|
||||
clusterSummary = this.store.selectSignal(selectClusterSummary);
|
||||
backNavigation = this.store.selectSignal(selectBackNavigation);
|
||||
|
||||
constructor(
|
||||
private store: Store<NiFiState>,
|
||||
|
|
Loading…
Reference in New Issue