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 } 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;
@@ -31,6 +33,7 @@ export class TsviewS3Preview extends DeesElement {
public static styles = [
cssManager.defaultStyles,
themeStyles,
css`
:host {
display: block;
@@ -104,9 +107,9 @@ export class TsviewS3Preview extends DeesElement {
.action-btn {
flex: 1;
padding: 8px 16px;
background: rgba(99, 102, 241, 0.2);
border: 1px solid #6366f1;
color: #818cf8;
background: rgba(255, 255, 255, 0.1);
border: 1px solid #404040;
color: #e0e0e0;
border-radius: 6px;
cursor: pointer;
font-size: 13px;
@@ -114,7 +117,7 @@ export class TsviewS3Preview extends DeesElement {
}
.action-btn:hover {
background: rgba(99, 102, 241, 0.3);
background: rgba(255, 255, 255, 0.15);
}
.action-btn.danger {
@@ -174,6 +177,7 @@ export class TsviewS3Preview extends DeesElement {
} else {
this.content = '';
this.contentType = '';
this.error = ''; // Clear error when no file selected
}
}
}
@@ -198,22 +202,6 @@ export class TsviewS3Preview extends DeesElement {
this.loading = false;
}
private getFileName(path: string): string {
const parts = path.split('/');
return parts[parts.length - 1] || path;
}
private formatSize(bytes: number): string {
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 formatDate(dateStr: string): string {
if (!dateStr) return '-';
const date = new Date(dateStr);
@@ -235,7 +223,13 @@ export class TsviewS3Preview extends DeesElement {
private getTextContent(): string {
try {
return atob(this.content);
// Properly decode base64 to UTF-8 text
const binaryString = atob(this.content);
const bytes = new Uint8Array(binaryString.length);
for (let i = 0; i < binaryString.length; i++) {
bytes[i] = binaryString.charCodeAt(i);
}
return new TextDecoder('utf-8').decode(bytes);
} catch {
return 'Unable to decode content';
}
@@ -249,7 +243,7 @@ export class TsviewS3Preview extends DeesElement {
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = this.getFileName(this.objectKey);
a.download = getFileName(this.objectKey);
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
@@ -260,7 +254,7 @@ export class TsviewS3Preview extends DeesElement {
}
private async handleDelete() {
if (!confirm(`Delete "${this.getFileName(this.objectKey)}"?`)) return;
if (!confirm(`Delete "${getFileName(this.objectKey)}"?`)) return;
try {
await apiService.deleteObject(this.bucketName, this.objectKey);
@@ -310,10 +304,10 @@ export class TsviewS3Preview extends DeesElement {
return html`
<div class="preview-container">
<div class="preview-header">
<div class="preview-title">${this.getFileName(this.objectKey)}</div>
<div class="preview-title">${getFileName(this.objectKey)}</div>
<div class="preview-meta">
<span class="meta-item">${this.contentType}</span>
<span class="meta-item">${this.formatSize(this.size)}</span>
<span class="meta-item">${formatSize(this.size)}</span>
<span class="meta-item">${this.formatDate(this.lastModified)}</span>
</div>
</div>