更新UI和增加删除操作
parent
ee6dd0f1ad
commit
7131c4067e
|
@ -52,3 +52,12 @@ class Docker:
|
|||
'size': it['Size'],
|
||||
'created': toISOTime(it['CreatedAt']),
|
||||
} for it in out]
|
||||
|
||||
|
||||
def rm(self, id = ''):
|
||||
cmd = 'docker rm ' + id
|
||||
out = subprocess.run(cmd, shell=True, stdout=subprocess.PIPE)
|
||||
|
||||
def rmi(self, id = ''):
|
||||
cmd = 'docker rmi ' + id
|
||||
out = subprocess.run(cmd, shell=True, stdout=subprocess.PIPE)
|
|
@ -7,7 +7,7 @@ gi.require_version('Gtk', '3.0')
|
|||
from gi.repository import Gtk
|
||||
|
||||
class Window(Gtk.Window):
|
||||
def __init__(self, title = 'Untitled window', width = 960, height = 640):
|
||||
def __init__(self, title = 'Untitled window', width = 896, height = 576):
|
||||
Gtk.Window.__init__(self, title = title)
|
||||
self.set_default_size(width, height)
|
||||
self.resize(width, height)
|
||||
|
|
|
@ -61,6 +61,12 @@ class Application(Gtk.Application):
|
|||
case 'images':
|
||||
output = client.images()
|
||||
|
||||
case 'rm':
|
||||
client.rm(params.get('id'))
|
||||
|
||||
case 'rmi':
|
||||
client.rmi(params.get('id'))
|
||||
|
||||
|
||||
|
||||
return (_error, output)
|
||||
|
|
|
@ -52,7 +52,7 @@ class Sidebar extends Component {
|
|||
background: #fff;
|
||||
}
|
||||
.item.active {
|
||||
color: var(--color-orange-3);
|
||||
color: var(--color-blue-3);
|
||||
box-shadow: 0 0 6px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
`
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import{css as p,html as c,Component as l,bind as a,unbind as d,styleMap as f,offset as h,outsideClick as m,clearOutsideClick as x}from"wkit";import"../base/button.js";const w="\u8BF7\u786E\u8BA4\u4F60\u7684\u64CD\u4F5C!";class u extends l{static props={title:"str!",confirmButtonType:"str!primary"};static styles=[p`:host{display:inline-flex}.container{position:relative}.tooltip{display:none;position:fixed;z-index:9;justify-content:center;align-items:center;max-width:260px;min-width:32px;padding:8px 12px 12px;border-radius:3px;font-size:var(--wc-popconfirm-font, 14px);background:var(--wc-popconfirm-background, #fff);color:var(--wc-popconfirm-color, var(--color-dark-1));box-shadow:0 0 3px var(--wc-popconfirm-shadow, rgba(0, 0, 0, 0.3));word-break:break-all;-webkit-user-select:none;user-select:none}.tooltip::after{position:absolute;display:block;width:8px;height:8px;border-radius:2px;background:var(--wc-popconfirm-background, #fff);content:"";transform:rotate(45deg);box-shadow:-1px -1px 0 var(--wc-popconfirm-shadow, rgba(0, 0, 0, 0.1))}.tooltip[placement=left-top]::after{right:16px;bottom:-4px;box-shadow:1px 1px 0 var(--wc-popconfirm-shadow, rgba(0, 0, 0, 0.1))}.tooltip[placement=left-bottom]::after{right:16px;top:-4px}.tooltip[placement=right-top]::after{left:16px;bottom:-4px;box-shadow:1px 1px 0 var(--wc-popconfirm-shadow, rgba(0, 0, 0, 0.1))}.tooltip[placement=right-bottom]::after{left:16px;top:-4px}`,p`.title{display:flex;align-items:center;gap:6px;padding:8px 0;--wc-icon-size: 16px}.title wc-icon{flex-shrink:0;color:var(--wc-popconfirm-icon-color, var(--color-red-1))}:host([hide-icon]) .title wc-icon{display:none}.actions{display:flex;justify-content:flex-end;gap:4px;margin-top:8px}.actions wc-button{min-width:40px;height:20px;font-size:12px}.actions wc-button:first-child{--wc-button-border-color: none}`];#t=!1;#i(s){let{left:t,top:i}=h(this),e="left",o={display:"block"},r=document.documentElement.scrollTop;if(!this.#t){if(t<260||t>260&&window.innerWidth-t>260)e="right",o.left=t+"px";else{let n=window.innerWidth-t+this.clientWidth;o.right=n+"px"}if(i<160)i+=8+this.clientHeight,e+="-bottom",o.top=i+"px";else{let n=window.innerHeight-i+8;e+="-top",o.bottom=n+"px",r>0&&(o.transform=`translateY(-${r}px)`)}this.#t=!0,this.$refs.tips.setAttribute("placement",e),this.$refs.tips.style.cssText=f(o),this.$refs.tips.$animate()}}#o(){this.#t&&(this.#t=!1,this.$refs.tips.$animate(!0))}#e(){this.$emit("confirm"),this.#o()}mounted(){this._outFn=m(this,s=>this.#o()),this._scrollFn=a(document,"scroll",s=>{if(this.#t){let t=document.documentElement.scrollTop;this.$refs.tips.style.transform=`translateY(-${t}px)`}})}unmounted(){d(document,"scroll",this._scrollFn),x(this._outFn)}render(){return c`
|
||||
import{css as p,html as c,Component as l,bind as a,unbind as d,styleMap as f,offset as h,outsideClick as m,clearOutsideClick as x}from"wkit";import"../base/button.js";const w="\u8BF7\u786E\u8BA4\u4F60\u7684\u64CD\u4F5C!";class u extends l{static props={title:"str!",confirmButtonType:"str!primary"};static styles=[p`:host{display:inline-flex}.container{position:relative}.tooltip{display:none;position:fixed;z-index:9;justify-content:center;align-items:center;max-width:260px;min-width:32px;padding:8px 12px 12px;border-radius:3px;font-size:var(--wc-popconfirm-font, 14px);background:var(--wc-popconfirm-background, #fff);color:var(--wc-popconfirm-color, var(--color-dark-1));box-shadow:0 0 3px var(--wc-popconfirm-shadow, rgba(0, 0, 0, 0.3));word-break:break-all;-webkit-user-select:none;user-select:none}.tooltip::after{position:absolute;display:block;width:8px;height:8px;border-radius:2px;background:var(--wc-popconfirm-background, #fff);content:"";transform:rotate(45deg);box-shadow:-1px -1px 0 var(--wc-popconfirm-shadow, rgba(0, 0, 0, 0.1))}.tooltip[placement=left-top]::after{right:16px;bottom:-4px;box-shadow:1px 1px 0 var(--wc-popconfirm-shadow, rgba(0, 0, 0, 0.1))}.tooltip[placement=left-bottom]::after{right:16px;top:-4px}.tooltip[placement=right-top]::after{left:16px;bottom:-4px;box-shadow:1px 1px 0 var(--wc-popconfirm-shadow, rgba(0, 0, 0, 0.1))}.tooltip[placement=right-bottom]::after{left:16px;top:-4px}`,p`.title{display:flex;align-items:center;gap:6px;padding:8px 0;--wc-icon-size: 16px}.title wc-icon{flex-shrink:0;color:var(--wc-popconfirm-icon-color, var(--color-red-1))}:host([hide-icon]) .title wc-icon{display:none}.actions{display:flex;justify-content:flex-end;gap:4px;margin-top:8px}.actions wc-button{min-width:40px;height:20px;font-size:12px}.actions wc-button:first-child{--wc-button-border-color: none}`];#t=!1;#i(s){let{left:t,top:e}=h(this),n="left",o={display:"block"},r=document.documentElement.scrollTop;if(!this.#t){if(t<260||t>260&&window.innerWidth-t>260)n="right",o.left=t+"px";else{let i=window.innerWidth-t-this.clientWidth-12;i<0&&(i=0),o.right=i+"px"}if(e<160)e+=8+this.clientHeight,n+="-bottom",o.top=e+"px";else{let i=window.innerHeight-e+8;n+="-top",o.bottom=i+"px",r>0&&(o.transform=`translateY(-${r}px)`)}this.#t=!0,this.$refs.tips.setAttribute("placement",n),this.$refs.tips.style.cssText=f(o),this.$refs.tips.$animate()}}#o(){this.#t&&(this.#t=!1,this.$refs.tips.$animate(!0))}#e(){this.$emit("confirm"),this.#o()}mounted(){this._outFn=m(this,s=>this.#o()),this._scrollFn=a(document,"scroll",s=>{if(this.#t){let t=document.documentElement.scrollTop;this.$refs.tips.style.transform=`translateY(-${t}px)`}})}unmounted(){d(document,"scroll",this._scrollFn),x(this._outFn)}render(){return c`
|
||||
<main class="container">
|
||||
<div class="wrapper" @click=${this.#i}>
|
||||
<slot></slot>
|
||||
|
@ -17,7 +17,6 @@ import{css as p,html as c,Component as l,bind as a,unbind as d,styleMap as f,off
|
|||
>确定</wc-button
|
||||
>
|
||||
</footer>
|
||||
<i class="trigon"></i>
|
||||
</div>
|
||||
</main>
|
||||
`}}u.reg("popconfirm");
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import{css as a,html as n,Component as d,bind as r,styleMap as c,offset as f}from"wkit";class h extends d{static props={title:"str!"};static styles=[a`:host{display:inline-flex}.container{position:relative}.tooltip{display:none;position:fixed;z-index:9;justify-content:center;align-items:center;max-width:360px;min-width:32px;padding:6px 8px;border-radius:3px;font-size:var(--wc-tooltip-font, 14px);background:var(--wc-tooltip-background, #fff);color:var(--wc-tooltip-color, var(--color-dark-1));box-shadow:0 0 3px var(--wc-tooltip-shadow, rgba(0, 0, 0, 0.3));word-break:break-all;-webkit-user-select:none;user-select:none}.tooltip::after{position:absolute;display:block;width:8px;height:8px;border-radius:2px;background:var(--wc-tooltip-background, #fff);content:"";transform:rotate(45deg);box-shadow:-1px -1px 0 var(--wc-tooltip-shadow, rgba(0, 0, 0, 0.1))}.tooltip[placement=left-top]::after{right:16px;bottom:-4px;box-shadow:1px 1px 0 var(--wc-tooltip-shadow, rgba(0, 0, 0, 0.1))}.tooltip[placement=left-bottom]::after{right:16px;top:-4px}.tooltip[placement=right-top]::after{left:16px;bottom:-4px;box-shadow:1px 1px 0 var(--wc-tooltip-shadow, rgba(0, 0, 0, 0.1))}.tooltip[placement=right-bottom]::after{left:16px;top:-4px}`];mounted(){r(this.$refs.wrap,"mouseenter",p=>{let{left:t,top:e}=f(this),i="left",o={display:"block"},l=document.documentElement.scrollTop;if(this.title.trim()!==""){if(t<360||t>360&&window.innerWidth-t>360)i="right",o.left=t+"px";else{let s=window.innerWidth-t-this.clientWidth;o.right=s+"px"}if(e<96)e+=8+this.clientHeight,i+="-bottom",o.top=e+"px";else{let s=window.innerHeight-e+8+l;i+="-top",o.bottom=s+"px"}this.$refs.tips.setAttribute("placement",i),this.$refs.tips.style.cssText=c(o),this.$refs.tips.$animate()}}),r(this.$refs.wrap,"mouseleave",p=>{this.$refs.tips.$animate(!0)})}render(){return n`
|
||||
import{css as a,html as n,Component as d,bind as s,styleMap as c,offset as f}from"wkit";class h extends d{static props={title:"str!"};static styles=[a`:host{display:inline-flex}.container{position:relative}.tooltip{display:none;position:fixed;z-index:9;justify-content:center;align-items:center;max-width:360px;min-width:32px;padding:6px 8px;border-radius:3px;font-size:var(--wc-tooltip-font, 14px);background:var(--wc-tooltip-background, #fff);color:var(--wc-tooltip-color, var(--color-dark-1));box-shadow:0 0 3px var(--wc-tooltip-shadow, rgba(0, 0, 0, 0.3));word-break:break-all;-webkit-user-select:none;user-select:none}.tooltip::after{position:absolute;display:block;width:8px;height:8px;border-radius:2px;background:var(--wc-tooltip-background, #fff);content:"";transform:rotate(45deg);box-shadow:-1px -1px 0 var(--wc-tooltip-shadow, rgba(0, 0, 0, 0.1))}.tooltip[placement=left-top]::after{right:16px;bottom:-4px;box-shadow:1px 1px 0 var(--wc-tooltip-shadow, rgba(0, 0, 0, 0.1))}.tooltip[placement=left-bottom]::after{right:16px;top:-4px}.tooltip[placement=right-top]::after{left:16px;bottom:-4px;box-shadow:1px 1px 0 var(--wc-tooltip-shadow, rgba(0, 0, 0, 0.1))}.tooltip[placement=right-bottom]::after{left:16px;top:-4px}`];mounted(){s(this.$refs.wrap,"mouseenter",p=>{let{left:t,top:e}=f(this),i="left",o={display:"block"},l=document.documentElement.scrollTop;if(this.title.trim()!==""){if(t<360||t>360&&window.innerWidth-t>360)i="right",o.left=t+"px";else{let r=window.innerWidth-t-this.clientWidth;o.right=r+"px"}if(e<96)e+=8+this.clientHeight,i+="-bottom",o.top=e+"px";else{let r=window.innerHeight-e+8+l;i+="-top",o.bottom=r+"px"}this.$refs.tips.setAttribute("placement",i),this.$refs.tips.style.cssText=c(o),this.$refs.tips.$animate()}}),s(this.$refs.wrap,"mouseleave",p=>{this.$refs.tips.$animate(!0)})}render(){return n`
|
||||
<main class="container">
|
||||
<div class="wrapper" ref="wrap"><slot></slot></div>
|
||||
<div class="tooltip" ref="tips" #animation=${{}}>
|
||||
<slot name="title">${this.title}</slot><i class="trigon"></i>
|
||||
<slot name="title">${this.title}</slot>
|
||||
</div>
|
||||
</main>
|
||||
`}}h.reg("tooltip");
|
||||
|
|
|
@ -15,3 +15,11 @@ export function getContainers(all = true) {
|
|||
export function getImages() {
|
||||
return native.handler('docker', { action: 'images' })
|
||||
}
|
||||
|
||||
export function removeContainer(id) {
|
||||
return native.handler('docker', { action: 'rm', id })
|
||||
}
|
||||
|
||||
export function removeImage(id) {
|
||||
return native.handler('docker', { action: 'rmi', id })
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
import { html, css, Component, classMap, nextTick, outsideClick } from 'wkit'
|
||||
|
||||
import { noop, getContainers } from '../utils/index.js'
|
||||
import { getContainers, removeContainer } from '../utils/index.js'
|
||||
|
||||
class Home extends Component {
|
||||
static props = {
|
||||
|
@ -48,15 +48,18 @@ class Home extends Component {
|
|||
border-bottom: 1px solid var(--color-plain-3);
|
||||
}
|
||||
.main .list {
|
||||
overflow: hidden;
|
||||
overflow: auto;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 3px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 12px 0;
|
||||
}
|
||||
.item {
|
||||
.item,
|
||||
.thead {
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
|
@ -67,38 +70,62 @@ class Home extends Component {
|
|||
border-radius: 24px;
|
||||
|
||||
--wc-icon-size: 16px;
|
||||
}
|
||||
.field {
|
||||
overflow: hidden;
|
||||
flex: 1;
|
||||
|
||||
&:hover {
|
||||
background: var(--color-plain-1);
|
||||
&.flex {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.field {
|
||||
&.flex-2 {
|
||||
flex: 2;
|
||||
}
|
||||
|
||||
&.name {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
&.center {
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
&.gap-12 {
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.text-ell {
|
||||
overflow: hidden;
|
||||
flex: 1;
|
||||
display: block;
|
||||
width: 100%;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
color: var(--color-blue-1);
|
||||
}
|
||||
|
||||
&.flex-2 {
|
||||
flex: 2;
|
||||
.action {
|
||||
cursor: pointer;
|
||||
|
||||
&.red {
|
||||
color: var(--color-red-1);
|
||||
}
|
||||
|
||||
&.name {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
&.center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.text-ell {
|
||||
overflow: hidden;
|
||||
display: block;
|
||||
width: 100%;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
&.green {
|
||||
color: var(--color-teal-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.thead {
|
||||
color: var(--color-dark-2);
|
||||
}
|
||||
.item {
|
||||
&:hover {
|
||||
background: var(--color-plain-1);
|
||||
}
|
||||
}
|
||||
`
|
||||
]
|
||||
|
||||
|
@ -107,7 +134,6 @@ class Home extends Component {
|
|||
|
||||
mounted() {
|
||||
this.#all = +localStorage.getItem('container_mode') === 1
|
||||
console.log('<><><>', this.#all)
|
||||
this.#fetch()
|
||||
}
|
||||
|
||||
|
@ -115,8 +141,17 @@ class Home extends Component {
|
|||
let list = await getContainers(this.#all)
|
||||
|
||||
list.forEach(it => {
|
||||
it.port = it.port.replace('0.0.0.0:', '').replace(':::', '')
|
||||
it.image = it.image.split(':')
|
||||
it.cmd = it.cmd.replace(/^"|"$/, '')
|
||||
it.port = it.port
|
||||
.replace('0.0.0.0:', '')
|
||||
.replace(':::', '')
|
||||
.replace(/\/tcp/g, '')
|
||||
it.state =
|
||||
it.state === 'running' ? '🟢' : it.state === 'created' ? '⚪' : '🔴'
|
||||
})
|
||||
|
||||
console.log(list)
|
||||
this.containers = list
|
||||
}
|
||||
|
||||
|
@ -136,6 +171,12 @@ class Home extends Component {
|
|||
this.$requestUpdate()
|
||||
}
|
||||
|
||||
async #remove(item) {
|
||||
console.log(item)
|
||||
await removeContainer(item.id)
|
||||
this.#fetch()
|
||||
}
|
||||
|
||||
render() {
|
||||
let list = this.containers
|
||||
let txt = this.#input
|
||||
|
@ -158,6 +199,14 @@ class Home extends Component {
|
|||
</wc-space>
|
||||
|
||||
<ul class="list">
|
||||
<li class="thead">
|
||||
<span class="field flex-2">容器</span>
|
||||
<span class="field flex-2">所属镜像</span>
|
||||
<span class="field">命令</span>
|
||||
<span class="field">端口</span>
|
||||
<span class="field center">状态</span>
|
||||
<span class="field center">操作</span>
|
||||
</li>
|
||||
${list.map(
|
||||
it => html`
|
||||
<li class="item">
|
||||
|
@ -168,18 +217,30 @@ class Home extends Component {
|
|||
<code>${it.id}</code>
|
||||
</section>
|
||||
<section class="field flex-2">
|
||||
<wc-tooltip title=${it.image}>
|
||||
<span class="text-ell">${it.image}</span>
|
||||
<span class="text-ell">${it.image[0]}</span>
|
||||
<code>${it.image[1]}</code>
|
||||
</section>
|
||||
<section class="field">
|
||||
<wc-tooltip title=${it.cmd}>
|
||||
<span class="text-ell">${it.cmd}</span>
|
||||
</wc-tooltip>
|
||||
</section>
|
||||
<section class="field center">${it.state}</section>
|
||||
<section class="field">
|
||||
<wc-tooltip title=${it.port}>
|
||||
<span class="text-ell">${it.port}</span>
|
||||
</wc-tooltip>
|
||||
</section>
|
||||
<section class="field center">
|
||||
<wc-icon name="trash"></wc-icon>
|
||||
<section class="field center">${it.state}</section>
|
||||
<section class="field flex gap-12 center">
|
||||
<span class="action ${it.state === '🟢' ? 'red' : 'green'}"
|
||||
>${it.state === '🟢' ? '⏹' : '⏸'}</span
|
||||
>
|
||||
<wc-popconfirm
|
||||
title="是否要删除此容器?"
|
||||
@confirm=${ev => this.#remove(it)}
|
||||
>
|
||||
<span class="action">🗑</span>
|
||||
</wc-popconfirm>
|
||||
</section>
|
||||
</li>
|
||||
`
|
||||
|
|
|
@ -48,15 +48,18 @@ class Images extends Component {
|
|||
border-bottom: 1px solid var(--color-plain-3);
|
||||
}
|
||||
.main .list {
|
||||
overflow: hidden;
|
||||
overflow: auto;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 3px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 12px 0;
|
||||
}
|
||||
.item {
|
||||
.item,
|
||||
.thead {
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
|
@ -67,36 +70,40 @@ class Images extends Component {
|
|||
border-radius: 24px;
|
||||
|
||||
--wc-icon-size: 16px;
|
||||
}
|
||||
.field {
|
||||
overflow: hidden;
|
||||
flex: 1;
|
||||
|
||||
&:hover {
|
||||
background: var(--color-plain-1);
|
||||
&.flex-2 {
|
||||
flex: 2;
|
||||
}
|
||||
|
||||
.field {
|
||||
&.name {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
&.center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.text-ell {
|
||||
overflow: hidden;
|
||||
flex: 1;
|
||||
display: block;
|
||||
width: 100%;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
color: var(--color-teal-1);
|
||||
}
|
||||
}
|
||||
|
||||
&.flex-2 {
|
||||
flex: 2;
|
||||
}
|
||||
|
||||
&.name {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
&.center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.text-ell {
|
||||
overflow: hidden;
|
||||
display: block;
|
||||
width: 100%;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
color: var(--color-teal-1);
|
||||
}
|
||||
.thead {
|
||||
color: var(--color-dark-2);
|
||||
}
|
||||
.item {
|
||||
&:hover {
|
||||
background: var(--color-plain-1);
|
||||
}
|
||||
}
|
||||
`
|
||||
|
@ -138,6 +145,13 @@ class Images extends Component {
|
|||
</wc-space>
|
||||
|
||||
<ul class="list">
|
||||
<li class="thead">
|
||||
<span class="field flex-2">镜像</span>
|
||||
<span class="field">版本</span>
|
||||
<span class="field center">大小</span>
|
||||
<span class="field center">创建时间</span>
|
||||
<span class="field center">操作</span>
|
||||
</li>
|
||||
${list.map(
|
||||
it => html`
|
||||
<li class="item">
|
||||
|
|
Loading…
Reference in New Issue