Feature/copy logs (#1491)

* make text selectable on mobile

* make logs copyable and adjust copy format

* fix linting

* fix linting further

* linting

* add formatting to copied logs

* fix copy abstraction and add formatting for server log copy
This commit is contained in:
Lucy C
2022-06-09 10:21:39 -06:00
parent 09922c8dfa
commit 3cde39c7ed
10 changed files with 74 additions and 22 deletions

View File

@@ -37,7 +37,9 @@ export class SuccessPage {
async copy(address: string): Promise<void> { async copy(address: string): Promise<void> {
const success = await this.copyToClipboard(address) const success = await this.copyToClipboard(address)
const message = success ? 'copied to clipboard!' : 'failed to copy' const message = success
? 'Copied to clipboard!'
: 'Failed to copy to clipboard.'
const toast = await this.toastCtrl.create({ const toast = await this.toastCtrl.create({
header: message, header: message,

View File

@@ -1,5 +1,12 @@
$wide-modal: 900px; $wide-modal: 900px;
body {
-webkit-user-select: text;
-moz-user-select: text;
-ms-user-select: text;
user-select: text;
}
ion-input { ion-input {
caret-color: gray; caret-color: gray;
} }
@@ -73,17 +80,17 @@ ion-modal::part(content) {
} }
/* Hide scrollbar for IE, Edge and Firefox */ /* Hide scrollbar for IE, Edge and Firefox */
-ms-overflow-style: none; /* IE and Edge */ /* IE and Edge */
scrollbar-width: none; /* Firefox */ -ms-overflow-style: none;
/* Firefox */
scrollbar-width: none;
} }
.divider { .divider {
background: linear-gradient( background: linear-gradient(90deg,
90deg, var(--ion-color-light) 0,
var(--ion-color-light) 0, var(--ion-color-dark) 50%,
var(--ion-color-dark) 50%, var(--ion-color-light) 100%);
var(--ion-color-light) 100%
);
height: 1px; height: 1px;
} }
@@ -98,5 +105,5 @@ ion-modal::part(content) {
} }
.montserrat { .montserrat {
font-family: 'Montserrat', sans-serif!important; font-family: 'Montserrat', sans-serif !important;
} }

View File

@@ -11,15 +11,18 @@ import { copyToClipboard } from 'src/app/util/web.util'
export class ActionSuccessPage { export class ActionSuccessPage {
@Input() actionRes: ActionResponse @Input() actionRes: ActionResponse
constructor ( constructor(
private readonly modalCtrl: ModalController, private readonly modalCtrl: ModalController,
private readonly toastCtrl: ToastController, private readonly toastCtrl: ToastController,
) { } ) {}
async copy (address: string) { async copy(address: string) {
let message = '' let message = ''
await copyToClipboard(address || '') await copyToClipboard(address || '').then(success => {
.then(success => { message = success ? 'copied to clipboard!' : 'failed to copy'}) message = success
? 'Copied to clipboard!'
: 'Failed to copy to clipboard.'
})
const toast = await this.toastCtrl.create({ const toast = await this.toastCtrl.create({
header: message, header: message,
@@ -29,7 +32,7 @@ export class ActionSuccessPage {
await toast.present() await toast.present()
} }
async dismiss () { async dismiss() {
return this.modalCtrl.dismiss() return this.modalCtrl.dismiss()
} }
} }

View File

@@ -99,7 +99,9 @@ export class AppInterfacesItemComponent {
async copy(address: string): Promise<void> { async copy(address: string): Promise<void> {
let message = '' let message = ''
await copyToClipboard(address || '').then(success => { await copyToClipboard(address || '').then(success => {
message = success ? 'copied to clipboard!' : 'failed to copy' message = success
? 'Copied to clipboard!'
: 'Failed to copy to clipboard.'
}) })
const toast = await this.toastCtrl.create({ const toast = await this.toastCtrl.create({

View File

@@ -4,6 +4,9 @@
<ion-back-button [defaultHref]="'/services/' + pkgId"></ion-back-button> <ion-back-button [defaultHref]="'/services/' + pkgId"></ion-back-button>
</ion-buttons> </ion-buttons>
<ion-title>Logs</ion-title> <ion-title>Logs</ion-title>
<ion-button slot="end" fill="clear" size="small" (click)="copy()">
<ion-icon slot="icon-only" name="copy-outline"></ion-icon>
</ion-button>
</ion-toolbar> </ion-toolbar>
</ion-header> </ion-header>

View File

@@ -1,7 +1,9 @@
import { Component } from '@angular/core' import { Component } from '@angular/core'
import { ActivatedRoute } from '@angular/router' import { ActivatedRoute } from '@angular/router'
import { getPkgId } from '@start9labs/shared' import { getPkgId } from '@start9labs/shared'
import { ToastController } from '@ionic/angular'
import { ApiService } from 'src/app/services/api/embassy-api.service' import { ApiService } from 'src/app/services/api/embassy-api.service'
import { copyToClipboard } from 'src/app/util/web.util'
@Component({ @Component({
selector: 'app-logs', selector: 'app-logs',
@@ -17,6 +19,7 @@ export class AppLogsPage {
constructor( constructor(
private readonly route: ActivatedRoute, private readonly route: ActivatedRoute,
private readonly embassyApi: ApiService, private readonly embassyApi: ApiService,
private readonly toastCtrl: ToastController,
) {} ) {}
fetchFetchLogs() { fetchFetchLogs() {
@@ -33,4 +36,22 @@ export class AppLogsPage {
}) })
} }
} }
async copy(): Promise<void> {
const logs = document
.getElementById('template')
?.cloneNode(true) as HTMLElement
const formatted = '```' + logs.innerHTML + '```'
const success = await copyToClipboard(formatted)
const message = success
? 'Copied to clipboard!'
: 'Failed to copy to clipboard.'
const toast = await this.toastCtrl.create({
header: message,
position: 'bottom',
duration: 1000,
})
await toast.present()
}
} }

View File

@@ -114,7 +114,9 @@ export class AppPropertiesPage {
async copy(text: string): Promise<void> { async copy(text: string): Promise<void> {
let message = '' let message = ''
await copyToClipboard(text).then(success => { await copyToClipboard(text).then(success => {
message = success ? 'copied to clipboard!' : 'failed to copy' message = success
? 'Copied to clipboard!'
: 'Failed to copy to clipboard.'
}) })
const toast = await this.toastCtrl.create({ const toast = await this.toastCtrl.create({

View File

@@ -4,6 +4,9 @@
<ion-back-button defaultHref="embassy"></ion-back-button> <ion-back-button defaultHref="embassy"></ion-back-button>
</ion-buttons> </ion-buttons>
<ion-title>OS Logs</ion-title> <ion-title>OS Logs</ion-title>
<ion-button slot="end" fill="clear" size="small" (click)="copy()">
<ion-icon slot="icon-only" name="copy-outline"></ion-icon>
</ion-button>
</ion-toolbar> </ion-toolbar>
</ion-header> </ion-header>

View File

@@ -1,5 +1,7 @@
import { Component } from '@angular/core' import { Component } from '@angular/core'
import { ToastController } from '@ionic/angular'
import { ApiService } from 'src/app/services/api/embassy-api.service' import { ApiService } from 'src/app/services/api/embassy-api.service'
import { copyToClipboard } from 'src/app/util/web.util'
@Component({ @Component({
selector: 'server-logs', selector: 'server-logs',
@@ -14,10 +16,15 @@ export class ServerLogsPage {
constructor( constructor(
private readonly embassyApi: ApiService, private readonly embassyApi: ApiService,
private readonly toastCtrl: ToastController,
) { } ) { }
fetchFetchLogs() { fetchFetchLogs() {
return async (params: { before_flag?: boolean, limit?: number, cursor?: string }) => { return async (params: {
before_flag?: boolean
limit?: number
cursor?: string
}) => {
return this.embassyApi.getServerLogs({ return this.embassyApi.getServerLogs({
before_flag: params.before_flag, before_flag: params.before_flag,
cursor: params.cursor, cursor: params.cursor,

View File

@@ -27,7 +27,9 @@ export class ServerSpecsPage {
async copy(address: string) { async copy(address: string) {
let message = '' let message = ''
await copyToClipboard(address || '').then(success => { await copyToClipboard(address || '').then(success => {
message = success ? 'copied to clipboard!' : 'failed to copy' message = success
? 'Copied to clipboard!'
: 'Failed to copy to clipboard.'
}) })
const toast = await this.toastCtrl.create({ const toast = await this.toastCtrl.create({