cleaned up #409 and renamed to Groups

This commit is contained in:
Eugene Pankov 2018-09-04 22:39:00 +02:00
parent f357dab8f0
commit d6f163b048
7 changed files with 100 additions and 157 deletions

View file

@ -83,6 +83,10 @@ $list-group-border-color: rgba(255,255,255,.1);
$list-group-hover-bg: rgba(255,255,255,.1); $list-group-hover-bg: rgba(255,255,255,.1);
$list-group-link-active-bg: rgba(255,255,255,.2); $list-group-link-active-bg: rgba(255,255,255,.2);
$list-group-action-color: $body-color;
$list-group-action-bg: rgba(255,255,255,.05);
$list-group-action-active-bg: $list-group-link-active-bg;
$pre-bg: $dropdown-bg; $pre-bg: $dropdown-bg;
$pre-color: $dropdown-link-color; $pre-color: $dropdown-link-color;

View file

@ -12,7 +12,7 @@ export interface SSHConnection {
user: string user: string
password?: string password?: string
privateKey?: string privateKey?: string
path?: string group?: string
scripts?: LoginScript[] scripts?: LoginScript[]
} }
@ -21,7 +21,7 @@ export class SSHSession extends BaseSession {
constructor (private shell: any, conn: SSHConnection) { constructor (private shell: any, conn: SSHConnection) {
super() super()
this.scripts = conn.scripts.slice(0); this.scripts = conn.scripts ? [...conn.scripts] : []
} }
start () { start () {
@ -101,3 +101,8 @@ export class SSHSession extends BaseSession {
return null return null
} }
} }
export interface ISSHConnectionGroup {
name: string
connections: SSHConnection[]
}

View file

@ -13,6 +13,14 @@
[(ngModel)]='connection.name', [(ngModel)]='connection.name',
) )
.form-group
label Group
input.form-control(
type='text',
placeholder='Ungrouped',
[(ngModel)]='connection.group',
)
.form-group .form-group
label Host label Host
input.form-control( input.form-control(

View file

@ -4,7 +4,7 @@
[(ngModel)]='quickTarget', [(ngModel)]='quickTarget',
autofocus, autofocus,
placeholder='Quick connect: [user@]host[:port]', placeholder='Quick connect: [user@]host[:port]',
(ngModelChange)='filter()', (ngModelChange)='refresh()',
(keyup.enter)='quickConnect()' (keyup.enter)='quickConnect()'
) )
@ -14,15 +14,15 @@
span {{lastConnection.name}} span {{lastConnection.name}}
.list-group.mt-3 .list-group.mt-3
a.list-group-item.list-group-item-action(*ngFor='let folder of childFolders', (click)='cd(folder)') ng-container(*ngFor='let group of childGroups')
i.fa.fa-fw.fa-folder .list-group-item.list-group-item-action.d-flex.align-items-center(
span {{folder}} (click)='groupCollapsed[group.name] = !groupCollapsed[group.name]'
a.list-group-item.list-group-item-action(*ngFor='let connection of childConnections', (click)='connect(connection)') )
i.fa.fa-fw.fa-globe .fa.fa-fw.fa-chevron-right(*ngIf='groupCollapsed[group.name]')
span {{connection.name}} .fa.fa-fw.fa-chevron-down(*ngIf='!groupCollapsed[group.name]')
a.list-group-item.list-group-item-action((click)='manageConnections()') .ml-2 {{group.name || "Ungrouped"}}
i.fa.fa-fw.fa-wrench ng-container(*ngIf='!groupCollapsed[group.name]')
span Manage connections .list-group-item.list-group-item-action.pl-5.d-flex.align-items-center(
*ngFor='let connection of group.connections',
//.modal-footer (click)='connect(connection)'
button.btn.btn-outline-primary((click)='close()') Cancel ) {{connection.name}}

View file

