+ {{ 'transports.make-selected-non-persistent' | translate }}
+
-
+
-
- {{ 'transports.state' | translate }}:
- {{ transportStatusText(transport, false) | translate }}
+
+
+ star
+ {{ 'transports.persistent' | translate }}
+
{{ 'transports.id' | translate }}:
+ {{ 'transports.offline' | translate }}
{{ 'transports.remote-node' | translate }}:
@@ -216,11 +252,13 @@
{{ 'common.uploaded' | translate }}:
- {{ transport.sent | autoScale }}
+ {{ transport.sent | autoScale }}
+ {{ 'transports.offline' | translate }}
{{ 'common.downloaded' | translate }}:
- {{ transport.recv | autoScale }}
+ {{ transport.recv | autoScale }}
+ {{ 'transports.offline' | translate }}
diff --git a/static/skywire-manager-src/src/app/components/pages/node/routing/transport-list/transport-list.component.scss b/static/skywire-manager-src/src/app/components/pages/node/routing/transport-list/transport-list.component.scss
index b4e0352459..a6512a5e70 100644
--- a/static/skywire-manager-src/src/app/components/pages/node/routing/transport-list/transport-list.component.scss
+++ b/static/skywire-manager-src/src/app/components/pages/node/routing/transport-list/transport-list.component.scss
@@ -1,4 +1,5 @@
@import "bootstrap_overrides";
+@import "variables";
.overflow {
display: block;
@@ -19,3 +20,17 @@
vertical-align: middle;
margin-right: 10px;
}
+
+.small-column {
+ width: 1px;
+ text-align: center;
+}
+
+.persistent-icon {
+ font-size: 14px !important;
+ color: $yellow;
+}
+
+.offline {
+ opacity: 0.35;
+}
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 6d4c2220ba..70c95b344c 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
@@ -1,10 +1,10 @@
import { Component, Input, OnDestroy } from '@angular/core';
import { MatDialog, MatDialogRef } from '@angular/material/dialog';
-import { Observable, Subscription, forkJoin } from 'rxjs';
+import { Observable, Subscription } from 'rxjs';
import { ActivatedRoute, Router } from '@angular/router';
import { TranslateService } from '@ngx-translate/core';
-import { Transport } from '../../../../../app.datatypes';
+import { Node, PersistentTransport, Transport } from '../../../../../app.datatypes';
import { CreateTransportComponent } from './create-transport/create-transport.component';
import { TransportService } from '../../../../../services/transport.service';
import { NodeComponent } from '../../node.component';
@@ -21,6 +21,7 @@ import { LabeledElementTypes, StorageService } from 'src/app/services/storage.se
import { LabeledElementTextComponent } from 'src/app/components/layout/labeled-element-text/labeled-element-text.component';
import { DataSorter, SortingColumn, SortingModes } from 'src/app/utils/lists/data-sorter';
import { DataFilterer } from 'src/app/utils/lists/data-filterer';
+import { NodeService } from 'src/app/services/node.service';
/**
* Shows the list of transports of a node. I can be used to show a short preview, with just some
@@ -35,10 +36,10 @@ export class TransportListComponent implements OnDestroy {
// Small text for identifying the list, needed for the helper objects.
private readonly listId = 'tr';
- @Input() nodePK: string;
+ nodePK: string;
// Vars with the data of the columns used for sorting the data.
- stateSortData = new SortingColumn(['isUp'], 'transports.state', SortingModes.Boolean);
+ persistentSortData = new SortingColumn(['isPersistent'], 'transports.persistent', SortingModes.Boolean);
idSortData = new SortingColumn(['id'], 'transports.id', SortingModes.Text, ['id_label']);
remotePkSortData = new SortingColumn(['remotePk'], 'transports.remote-node', SortingModes.Text, ['remote_pk_label']);
typeSortData = new SortingColumn(['type'], 'transports.type', SortingModes.Text);
@@ -69,16 +70,43 @@ export class TransportListComponent implements OnDestroy {
this.dataSorter.setData(this.filteredTransports);
}
+ currentNode: Node;
allTransports: Transport[];
filteredTransports: Transport[];
transportsToShow: Transport[];
- hasOfflineTransports = false;
numberOfPages = 1;
currentPage = 1;
// Used as a helper var, as the URL is read asynchronously.
currentPageInUrl = 1;
- @Input() set transports(val: Transport[]) {
- this.allTransports = val;
+ @Input() set node(val: Node) {
+ this.currentNode = val;
+ this.allTransports = val.transports;
+ this.nodePK = val.localPk;
+
+ const persistentTransportsMap: Map = new Map();
+ val.persistentTransports.forEach(pt => persistentTransportsMap.set(this.getPersistentTransportID(pt.pk, pt.type), pt));
+
+ this.allTransports.forEach(transport => {
+ if (persistentTransportsMap.has(this.getPersistentTransportID(transport.remotePk, transport.type))) {
+ transport.isPersistent = true;
+ persistentTransportsMap.delete(this.getPersistentTransportID(transport.remotePk, transport.type));
+ } else {
+ transport.isPersistent = false;
+ }
+ });
+
+ persistentTransportsMap.forEach((persistentTransport, key) => {
+ this.allTransports.push({
+ id: this.getPersistentTransportID(persistentTransport.pk, persistentTransport.type),
+ localPk: val.localPk,
+ remotePk: persistentTransport.pk,
+ type: persistentTransport.type,
+ recv: 0,
+ sent: 0,
+ isPersistent: true,
+ notFound: true,
+ });
+ });
// Add the label data to the array, to be able to use it for filtering and sorting.
this.allTransports.forEach(transport => {
@@ -95,21 +123,21 @@ export class TransportListComponent implements OnDestroy {
// Array with the properties of the columns that can be used for filtering the data.
filterProperties: FilterProperties[] = [
{
- filterName: 'transports.filter-dialog.online',
- keyNameInElementsArray: 'isUp',
+ filterName: 'transports.filter-dialog.persistent',
+ keyNameInElementsArray: 'isPersistent',
type: FilterFieldTypes.Select,
printableLabelsForValues: [
{
value: '',
- label: 'transports.filter-dialog.online-options.any',
+ label: 'transports.filter-dialog.persistent-options.any',
},
{
value: 'true',
- label: 'transports.filter-dialog.online-options.online',
+ label: 'transports.filter-dialog.persistent-options.persistent',
},
{
value: 'false',
- label: 'transports.filter-dialog.online-options.offline',
+ label: 'transports.filter-dialog.persistent-options.non-persistent',
}
],
},
@@ -131,6 +159,7 @@ export class TransportListComponent implements OnDestroy {
labeledElementTypes = LabeledElementTypes;
+ private persistentTransportSubscription: Subscription;
private navigationsSubscription: Subscription;
private operationSubscriptionsGroup: Subscription[] = [];
private languageSubscription: Subscription;
@@ -143,10 +172,11 @@ export class TransportListComponent implements OnDestroy {
private snackbarService: SnackbarService,
private translateService: TranslateService,
private storageService: StorageService,
+ private nodeService: NodeService,
) {
// Initialize the data sorter.
const sortableColumns: SortingColumn[] = [
- this.stateSortData,
+ this.persistentSortData,
this.idSortData,
this.remotePkSortData,
this.typeSortData,
@@ -163,14 +193,6 @@ export class TransportListComponent implements OnDestroy {
this.dataFiltererSubscription = this.dataFilterer.dataFiltered.subscribe(data => {
this.filteredTransports = data;
- // Check if there are offline transports.
- this.hasOfflineTransports = false;
- this.filteredTransports.forEach(transport => {
- if (!transport.isUp) {
- this.hasOfflineTransports = true;
- }
- });
-
this.dataSorter.setData(this.filteredTransports);
});
@@ -191,7 +213,7 @@ export class TransportListComponent implements OnDestroy {
// Refresh the data after languaje changes, to ensure the labels used for filtering
// are updated.
this.languageSubscription = this.translateService.onLangChange.subscribe(() => {
- this.transports = this.allTransports;
+ this.node = this.currentNode;
});
}
@@ -205,33 +227,9 @@ export class TransportListComponent implements OnDestroy {
this.dataFiltererSubscription.unsubscribe();
this.dataFilterer.dispose();
- }
-
- /**
- * Returns the scss class to be used to show the current status of the transport.
- * @param forDot If true, returns a class for creating a colored dot. If false,
- * returns a class for a colored text.
- */
- transportStatusClass(transport: Transport, forDot: boolean): string {
- switch (transport.isUp) {
- case true:
- return forDot ? 'dot-green' : 'green-clear-text';
- default:
- return forDot ? 'dot-red' : 'red-clear-text';
- }
- }
- /**
- * Returns the text to be used to indicate the current status of a transport.
- * @param forTooltip If true, returns a text for a tooltip. If false, returns a
- * text for the transport list shown on small screens.
- */
- transportStatusText(transport: Transport, forTooltip: boolean): string {
- switch (transport.isUp) {
- case true:
- return 'transports.statuses.online' + (forTooltip ? '-tooltip' : '');
- default:
- return 'transports.statuses.offline' + (forTooltip ? '-tooltip' : '');
+ if (this.persistentTransportSubscription) {
+ this.persistentTransportSubscription.unsubscribe();
}
}
@@ -294,36 +292,6 @@ export class TransportListComponent implements OnDestroy {
});
}
- /**
- * Removes all offline transports.
- */
- removeOffline() {
- let confirmationText = 'transports.remove-all-offline-confirmation';
- if (this.dataFilterer.currentFiltersTexts && this.dataFilterer.currentFiltersTexts.length > 0) {
- confirmationText = 'transports.remove-all-filtered-offline-confirmation';
- }
-
- const confirmationDialog = GeneralUtils.createConfirmationDialog(this.dialog, confirmationText);
-
- confirmationDialog.componentInstance.operationAccepted.subscribe(() => {
- // Prepare all offline transports to be removed.
- const transportsToRemove: string[] = [];
- this.filteredTransports.forEach(transport => {
- if (!transport.isUp) {
- transportsToRemove.push(transport.id);
- }
- });
-
- if (transportsToRemove.length > 0) {
- // Remove the transports.
- confirmationDialog.componentInstance.showProcessing();
- this.deleteRecursively(transportsToRemove, confirmationDialog);
- } else {
- confirmationDialog.close();
- }
- });
- }
-
/**
* Shows the transport creation modal window.
*/
@@ -335,23 +303,142 @@ export class TransportListComponent implements OnDestroy {
* Opens the modal window used on small screens with the options of an element.
*/
showOptionsDialog(transport: Transport) {
- const options: SelectableOption[] = [
- {
+ const options: SelectableOption[] = [];
+ if (transport.isPersistent) {
+ options.push({
+ icon: 'star_outline',
+ label: 'transports.make-non-persistent',
+ });
+ } else {
+ options.push({
+ icon: 'star',
+ label: 'transports.make-persistent',
+ });
+ }
+
+ if (!transport.notFound) {
+ options.push({
icon: 'visibility',
label: 'transports.details.title',
- },
- {
+ });
+ options.push({
icon: 'close',
label: 'transports.delete',
- }
- ];
+ });
+ }
SelectOptionComponent.openDialog(this.dialog, options, 'common.options').afterClosed().subscribe((selectedOption: number) => {
if (selectedOption === 1) {
- this.details(transport);
+ this.changeIfPersistent([transport], !transport.isPersistent);
} else if (selectedOption === 2) {
- this.delete(transport.id);
+ this.details(transport);
+ } else if (selectedOption === 3) {
+ this.delete(transport);
+ }
+ });
+ }
+
+ /**
+ * Adds or removes the selected transports from the persistent transports list.
+ */
+ changeIfPersistentOfSelected(makePersistent: boolean) {
+ const elementsToChange: Transport[] = [];
+ this.allTransports.forEach(t => {
+ if (this.selections.has(t.id) && this.selections.get(t.id)) {
+ elementsToChange.push(t);
+ }
+ });
+ this.changeIfPersistent(elementsToChange, makePersistent);
+ }
+
+ /**
+ * Adds or removes transports from the persistent transports list.
+ */
+ changeIfPersistent(transports: Transport[], makePersistent: boolean) {
+ if (transports.length < 1) {
+ return;
+ }
+
+ let confirmationText = 'transports.';
+ if (transports.length === 1) {
+ if (makePersistent) {
+ confirmationText += 'make-persistent-confirmation';
+ } else {
+ confirmationText += 'make' + (transports[0].notFound ? '-offline' : '') + '-non-persistent-confirmation';
}
+ } else {
+ confirmationText += makePersistent ? 'make-selected-persistent-confirmation' : 'make-selected-non-persistent-confirmation';
+ }
+
+ const confirmationDialog = GeneralUtils.createConfirmationDialog(this.dialog, confirmationText);
+
+ confirmationDialog.componentInstance.operationAccepted.subscribe(() => {
+ confirmationDialog.componentInstance.showProcessing();
+
+ this.persistentTransportSubscription = this.transportService.getPersistentTransports(this.nodePK).subscribe((list: any[]) => {
+ const dataToUse = list;
+ let nothingToDo = false;
+
+ const transportsMap: Map = new Map();
+ transports.forEach(t => transportsMap.set(this.getPersistentTransportID(t.remotePk, t.type), t));
+
+ if (makePersistent) {
+ // Remove al transports that already are persistent.
+ dataToUse.forEach(tp => {
+ if (transportsMap.has(this.getPersistentTransportID(tp.pk, tp.type))) {
+ transportsMap.delete(this.getPersistentTransportID(tp.pk, tp.type));
+ }
+ });
+
+ nothingToDo = transportsMap.size === 0;
+
+ // Add the new transports to the persistent transports list.
+ if (!nothingToDo) {
+ transportsMap.forEach(t => {
+ dataToUse.push({
+ pk: t.remotePk,
+ type: t.type,
+ });
+ });
+ }
+ } else {
+ nothingToDo = true;
+ // Remove all selected transports.
+ for (let i = 0; i < dataToUse.length; i++) {
+ if (transportsMap.has(this.getPersistentTransportID(dataToUse[i].pk, dataToUse[i].type))) {
+ dataToUse.splice(i, 1);
+ nothingToDo = false;
+ i--;
+ }
+ }
+ }
+
+ if (!nothingToDo) {
+ // Update the list.
+ this.persistentTransportSubscription = this.transportService.savePersistentTransportsData(
+ NodeComponent.getCurrentNodeKey(),
+ dataToUse
+ ).subscribe(() => {
+ confirmationDialog.close();
+ // Make the parent page reload the data.
+ NodeComponent.refreshCurrentDisplayedData();
+ this.snackbarService.showDone('transports.changes-made');
+ }, (err: OperationError) => {
+ err = processServiceError(err);
+ confirmationDialog.componentInstance.showDone('confirmation.error-header-text', err.translatableErrorMsg);
+ });
+ } else {
+ // The persistent transport list already has or not (as needed) the transport.
+ confirmationDialog.close();
+ this.snackbarService.showDone('transports.no-changes-needed');
+
+ // Make the parent page reload the data, to make sure the UI shows the correct values.
+ NodeComponent.refreshCurrentDisplayedData();
+ }
+ }, (err: OperationError) => {
+ err = processServiceError(err);
+ confirmationDialog.componentInstance.showDone('confirmation.error-header-text', err.translatableErrorMsg);
+ });
});
}
@@ -365,14 +452,15 @@ export class TransportListComponent implements OnDestroy {
/**
* Deletes a specific element.
*/
- delete(id: string) {
- const confirmationDialog = GeneralUtils.createConfirmationDialog(this.dialog, 'transports.delete-confirmation');
+ delete(transport: Transport) {
+ const confirmationMsg = 'transports.delete-' + (transport.isPersistent ? 'persistent-' : '') + 'confirmation';
+ const confirmationDialog = GeneralUtils.createConfirmationDialog(this.dialog, confirmationMsg);
confirmationDialog.componentInstance.operationAccepted.subscribe(() => {
confirmationDialog.componentInstance.showProcessing();
// Start the operation and save it for posible cancellation.
- this.operationSubscriptionsGroup.push(this.startDeleting(id).subscribe(() => {
+ this.operationSubscriptionsGroup.push(this.startDeleting(transport.id).subscribe(() => {
confirmationDialog.close();
// Make the parent page reload the data.
NodeComponent.refreshCurrentDisplayedData();
@@ -391,6 +479,10 @@ export class TransportListComponent implements OnDestroy {
NodeComponent.refreshCurrentDisplayedData();
}
+ private getPersistentTransportID(pk: string, type: string): string {
+ return pk.toUpperCase() + type.toUpperCase();
+ }
+
/**
* Recalculates which elements should be shown on the UI.
*/
diff --git a/static/skywire-manager-src/src/app/services/node.service.ts b/static/skywire-manager-src/src/app/services/node.service.ts
index 9a7679e130..5a0c8f3beb 100644
--- a/static/skywire-manager-src/src/app/services/node.service.ts
+++ b/static/skywire-manager-src/src/app/services/node.service.ts
@@ -602,7 +602,7 @@ export class NodeService {
/**
* Gets the details of a specific node.
*/
- private getNode(nodeKey: string): Observable {
+ public getNode(nodeKey: string): Observable {
// Get the node data.
return this.apiService.get(`visors/${nodeKey}/summary`).pipe(
map((response: any) => {
@@ -643,7 +643,6 @@ export class NodeService {
if (response.overview.transports) {
(response.overview.transports as any[]).forEach(transport => {
node.transports.push({
- isUp: transport.is_up,
id: transport.id,
localPk: transport.local_pk,
remotePk: transport.remote_pk,
@@ -654,6 +653,17 @@ export class NodeService {
});
}
+ // Persistent Transports.
+ node.persistentTransports = [];
+ if (response.persistent_transports) {
+ (response.persistent_transports as any[]).forEach(persistentTransport => {
+ node.persistentTransports.push({
+ pk: persistentTransport.pk,
+ type: persistentTransport.type,
+ });
+ });
+ }
+
// Routes.
node.routes = [];
if (response.routes) {
diff --git a/static/skywire-manager-src/src/app/services/transport.service.ts b/static/skywire-manager-src/src/app/services/transport.service.ts
index d4c6e59596..3ef4f566a4 100644
--- a/static/skywire-manager-src/src/app/services/transport.service.ts
+++ b/static/skywire-manager-src/src/app/services/transport.service.ts
@@ -1,5 +1,6 @@
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
+import { PersistentTransport } from '../app.datatypes';
import { ApiService } from './api.service';
@@ -23,7 +24,6 @@ export class TransportService {
create(nodeKey: string, remoteKey: string, type: string): Observable {
const data = {
remote_pk: remoteKey,
- public: true,
};
if (type) {
@@ -37,6 +37,20 @@ export class TransportService {
return this.apiService.delete(`visors/${nodeKey}/transports/${transportId}`);
}
+ /**
+ * Rewrites the list of persistent transports.
+ */
+ savePersistentTransportsData(nodeKey: string, newData: PersistentTransport[]) {
+ return this.apiService.put(`visors/${nodeKey}/persistent-transports`, newData);
+ }
+
+ /**
+ * Gets the persistent transports list
+ */
+ getPersistentTransports(nodeKey: string) {
+ return this.apiService.get(`visors/${nodeKey}/persistent-transports`);
+ }
+
/**
* Gets the list of the transport types the node can work with.
*/
diff --git a/static/skywire-manager-src/src/assets/i18n/en.json b/static/skywire-manager-src/src/assets/i18n/en.json
index afdcde3b47..46bf47175b 100644
--- a/static/skywire-manager-src/src/assets/i18n/en.json
+++ b/static/skywire-manager-src/src/assets/i18n/en.json
@@ -455,34 +455,41 @@
"transports": {
"title": "Transports",
- "remove-all-offline": "Remove all offline transports",
- "remove-all-offline-confirmation": "Are you sure you want to remove all offline transports?",
- "remove-all-filtered-offline-confirmation": "All offline transports satisfying the current filtering criteria will be removed. Are you sure you want to continue?",
"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",
+ "offline": "Offline",
+ "persistent": "Persistent",
+ "persistent-tooltip": "Persistent transports, which are created automatically when the visor is turned on and are automatically recreated in case of disconnection.",
+ "persistent-transport-tooltip": "This transport is persistent, so it is created automatically when the visor is turned on and automatically recreated in case of disconnection.",
+ "persistent-transport-button-tooltip": "This transport is persistent, so it is created automatically when the visor is turned on and automatically recreated in case of disconnection. Press to make non-persistent.",
+ "non-persistent-transport-button-tooltip": "Press to make this transport persistent. Persistent transports are created automatically when the visor is turned on and automatically recreated in case of disconnection.",
+ "make-persistent": "Make persistent",
+ "make-non-persistent": "Make non-persistent",
+ "make-selected-persistent": "Make all selected persistent",
+ "make-selected-non-persistent": "Make all selected non-persistent",
+ "changes-made": "Changes made.",
+ "no-changes-needed": "No changes were needed.",
"id": "ID",
"remote-node": "Remote",
"type": "Type",
"create": "Create transport",
+ "make-persistent-confirmation": "Are you sure you want to make the transport persistent?",
+ "make-non-persistent-confirmation": "Are you sure you want to make the transport non-persistent?",
+ "make-selected-persistent-confirmation": "Are you sure you want to make the selected transports persistent?",
+ "make-selected-non-persistent-confirmation": "Are you sure you want to make the selected transports non-persistent?",
+ "make-offline-non-persistent-confirmation": "Are you sure you want to make the transport non-persistent? It will not be shown in the list while offline anymore.",
"delete-confirmation": "Are you sure you want to delete the transport?",
+ "delete-persistent-confirmation": "This transport is persistent, so it may be recreated shortly after deletion. Are you sure you want to delete it?",
"delete-selected-confirmation": "Are you sure you want to delete the selected transports?",
"delete": "Delete transport",
"deleted": "Delete operation completed.",
"empty": "Visor doesn't have any transports.",
"empty-with-filter": "No transport matches the selected filtering criteria.",
- "statuses": {
- "online": "Online",
- "online-tooltip": "Transport is online",
- "offline": "Offline",
- "offline-tooltip": "Transport is offline"
- },
"details": {
"title": "Details",
"basic": {
"title": "Basic info",
- "state": "State:",
+ "persistent": "Persistent:",
"id": "ID:",
"local-pk": "Local public key:",
"remote-pk": "Remote public key:",
@@ -498,6 +505,9 @@
"remote-key": "Remote public key",
"label": "Identification name (optional)",
"transport-type": "Transport type",
+ "make-persistent": "Make persistent",
+ "persistent-tooltip": "Persistent transports are created automatically when the visor is turned on and automatically recreated in case of disconnection.",
+ "only-persistent-created": "The persistent transport was created, but it may have not been activated.",
"success": "Transport created.",
"success-without-label": "The transport was created, but it was not possible to save the label.",
"errors": {
@@ -507,14 +517,14 @@
}
},
"filter-dialog": {
- "online": "The transport must be",
+ "persistent": "The transport must be",
"id": "The id must contain",
"remote-node": "The remote key must contain",
- "online-options": {
- "any": "Online or offline",
- "online": "Online",
- "offline": "Offline"
+ "persistent-options": {
+ "any": "Any",
+ "persistent": "Persistent",
+ "non-persistent": "Non-persistent"
}
}
},
diff --git a/static/skywire-manager-src/src/assets/i18n/es.json b/static/skywire-manager-src/src/assets/i18n/es.json
index 4fa85eca57..488e816960 100644
--- a/static/skywire-manager-src/src/assets/i18n/es.json
+++ b/static/skywire-manager-src/src/assets/i18n/es.json
@@ -16,7 +16,7 @@
"time-in-ms": "{{ time }}ms.",
"time-in-segs": "{{ time }}s.",
"ok": "Ok",
- "yes": "Yes",
+ "yes": "Sí",
"no": "No",
"unknown": "Desconocido",
"close": "Cerrar",
@@ -455,34 +455,41 @@
"transports": {
"title": "Transportes",
- "remove-all-offline": "Remover todos los transportes offline",
- "remove-all-offline-confirmation": "¿Seguro que desea remover todos los transportes offline?",
- "remove-all-filtered-offline-confirmation": "Todos los transportes offline que satisfagan los criterios de filtrado actuales serán removidos. ¿Seguro que desea continuar?",
"info": "Conexiones que tiene con visores remotos de Skywire, para permitir que las aplicaciones Skywire locales se comuniquen con las aplicaciones que se ejecutan en esos visores remotos.",
"list-title": "Lista de transportes",
- "state": "Estado",
- "state-tooltip": "Estado actual",
+ "offline": "Offline",
+ "persistent": "Persistente",
+ "persistent-tooltip": "Transportes persistentes, los cuales son creados automáticamente al iniciar el visor y son recreados automáticamente en caso de desconexión.",
+ "persistent-transport-tooltip": "Este transporte es persistente, así que es creado automáticamente al iniciar el visor y es recreado automáticamente en caso de desconexión.",
+ "persistent-transport-button-tooltip": "Este transporte es persistente, así que es creado automáticamente al iniciar el visor y es recreado automáticamente en caso de desconexión. Presione aquí para volverlo no persistente.",
+ "non-persistent-transport-button-tooltip": "Presione aquí para volver persistente el transporte. Los transportes persistentes son creados automáticamente al iniciar el visor y son recreados automáticamente en caso de desconexión.",
+ "make-persistent": "Volver persistente",
+ "make-non-persistent": "Volver no persistente",
+ "make-selected-persistent": "Volver persistentes los seleccionados",
+ "make-selected-non-persistent": "Volver no persistentes los seleccionados",
+ "changes-made": "Cambios hechos.",
+ "no-changes-needed": "Ningún cambio fue necesario.",
"id": "ID",
"remote-node": "Remoto",
"type": "Tipo",
"create": "Crear transporte",
+ "make-persistent-confirmation": "¿Seguro que desea volver persistente el transporte?",
+ "make-non-persistent-confirmation": "¿Seguro que desea volver no persistente el transporte?",
+ "make-selected-persistent-confirmation": "¿Seguro que desea volver persistentes los transportes seleccionados?",
+ "make-selected-non-persistent-confirmation": "¿Seguro que desea volver no persistentes los transportes seleccionados?",
+ "make-offline-non-persistent-confirmation": "¿Seguro que desea volver no persistente el transporte? No seguirá siendo mostrado en la lista mientras se encuentre offline.",
"delete-confirmation": "¿Seguro que desea borrar el transporte?",
+ "delete-persistent-confirmation": "Este transporte es persistente, así que puede ser recreado poco después de ser borrado. ¿Seguro que desea borrarlo?",
"delete-selected-confirmation": "¿Seguro que desea borrar los transportes seleccionados?",
"delete": "Borrar transporte",
"deleted": "Operación de borrado completada.",
"empty": "El visor no tiene ningún transporte.",
"empty-with-filter": "Ningun transporte coincide con los criterios de filtrado seleccionados.",
- "statuses": {
- "online": "Online",
- "online-tooltip": "El transporte está online",
- "offline": "Offline",
- "offline-tooltip": "El transporte está offline"
- },
"details": {
"title": "Detalles",
"basic": {
"title": "Información básica",
- "state": "Estado:",
+ "persistent": "Persistente:",
"id": "ID:",
"local-pk": "Llave pública local:",
"remote-pk": "Llave pública remota:",
@@ -498,6 +505,9 @@
"remote-key": "Llave pública remota",
"label": "Nombre del transporte (opcional)",
"transport-type": "Tipo de transporte",
+ "make-persistent": "Hacer persistente",
+ "persistent-tooltip": "Los transportes persistentes son creados automáticamente al iniciar el visor y son recreados automáticamente en caso de desconexión.",
+ "only-persistent-created": "El transporte persistente fue creado, pero podría no haber sido activado.",
"success": "Transporte creado.",
"success-without-label": "El transporte fue creado, pero no fue posible guardar la etiqueta.",
"errors": {
@@ -507,14 +517,14 @@
}
},
"filter-dialog": {
- "online": "El transporte debe estar",
+ "persistent": "El transporte debe ser",
"id": "El id debe contener",
"remote-node": "La llave remota debe contener",
- "online-options": {
- "any": "Online u offline",
- "online": "Online",
- "offline": "Offline"
+ "persistent-options": {
+ "any": "Cualquiera",
+ "persistent": "Persistente",
+ "non-persistent": "No persistente"
}
}
},
diff --git a/static/skywire-manager-src/src/assets/i18n/es_base.json b/static/skywire-manager-src/src/assets/i18n/es_base.json
index 76f33d7931..1931abc858 100644
--- a/static/skywire-manager-src/src/assets/i18n/es_base.json
+++ b/static/skywire-manager-src/src/assets/i18n/es_base.json
@@ -455,34 +455,41 @@
"transports": {
"title": "Transports",
- "remove-all-offline": "Remove all offline transports",
- "remove-all-offline-confirmation": "Are you sure you want to remove all offline transports?",
- "remove-all-filtered-offline-confirmation": "All offline transports satisfying the current filtering criteria will be removed. Are you sure you want to continue?",
"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",
+ "offline": "Offline",
+ "persistent": "Persistent",
+ "persistent-tooltip": "Persistent transports, which are created automatically when the visor is turned on and are automatically recreated in case of disconnection.",
+ "persistent-transport-tooltip": "This transport is persistent, so it is created automatically when the visor is turned on and automatically recreated in case of disconnection.",
+ "persistent-transport-button-tooltip": "This transport is persistent, so it is created automatically when the visor is turned on and automatically recreated in case of disconnection. Press to make non-persistent.",
+ "non-persistent-transport-button-tooltip": "Press to make this transport persistent. Persistent transports are created automatically when the visor is turned on and automatically recreated in case of disconnection.",
+ "make-persistent": "Make persistent",
+ "make-non-persistent": "Make non-persistent",
+ "make-selected-persistent": "Make all selected persistent",
+ "make-selected-non-persistent": "Make all selected non-persistent",
+ "changes-made": "Changes made.",
+ "no-changes-needed": "No changes were needed.",
"id": "ID",
"remote-node": "Remote",
"type": "Type",
"create": "Create transport",
+ "make-persistent-confirmation": "Are you sure you want to make the transport persistent?",
+ "make-non-persistent-confirmation": "Are you sure you want to make the transport non-persistent?",
+ "make-selected-persistent-confirmation": "Are you sure you want to make the selected transports persistent?",
+ "make-selected-non-persistent-confirmation": "Are you sure you want to make the selected transports non-persistent?",
+ "make-offline-non-persistent-confirmation": "Are you sure you want to make the transport non-persistent? It will not be shown in the list while offline anymore.",
"delete-confirmation": "Are you sure you want to delete the transport?",
+ "delete-persistent-confirmation": "This transport is persistent, so it may be recreated shortly after deletion. Are you sure you want to delete it?",
"delete-selected-confirmation": "Are you sure you want to delete the selected transports?",
"delete": "Delete transport",
"deleted": "Delete operation completed.",
"empty": "Visor doesn't have any transports.",
"empty-with-filter": "No transport matches the selected filtering criteria.",
- "statuses": {
- "online": "Online",
- "online-tooltip": "Transport is online",
- "offline": "Offline",
- "offline-tooltip": "Transport is offline"
- },
"details": {
"title": "Details",
"basic": {
"title": "Basic info",
- "state": "State:",
+ "persistent": "Persistent:",
"id": "ID:",
"local-pk": "Local public key:",
"remote-pk": "Remote public key:",
@@ -498,6 +505,9 @@
"remote-key": "Remote public key",
"label": "Identification name (optional)",
"transport-type": "Transport type",
+ "make-persistent": "Make persistent",
+ "persistent-tooltip": "Persistent transports are created automatically when the visor is turned on and automatically recreated in case of disconnection.",
+ "only-persistent-created": "The persistent transport was created, but it may have not been activated.",
"success": "Transport created.",
"success-without-label": "The transport was created, but it was not possible to save the label.",
"errors": {
@@ -507,14 +517,14 @@
}
},
"filter-dialog": {
- "online": "The transport must be",
+ "persistent": "The transport must be",
"id": "The id must contain",
"remote-node": "The remote key must contain",
- "online-options": {
- "any": "Online or offline",
- "online": "Online",
- "offline": "Offline"
+ "persistent-options": {
+ "any": "Any",
+ "persistent": "Persistent",
+ "non-persistent": "Non-persistent"
}
}
},
diff --git a/static/skywire-manager-src/src/assets/scss/_text.scss b/static/skywire-manager-src/src/assets/scss/_text.scss
index 012e6c80b7..fe2c883c00 100644
--- a/static/skywire-manager-src/src/assets/scss/_text.scss
+++ b/static/skywire-manager-src/src/assets/scss/_text.scss
@@ -45,3 +45,7 @@ span {
.red-clear-text {
color: $red-clear;
}
+
+.grey-text {
+ color: $light-gray !important;
+}
|