kill all sessions and remove ripple effect (#1567)

* button to kill all sessions, session sorting, remove ripple effect from buttons

* pr cleanup

Co-authored-by: Matt Hill <matthill@Matt-M1.local>
Co-authored-by: Lucy Cifferello <12953208+elvece@users.noreply.github.com>
This commit is contained in:
Matt Hill
2022-06-23 16:59:13 -06:00
committed by GitHub
parent 0fbcc11f99
commit 83755e93dc
7 changed files with 168 additions and 65 deletions

View File

@@ -11,7 +11,7 @@
<ion-item-group>
<ion-item-divider>Saved Marketplaces</ion-item-divider>
<ion-item button detail="false" (click)="presentModalAdd()">
<ion-icon slot="start" name="add" size="large" color="dark"></ion-icon>
<ion-icon slot="start" name="add" color="dark"></ion-icon>
<ion-label>
<ion-text color="dark">
<b>Add alt marketplace</b>
@@ -37,9 +37,6 @@
<h2>{{ mp.name }}</h2>
<p>{{ mp.url }}</p>
</ion-label>
<ion-note *ngIf="mp.id === selectedId" slot="end">
<ion-text color="success">Selected</ion-text>
</ion-note>
</ion-item>
</ion-item-group>
</ion-content>

View File

@@ -328,7 +328,7 @@ export class ServerShowPage {
},
{
title: 'Sideload Service',
description: `Manually install any service package`,
description: `Manually install a service`,
icon: 'push-outline',
action: () =>
this.navCtrl.navigateForward(['sideload'], {

View File

@@ -8,22 +8,33 @@
</ion-header>
<ion-content class="ion-padding-top">
<!-- loading -->
<ion-item-group *ngIf="loading">
<div *ngFor="let entry of ['This Session', 'Other Sessions']">
<div *ngFor="let entry of ['This Session', 'Other Sessions']">
<ion-item-divider>{{ entry }}</ion-item-divider>
<ion-item style="padding-bottom: 6px;">
<ion-avatar slot="start" style="margin-right: 30px;">
<ion-skeleton-text animated style="width: 40px; height: 40px; border-radius: 0;"></ion-skeleton-text>
<ion-item style="padding-bottom: 6px">
<ion-avatar slot="start" style="margin-right: 30px">
<ion-skeleton-text
animated
style="width: 40px; height: 40px; border-radius: 0"
></ion-skeleton-text>
</ion-avatar>
<ion-label>
<ion-skeleton-text animated style="width: 150px; height: 20px; margin-bottom: 10px;"></ion-skeleton-text>
<ion-skeleton-text animated style="width: 250px; height: 14px; margin-bottom: 12px;"></ion-skeleton-text>
<ion-skeleton-text animated style="width: 350px;"></ion-skeleton-text>
<ion-skeleton-text
animated
style="width: 150px; height: 20px; margin-bottom: 10px"
></ion-skeleton-text>
<ion-skeleton-text
animated
style="width: 250px; height: 14px; margin-bottom: 12px"
></ion-skeleton-text>
<ion-skeleton-text animated style="width: 350px"></ion-skeleton-text>
</ion-label>
<ion-button *ngIf="entry === 'second'" slot="end" fill="clear">
<ion-skeleton-text animated style="width: 60px; border-radius: 0"></ion-skeleton-text>
<ion-skeleton-text
animated
style="width: 60px; border-radius: 0"
></ion-skeleton-text>
</ion-button>
</ion-item>
</div>
@@ -31,35 +42,61 @@
<!-- not loading -->
<ion-item-group *ngIf="!loading">
<ion-item-divider>This Session</ion-item-divider>
<ion-item *ngIf="sessionInfo.sessions[sessionInfo.current] as current">
<ion-icon slot="start" size="large" [name]="getPlatformIcon(current.metadata.platforms)"></ion-icon>
<ion-item-divider>Current Session</ion-item-divider>
<ion-item>
<ion-icon
slot="start"
size="large"
[name]="getPlatformIcon(currentSession.metadata.platforms)"
></ion-icon>
<ion-label>
<h1>{{ getPlatformName(current.metadata.platforms) }}</h1>
<h2>Last Active: {{ current['last-active'] | date : 'medium' }}</h2>
<p>{{ current['user-agent'] }}</p>
<h1>{{ getPlatformName(currentSession.metadata.platforms) }}</h1>
<h2>
Last Active: {{ currentSession['last-active'] | date : 'medium' }}
</h2>
<p>{{ currentSession['user-agent'] }}</p>
</ion-label>
</ion-item>
<ion-item-divider>Other Sessions</ion-item-divider>
<div *ngFor="let session of sessionInfo.sessions | keyvalue : asIsOrder;">
<ion-item
[id]="session.key"
*ngIf="session.key !== sessionInfo.current"
<ion-item-divider>
Other Sessions
<ion-button
*ngIf="otherSessions.length"
slot="end"
fill="clear"
color="danger"
strong
(click)="presentAlertKillAll()"
>
<ion-icon slot="start" size="large" [name]="getPlatformIcon(session.value.metadata.platforms)"></ion-icon>
Kill All
</ion-button>
</ion-item-divider>
<div *ngFor="let session of otherSessions">
<ion-item>
<ion-icon
slot="start"
size="large"
[name]="getPlatformIcon(session.metadata.platforms)"
></ion-icon>
<ion-label>
<h1>{{ getPlatformName(session.value.metadata.platforms) }}</h1>
<h2>Last Active: {{ session.value['last-active'] | date : 'medium' }}</h2>
<p>{{ session.value['user-agent'] }}</p>
<h1>{{ getPlatformName(session.metadata.platforms) }}</h1>
<h2>Last Active: {{ session['last-active'] | date : 'medium' }}</h2>
<p>{{ session['user-agent'] }}</p>
</ion-label>
<ion-button slot="end" fill="clear" color="danger" (click)="presentAlertKill(session.key)">
<ion-icon slot="start" name="close"></ion-icon>
Kill
<ion-button
slot="end"
fill="clear"
color="danger"
(click)="presentAlertKill(session.id)"
>
<ion-icon slot="icon-only" name="close"></ion-icon>
</ion-button>
</ion-item>
</div>
<ion-item *ngIf="!otherSessions.length">
<ion-label>
<p>You are not logged in anywhere else</p>
</ion-label>
</ion-item>
</ion-item-group>
</ion-content>
</ion-content>

View File

@@ -1,8 +1,12 @@
import { Component } from '@angular/core'
import { AlertController, LoadingController } from '@ionic/angular'
import {
AlertController,
IonicSafeString,
LoadingController,
} from '@ionic/angular'
import { ErrorToastService } from '@start9labs/shared'
import { ApiService } from 'src/app/services/api/embassy-api.service'
import { PlatformType, RR } from 'src/app/services/api/api.types'
import { PlatformType, Session } from 'src/app/services/api/api.types'
@Component({
selector: 'sessions',
@@ -11,7 +15,8 @@ import { PlatformType, RR } from 'src/app/services/api/api.types'
})
export class SessionsPage {
loading = true
sessionInfo: RR.GetSessionsRes
currentSession: Session
otherSessions: SessionWithId[] = []
constructor(
private readonly loadingCtrl: LoadingController,
@@ -22,7 +27,22 @@ export class SessionsPage {
async ngOnInit() {
try {
this.sessionInfo = await this.embassyApi.getSessions({})
const sessionInfo = await this.embassyApi.getSessions({})
this.currentSession = sessionInfo.sessions[sessionInfo.current]
delete sessionInfo.sessions[sessionInfo.current]
this.otherSessions = Object.entries(sessionInfo.sessions)
.map(([id, session]) => {
return {
id,
...session,
}
})
.sort((a, b) => {
return (
new Date(b['last-active']).valueOf() -
new Date(a['last-active']).valueOf()
)
})
} catch (e: any) {
this.errToast.present(e)
} finally {
@@ -30,19 +50,21 @@ export class SessionsPage {
}
}
async presentAlertKill(id: string) {
async presentAlertKillAll() {
const alert = await this.alertCtrl.create({
header: 'Caution',
message: `Are you sure you want to kill this session?`,
header: 'Confirm',
message: new IonicSafeString(
`Kill all sessions?<br /><br />Note: you will <b>not</b> be logged out of your current session on this device.`,
),
buttons: [
{
text: 'Cancel',
role: 'cancel',
},
{
text: 'Kill',
text: 'Kill All',
handler: () => {
this.kill(id)
this.kill(this.otherSessions.map(s => s.id))
},
cssClass: 'enter-click',
},
@@ -51,15 +73,36 @@ export class SessionsPage {
await alert.present()
}
async kill(id: string): Promise<void> {
async presentAlertKill(id: string) {
const alert = await this.alertCtrl.create({
header: 'Confirm',
message: `Kill this session?`,
buttons: [
{
text: 'Cancel',
role: 'cancel',
},
{
text: 'Kill',
handler: () => {
this.kill([id])
},
cssClass: 'enter-click',
},
],
})
await alert.present()
}
async kill(ids: string[]): Promise<void> {
const loader = await this.loadingCtrl.create({
message: 'Killing session...',
})
await loader.present()
try {
await this.embassyApi.killSessions({ ids: [id] })
delete this.sessionInfo.sessions[id]
await this.embassyApi.killSessions({ ids })
this.otherSessions = this.otherSessions.filter(s => !ids.includes(s.id))
} catch (e: any) {
this.errToast.present(e)
} finally {
@@ -99,3 +142,7 @@ export class SessionsPage {
return 0
}
}
interface SessionWithId extends Session {
id: string
}

View File

@@ -9,13 +9,15 @@
<ion-content class="ion-padding-top">
<ion-item-group>
<!-- always -->
<ion-item>
<ion-label>
<h2>
Adding SSH keys to your Embassy is useful for command line access, as well as for debugging purposes.
<a [href]="docsUrl" target="_blank" rel="noreferrer">View instructions</a>
Adding SSH keys to your Embassy is useful for command line access, as
well as for debugging purposes.
<a [href]="docsUrl" target="_blank" rel="noreferrer"
>View instructions</a
>
</h2>
</ion-label>
</ion-item>
@@ -23,23 +25,37 @@
<ion-item-divider>Saved Keys</ion-item-divider>
<ion-item button detail="false" (click)="presentModalAdd()">
<ion-icon slot="start" name="add" size="large"></ion-icon>
<ion-label>Add new key</ion-label>
<ion-icon slot="start" name="add" color="dark"></ion-icon>
<ion-label>
<b>Add new key</b>
</ion-label>
</ion-item>
<!-- loading -->
<ng-container *ngIf="loading">
<ion-item *ngFor="let entry of ['', '']">
<ion-avatar slot="start" style="margin-right: 30px;">
<ion-skeleton-text animated style="width: 30px; height: 30px; border-radius: 0;"></ion-skeleton-text>
<ion-avatar slot="start" style="margin-right: 30px">
<ion-skeleton-text
animated
style="width: 30px; height: 30px; border-radius: 0"
></ion-skeleton-text>
</ion-avatar>
<ion-label>
<ion-skeleton-text animated style="width: 100px; height: 20px; margin-bottom: 12px;"></ion-skeleton-text>
<ion-skeleton-text animated style="width: 150px; margin-bottom: 18px;"></ion-skeleton-text>
<ion-skeleton-text animated style="width: 300px;"></ion-skeleton-text>
<ion-skeleton-text
animated
style="width: 100px; height: 20px; margin-bottom: 12px"
></ion-skeleton-text>
<ion-skeleton-text
animated
style="width: 150px; margin-bottom: 18px"
></ion-skeleton-text>
<ion-skeleton-text animated style="width: 300px"></ion-skeleton-text>
</ion-label>
<ion-button slot="end" fill="clear">
<ion-skeleton-text animated style="width: 60px; border-radius: 0"></ion-skeleton-text>
<ion-skeleton-text
animated
style="width: 60px; border-radius: 0"
></ion-skeleton-text>
</ion-button>
</ion-item>
</ng-container>
@@ -53,13 +69,16 @@
<h2>{{ ssh['created-at'] | date: 'short' }}</h2>
<p>{{ ssh.alg }} {{ ssh.fingerprint }}</p>
</ion-label>
<ion-button slot="end" fill="clear" color="danger" (click)="presentAlertDelete(i)">
<ion-button
slot="end"
fill="clear"
color="danger"
(click)="presentAlertDelete(i)"
>
<ion-icon slot="start" name="close"></ion-icon>
Remove
</ion-button>
</ion-item>
</ng-container>
</ng-container>
</ion-item-group>
</ion-content>
</ion-content>

View File

@@ -163,8 +163,10 @@
</ion-item>
</ng-container>
<ion-item button detail="false" (click)="presentModalAdd()">
<ion-icon slot="start" name="add" size="large"></ion-icon>
<ion-label>Join other network</ion-label>
<ion-icon slot="start" name="add" color="dark"></ion-icon>
<ion-label>
<b>Join another network</b>
</ion-label>
</ion-item>
</ng-container>
</ion-item-group>

View File

@@ -247,6 +247,7 @@ ion-item-divider {
ion-item {
border-radius: 6px;
--ripple-color: transparent;
}
ion-label {