feat(tsview): add database and S3 handlers, tswatch/watch scripts, web utilities, assets and release config

This commit is contained in:
2026-01-25 11:02:53 +00:00
parent cf07f8cad9
commit afc32f3578
52 changed files with 1078 additions and 237 deletions

View File

@@ -1,5 +1,7 @@
import * as plugins from '../plugins.js';
import { apiService, type IS3Object } from '../services/index.js';
import { formatSize, getFileName } from '../utilities/index.js';
import { themeStyles } from '../styles/index.js';
const { html, css, cssManager, customElement, property, state, DeesElement } = plugins;
@@ -11,6 +13,9 @@ export class TsviewS3Keys extends DeesElement {
@property({ type: String })
public accessor currentPrefix: string = '';
@property({ type: Number })
public accessor refreshKey: number = 0;
@state()
private accessor allKeys: IS3Object[] = [];
@@ -28,6 +33,7 @@ export class TsviewS3Keys extends DeesElement {
public static styles = [
cssManager.defaultStyles,
themeStyles,
css`
:host {
display: block;
@@ -58,7 +64,7 @@ export class TsviewS3Keys extends DeesElement {
.filter-input:focus {
outline: none;
border-color: #6366f1;
border-color: #404040;
}
.filter-input::placeholder {
@@ -78,7 +84,7 @@ export class TsviewS3Keys extends DeesElement {
thead {
position: sticky;
top: 0;
background: #1a1a2e;
background: #1a1a1a;
z-index: 1;
}
@@ -103,7 +109,7 @@ export class TsviewS3Keys extends DeesElement {
}
tr.selected td {
background: rgba(99, 102, 241, 0.15);
background: rgba(255, 255, 255, 0.08);
}
.key-cell {
@@ -148,7 +154,7 @@ export class TsviewS3Keys extends DeesElement {
}
updated(changedProperties: Map<string, unknown>) {
if (changedProperties.has('bucketName') || changedProperties.has('currentPrefix')) {
if (changedProperties.has('bucketName') || changedProperties.has('currentPrefix') || changedProperties.has('refreshKey')) {
this.loadObjects();
}
}
@@ -193,30 +199,13 @@ export class TsviewS3Keys extends DeesElement {
}
}
private getFileName(path: string): string {
const parts = path.replace(/\/$/, '').split('/');
return parts[parts.length - 1] || path;
}
private formatSize(bytes?: number): string {
if (!bytes) return '-';
const units = ['B', 'KB', 'MB', 'GB', 'TB'];
let size = bytes;
let unitIndex = 0;
while (size >= 1024 && unitIndex < units.length - 1) {
size /= 1024;
unitIndex++;
}
return `${size.toFixed(unitIndex > 0 ? 1 : 0)} ${units[unitIndex]}`;
}
private get filteredItems() {
const filter = this.filterText.toLowerCase();
const folders = this.prefixes
.filter((p) => !filter || this.getFileName(p).toLowerCase().includes(filter))
.filter((p) => !filter || getFileName(p).toLowerCase().includes(filter))
.map((p) => ({ key: p, isFolder: true, size: undefined }));
const files = this.allKeys
.filter((o) => !filter || this.getFileName(o.key).toLowerCase().includes(filter))
.filter((o) => !filter || getFileName(o.key).toLowerCase().includes(filter))
.map((o) => ({ key: o.key, isFolder: false, size: o.size }));
return [...folders, ...files];
}
@@ -267,11 +256,11 @@ export class TsviewS3Keys extends DeesElement {
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" />
</svg>
`}
<span class="key-name">${this.getFileName(item.key)}</span>
<span class="key-name">${getFileName(item.key)}</span>
</div>
</td>
<td class="size-cell">
${item.isFolder ? '-' : this.formatSize(item.size)}
${item.isFolder ? '-' : formatSize(item.size)}
</td>
</tr>
`