diff --git a/static/skywire-manager-src/src/app/components/layout/button/button.component.html b/static/skywire-manager-src/src/app/components/layout/button/button.component.html index 634aaa995b..26b8add151 100644 --- a/static/skywire-manager-src/src/app/components/layout/button/button.component.html +++ b/static/skywire-manager-src/src/app/components/layout/button/button.component.html @@ -1,29 +1,12 @@ - - - done - error_outline - - - - - diff --git a/static/skywire-manager-src/src/app/components/layout/button/button.component.scss b/static/skywire-manager-src/src/app/components/layout/button/button.component.scss index e457ee6c2b..5041a97a70 100644 --- a/static/skywire-manager-src/src/app/components/layout/button/button.component.scss +++ b/static/skywire-manager-src/src/app/components/layout/button/button.component.scss @@ -9,10 +9,6 @@ button { mat-spinner ::ng-deep circle { stroke: $white; } - - .dot-red { - margin-left: 10px; - } } mat-icon, mat-spinner { @@ -21,3 +17,9 @@ mat-icon, mat-spinner { position: relative; top: -2px; } + +.for-dark-background:disabled { + background-color: #000000 !important; + color: white !important; + opacity: 0.3; +} diff --git a/static/skywire-manager-src/src/app/components/layout/button/button.component.ts b/static/skywire-manager-src/src/app/components/layout/button/button.component.ts index df99fef5d3..155421cf16 100644 --- a/static/skywire-manager-src/src/app/components/layout/button/button.component.ts +++ b/static/skywire-manager-src/src/app/components/layout/button/button.component.ts @@ -2,7 +2,7 @@ import { Component, EventEmitter, Input, Output, ViewChild, OnDestroy } from '@a import { MatButton } from '@angular/material/button'; enum ButtonStates { - Normal, Success, Error, Loading + Normal, Error, Loading } /** @@ -17,20 +17,17 @@ export class ButtonComponent implements OnDestroy { @ViewChild('button1') button1: MatButton; @ViewChild('button2') button2: MatButton; - // Should be be 'mat-button' or 'mat-raised-button'. - @Input() type = 'mat-button'; + // If the button will be in front of the dark background. + @Input() forDarkBackground = false; @Input() disabled = false; // Must be one of the colors defined on the default theme. @Input() color = ''; @Input() loadingSize = 24; // Click event. @Output() action = new EventEmitter(); - notification = false; state = ButtonStates.Normal; buttonStates = ButtonStates; - private readonly successDuration = 3000; - ngOnDestroy() { this.action.complete(); } @@ -45,7 +42,6 @@ export class ButtonComponent implements OnDestroy { reset() { this.state = ButtonStates.Normal; this.disabled = false; - this.notification = false; } focus() { @@ -70,19 +66,8 @@ export class ButtonComponent implements OnDestroy { this.disabled = true; } - showSuccess() { - this.state = ButtonStates.Success; - this.disabled = false; - - setTimeout(() => this.state = ButtonStates.Normal, this.successDuration); - } - showError() { this.state = ButtonStates.Error; this.disabled = false; } - - notify(notification: boolean) { - this.notification = notification; - } } diff --git a/static/skywire-manager-src/src/app/components/layout/confirmation/confirmation.component.html b/static/skywire-manager-src/src/app/components/layout/confirmation/confirmation.component.html index c8f39b529e..20f5edb545 100644 --- a/static/skywire-manager-src/src/app/components/layout/confirmation/confirmation.component.html +++ b/static/skywire-manager-src/src/app/components/layout/confirmation/confirmation.component.html @@ -14,7 +14,6 @@
@@ -22,7 +21,6 @@ {{ (state !== confirmationStates.Done ? data.confirmButtonText : 'confirmation.close') | translate }} diff --git a/static/skywire-manager-src/src/app/components/layout/edit-label/edit-label.component.html b/static/skywire-manager-src/src/app/components/layout/edit-label/edit-label.component.html index 89012ac974..b6e5d5cfb4 100644 --- a/static/skywire-manager-src/src/app/components/layout/edit-label/edit-label.component.html +++ b/static/skywire-manager-src/src/app/components/layout/edit-label/edit-label.component.html @@ -3,6 +3,6 @@ - {{ 'common.save' | translate }} + {{ 'common.save' | translate }} diff --git a/static/skywire-manager-src/src/app/components/layout/filters-selection/filters-selection.component.html b/static/skywire-manager-src/src/app/components/layout/filters-selection/filters-selection.component.html index 400e3fda50..16b1da05fe 100644 --- a/static/skywire-manager-src/src/app/components/layout/filters-selection/filters-selection.component.html +++ b/static/skywire-manager-src/src/app/components/layout/filters-selection/filters-selection.component.html @@ -26,7 +26,6 @@ diff --git a/static/skywire-manager-src/src/app/components/pages/node-list/node-list.component.html b/static/skywire-manager-src/src/app/components/pages/node-list/node-list.component.html index e0a7122717..438f5cf4a4 100644 --- a/static/skywire-manager-src/src/app/components/pages/node-list/node-list.component.html +++ b/static/skywire-manager-src/src/app/components/pages/node-list/node-list.component.html @@ -29,15 +29,14 @@
-
+
- {{ 'filters.active-filters' | translate }}
{{ filterTexts.filterName | translate }}: {{ filterTexts.translatableValue | translate }} {{ filterTexts.value }}
-
{{ 'filters.press-to-remove' | translate }}
+
{{ 'filters.press-to-remove' | translate }}
@@ -93,7 +92,10 @@ {{ 'nodes.dmsg-server' | translate }} - {{ dataSorter.sortingArrow }} + + {{ dataSorter.sortingArrow }} + * + {{ 'nodes.ping' | translate }} @@ -177,7 +179,8 @@
{{ 'tables.sorting-title' | translate }}
{{ dataSorter.currentSortingColumn.label | translate }} - {{ (!dataSorter.sortingInReverseOrder ? 'tables.ascending-order' : 'tables.descending-order') | translate }} + {{ 'tables.label' | translate }} + {{ 'tables.inverted-order' | translate }}
diff --git a/static/skywire-manager-src/src/app/components/pages/node-list/node-list.component.ts b/static/skywire-manager-src/src/app/components/pages/node-list/node-list.component.ts index ef1067b5d8..9c1ee4e868 100644 --- a/static/skywire-manager-src/src/app/components/pages/node-list/node-list.component.ts +++ b/static/skywire-manager-src/src/app/components/pages/node-list/node-list.component.ts @@ -42,7 +42,7 @@ export class NodeListComponent implements OnInit, OnDestroy { stateSortData = new SortingColumn(['online'], 'transports.state', SortingModes.Boolean); labelSortData = new SortingColumn(['label'], 'nodes.label', SortingModes.Text); keySortData = new SortingColumn(['local_pk'], 'nodes.key', SortingModes.Text); - dmsgServerSortData = new SortingColumn(['dmsgServerPk'], 'nodes.dmsg-server', SortingModes.Text); + dmsgServerSortData = new SortingColumn(['dmsgServerPk'], 'nodes.dmsg-server', SortingModes.Text, ['dmsgServerPk_label']); pingSortData = new SortingColumn(['roundTripPing'], 'nodes.ping', SortingModes.Number); private dataSortedSubscription: Subscription; @@ -324,7 +324,7 @@ export class NodeListComponent implements OnInit, OnDestroy { if (result.data) { this.allNodes = result.data as Node[]; if (this.showDmsgInfo) { - // Add the label data to the array, to be able to use it for filtering. + // Add the label data to the array, to be able to use it for filtering and sorting. this.allNodes.forEach(node => { node['dmsgServerPk_label'] = LabeledElementTextComponent.getCompleteLabel(this.storageService, this.translateService, node.dmsgServerPk); @@ -394,10 +394,16 @@ export class NodeListComponent implements OnInit, OnDestroy { } logout() { - this.authService.logout().subscribe( - () => this.router.navigate(['login']), - () => this.snackbarService.showError('common.logout-error') - ); + const confirmationDialog = GeneralUtils.createConfirmationDialog(this.dialog, 'common.logout-confirmation'); + + confirmationDialog.componentInstance.operationAccepted.subscribe(() => { + confirmationDialog.componentInstance.closeModal(); + + this.authService.logout().subscribe( + () => this.router.navigate(['login']), + () => this.snackbarService.showError('common.logout-error') + ); + }); } // Updates all visors. diff --git a/static/skywire-manager-src/src/app/components/pages/node/apps/node-apps-list/node-apps-list.component.html b/static/skywire-manager-src/src/app/components/pages/node/apps/node-apps-list/node-apps-list.component.html index e1b9a0183b..498c645ef4 100644 --- a/static/skywire-manager-src/src/app/components/pages/node/apps/node-apps-list/node-apps-list.component.html +++ b/static/skywire-manager-src/src/app/components/pages/node/apps/node-apps-list/node-apps-list.component.html @@ -1,15 +1,14 @@
-
+
{{ 'apps.apps-list.title' | translate }}
- {{ 'filters.active-filters' | translate }}
{{ filterTexts.filterName | translate }}: {{ filterTexts.translatableValue | translate }} {{ filterTexts.value }}
-
{{ 'filters.press-to-remove' | translate }}
+
{{ 'filters.press-to-remove' | translate }}
@@ -160,7 +159,8 @@
{{ 'tables.sorting-title' | translate }}
{{ dataSorter.currentSortingColumn.label | translate }} - {{ (!dataSorter.sortingInReverseOrder ? 'tables.ascending-order' : 'tables.descending-order') | translate }} + {{ 'tables.label' | translate }} + {{ 'tables.inverted-order' | translate }}
diff --git a/static/skywire-manager-src/src/app/components/pages/node/apps/node-apps/skysocks-client-settings/skysocks-client-settings.component.html b/static/skywire-manager-src/src/app/components/pages/node/apps/node-apps/skysocks-client-settings/skysocks-client-settings.component.html index 7a0245b33b..0c762315df 100644 --- a/static/skywire-manager-src/src/app/components/pages/node/apps/node-apps/skysocks-client-settings/skysocks-client-settings.component.html +++ b/static/skywire-manager-src/src/app/components/pages/node/apps/node-apps/skysocks-client-settings/skysocks-client-settings.component.html @@ -25,7 +25,6 @@
-
- {{ 'routes.title' | translate }} +
+ + {{ 'routes.title' | translate }} + help +
- {{ 'filters.active-filters' | translate }}
{{ filterTexts.filterName | translate }}: {{ filterTexts.translatableValue | translate }} {{ filterTexts.value }}
-
{{ 'filters.press-to-remove' | translate }}
+
{{ 'filters.press-to-remove' | translate }}
@@ -118,7 +120,8 @@
{{ 'tables.sorting-title' | translate }}
{{ dataSorter.currentSortingColumn.label | translate }} - {{ (!dataSorter.sortingInReverseOrder ? 'tables.ascending-order' : 'tables.descending-order') | translate }} + {{ 'tables.label' | translate }} + {{ 'tables.inverted-order' | translate }}
diff --git a/static/skywire-manager-src/src/app/components/pages/node/routing/transport-list/create-transport/create-transport.component.html b/static/skywire-manager-src/src/app/components/pages/node/routing/transport-list/create-transport/create-transport.component.html index e6b036a26d..f6ed78df48 100644 --- a/static/skywire-manager-src/src/app/components/pages/node/routing/transport-list/create-transport/create-transport.component.html +++ b/static/skywire-manager-src/src/app/components/pages/node/routing/transport-list/create-transport/create-transport.component.html @@ -34,7 +34,6 @@
-
- {{ 'transports.title' | translate }} +
+ + {{ 'transports.title' | translate }} + help +
- {{ 'filters.active-filters' | translate }}
{{ filterTexts.filterName | translate }}: {{ filterTexts.translatableValue | translate }} {{ filterTexts.value }}
-
{{ 'filters.press-to-remove' | translate }}
+
{{ 'filters.press-to-remove' | translate }}
@@ -17,12 +19,10 @@ add filter_list @@ -73,11 +73,17 @@ {{ 'transports.id' | translate }} - {{ dataSorter.sortingArrow }} + + {{ dataSorter.sortingArrow }} + * + {{ 'transports.remote-node' | translate }} - {{ dataSorter.sortingArrow }} + + {{ dataSorter.sortingArrow }} + * + {{ 'transports.type' | translate }} @@ -163,7 +169,8 @@
{{ 'tables.sorting-title' | translate }}
{{ dataSorter.currentSortingColumn.label | translate }} - {{ (!dataSorter.sortingInReverseOrder ? 'tables.ascending-order' : 'tables.descending-order') | translate }} + {{ 'tables.label' | translate }} + {{ 'tables.inverted-order' | translate }}
diff --git a/static/skywire-manager-src/src/app/components/pages/node/routing/transport-list/transport-list.component.ts b/static/skywire-manager-src/src/app/components/pages/node/routing/transport-list/transport-list.component.ts index 5be1096589..6bdfc80318 100644 --- a/static/skywire-manager-src/src/app/components/pages/node/routing/transport-list/transport-list.component.ts +++ b/static/skywire-manager-src/src/app/components/pages/node/routing/transport-list/transport-list.component.ts @@ -39,8 +39,8 @@ export class TransportListComponent implements OnDestroy { // Vars with the data of the columns used for sorting the data. stateSortData = new SortingColumn(['is_up'], 'transports.state', SortingModes.Boolean); - idSortData = new SortingColumn(['id'], 'transports.id', SortingModes.Text); - remotePkSortData = new SortingColumn(['remote_pk'], 'transports.remote-node', SortingModes.Text); + idSortData = new SortingColumn(['id'], 'transports.id', SortingModes.Text, ['id_label']); + remotePkSortData = new SortingColumn(['remote_pk'], 'transports.remote-node', SortingModes.Text, ['remote_pk_label']); typeSortData = new SortingColumn(['type'], 'transports.type', SortingModes.Text); uploadedSortData = new SortingColumn(['log', 'sent'], 'common.uploaded', SortingModes.NumberReversed); downloadedSortData = new SortingColumn(['log', 'recv'], 'common.downloaded', SortingModes.NumberReversed); @@ -79,7 +79,7 @@ export class TransportListComponent implements OnDestroy { @Input() set transports(val: Transport[]) { this.allTransports = val; - // Add the label data to the array, to be able to use it for filtering. + // Add the label data to the array, to be able to use it for filtering and sorting. this.allTransports.forEach(transport => { transport['id_label'] = LabeledElementTextComponent.getCompleteLabel(this.storageService, this.translateService, transport.id); diff --git a/static/skywire-manager-src/src/app/components/pages/settings/all-labels/label-list/label-list.component.html b/static/skywire-manager-src/src/app/components/pages/settings/all-labels/label-list/label-list.component.html index 58487ae678..2fac4f24a8 100644 --- a/static/skywire-manager-src/src/app/components/pages/settings/all-labels/label-list/label-list.component.html +++ b/static/skywire-manager-src/src/app/components/pages/settings/all-labels/label-list/label-list.component.html @@ -1,15 +1,17 @@
-
- {{ 'labels.title' | translate }} +
+ + {{ 'labels.title' | translate }} + help +
- {{ 'filters.active-filters' | translate }}
{{ filterTexts.filterName | translate }}: {{ filterTexts.translatableValue | translate }} {{ filterTexts.value }}
-
{{ 'filters.press-to-remove' | translate }}
+
{{ 'filters.press-to-remove' | translate }}
@@ -118,7 +120,8 @@
{{ 'tables.sorting-title' | translate }}
{{ dataSorter.currentSortingColumn.label | translate }} - {{ (!dataSorter.sortingInReverseOrder ? 'tables.ascending-order' : 'tables.descending-order') | translate }} + {{ 'tables.label' | translate }} + {{ 'tables.inverted-order' | translate }}
diff --git a/static/skywire-manager-src/src/app/components/pages/settings/password/password.component.html b/static/skywire-manager-src/src/app/components/pages/settings/password/password.component.html index ecf03f9460..81d80cc8a6 100644 --- a/static/skywire-manager-src/src/app/components/pages/settings/password/password.component.html +++ b/static/skywire-manager-src/src/app/components/pages/settings/password/password.component.html @@ -48,9 +48,9 @@ {{ (forInitialConfig ? 'settings.password.initial-config.set-password': 'settings.change-password') | translate }} diff --git a/static/skywire-manager-src/src/app/components/pages/settings/settings.component.ts b/static/skywire-manager-src/src/app/components/pages/settings/settings.component.ts index a4e03006a1..51dd2d96e5 100644 --- a/static/skywire-manager-src/src/app/components/pages/settings/settings.component.ts +++ b/static/skywire-manager-src/src/app/components/pages/settings/settings.component.ts @@ -1,11 +1,13 @@ import { Component, OnInit, OnDestroy } from '@angular/core'; import { Router } from '@angular/router'; import { Subscription } from 'rxjs'; +import { MatDialog } from '@angular/material/dialog'; import { TabButtonData } from '../../layout/tab-bar/tab-bar.component'; import { AuthService } from '../../../services/auth.service'; import { SnackbarService } from '../../../services/snackbar.service'; import { SidenavService } from 'src/app/services/sidenav.service'; +import GeneralUtils from 'src/app/utils/generalUtils'; /** * Page with the general settings of the app. @@ -25,6 +27,7 @@ export class SettingsComponent implements OnInit, OnDestroy { private router: Router, private snackbarService: SnackbarService, private sidenavService: SidenavService, + private dialog: MatDialog, ) { // Data for populating the tab bar. this.tabsData = [ @@ -71,9 +74,15 @@ export class SettingsComponent implements OnInit, OnDestroy { } logout() { - this.authService.logout().subscribe( - () => this.router.navigate(['login']), - () => this.snackbarService.showError('common.logout-error') - ); + const confirmationDialog = GeneralUtils.createConfirmationDialog(this.dialog, 'common.logout-confirmation'); + + confirmationDialog.componentInstance.operationAccepted.subscribe(() => { + confirmationDialog.componentInstance.closeModal(); + + this.authService.logout().subscribe( + () => this.router.navigate(['login']), + () => this.snackbarService.showError('common.logout-error') + ); + }); } } diff --git a/static/skywire-manager-src/src/app/utils/lists/data-sorter.ts b/static/skywire-manager-src/src/app/utils/lists/data-sorter.ts index 27f9dee2c5..b162f7fa44 100644 --- a/static/skywire-manager-src/src/app/utils/lists/data-sorter.ts +++ b/static/skywire-manager-src/src/app/utils/lists/data-sorter.ts @@ -23,11 +23,18 @@ export class SortingColumn { * How the data must be sorted. */ sortingMode: SortingModes; + /** + * Similar to "properties", but for finding the property which contains the label of the value + * shown in the cell, instead of the value itself. If set, the user will be able to select + * to sort the data using the value or the label shown in the cell. + */ + labelProperties: string[]; - constructor(properties: string[], label: string, sortingMode: SortingModes) { + constructor(properties: string[], label: string, sortingMode: SortingModes, labelProperties?: string[]) { this.properties = properties; this.label = label; this.sortingMode = sortingMode; + this.labelProperties = labelProperties; } /** @@ -75,6 +82,8 @@ export class DataSorter { private sortBy: SortingColumn; // If the data must be sorted in reversed order. private sortReverse = false; + // If the data must be sorted using the label shown in the cell instead of the data itself. + private sortByLabel = false; // Data to sort. private data: any[]; // Index inside sortableColumns of the default column. @@ -83,6 +92,7 @@ export class DataSorter { // Prefixes used, along the ID, for saving the sorting options in localStorage. private readonly columnStorageKeyPrefix = 'col_'; private readonly orderStorageKeyPrefix = 'order_'; + private readonly labelStorageKeyPrefix = 'label_'; private dataUpdatedSubject = new Subject(); @@ -115,6 +125,14 @@ export class DataSorter { return this.dataUpdatedSubject.asObservable(); } + /** + * Allow to know if the data is currently being sorted by the label shown in the cells and not + * the value itself. + */ + get currentlySortingByLabel(): boolean { + return this.sortByLabel; + } + /** * @param columns Array with the data about the columns that can be used for sorting the list. * @param defaultColumnIndex Index in the "columns" array that must be used by default for @@ -145,6 +163,7 @@ export class DataSorter { } this.sortReverse = localStorage.getItem(this.orderStorageKeyPrefix + id) === 'true'; + this.sortByLabel = localStorage.getItem(this.labelStorageKeyPrefix + id) === 'true'; } /** @@ -168,17 +187,52 @@ export class DataSorter { * Changes the column and/or order used for sorting the data. */ changeSortingOrder(column: SortingColumn) { - if (this.sortBy !== column) { - this.sortBy = column; - this.sortReverse = false; + if (this.sortBy !== column && !column.labelProperties) { + // If a different column which can not be sorted by label was selected, use the new column. + this.changeSortingParams(column, false, false); + } else if (column.labelProperties) { + // If a column which can be sorted by label was selected, create options for allowing the + // user to select how to sort the data. + const options: SelectableOption[] = [{ + label: this.translateService.instant('tables.sort-by-value'), + }, + { + label: this.translateService.instant('tables.sort-by-value') + ' ' + this.translateService.instant('tables.inverted-order'), + }, + { + label: this.translateService.instant('tables.sort-by-label'), + }, + { + label: this.translateService.instant('tables.sort-by-label') + ' ' + this.translateService.instant('tables.inverted-order'), + }]; - localStorage.setItem(this.columnStorageKeyPrefix + this.id, column.id); - localStorage.setItem(this.orderStorageKeyPrefix + this.id, String(this.sortReverse)); + // Open the option selection modal window. + SelectOptionComponent.openDialog(this.dialog, options, 'tables.title').afterClosed().subscribe((result: number) => { + if (result) { + // Use the selection made by the user. + this.changeSortingParams(column, result > 2, result % 2 === 0); + } + }); } else { + // If the same column was selected, change the order. this.sortReverse = !this.sortReverse; - localStorage.setItem(this.orderStorageKeyPrefix + this.id, String(this.sortReverse)); + + this.sortData(); } + } + + /** + * Changes the current sorting params, saves them and sorts the data. + */ + changeSortingParams(column: SortingColumn, sortByLabel: boolean, sortReverse: boolean) { + this.sortBy = column; + this.sortByLabel = sortByLabel; + this.sortReverse = sortReverse; + + localStorage.setItem(this.columnStorageKeyPrefix + this.id, column.id); + localStorage.setItem(this.orderStorageKeyPrefix + this.id, String(this.sortReverse)); + localStorage.setItem(this.labelStorageKeyPrefix + this.id, String(this.sortByLabel)); this.sortData(); } @@ -187,28 +241,60 @@ export class DataSorter { * Opens the modal window used on small screens for selecting how to sort the data. */ openSortingOrderModal() { - // Create 2 options for every sortable column, for ascending and descending order. + // Create options for every sortable column, including variations. const options: SelectableOption[] = []; + const optionParams = []; this.sortableColumns.forEach(column => { + // Options for the normal and inverted mode. const label = this.translateService.instant(column.label); options.push({ - label: label + ' ' + this.translateService.instant('tables.ascending-order'), + label: label, + }); + optionParams.push({ + sortBy: column, + sortReverse: false, + sortByLabel: false, }); options.push({ - label: label + ' ' + this.translateService.instant('tables.descending-order'), + label: label + ' ' + this.translateService.instant('tables.inverted-order'), + }); + optionParams.push({ + sortBy: column, + sortReverse: true, + sortByLabel: false, }); + + // Options for using the label to sort the data. + if (column.labelProperties) { + options.push({ + label: label + ' ' + this.translateService.instant('tables.label'), + }); + optionParams.push({ + sortBy: column, + sortReverse: false, + sortByLabel: true, + }); + options.push({ + label: label + ' ' + this.translateService.instant('tables.label') + + ' ' + this.translateService.instant('tables.inverted-order'), + }); + optionParams.push({ + sortBy: column, + sortReverse: true, + sortByLabel: true, + }); + } }); // Open the option selection modal window. SelectOptionComponent.openDialog(this.dialog, options, 'tables.title').afterClosed().subscribe((result: number) => { if (result) { - result = (result - 1) / 2; - const index = Math.floor(result); - // Use the column and order selected by the user. - this.sortBy = this.sortableColumns[index]; - this.sortReverse = result !== index; - - this.sortData(); + // Use the selection made by the user. + this.changeSortingParams( + optionParams[result - 1].sortBy, + optionParams[result - 1].sortReverse, + optionParams[result - 1].sortByLabel + ); } }); } @@ -221,12 +307,12 @@ export class DataSorter { // Sort all the data. this.data.sort((a, b) => { // Sort using the currently selected column. - let response = this.getSortResponse(this.sortBy, a, b); + let response = this.getSortResponse(this.sortBy, a, b, true); // If the 2 values are equal, sort using the default column, if it is not already // the selected one. if (response === 0) { if (this.sortableColumns[this.defaultColumnIndex] !== this.sortBy) { - response = this.getSortResponse(this.sortableColumns[this.defaultColumnIndex], a, b); + response = this.getSortResponse(this.sortableColumns[this.defaultColumnIndex], a, b, false); } } @@ -243,24 +329,32 @@ export class DataSorter { * @param sortingColumn Column being used to sort the data. * @param a First value. * @param b Second value. + * @param sortByLabelIfRequested if true and this.sortByLabel is also true, the data will be + * sorted using the label instead of the value itself. */ - private getSortResponse(sortingColumn: SortingColumn, a, b) { + private getSortResponse(sortingColumn: SortingColumn, a, b, sortByLabelIfRequested: boolean) { + // List of params for getting the value that will be used for sorting the data. + const propertiesList = this.sortByLabel && sortByLabelIfRequested && sortingColumn.labelProperties ? + sortingColumn.labelProperties : sortingColumn.properties; + // Get the data from the property. let aVal = a, bVal = b; - sortingColumn.properties.forEach(property => { + propertiesList.forEach(property => { aVal = aVal[property]; bVal = bVal[property]; }); + const sortingMode = this.sortByLabel && sortByLabelIfRequested ? SortingModes.Text : sortingColumn.sortingMode; + // Use the selected sorting method. let response = 0; - if (sortingColumn.sortingMode === SortingModes.Text) { + if (sortingMode === SortingModes.Text) { response = !this.sortReverse ? (aVal as string).localeCompare(bVal) : (bVal as string).localeCompare(aVal); - } else if (sortingColumn.sortingMode === SortingModes.NumberReversed) { + } else if (sortingMode === SortingModes.NumberReversed) { response = !this.sortReverse ? bVal - aVal : aVal - bVal; - } else if (sortingColumn.sortingMode === SortingModes.Number) { + } else if (sortingMode === SortingModes.Number) { response = !this.sortReverse ? aVal - bVal : bVal - aVal; - } else if (sortingColumn.sortingMode === SortingModes.Boolean) { + } else if (sortingMode === SortingModes.Boolean) { if (aVal.is_up && !bVal.is_up) { response = -1; } else if (!aVal.is_up && bVal.is_up) { diff --git a/static/skywire-manager-src/src/assets/i18n/en.json b/static/skywire-manager-src/src/assets/i18n/en.json index b6bc81ddbe..125aa68684 100644 --- a/static/skywire-manager-src/src/assets/i18n/en.json +++ b/static/skywire-manager-src/src/assets/i18n/en.json @@ -12,6 +12,7 @@ "options": "Options", "logout": "Logout", "logout-error": "Error logging out.", + "logout-confirmation": "Are you sure you want to log out?", "time-in-ms": "{{ time }}ms", "ok": "Ok", "unknown": "Unknown" @@ -31,6 +32,7 @@ "labels": { "title": "Labels", + "info": "Labels you have entered to easily identify visors, transports and other elements, instead of having to read machine generated identifiers.", "list-title": "Label list", "label": "Label", "id": "Element ID", @@ -57,16 +59,17 @@ "filters": { "filter-action": "Filter", - "active-filters": "Active filters: ", - "press-to-remove": "(Press to remove)", + "press-to-remove": "(Press to remove the filters)", "remove-confirmation": "Are you sure you want to remove the filters?" }, "tables": { "title": "Order by", "sorting-title": "Ordered by:", - "ascending-order": "(ascending)", - "descending-order": "(descending)" + "sort-by-value": "Value", + "sort-by-label": "Label", + "label": "(label)", + "inverted-order": "(inverted)" }, "start": { @@ -355,6 +358,7 @@ "transports": { "title": "Transports", + "info": "Connections you have with remote Skywire visors, to allow local Skywire apps to communicate with apps running on those remote visors.", "list-title": "Transport list", "state": "State", "state-tooltip": "Current state", @@ -415,6 +419,7 @@ "routes": { "title": "Routes", + "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", diff --git a/static/skywire-manager-src/src/assets/scss/_responsive_tables.scss b/static/skywire-manager-src/src/assets/scss/_responsive_tables.scss index b0d54bc11b..c6f944fd23 100644 --- a/static/skywire-manager-src/src/assets/scss/_responsive_tables.scss +++ b/static/skywire-manager-src/src/assets/scss/_responsive_tables.scss @@ -178,17 +178,39 @@ $responsive-table-colors: ( // Styles for the headers shown above most of the tables. .generic-title-container { - padding-right: 5px; + @media (min-width: map-get($grid-breakpoints, md)) { + & { + padding-right: 5px; + } + } + + @media (max-width: (map-get($grid-breakpoints, md) - 1)) { + & { + margin-right: -15px; + } + } .title { margin-right: auto; font-size: $font-size-base; font-weight: bold; + @media (min-width: map-get($grid-breakpoints, md)) { + & { + margin-left: 1.25rem !important; + } + } + .filter-label { font-size: $font-size-mini; font-weight: lighter; } + + .help { + opacity: 0.5; + font-size: 14px; + cursor: default; + } } .icon-button { diff --git a/static/skywire-manager-src/src/assets/scss/utilities/_utilities.scss b/static/skywire-manager-src/src/assets/scss/utilities/_utilities.scss index 7350db1b13..03c99a7cb2 100644 --- a/static/skywire-manager-src/src/assets/scss/utilities/_utilities.scss +++ b/static/skywire-manager-src/src/assets/scss/utilities/_utilities.scss @@ -27,10 +27,6 @@ margin-top: 2rem !important; } -.ml-3\.5 { - margin-left: 1.25rem !important; -} - .highlight-internal-icon { @extend .cursor-pointer; diff --git a/static/skywire-manager-src/src/styles.scss b/static/skywire-manager-src/src/styles.scss index 5ffd852a48..10b0b8e005 100644 --- a/static/skywire-manager-src/src/styles.scss +++ b/static/skywire-manager-src/src/styles.scss @@ -76,3 +76,7 @@ button:focus { .mat-snack-bar-container { max-width: 90vw !important; } + +.transparent-50 { + opacity: 0.5; +}