jcloud/dashboard/src/utils.js
2025-04-12 17:39:38 +08:00

211 lines
5.7 KiB
JavaScript

import { DateTime, Duration } from 'luxon';
import theme from '../tailwind.theme.json';
let utils = {
methods: {
$plural(number, singular, plural) {
if (number === 1) {
return singular;
}
return plural;
},
$date(date, serverDatesTimezone = 'Asia/Kolkata') {
// assuming all dates on the server are stored in our timezone
let localZone = DateTime.local().zoneName;
return DateTime.fromSQL(date, { zone: serverDatesTimezone }).setZone(
localZone
);
},
round(number, precision) {
let multiplier = Math.pow(10, precision || 0);
return Math.round(number * multiplier) / multiplier;
},
formatDate(value, type = 'DATETIME_FULL', isUTC = false) {
let datetime = isUTC ? this.$date(value, 'UTC') : this.$date(value);
let format = value;
if (type === 'relative') {
format = datetime.toRelative();
} else {
let formatOptions = DateTime[type];
format = datetime.toLocaleString(formatOptions);
}
return format;
},
$formatDuration(value) {
// Remove decimal seconds
value = value.split('.')[0];
// Add leading zero
// 0:0:2 -> 00:00:02
const formattedDuration = value
.split(':')
.map(x => x.padStart(2, '0'))
.join(':');
const dateTime = Duration.fromISOTime(formattedDuration).toObject();
const hourString = dateTime.hours ? `${dateTime.hours}h` : '';
const minuteString = dateTime.minutes ? `${dateTime.minutes}m` : '';
const secondString = `${dateTime.seconds}s`;
return `${hourString} ${minuteString} ${secondString}`;
},
formatBytes(bytes, decimals = 2, current = 0) {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const dm = decimals < 0 ? 0 : decimals;
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
const i = Math.floor(Math.log(Math.abs(bytes)) / Math.log(k));
return (
parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) +
' ' +
sizes[i + current]
);
},
$formatCPUTime(duration) {
return duration / 1000000;
},
$planTitle(plan) {
let china = this.$account.team.country == 'china';
let currency = china ? '¥' : '$';
let price_field = china ? 'price_cny' : 'price_usd';
let price =
plan.block_monthly == 1 ? plan[price_field] * 12 : plan[price_field];
return price > 0 ? `${currency}${price}` : plan.plan_title;
},
trialEndsInDaysText(date) {
let diff = this.$date(date).diff(DateTime.local(), ['days']).toObject();
let days = diff.days;
if (days > 1) {
return `in ${Math.floor(days)} days`;
}
return 'in a day';
},
$routeTo404PageIfNotFound(errorMessage) {
if (errorMessage.indexOf('not found') >= 0) {
this.$router.push({
name: 'NotFound',
// preserve current path and remove the first char to avoid the target URL starting with `//`
params: { pathMatch: this.$route.path.substring(1).split('/') },
// preserve existing query and hash if any
query: this.$route.query,
hash: this.$route.hash
});
}
},
$siteStatus(site) {
let status = site.status;
if (site.update_available && site.status == 'Active') {
status = 'Update Available';
}
let usage = Math.max(
site.current_cpu_usage,
site.current_database_usage,
site.current_disk_usage
);
if (usage && usage >= 80 && status == 'Active') {
status = 'Attention Required';
}
if (site.trial_end_date) {
status = 'Trial';
}
return status;
},
$sanitize(text) {
if (!text) return text;
const map = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
"'": '&#x27;',
'/': '&#x2F;'
};
const reg = /[&<>"'/]/gi;
return text.replace(reg, match => map[match]);
}
},
computed: {
$theme() {
return theme;
},
$platform() {
const ua = navigator.userAgent.toLowerCase();
if (ua.indexOf('win') > -1) {
return 'win';
} else if (ua.indexOf('mac') > -1) {
return 'mac';
} else if (ua.indexOf('x11') > -1 || ua.indexOf('linux') > -1) {
return 'linux';
}
}
}
};
export function validateGST(gst) {
// https://github.com/raysk4ever/raysk-vali/blob/master/validate.js#L51
const gstReg = new RegExp(
/\d{2}[A-Z]{5}\d{4}[A-Z]{1}[A-Z\d]{1}[Z]{1}[A-Z\d]{1}/
);
return gstReg.test(gst);
}
export default function install(Vue) {
Vue.mixin(utils);
}
export function isWasmSupported() {
// Check if browser supports WASM
// ref: https://stackoverflow.com/a/47880734/10309266
return (() => {
try {
if (
typeof WebAssembly === 'object' &&
typeof WebAssembly.instantiate === 'function'
) {
const module = new WebAssembly.Module(
Uint8Array.of(0x0, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00)
);
if (module instanceof WebAssembly.Module)
return (
new WebAssembly.Instance(module) instanceof WebAssembly.Instance
);
}
} catch (e) {} // eslint-disable-line no-empty
return false;
})();
}
export async function trypromise(promise) {
try {
let data = await promise;
return [null, data];
} catch (error) {
return [error, null];
}
}
export function validateSubdomain(subdomain) {
if (!subdomain) {
return 'Subdomain cannot be empty';
}
if (subdomain.length < 5) {
return 'Subdomain too short. Use 5 or more characters';
}
if (subdomain.length > 32) {
return 'Subdomain too long. Use 32 or less characters';
}
if (!subdomain.match(/^[a-z0-9][a-z0-9-]*[a-z0-9]$/)) {
return 'Subdomain contains invalid characters. Use lowercase characters, numbers and hyphens';
}
return null;
}
export { utils };
export { default as dayjs } from './utils/dayjs';