Skip to content

Commit

Permalink
user follow enhancements (#492)
Browse files Browse the repository at this point in the history
* user follow enhancements

- display last vm and last seen in user follow list
- renamed User List to User Follow
- added recentOnly filter
  • Loading branch information
sei-aschlackman authored May 21, 2024
1 parent 7634d1f commit 930c610
Show file tree
Hide file tree
Showing 12 changed files with 1,451 additions and 86 deletions.
1,310 changes: 1,261 additions & 49 deletions package-lock.json

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"license": "MIT",
"config": {
"openapiArgs": "--additional-properties ngVersion=14.2 --additional-properties modelPropertyNaming=original --type-mappings=DateTime=string",
"deleteGeneratedCommand": "rimraf src/app/generated/vm-api/*"
"deleteGeneratedCommand": "rimraf src/app/generated/vm-api/"
},
"scripts": {
"ng": "ng",
Expand Down Expand Up @@ -65,6 +65,7 @@
"@types/jasmine": "^5.1.4",
"@types/jasminewd2": "^2.0.13",
"cross-env": "^7.0.3",
"cross-var": "^1.1.0",
"jasmine-core": "^5.1.2",
"jasmine-spec-reporter": "^7.0.0",
"karma": "^6.4.3",
Expand Down
62 changes: 45 additions & 17 deletions src/app/components/user-list/team-users/team-users.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -18,35 +18,29 @@
headerHeight="headerSize"
[ngStyle]="{ height: tableHeight }"
>
<mat-table [dataSource]="userDatasource" class="mat-elevation-z8">
<mat-table [dataSource]="userDatasource" matSort class="mat-elevation-z8">
<!-- Name Column -->
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef>Name</mat-header-cell>
<ng-container matColumnDef="username">
<mat-header-cell *matHeaderCellDef mat-sort-header
>Name</mat-header-cell
>
<mat-cell *matCellDef="let element">
<div class="open-tab-icon">
<button
mat-icon-button
style="outline: none"
class="text"
(click)="openInTab(element)"
matTooltip="Follow {{ element.username }} in new browser tab"
>
<mat-icon class="tab-icon" svgIcon="ic_open_tab"></mat-icon>
</button>
</div>
<a
class="link"
(click)="openHere($event, element)"
(click)="openUserHere($event, element)"
matTooltip="Follow {{ element.username }}"
[attr.href]="getFollowUrl(element)"
>
{{ element.username }}
</a>
</mat-cell>
</ng-container>

<!-- Vm Column -->
<ng-container matColumnDef="vm">
<mat-header-cell *matHeaderCellDef>Virtual Machine</mat-header-cell>
<ng-container matColumnDef="activeVmId">
<mat-header-cell *matHeaderCellDef mat-sort-header
>Virtual Machine</mat-header-cell
>
<mat-cell *matCellDef="let element">
<div
*ngIf="
Expand All @@ -62,6 +56,40 @@
</mat-cell>
</ng-container>

<!-- LastVm Column -->
<ng-container matColumnDef="lastVmId">
<mat-header-cell *matHeaderCellDef mat-sort-header
>Last Virtual Machine</mat-header-cell
>
<mat-cell *matCellDef="let element">
<a
*ngIf="
this.vmsQuery.selectEntity(element.lastVmId) | async as vm;
else noVm
"
class="link"
(click)="openVmHere($event, vm.url, vm.name)"
matTooltip="Open {{ vm.name }}"
[attr.href]="getVmUrl(vm.url)"
>
{{ vm.name }}
</a>
<ng-template #noVm>
<div>None</div>
</ng-template>
</mat-cell>
</ng-container>

<!-- LastSeen Column -->
<ng-container matColumnDef="lastSeen">
<mat-header-cell *matHeaderCellDef mat-sort-header
>Last Seen</mat-header-cell
>
<mat-cell *matCellDef="let element">
<div>{{ element.lastSeen | date: 'short' }}</div>
</mat-cell>
</ng-container>

<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
</mat-table>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
.link {
text-decoration: underline;
cursor: pointer;
color: var(--mat-app-text-color, inherit);
}

.user-spacing {
Expand Down
92 changes: 77 additions & 15 deletions src/app/components/user-list/team-users/team-users.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import {
Input,
Output,
EventEmitter,
ViewChild,
AfterViewInit,
} from '@angular/core';
import { ComnSettingsService } from '@cmusei/crucible-common';
import {
Expand All @@ -34,14 +36,15 @@ import {
MatRowDef,
MatRow,
} from '@angular/material/table';
import { NgStyle, NgIf, AsyncPipe } from '@angular/common';
import { NgStyle, NgIf, AsyncPipe, DatePipe } from '@angular/common';
import { CdkVirtualScrollViewport } from '@angular/cdk/scrolling';
import {
MatExpansionPanel,
MatExpansionPanelHeader,
MatExpansionPanelTitle,
MatExpansionPanelDescription,
} from '@angular/material/expansion';
import { MatSort, MatSortModule } from '@angular/material/sort';

@Component({
selector: 'app-team-users',
Expand Down Expand Up @@ -72,16 +75,28 @@ import {
MatRowDef,
MatRow,
AsyncPipe,
DatePipe,
MatSortModule,
],
})
export class TeamUsersComponent {
export class TeamUsersComponent implements AfterViewInit {
@Input() team: VmTeam = null;

@Input() set hideInactive(val: boolean) {
this.hideInactiveInternal = val;
this.updateDataSource();
}

@Input() set recentOnly(val: boolean) {
this.recentOnlyInternal = val;
this.updateDataSource();
}

@Input() set recentMinutes(val: number) {
this.recentMinutesInternal = val;
this.updateDataSource();
}

@Input() set users(val: Array<VmUser>) {
this.userList = val;
this.updateDataSource();
Expand All @@ -96,16 +111,25 @@ export class TeamUsersComponent {

private userList: Array<VmUser>;
private hideInactiveInternal = false;
private recentOnlyInternal = false;
private recentMinutesInternal = 0;

public userDatasource = new TableVirtualScrollDataSource<VmUser>(
new Array<VmUser>(),
);
public displayedColumns: string[] = ['name', 'vm'];
public displayedColumns: string[] = [
'username',
'activeVmId',
'lastVmId',
'lastSeen',
];
public itemSize = 48;
public headerSize = 56;
public maxSize = this.itemSize * 7;
public tableHeight = '0px';

@ViewChild(MatSort) sort: MatSort;

constructor(
public vmsQuery: VmsQuery,
private settingsService: ComnSettingsService,
Expand All @@ -116,18 +140,33 @@ export class TeamUsersComponent {
};
}

public openInTab(user: VmUser) {
window.open(this.getUrl(user), '_blank');
ngAfterViewInit() {
this.userDatasource.sort = this.sort;
}

public openHere($event, user: VmUser) {
public openUserInTab(user: VmUser) {
window.open(this.getFollowUrl(user), '_blank');
}

public openUserHere($event, user: VmUser) {
$event.preventDefault();
const url = this.getUrl(user);
const url = this.getFollowUrl(user);
const val = <{ [name: string]: string }>{ name: user.username, url };
this.openTab.emit(val);
}

private getUrl(user: VmUser) {
public openInTab(url: string) {
window.open(this.getThemedUrl(url), '_blank');
}

public openVmHere($event, url: string, tabName: string) {
$event.preventDefault();
const vmUrl = this.getVmUrl(url);
const val = <{ [name: string]: string }>{ name: tabName, url: vmUrl };
this.openTab.emit(val);
}

public getFollowUrl(user: VmUser) {
return this.themeService.addThemeQueryParam(
this.settingsService.settings.UserFollowUrl.replace(
'{userId}',
Expand All @@ -136,14 +175,37 @@ export class TeamUsersComponent {
);
}

public getVmUrl(url: string) {
const val = new URL(url);
val.searchParams.set('readOnly', 'true');
return this.getThemedUrl(val.toString());
}

public getThemedUrl(url: string) {
return this.themeService.addThemeQueryParam(url);
}

private updateDataSource() {
if (this.hideInactiveInternal) {
this.userDatasource.data = this.userList.filter(
(x) => x.activeVmId != null,
);
} else {
this.userDatasource.data = this.userList;
}
const recent = new Date();
recent.setMinutes(recent.getMinutes() - this.recentMinutesInternal);

this.userDatasource.data = this.userList.filter((x) => {
let filter = true;

if (this.hideInactiveInternal) {
filter = x.activeVmId != null;
}

if (this.recentOnlyInternal) {
if (!x.lastSeen) {
return false;
}
const time = new Date(x.lastSeen);
filter = filter && time > recent;
}

return filter;
});

this.calculateTableHeight();
}
Expand Down
38 changes: 38 additions & 0 deletions src/app/components/user-list/user-list.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,42 @@
(change)="setHideInactive($event.checked)"
>Hide Inactive</mat-checkbox
>
<mat-checkbox
class="search-checkbox text"
color="primary"
(change)="setRecentOnly($event.checked)"
>Recent Only</mat-checkbox
>
<mat-form-field *ngIf="recentOnly" matTooltip="Time to filter recent by">
<mat-select required [(ngModel)]="recentMinutes">
<mat-option [value]="15">15 minutes</mat-option>
<mat-option [value]="30">30 minutes</mat-option>
<mat-option [value]="45">45 minutes</mat-option>
<mat-option [value]="60">1 hour</mat-option>
<mat-option [value]="120">2 hours</mat-option>
<mat-option [value]="180">3 hours</mat-option>
<mat-option [value]="240">4 hours</mat-option>
<mat-option [value]="300">5 hours</mat-option>
<mat-option [value]="360">6 hours</mat-option>
<mat-option [value]="1440">1 day</mat-option>
<mat-option [value]="2880">2 days</mat-option>
<mat-option [value]="4320">3 days</mat-option>
<mat-option [value]="5760">4 days</mat-option>
<mat-option [value]="7200">5 days</mat-option>
<mat-option [value]="8640">6 days</mat-option>
<mat-option [value]="10080">1 week</mat-option>
<mat-option [value]="20160">2 weeks</mat-option>
<mat-option [value]="30240">3 weeks</mat-option>
<mat-option [value]="43800">1 month</mat-option>
<mat-option [value]="87600">2 months</mat-option>
<mat-option [value]="131400">3 months</mat-option>
<mat-option [value]="175200">4 months</mat-option>
<mat-option [value]="219000">5 months</mat-option>
<mat-option [value]="262800">6 months</mat-option>
<mat-option [value]="525960">1 year</mat-option>
<mat-option [value]="1.052e6">2 years</mat-option>
</mat-select>
</mat-form-field>
</div>

<mat-accordion multi>
Expand All @@ -44,6 +80,8 @@
[users]="userQueryMap.get(team.id) | async"
[searchTerm]="searchTerm$ | async"
[hideInactive]="hideInactive"
[recentOnly]="recentOnly"
[recentMinutes]="recentMinutes"
(openTab)="onOpenTab($event)"
></app-team-users>
</div>
Expand Down
11 changes: 10 additions & 1 deletion src/app/components/user-list/user-list.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import {
MatPrefix,
MatSuffix,
} from '@angular/material/form-field';
import { MatOption, MatSelect } from '@angular/material/select';

@Component({
selector: 'app-user-list',
Expand All @@ -55,12 +56,14 @@ import {
NgFor,
TeamUsersComponent,
AsyncPipe,
MatOption,
MatSelect,
],
})
export class UserListComponent {
@Input() viewId: string;
@Input() set teams(val: Array<VmTeam>) {
this._teams = val;
this._teams = val.sort((a, b) => a.name.localeCompare(b.name));
this.userQueryMap.clear();

val.forEach((t) => {
Expand All @@ -80,6 +83,8 @@ export class UserListComponent {

public _teams: Array<VmTeam>;
public hideInactive = false;
public recentOnly = false;
public recentMinutes = 15;

@ViewChild(MatAccordion) accordion: MatAccordion;

Expand Down Expand Up @@ -117,6 +122,10 @@ export class UserListComponent {
this.hideInactive = value;
}

public setRecentOnly(value: boolean) {
this.recentOnly = value;
}

public trackByTeamId(item: VmTeam) {
return item.id;
}
Expand Down
2 changes: 1 addition & 1 deletion src/app/components/vm-main/vm-main.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
(showIPv4OnlySelectedChanged)="showIPv4OnlySelectedChanged($event)"
></app-vm-list>
</mat-tab>
<mat-tab label="User List" #userTab>
<mat-tab label="User Follow" #userTab>
<ng-template matTabContent>
<app-user-list
[viewId]="getCurrentViewId()"
Expand Down
1 change: 1 addition & 0 deletions src/app/generated/vm-api/.openapi-generator/FILES
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
.gitignore
.openapi-generator-ignore
README.md
api.module.ts
api/api.ts
Expand Down
2 changes: 2 additions & 0 deletions src/app/generated/vm-api/model/vmUser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,7 @@ export interface VmUser {
* Id of the Vm this User is currently viewing, if any
*/
activeVmId?: string | null;
lastVmId?: string | null;
lastSeen?: string | null;
}

Loading

0 comments on commit 930c610

Please sign in to comment.