Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Show more info about the routes in the manager #645

Merged
merged 1 commit into from
Dec 22, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@
routeRule.forwardFields.nextTid :
routeRule.intermediaryForwardFields.nextTid
}}
{{
getLabel(routeRule.forwardFields ?
routeRule.forwardFields.nextTid :
routeRule.intermediaryForwardFields.nextTid)
}}
</div>
</div>

Expand All @@ -69,6 +74,11 @@
routeRule.appFields.routeDescriptor.dstPk :
routeRule.forwardFields.routeDescriptor.dstPk
}}
{{
getLabel(routeRule.appFields ?
routeRule.appFields.routeDescriptor.dstPk :
routeRule.forwardFields.routeDescriptor.dstPk)
}}
</div>
<div class="item">
<span>{{ 'routes.details.specific-fields.source-pk' | translate }}</span>
Expand All @@ -77,6 +87,11 @@
routeRule.appFields.routeDescriptor.srcPk :
routeRule.forwardFields.routeDescriptor.srcPk
}}
{{
getLabel(routeRule.appFields ?
routeRule.appFields.routeDescriptor.srcPk :
routeRule.forwardFields.routeDescriptor.srcPk)
}}
</div>
<div class="item">
<span>{{ 'routes.details.specific-fields.destination-port' | translate }}</span>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { MatDialogRef, MAT_DIALOG_DATA, MatDialog, MatDialogConfig } from '@angu

import { AppConfig } from 'src/app/app.config';
import { Route } from 'src/app/app.datatypes';
import { StorageService } from 'src/app/services/storage.service';

