Files
dees-catalog/ts_web/elements/00group-dataview/dees-storage-browser/utilities.ts

121 lines
3.1 KiB
TypeScript

/**
* Shared utilities for S3 browser components
*/
export interface IMoveValidation {
valid: boolean;
error?: string;
}
/**
* Format a byte size into a human-readable string
*/
export function formatSize(bytes?: number): string {
if (bytes === undefined || bytes === null) return '-';
if (bytes === 0) return '0 B';
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]}`;
}
/**
* Format a count into a compact human-readable string
*/
export function formatCount(count?: number): string {
if (count === undefined || count === null) return '';
if (count >= 1000000) return `${(count / 1000000).toFixed(1)}M`;
if (count >= 1000) return `${(count / 1000).toFixed(1)}K`;
return count.toString();
}
/**
* Extract the file name from a path
*/
export function getFileName(path: string): string {
const parts = path.replace(/\/$/, '').split('/');
return parts[parts.length - 1] || path;
}
/**
* Validates if a move operation is allowed
*/
export function validateMove(sourceKey: string, destPrefix: string): IMoveValidation {
if (sourceKey.endsWith('/')) {
if (destPrefix.startsWith(sourceKey)) {
return { valid: false, error: 'Cannot move a folder into itself' };
}
}
const sourceParent = getParentPrefix(sourceKey);
if (sourceParent === destPrefix) {
return { valid: false, error: 'Item is already in this location' };
}
return { valid: true };
}
/**
* Gets the parent prefix (directory) of a given key
*/
export function getParentPrefix(key: string): string {
const trimmed = key.endsWith('/') ? key.slice(0, -1) : key;
const lastSlash = trimmed.lastIndexOf('/');
return lastSlash >= 0 ? trimmed.substring(0, lastSlash + 1) : '';
}
/**
* Get content type from file extension
*/
export function getContentType(ext: string): string {
const contentTypes: Record<string, string> = {
json: 'application/json',
txt: 'text/plain',
html: 'text/html',
css: 'text/css',
js: 'application/javascript',
ts: 'text/typescript',
md: 'text/markdown',
xml: 'application/xml',
yaml: 'text/yaml',
yml: 'text/yaml',
csv: 'text/csv',
};
return contentTypes[ext] || 'application/octet-stream';
}
/**
* Get default content for a new file based on extension
*/
export function getDefaultContent(ext: string): string {
const defaults: Record<string, string> = {
json: '{\n \n}',
html: '<!DOCTYPE html>\n<html>\n<head>\n <title></title>\n</head>\n<body>\n \n</body>\n</html>',
md: '# Title\n\n',
txt: '',
};
return defaults[ext] || '';
}
/**
* Parse a prefix into cumulative path segments
*/
export function getPathSegments(prefix: string): string[] {
if (!prefix) return [];
const parts = prefix.split('/').filter(p => p);
const segments: string[] = [];
let cumulative = '';
for (const part of parts) {
cumulative += part + '/';
segments.push(cumulative);
}
return segments;
}