rfellows commented on code in PR #8191:
URL: https://github.com/apache/nifi/pull/8191#discussion_r1437892895
##
nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/users/ui/user-listing/user-access-policies/user-access-policies.component.html:
##
@@ -0,0 +1,82 @@
+
+
+
+User Policies
+
+User
+{{ request.identity }}
+
+
+
+
+
+
+Policy
+
+
+{{ formatPolicy(item) }}
+
+
+{{ item.id }}
+
+
+
+
+
+
+Action
+
+{{ item.component.action }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Some policies may be inherited by descendant components
unless explicitly overridden.
+
+Close
+
+
Review Comment:
This dialog is too wide when opened. Also, consider using `mat-dialog-title`
`` and `` to identify the dialog
structure.
##
nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/users/ui/user-listing/user-table/user-table.component.ts:
##
@@ -0,0 +1,245 @@
+/*
+ * 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 { AfterViewInit, Component, EventEmitter, Input, Output } from
'@angular/core';
+import { MatTableDataSource } from '@angular/material/table';
+import { Sort } from '@angular/material/sort';
+import { FormBuilder, FormGroup } from '@angular/forms';
+import { debounceTime } from 'rxjs';
+import { NiFiCommon } from '../../../../../service/nifi-common.service';
+import { CurrentUser } from '../../../../../state/current-user';
+import { AccessPolicySummaryEntity, UserEntity, UserGroupEntity } from
'../../../../../state/shared';
+
+export interface TenantItem {
+id: string;
+user: string;
+tenantType: 'user' | 'userGroup';
+membership: string[];
+configurable: boolean;
+}
+
+export interface Tenants {
+users: UserEntity[];
+userGroups: UserGroupEntity[];
+}
+
+@Component({
+selector: 'user-table',
+templateUrl: './user-table.component.html',
+styleUrls: ['./user-table.component.scss',
'../../../../../../assets/styles/listing-table.scss']
+})
+export class UserTable implements AfterViewInit {
+filterTerm: string = '';
+filterColumn: 'user' | 'membership' = 'user';
+totalCount: number = 0;
+filteredCount: number = 0;
+
+displayedColumns: string[] = ['user', 'membership', 'actions'];
+dataSource: MatTableDataSource = new
MatTableDataSource();
+filterForm: FormGroup;
+
+userLookup: Map = new Map();
+userGroupLookup: Map = new Map();
+
+@Input() set tenants(tenants: Tenants) {
+this.userLookup.clear();
+this.userGroupLookup.clear();
+
+const tenantItems: TenantItem[] = [];
+tenants.users.forEach((user) => {
+this.userLookup.set(user.id, user);
+tenantItems.push({
+id: user.id,
+tenantType: 'user',
+user: user.component.identity,
+membership: user.component.userGroups.map((userGroup) =>
userGroup.component.identity),
+configurable: user.component.configurable
+});
+});
+tenants.userGroups.forEach((userGroup) => {
+this.userGroupLookup.set(userGroup.id, userGroup);
+tenantItems.push({
+id: userGroup.id,
+tenantType: 'userGroup',
+user: userGroup.component.identity,
+membership: userGroup.component.users.map((user) =>
user.component.identity),
+configurable: userGroup.component.configurable
+});
+});
+
+