@ -4,19 +4,18 @@ import { ToastrService } from 'ngx-toastr'
import { ConfigService, AppService } from 'terminus-core' import { ConfigService, AppService } from 'terminus-core'
import { SettingsTabComponent } from 'terminus-settings' import { SettingsTabComponent } from 'terminus-settings'
import { SSHService } from '../services/ssh.service' import { SSHService } from '../services/ssh.service'
import { SSHConnection } from '../api' import { SSHConnection, ISSHConnectionGroup } from '../api'
@Component({ @Component({
template: require('./sshModal.component.pug'), template: require('./sshModal.component.pug'),
//styles: [require('./sshModal.component.scss')],
}) })
export class SSHModalComponent { export class SSHModalComponent {
connections: SSHConnection[] connections: SSHConnection[]
childFolders: ISSHConnectionGroup[]
quickTarget: string quickTarget: string
lastConnection: SSHConnection lastConnection: SSHConnection
currentPath: string childGroups: ISSHConnectionGroup[]
childFolders: string[] groupCollapsed: {[id: string]: boolean} = {}
childConnections: SSHConnection[]
constructor ( constructor (
public modalInstance: NgbActiveModal, public modalInstance: NgbActiveModal,
@ -31,18 +30,7 @@ export class SSHModalComponent {
if (window.localStorage.lastConnection) { if (window.localStorage.lastConnection) {
this.lastConnection = JSON.parse(window.localStorage.lastConnection) this.lastConnection = JSON.parse(window.localStorage.lastConnection)
} }
this.currentPath = "/" this.refresh()
this.findChildren()
}
filter () {
if (!this.quickTarget) {
this.findChildren()
}
else {
this.childFolders = [];
this.childConnections = this.connections.filter(connection => connection.name.toLowerCase().indexOf(this.quickTarget) >= 0)
}
} }
quickConnect () { quickConnect () {
@ -81,37 +69,25 @@ export class SSHModalComponent {
this.modalInstance.close() this.modalInstance.close()
} }
findChildren () { refresh () {
this.childFolders = [] this.childGroups = []
this.childConnections = []
if (this.currentPath != "/") let connections = this.connections
this.childFolders.push("..") if (this.quickTarget) {
connections = connections.filter(connection => (connection.name + connection.group).toLowerCase().indexOf(this.quickTarget) >= 0)
}
for (let connection of this.connections) { for (let connection of connections) {
if (!connection.path) connection.group = connection.group || null
connection.path = "/" let group = this.childGroups.find(x => x.name === connection.group)
if (connection.path.startsWith(this.currentPath)) { if (!group) {
let folder = connection.path.substr(this.currentPath.length, connection.path.indexOf("/", this.currentPath.length) - this.currentPath.length) group = {
if (folder.length == 0) { name: connection.group,
this.childConnections.push(connection) connections: [],
}
else if (this.childFolders.indexOf(folder) < 0) {
this.childFolders.push(folder)
} }
this.childGroups.push(group)
} }
group.connections.push(connection)
} }
} }
cd (path: string) {
if (path == "..") {
path = this.currentPath.substr(0, this.currentPath.lastIndexOf("/", this.currentPath.length - 2) + 1)
}
else {
path = this.currentPath + path + '/'
}
this.currentPath = path
this.findChildren()
}
} }

View file

@ -1,33 +1,25 @@
h3 Connections ({{currentPath}}) h3 Connections
.list-group.mt-3.mb-3 .list-group.mt-3.mb-3
.list-group-item(*ngFor='let folder of childFolders') ng-container(*ngFor='let group of childGroups')
.d-flex.w-100 .list-group-item.list-group-item-action.d-flex.align-items-center((click)='groupCollapsed[group.name] = !groupCollapsed[group.name]')
a.mr-auto.list-group-item-action((click)='cd(folder)') .fa.fa-fw.fa-chevron-right(*ngIf='groupCollapsed[group.name]')
div.fa.fa-fw.fa-folder .fa.fa-fw.fa-chevron-down(*ngIf='!groupCollapsed[group.name]')
span.ml-2 {{folder}} span.ml-3.mr-auto {{group.name || "Ungrouped"}}
button.btn.btn-outline-info.ml-2(*ngIf='folder != ".."', (click)='editFolder(folder)') button.btn.btn-outline-info.ml-2((click)='editGroup(group)')
i.fa.fa-pencil i.fa.fa-pencil
button.btn.btn-outline-info.disabled.ml-2(*ngIf='folder == ".."') button.btn.btn-outline-danger.ml-1((click)='deleteGroup(group)')
i.fa.fa-pencil
button.btn.btn-outline-danger.ml-1(*ngIf='folder != ".."', (click)='deleteFolder(folder)')
i.fa.fa-trash-o
button.btn.btn-outline-danger.disabled.ml-1(*ngIf='folder == ".."')
i.fa.fa-trash-o
.list-group-item(*ngFor='let connection of childConnections')
.d-flex.w-100
.mr-auto
div.fa.fa-fw.fa-globe
span.ml-2 {{connection.name}}
.text-muted {{connection.host}}
button.btn.btn-outline-info.ml-2((click)='editConnection(connection)')
i.fa.fa-pencil
button.btn.btn-outline-danger.ml-1((click)='deleteConnection(connection)')
i.fa.fa-trash-o i.fa.fa-trash-o
ng-container(*ngIf='!groupCollapsed[group.name]')
.list-group-item.pl-5.d-flex.align-items-center(*ngFor='let connection of group.connections')
.mr-auto
div {{connection.name}}
.text-muted {{connection.host}}
button.btn.btn-outline-info.ml-2((click)='editConnection(connection)')
i.fa.fa-pencil
button.btn.btn-outline-danger.ml-1((click)='deleteConnection(connection)')
i.fa.fa-trash-o
button.btn.btn-outline-primary((click)='createFolder()') button.btn.btn-outline-primary((click)='createConnection()')
div.fa.fa-fw.fa-folder
span.ml-2 Add Folder
button.btn.btn-outline-primary.ml-2((click)='createConnection()')
div.fa.fa-fw.fa-globe div.fa.fa-fw.fa-globe
span.ml-2 Add connection span.ml-2 Add connection

View file

@ -1,7 +1,7 @@
import { Component } from '@angular/core' import { Component } from '@angular/core'
import { NgbModal } from '@ng-bootstrap/ng-bootstrap' import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
import { ConfigService } from 'terminus-core' import { ConfigService } from 'terminus-core'
import { SSHConnection } from '../api' import { SSHConnection, ISSHConnectionGroup } from '../api'
import { EditConnectionModalComponent } from './editConnectionModal.component' import { EditConnectionModalComponent } from './editConnectionModal.component'
import { PromptModalComponent } from './promptModal.component' import { PromptModalComponent } from './promptModal.component'
@ -10,17 +10,15 @@ import { PromptModalComponent } from './promptModal.component'
}) })
export class SSHSettingsTabComponent { export class SSHSettingsTabComponent {
connections: SSHConnection[] connections: SSHConnection[]
currentPath: string childGroups: ISSHConnectionGroup[]
childFolders: string[] groupCollapsed: {[id: string]: boolean} = {}
childConnections: SSHConnection[]
constructor ( constructor (
public config: ConfigService, public config: ConfigService,
private ngbModal: NgbModal, private ngbModal: NgbModal,
) { ) {
this.connections = this.config.store.ssh.connections this.connections = this.config.store.ssh.connections
this.currentPath = "/" this.refresh()
this.findChildren()
} }
createConnection () { createConnection () {
@ -29,7 +27,6 @@ export class SSHSettingsTabComponent {
host: '', host: '',
port: 22, port: 22,
user: 'root', user: 'root',
path: this.currentPath
} }
let modal = this.ngbModal.open(EditConnectionModalComponent) let modal = this.ngbModal.open(EditConnectionModalComponent)
@ -38,7 +35,7 @@ export class SSHSettingsTabComponent {
this.connections.push(result) this.connections.push(result)
this.config.store.ssh.connections = this.connections this.config.store.ssh.connections = this.connections
this.config.save() this.config.save()
this.childConnections.push(result) this.refresh()
}) })
} }
@ -48,6 +45,7 @@ export class SSHSettingsTabComponent {
modal.result.then(result => { modal.result.then(result => {
Object.assign(connection, result) Object.assign(connection, result)
this.config.save() this.config.save()
this.refresh()
}) })
} }
@ -56,89 +54,49 @@ export class SSHSettingsTabComponent {
this.connections = this.connections.filter(x => x !== connection) this.connections = this.connections.filter(x => x !== connection)
this.config.store.ssh.connections = this.connections this.config.store.ssh.connections = this.connections
this.config.save() this.config.save()
this.childConnections = this.connections.filter(x => x !== connection) this.refresh()
} }
} }
createFolder () { editGroup (group: ISSHConnectionGroup) {
let modal = this.ngbModal.open(PromptModalComponent) let modal = this.ngbModal.open(PromptModalComponent)
modal.componentInstance.prompt = 'folder name' modal.componentInstance.prompt = 'New group name'
modal.componentInstance.password = false modal.componentInstance.value = group
modal.result.then(result => { modal.result.then(result => {
if (result) { if (result) {
if (!this.childFolders.includes(result)) { for (let connection of this.connections.filter(x => x.group === group.name)) {
this.childFolders.push(result) connection.group = result
}
}
})
}
editFolder (folder: string) {
let modal = this.ngbModal.open(PromptModalComponent)
modal.componentInstance.prompt = 'folder name'
modal.componentInstance.password = false
modal.componentInstance.value = folder
modal.result.then(result => {
if (result) {
let oldPath = this.currentPath + folder + "/"
let newPath = this.currentPath + result + "/"
for (let connection of this.connections) {
connection.path = connection.path.replace(oldPath, newPath)
}
let i = this.childFolders.indexOf(folder)
if (this.childFolders.includes(result)) {
this.childFolders.splice(i, 1)
}
else {
this.childFolders.splice(i, 1, result)
} }
this.config.save() this.config.save()
this.refresh()
} }
}) })
} }
deleteFolder (folder: string) { deleteGroup (group: ISSHConnectionGroup) {
if (confirm(`Delete "${folder}"?`)) { if (confirm(`Delete "${group}"?`)) {
let oldPath = this.currentPath + folder + "/" for (let connection of this.connections.filter(x => x.group === group.name)) {
for (let connection of this.connections) { connection.group = null
connection.path = connection.path.replace(oldPath, this.currentPath)
} }
this.config.save() this.config.save()
this.findChildren() this.refresh()
} }
} }
findChildren () { refresh () {
this.childFolders = [] this.childGroups = []
this.childConnections = []
if (this.currentPath != "/")
this.childFolders.push("..")
for (let connection of this.connections) { for (let connection of this.connections) {
if (!connection.path) connection.group = connection.group || null
connection.path = "/" let group = this.childGroups.find(x => x.name === connection.group)
if (connection.path.startsWith(this.currentPath)) { if (!group) {
let folder = connection.path.substr(this.currentPath.length, connection.path.indexOf("/", this.currentPath.length) - this.currentPath.length) group = {
if (folder.length == 0) { name: connection.group,
this.childConnections.push(connection) connections: [],
}
else if (this.childFolders.indexOf(folder) < 0) {
this.childFolders.push(folder)
} }
this.childGroups.push(group)
} }
group.connections.push(connection)
} }
} }
cd (path: string) {
if (path == "..") {
path = this.currentPath.substr(0, this.currentPath.lastIndexOf("/", this.currentPath.length - 2) + 1)
}
else {
path = this.currentPath + path + '/'
}
this.currentPath = path
this.findChildren()
}
} }