/**
* Modal window for showing the details of a route.
Expand Down Expand Up @@ -39,6 +40,7 @@ export class RouteDetailsComponent {
constructor(
@Inject(MAT_DIALOG_DATA) data: Route,
private dialogRef: MatDialogRef<RouteDetailsComponent>,
private storageService: StorageService,
) {
this.routeRule = data;
}
Expand All @@ -54,4 +56,17 @@ export class RouteDetailsComponent {
closePopup() {
this.dialogRef.close();
}

/**
* Gets the label the user has set for an ID or pk.
*/
getLabel(id: string) {
const label = this.storageService.getLabelInfo(id);

if (label) {
return ' (' + label.label + ')';
}

return '';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,17 @@
{{ 'routes.key' | translate }}
<mat-icon *ngIf="dataSorter.currentSortingColumn === keySortData" [inline]="true">{{ dataSorter.sortingArrow }}</mat-icon>
</th>
<th class="sortable-column" (click)="dataSorter.changeSortingOrder(ruleSortData)">
{{ 'routes.rule' | translate }}
<mat-icon *ngIf="dataSorter.currentSortingColumn === ruleSortData" [inline]="true">{{ dataSorter.sortingArrow }}</mat-icon>
<th class="sortable-column" (click)="dataSorter.changeSortingOrder(typeSortData)">
{{ 'routes.type' | translate }}
<mat-icon *ngIf="dataSorter.currentSortingColumn === typeSortData" [inline]="true">{{ dataSorter.sortingArrow }}</mat-icon>
</th>
<th class="sortable-column" (click)="dataSorter.changeSortingOrder(sourceSortData)">
{{ 'routes.source' | translate }}
<mat-icon *ngIf="dataSorter.currentSortingColumn === sourceSortData" [inline]="true">{{ dataSorter.sortingArrow }}</mat-icon>
</th>
<th class="sortable-column" (click)="dataSorter.changeSortingOrder(destinationSortData)">
{{ 'routes.destination' | translate }}
<mat-icon *ngIf="dataSorter.currentSortingColumn === destinationSortData" [inline]="true">{{ dataSorter.sortingArrow }}</mat-icon>
</th>
<th class="actions"></th>
</tr>
Expand All @@ -85,8 +93,47 @@
{{ route.key }}
</td>
<td>
<app-copy-to-clipboard-text [text]="route.rule"></app-copy-to-clipboard-text>
{{ getTypeName(route.type) }}
</td>
<!-- Source and destination for app and forward routes. -->
<ng-container *ngIf="route.appFields || route.forwardFields">
<td>
<app-labeled-element-text
[short]="true"
id="{{ route.src }}"
shortTextLength="7"
(labelEdited)="refreshData()"
[elementType]="labeledElementTypes.Node">
</app-labeled-element-text>
</td>
<td>
<app-labeled-element-text
[short]="true"
id="{{ route.dst }}"
shortTextLength="7"
(labelEdited)="refreshData()"
[elementType]="labeledElementTypes.Node">
</app-labeled-element-text>
</td>
</ng-container>
<!-- Source and destination for intermediary forward routes. -->
<ng-container *ngIf="(!route.appFields && !route.forwardFields) && route.intermediaryForwardFields">
<td>---</td>
<td>
<app-labeled-element-text
[short]="true"
id="{{ route.dst }}"
shortTextLength="5"
(labelEdited)="refreshData()"
[elementType]="labeledElementTypes.Transport">
</app-labeled-element-text>
</td>
</ng-container>
<!-- Source and destination for special cases. -->
<ng-container *ngIf="!route.appFields && !route.forwardFields && !route.intermediaryForwardFields">
<td>---</td>
<td>---</td>
</ng-container>
<td class="actions">
<button
(click)="details(route)"
Expand Down Expand Up @@ -144,9 +191,54 @@
{{ route.key }}
</div>
<div class="list-row long-content">
<span class="title">{{ 'routes.rule' | translate }}</span>:
<app-copy-to-clipboard-text text="{{ route.rule }}"></app-copy-to-clipboard-text>
<span class="title">{{ 'routes.type' | translate }}</span>:
{{ getTypeName(route.type) }}
</div>
<!-- Source and destination for app and forward routes. -->
<ng-container *ngIf="route.appFields || route.forwardFields">
<div class="list-row long-content">
<span class="title">{{ 'routes.source' | translate }}</span>:
<app-labeled-element-text
id="{{ route.src }}"
(labelEdited)="refreshData()"
[elementType]="labeledElementTypes.Node">
</app-labeled-element-text>
</div>
<div class="list-row long-content">
<span class="title">{{ 'routes.destination' | translate }}</span>:
<app-labeled-element-text
id="{{ route.dst }}"
(labelEdited)="refreshData()"
[elementType]="labeledElementTypes.Node">
</app-labeled-element-text>
</div>
</ng-container>
<!-- Source and destination for intermediary forward routes. -->
<ng-container *ngIf="(!route.appFields && !route.forwardFields) && route.intermediaryForwardFields">
<div class="list-row long-content">
<span class="title">{{ 'routes.source' | translate }}</span>:
---
</div>
<div class="list-row long-content">
<span class="title">{{ 'routes.destination' | translate }}</span>:
<app-labeled-element-text
id="{{ route.dst }}"
(labelEdited)="refreshData()"
[elementType]="labeledElementTypes.Transport">
</app-labeled-element-text>
</div>
</ng-container>
<!-- Source and destination for special cases. -->
<ng-container *ngIf="!route.appFields && !route.forwardFields && !route.intermediaryForwardFields">
<div class="list-row long-content">
<span class="title">{{ 'routes.source' | translate }}</span>:
---
</div>
<div class="list-row long-content">
<span class="title">{{ 'routes.destination' | translate }}</span>:
---
</div>
</ng-container>
</div>
<div class="margin-part"></div>
<div class="right-part">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import { TranslateService } from '@ngx-translate/core';
import { FilterProperties, FilterFieldTypes } from 'src/app/utils/filters';
import { SortingColumn, SortingModes, DataSorter } from 'src/app/utils/lists/data-sorter';
import { DataFilterer } from 'src/app/utils/lists/data-filterer';
import { LabeledElementTextComponent } from 'src/app/components/layout/labeled-element-text/labeled-element-text.component';
import { LabeledElementTypes, StorageService } from 'src/app/services/storage.service';

/**
* Shows the list of routes of a node. I can be used to show a short preview, with just some
Expand All @@ -36,7 +38,11 @@ export class RouteListComponent implements OnDestroy {

// Vars with the data of the columns used for sorting the data.
keySortData = new SortingColumn(['key'], 'routes.key', SortingModes.Number);
ruleSortData = new SortingColumn(['rule'], 'routes.rule', SortingModes.Text);
typeSortData = new SortingColumn(['type'], 'routes.type', SortingModes.Number);
sourceSortData = new SortingColumn(['src'], 'routes.source', SortingModes.Text, ['src_label']);
destinationSortData = new SortingColumn(['dst'], 'routes.destination', SortingModes.Text, ['dst_label']);

labeledElementTypes = LabeledElementTypes;

private dataSortedSubscription: Subscription;
private dataFiltererSubscription: Subscription;
Expand Down Expand Up @@ -72,6 +78,42 @@ export class RouteListComponent implements OnDestroy {
@Input() set routes(val: Route[]) {
this.allRoutes = val;

// Include additional properties with helpful data. Mostly for displating the data and for
// using the filterer and sorter objects.
this.allRoutes.forEach(route => {
// Save the type in the root of the object to be able to use it with the filterer.
if (route.ruleSummary.ruleType || route.ruleSummary.ruleType === 0) {
route['type'] = route.ruleSummary.ruleType;
} else {
route['type'] = '';
}

if (route.appFields || route.forwardFields) {
const routeDescriptor = route.appFields ? route.appFields.routeDescriptor : route.forwardFields.routeDescriptor;

// Save the source and destination visor keys and the associated labels.
route['src'] = routeDescriptor.srcPk;
route['src_label'] =
LabeledElementTextComponent.getCompleteLabel(this.storageService, this.translateService, route['src']);
route['dst'] = routeDescriptor.dstPk;
route['dst_label'] =
LabeledElementTextComponent.getCompleteLabel(this.storageService, this.translateService, route['dst']);
} else if (route.intermediaryForwardFields) {
// Save the destination transport id and the associated label. There is no source transport.
route['src'] = '';
route['src_label'] = '';
route['dst'] = route.intermediaryForwardFields.nextTid;
route['dst_label'] =
LabeledElementTextComponent.getCompleteLabel(this.storageService, this.translateService, route['dst']);
} else {
// Special case.
route['src'] = '';
route['src_label'] = '';
route['dst'] = '';
route['dst_label'] = '';
}
});

this.dataFilterer.setData(this.allRoutes);
}

Expand All @@ -84,13 +126,30 @@ export class RouteListComponent implements OnDestroy {
maxlength: 8,
},
{
filterName: 'routes.filter-dialog.rule',
keyNameInElementsArray: 'rule',
filterName: 'routes.filter-dialog.source',
keyNameInElementsArray: 'src',
secondaryKeyNameInElementsArray: 'src_label',
type: FilterFieldTypes.TextInput,
maxlength: 150,
}
maxlength: 66,
},
{
filterName: 'routes.filter-dialog.destination',
keyNameInElementsArray: 'dst',
secondaryKeyNameInElementsArray: 'dst_label',
type: FilterFieldTypes.TextInput,
maxlength: 66,
},
];

/**
* Map with the types of route rules that the hypervisor can return and are known by this app.
*/
private ruleTypes = new Map<number, string>([
[0, 'App'],
[1, 'Forward'],
[2, 'Int. forward']
]);

private navigationsSubscription: Subscription;
private operationSubscriptionsGroup: Subscription[] = [];

Expand All @@ -101,18 +160,42 @@ export class RouteListComponent implements OnDestroy {
private router: Router,
private snackbarService: SnackbarService,
private translateService: TranslateService,
private storageService: StorageService,
) {
// Initialize the data sorter.
const sortableColumns: SortingColumn[] = [
this.keySortData,
this.ruleSortData,
this.typeSortData,
this.sourceSortData,
this.destinationSortData,
];
this.dataSorter = new DataSorter(this.dialog, this.translateService, sortableColumns, 0, this.listId);
this.dataSortedSubscription = this.dataSorter.dataSorted.subscribe(() => {
// When this happens, the data in allRoutes has already been sorted.
this.recalculateElementsToShow();
});

// Include the known route types in the filterer config array.
const typeFilterConfig: FilterProperties = {
filterName: 'routes.filter-dialog.type',
keyNameInElementsArray: 'type',
type: FilterFieldTypes.Select,
printableLabelsForValues: [
{
value: '',
label: 'routes.filter-dialog.any-type-option',
}
],
};
this.ruleTypes.forEach((v, k) => {
typeFilterConfig.printableLabelsForValues.push({
value: k + '',
label: v,
});
});
this.filterProperties = [typeFilterConfig].concat(this.filterProperties);

// Initialize the data filterer.
this.dataFilterer = new DataFilterer(this.dialog, this.route, this.router, this.filterProperties, this.listId);
this.dataFiltererSubscription = this.dataFilterer.dataFiltered.subscribe(data => {
this.filteredRoutes = data;
Expand Down Expand Up @@ -142,6 +225,24 @@ export class RouteListComponent implements OnDestroy {
this.dataSorter.dispose();
}

/**
* Asks the node data to be refreshed.
*/
refreshData() {
NodeComponent.refreshCurrentDisplayedData();
}

/**
* Gets the name of a route type.
*/
getTypeName(type: number): string {
if (this.ruleTypes.has(type)) {
return this.ruleTypes.get(type);
}

return 'Unknown';
}

/**
* Changes the selection state of an entry (modifies the state of its checkbox).
*/
Expand All @@ -154,7 +255,7 @@ export class RouteListComponent implements OnDestroy {
}

/**
* Check if at lest one entry has been selected via its checkbox.
* Checks if at lest one entry has been selected via its checkbox.
*/
hasSelectedElements(): boolean {
if (!this.selections) {
Expand Down
9 changes: 7 additions & 2 deletions static/skywire-manager-src/src/assets/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -494,7 +494,9 @@
"info": "Paths used to reach the remote visors to which transports have been established. Routes are automatically generated as needed.",
"list-title": "Route list",
"key": "Key",
"rule": "Rule",
"type": "Type",
"source": "Source",
"destination": "Destination",
"delete-confirmation": "Are you sure you want to delete the route?",
"delete-selected-confirmation": "Are you sure you want to delete the selected routes?",
"delete": "Delete route",
Expand Down Expand Up @@ -530,7 +532,10 @@
},
"filter-dialog": {
"key": "The key must contain",
"rule": "The rule must contain"
"type": "The type must be",
"source": "The source must contain",
"destination": "The destination must contain",
"any-type-option": "Any"
}
},

Expand Down
Loading