199 lines
4.2 KiB
JavaScript
199 lines
4.2 KiB
JavaScript
/**
|
|
* {}
|
|
* @author yutent<yutent.io@gmail.com>
|
|
* @date 2023/08/08 18:19:17
|
|
*/
|
|
import { html, css, Component, classMap, nextTick, outsideClick } from 'wkit'
|
|
|
|
import { docker } from '../utils/index.js'
|
|
|
|
class Images extends Component {
|
|
static props = {}
|
|
|
|
static styles = [
|
|
css`
|
|
:host {
|
|
display: block;
|
|
width: 100%;
|
|
height: 100%;
|
|
color: var(--color-dark-1);
|
|
background: #fff;
|
|
}
|
|
.visible {
|
|
display: block;
|
|
}
|
|
|
|
ul li {
|
|
list-style: none;
|
|
}
|
|
|
|
.noselect {
|
|
-webkit-touch-callout: none;
|
|
-webkit-user-select: none;
|
|
user-select: none;
|
|
}
|
|
`,
|
|
|
|
css`
|
|
.main {
|
|
display: flex;
|
|
flex-direction: column;
|
|
height: 100%;
|
|
padding: 16px;
|
|
}
|
|
.main .toolbar {
|
|
height: 48px;
|
|
border-bottom: 1px solid var(--color-plain-3);
|
|
}
|
|
.main .list {
|
|
overflow: auto;
|
|
flex: 1;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 3px;
|
|
width: 100%;
|
|
height: 100%;
|
|
padding: 12px 0;
|
|
}
|
|
.item,
|
|
.thead {
|
|
flex-shrink: 0;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 12px;
|
|
width: 100%;
|
|
height: 48px;
|
|
padding: 0 12px;
|
|
line-height: 1.25;
|
|
border-radius: 24px;
|
|
|
|
--wc-icon-size: 16px;
|
|
}
|
|
.field {
|
|
overflow: hidden;
|
|
flex: 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-blue-1);
|
|
}
|
|
.action {
|
|
&.red {
|
|
color: var(--color-red-1);
|
|
}
|
|
&.green {
|
|
color: var(--color-teal-1);
|
|
}
|
|
}
|
|
}
|
|
|
|
.thead {
|
|
color: var(--color-dark-2);
|
|
}
|
|
.item {
|
|
&:hover {
|
|
background: var(--color-plain-1);
|
|
}
|
|
}
|
|
`
|
|
]
|
|
|
|
#input = ''
|
|
|
|
async mounted() {
|
|
this.#fetch()
|
|
}
|
|
|
|
async #fetch() {
|
|
let list = await docker.images()
|
|
this.$store.images = list
|
|
}
|
|
|
|
#filter(ev) {
|
|
let txt = ev.currentTarget.value.trim()
|
|
if (this.#input === txt) {
|
|
return
|
|
}
|
|
this.#input = txt
|
|
this.$requestUpdate()
|
|
}
|
|
|
|
async #remove(item) {
|
|
await docker.rmi(item.id)
|
|
this.#fetch()
|
|
}
|
|
|
|
render() {
|
|
let list = this.$store.images
|
|
let txt = this.#input
|
|
if (txt) {
|
|
list = list.filter(it => it.name.includes(txt))
|
|
}
|
|
|
|
return html`
|
|
<main class="main noselect">
|
|
<wc-space class="toolbar">
|
|
<wc-input
|
|
size="small"
|
|
round
|
|
placeholder="搜索镜像"
|
|
@input=${this.#filter}
|
|
></wc-input>
|
|
</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">
|
|
<section class="field flex-2 name">
|
|
<span class="text-ell">${it.name}</span>
|
|
<code>${it.id}</code>
|
|
</section>
|
|
<section class="field">${it.tag}</section>
|
|
<section class="field center">${it.size}</section>
|
|
<section class="field center">
|
|
<wc-time stamp=${new Date(it.created).getTime()}></wc-time>
|
|
</section>
|
|
<section class="field center">
|
|
<wc-popconfirm
|
|
title="是否要删除此镜像?"
|
|
@confirm=${ev => this.#remove(it)}
|
|
>
|
|
<span class="action">🗑</span>
|
|
</wc-popconfirm>
|
|
</section>
|
|
</li>
|
|
`
|
|
)}
|
|
</ul>
|
|
</main>
|
|
`
|
|
}
|
|
}
|
|
|
|
Images.reg('images')
|