diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index ee0f302..0000000 --- a/.eslintignore +++ /dev/null @@ -1,6 +0,0 @@ -dist -node_modules -packages/github-action/* -packages/worker/bin/* -packages/worker/config/* -packages/dashboard/quasar.config.js diff --git a/.eslintrc b/.eslintrc deleted file mode 100644 index d323a75..0000000 --- a/.eslintrc +++ /dev/null @@ -1,23 +0,0 @@ -{ - "root": true, - "parserOptions": { - "ecmaVersion": "latest", - "sourceType": "module" - }, - "env": { - "browser": true, - "es6": true, - "node": true - }, - "extends": [ - "typescript", - "prettier" - ], - "ignorePatterns": [], - "rules": { - "@typescript-eslint/ban-ts-comment": "off", - "@typescript-eslint/no-explicit-any": "off", - "@typescript-eslint/no-var-requires": "off", - "@typescript-eslint/no-unused-vars": "warn" - } -} diff --git a/.npmrc b/.npmrc deleted file mode 100644 index 13833b4..0000000 --- a/.npmrc +++ /dev/null @@ -1,3 +0,0 @@ -git-checks=false -shamefully-hoist=true -auto-install-peers=true diff --git a/biome.json b/biome.json new file mode 100644 index 0000000..96c7588 --- /dev/null +++ b/biome.json @@ -0,0 +1,45 @@ +{ + "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json", + "vcs": { + "enabled": false, + "clientKind": "git", + "useIgnoreFile": false + }, + "files": { + "ignoreUnknown": false, + "ignore": [] + }, + "formatter": { + "enabled": true, + "indentStyle": "tab" + }, + "organizeImports": { + "enabled": true + }, + "linter": { + "enabled": true, + "rules": { + "recommended": true, + "suspicious": { + "noExplicitAny": "off", + "noImplicitAnyLet": "off" + }, + "style": { + "noParameterAssign": "off" + }, + "complexity": { + "noForEach": "off", + "useLiteralKeys": "off" + }, + "performance": { + "noAccumulatingSpread": "off", + "noDelete": "off" + } + } + }, + "javascript": { + "formatter": { + "quoteStyle": "double" + } + } +} diff --git a/package.json b/package.json index af4676a..50f1c43 100644 --- a/package.json +++ b/package.json @@ -1,25 +1,21 @@ { - "name": "r2-explorer-root", - "version": "0.0.0", - "private": true, - "scripts": { - "prepare": "husky install", - "lint": "(eslint . || (eslint . --fix; exit 1)) && (prettier --check '*.{json,js}' 'packages/*/src/**/*.{js,ts}' || (prettier -w '*.{json,js}' 'packages/*/src/**/*.{js,ts}'; exit 1))", - "build-dashboard": "pnpm run --filter r2-explorer-dashboard build", - "build-worker": "pnpm run --filter r2-explorer build", - "build": "pnpm build-dashboard && pnpm build-worker", - "deploy-dashboard": "pnpm run --filter r2-explorer-dashboard deploy", - "deploy-dashboard-dev": "pnpm run --filter r2-explorer-dashboard deploy-dev", - "deploy-dev-worker": "pnpm run --filter r2-explorer-dev-worker deploy", - "publish-npm": "pnpm run --filter worker publish" - }, - "devDependencies": { - "esbuild": "0.17.19", - "eslint": "^8.57.0", - "eslint-config-prettier": "^9.1.0", - "eslint-config-typescript": "^3.0.0", - "husky": "^9.0.11", - "prettier": "^3.2.5", - "typescript": "^4.7.4" - } + "name": "r2-explorer-root", + "version": "0.0.0", + "private": true, + "scripts": { + "prepare": "husky", + "workers-ci": "export WORKERS_CI=1 && node packages/github-action/prepareDeploy.js", + "lint": "npx @biomejs/biome check template/ packages/dashboard/src packages/worker/src || (npx @biomejs/biome check --write template/ packages/dashboard/src packages/worker/src/; exit 1)", + "build-dashboard": "pnpm run --filter r2-explorer-dashboard build", + "build-worker": "pnpm run --filter r2-explorer build", + "build": "pnpm build-dashboard && pnpm build-worker", + "deploy-dashboard": "pnpm run --filter r2-explorer-dashboard deploy", + "deploy-dashboard-dev": "pnpm run --filter r2-explorer-dashboard deploy-dev", + "deploy-dev-worker": "pnpm run --filter r2-explorer-dev-worker deploy", + "publish-npm": "pnpm run --filter worker publish" + }, + "devDependencies": { + "@biomejs/biome": "1.9.4", + "husky": "^9.1.7" + } } diff --git a/packages/dashboard/jsconfig.json b/packages/dashboard/jsconfig.json index 456944a..dfc5b6a 100644 --- a/packages/dashboard/jsconfig.json +++ b/packages/dashboard/jsconfig.json @@ -1,39 +1,17 @@ { - "compilerOptions": { - "baseUrl": ".", - "paths": { - "src/*": [ - "src/*" - ], - "app/*": [ - "*" - ], - "components/*": [ - "src/components/*" - ], - "layouts/*": [ - "src/layouts/*" - ], - "pages/*": [ - "src/pages/*" - ], - "assets/*": [ - "src/assets/*" - ], - "boot/*": [ - "src/boot/*" - ], - "stores/*": [ - "src/stores/*" - ], - "vue$": [ - "node_modules/vue/dist/vue.runtime.esm-bundler.js" - ] - } - }, - "exclude": [ - "dist", - ".quasar", - "node_modules" - ] -} \ No newline at end of file + "compilerOptions": { + "baseUrl": ".", + "paths": { + "src/*": ["src/*"], + "app/*": ["*"], + "components/*": ["src/components/*"], + "layouts/*": ["src/layouts/*"], + "pages/*": ["src/pages/*"], + "assets/*": ["src/assets/*"], + "boot/*": ["src/boot/*"], + "stores/*": ["src/stores/*"], + "vue$": ["node_modules/vue/dist/vue.runtime.esm-bundler.js"] + } + }, + "exclude": ["dist", ".quasar", "node_modules"] +} diff --git a/packages/dashboard/package.json b/packages/dashboard/package.json index 384af3b..67f3eb6 100644 --- a/packages/dashboard/package.json +++ b/packages/dashboard/package.json @@ -1,38 +1,38 @@ { - "name": "r2-explorer-dashboard", - "version": "0.0.1", - "description": "R2-Explorer", - "productName": "r2-explorer", - "author": "Gabriel Massadas", - "private": true, - "scripts": { - "test": "echo \"No test specified\" && exit 0", - "dev": "quasar dev", - "build": "quasar build", - "deploy": "wrangler pages deploy --branch main --project-name r2-explorer-dashboard dist/spa/", - "deploy-dev": "wrangler pages deploy --branch dev --project-name r2-explorer-dashboard dist/spa/" - }, - "dependencies": { - "@quasar/extras": "^1.16.9", - "axios": "^1.2.1", - "fflate": "^0.8.1", - "html-to-text": "^9.0.5", - "pdfvuer": "^2.0.1", - "pinia": "^2.0.11", - "postal-mime": "^2.0.1", - "quasar": "^2.14.7", - "vue": "^3.3.11", - "vue-router": "^4.2.5" - }, - "devDependencies": { - "@quasar/app-vite": "^1.8.0", - "autoprefixer": "^10.4.2", - "dotenv": "^16.3.1", - "postcss": "^8.4.14" - }, - "engines": { - "node": "^20 || ^18 || ^16 || ^14.19", - "npm": ">= 6.13.4", - "yarn": ">= 1.21.1" - } + "name": "r2-explorer-dashboard", + "version": "0.0.1", + "description": "R2-Explorer", + "productName": "r2-explorer", + "author": "Gabriel Massadas", + "private": true, + "scripts": { + "test": "echo \"No test specified\" && exit 0", + "dev": "quasar dev", + "build": "quasar build", + "deploy": "wrangler pages deploy --branch main --project-name r2-explorer-dashboard dist/spa/", + "deploy-dev": "wrangler pages deploy --branch dev --project-name r2-explorer-dashboard dist/spa/" + }, + "dependencies": { + "@quasar/extras": "^1.16.9", + "axios": "^1.2.1", + "fflate": "^0.8.1", + "html-to-text": "^9.0.5", + "pdfvuer": "^2.0.1", + "pinia": "^2.0.11", + "postal-mime": "^2.0.1", + "quasar": "^2.14.7", + "vue": "^3.3.11", + "vue-router": "^4.2.5" + }, + "devDependencies": { + "@quasar/app-vite": "^1.8.0", + "autoprefixer": "^10.4.2", + "dotenv": "^16.3.1", + "postcss": "^8.4.14" + }, + "engines": { + "node": "^20 || ^18 || ^16 || ^14.19", + "npm": ">= 6.13.4", + "yarn": ">= 1.21.1" + } } diff --git a/packages/dashboard/postcss.config.cjs b/packages/dashboard/postcss.config.cjs index 94b7b1c..5cd2f46 100644 --- a/packages/dashboard/postcss.config.cjs +++ b/packages/dashboard/postcss.config.cjs @@ -2,26 +2,26 @@ // https://github.com/michael-ciniawsky/postcss-load-config module.exports = { - plugins: [ - // https://github.com/postcss/autoprefixer - require('autoprefixer')({ - overrideBrowserslist: [ - 'last 4 Chrome versions', - 'last 4 Firefox versions', - 'last 4 Edge versions', - 'last 4 Safari versions', - 'last 4 Android versions', - 'last 4 ChromeAndroid versions', - 'last 4 FirefoxAndroid versions', - 'last 4 iOS versions' - ] - }) + plugins: [ + // https://github.com/postcss/autoprefixer + require("autoprefixer")({ + overrideBrowserslist: [ + "last 4 Chrome versions", + "last 4 Firefox versions", + "last 4 Edge versions", + "last 4 Safari versions", + "last 4 Android versions", + "last 4 ChromeAndroid versions", + "last 4 FirefoxAndroid versions", + "last 4 iOS versions", + ], + }), - // https://github.com/elchininet/postcss-rtlcss - // If you want to support RTL css, then - // 1. yarn/npm install postcss-rtlcss - // 2. optionally set quasar.config.js > framework > lang to an RTL language - // 3. uncomment the following line: - // require('postcss-rtlcss') - ] -} + // https://github.com/elchininet/postcss-rtlcss + // If you want to support RTL css, then + // 1. yarn/npm install postcss-rtlcss + // 2. optionally set quasar.config.js > framework > lang to an RTL language + // 3. uncomment the following line: + // require('postcss-rtlcss') + ], +}; diff --git a/packages/dashboard/quasar.config.js b/packages/dashboard/quasar.config.js index 20d88f4..6cc3194 100644 --- a/packages/dashboard/quasar.config.js +++ b/packages/dashboard/quasar.config.js @@ -8,210 +8,193 @@ // Configuration for your app // https://v2.quasar.dev/quasar-cli-vite/quasar-config-js +const { configure } = require("quasar/wrappers"); -const { configure } = require('quasar/wrappers'); +module.exports = configure((/* ctx */) => ({ + // eslint: { + // fix: true, + // include: [], + // exclude: [], + // rawOptions: {}, + // warnings: true, + // errors: true + // }, + // https://v2.quasar.dev/quasar-cli-vite/prefetch-feature + // preFetch: true, -module.exports = configure(function (/* ctx */) { - return { - // eslint: { - // fix: true, - // include: [], - // exclude: [], - // rawOptions: {}, - // warnings: true, - // errors: true - // }, + // app boot file (/src/boot) + // --> boot files are part of "main.js" + // https://v2.quasar.dev/quasar-cli-vite/boot-files + boot: ["axios", "auth", "bus"], - // https://v2.quasar.dev/quasar-cli-vite/prefetch-feature - // preFetch: true, + // https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#css + css: ["app.scss"], - // app boot file (/src/boot) - // --> boot files are part of "main.js" - // https://v2.quasar.dev/quasar-cli-vite/boot-files - boot: [ - 'axios', - 'auth', - 'bus', - ], + // https://github.com/quasarframework/quasar/tree/dev/extras + extras: [ + // 'ionicons-v4', + // 'mdi-v5', + // 'fontawesome-v6', + // 'eva-icons', + // 'themify', + // 'line-awesome', + // 'roboto-font-latin-ext', // this or either 'roboto-font', NEVER both! - // https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#css - css: [ - 'app.scss' - ], + "roboto-font", // optional, you are not bound to it + "material-icons", // optional, you are not bound to it + ], - // https://github.com/quasarframework/quasar/tree/dev/extras - extras: [ - // 'ionicons-v4', - // 'mdi-v5', - // 'fontawesome-v6', - // 'eva-icons', - // 'themify', - // 'line-awesome', - // 'roboto-font-latin-ext', // this or either 'roboto-font', NEVER both! + // Full list of options: https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#build + build: { + env: require("dotenv").config().parsed, + target: { + browser: ["es2019", "edge88", "firefox78", "chrome87", "safari13.1"], + node: "node16", + }, - 'roboto-font', // optional, you are not bound to it - 'material-icons', // optional, you are not bound to it - ], + vueRouterMode: "history", // available values: 'hash', 'history' + // vueRouterBase, + // vueDevtools, + // vueOptionsAPI: false, - // Full list of options: https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#build - build: { - env: require('dotenv').config().parsed, - target: { - browser: [ 'es2019', 'edge88', 'firefox78', 'chrome87', 'safari13.1' ], - node: 'node16' - }, + // rebuildCache: true, // rebuilds Vite/linter/etc cache on startup - vueRouterMode: 'history', // available values: 'hash', 'history' - // vueRouterBase, - // vueDevtools, - // vueOptionsAPI: false, + publicPath: "/", + // analyze: true, + // env: {}, + // rawDefine: {} + // ignorePublicFolder: true, + // minify: false, + // polyfillModulePreload: true, + // distDir - // rebuildCache: true, // rebuilds Vite/linter/etc cache on startup + // extendViteConf (viteConf) {}, + // viteVuePluginOptions: {}, - publicPath: '/', - // analyze: true, - // env: {}, - // rawDefine: {} - // ignorePublicFolder: true, - // minify: false, - // polyfillModulePreload: true, - // distDir + // vitePlugins: [ + // [ 'package-name', { ..options.. } ] + // ] + }, - // extendViteConf (viteConf) {}, - // viteVuePluginOptions: {}, + // Full list of options: https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#devServer + devServer: { + // https: true + open: true, // opens browser window automatically + }, + // https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#framework + framework: { + config: {}, - // vitePlugins: [ - // [ 'package-name', { ..options.. } ] - // ] - }, + // iconSet: 'material-icons', // Quasar icon set + // lang: 'en-US', // Quasar language pack - // Full list of options: https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#devServer - devServer: { - // https: true - open: true // opens browser window automatically - }, + // For special cases outside of where the auto-import strategy can have an impact + // (like functional components as one of the examples), + // you can manually specify Quasar components/directives to be available everywhere: + // + // components: [], + // directives: [], - // https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#framework - framework: { - config: {}, + // Quasar plugins + plugins: ["Notify"], + }, - // iconSet: 'material-icons', // Quasar icon set - // lang: 'en-US', // Quasar language pack + // animations: 'all', // --- includes all animations + // https://v2.quasar.dev/options/animations + animations: [], - // For special cases outside of where the auto-import strategy can have an impact - // (like functional components as one of the examples), - // you can manually specify Quasar components/directives to be available everywhere: - // - // components: [], - // directives: [], + // https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#property-sourcefiles + // sourceFiles: { + // rootComponent: 'src/App.vue', + // router: 'src/router/index', + // store: 'src/store/index', + // registerServiceWorker: 'src-pwa/register-service-worker', + // serviceWorker: 'src-pwa/custom-service-worker', + // pwaManifestFile: 'src-pwa/manifest.json', + // electronMain: 'src-electron/electron-main', + // electronPreload: 'src-electron/electron-preload' + // }, - // Quasar plugins - plugins: [ - 'Notify' - ] - }, + // https://v2.quasar.dev/quasar-cli-vite/developing-ssr/configuring-ssr + ssr: { + // ssrPwaHtmlFilename: 'offline.html', // do NOT use index.html as name! + // will mess up SSR - // animations: 'all', // --- includes all animations - // https://v2.quasar.dev/options/animations - animations: [], + // extendSSRWebserverConf (esbuildConf) {}, + // extendPackageJson (json) {}, - // https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#property-sourcefiles - // sourceFiles: { - // rootComponent: 'src/App.vue', - // router: 'src/router/index', - // store: 'src/store/index', - // registerServiceWorker: 'src-pwa/register-service-worker', - // serviceWorker: 'src-pwa/custom-service-worker', - // pwaManifestFile: 'src-pwa/manifest.json', - // electronMain: 'src-electron/electron-main', - // electronPreload: 'src-electron/electron-preload' - // }, + pwa: false, - // https://v2.quasar.dev/quasar-cli-vite/developing-ssr/configuring-ssr - ssr: { - // ssrPwaHtmlFilename: 'offline.html', // do NOT use index.html as name! - // will mess up SSR + // manualStoreHydration: true, + // manualPostHydrationTrigger: true, - // extendSSRWebserverConf (esbuildConf) {}, - // extendPackageJson (json) {}, + prodPort: 3000, // The default port that the production server should use + // (gets superseded if process.env.PORT is specified at runtime) - pwa: false, + middlewares: [ + "render", // keep this as last one + ], + }, - // manualStoreHydration: true, - // manualPostHydrationTrigger: true, + // https://v2.quasar.dev/quasar-cli-vite/developing-pwa/configuring-pwa + pwa: { + workboxMode: "generateSW", // or 'injectManifest' + injectPwaMetaTags: true, + swFilename: "sw.js", + manifestFilename: "manifest.json", + useCredentialsForManifestTag: false, + // useFilenameHashes: true, + // extendGenerateSWOptions (cfg) {} + // extendInjectManifestOptions (cfg) {}, + // extendManifestJson (json) {} + // extendPWACustomSWConf (esbuildConf) {} + }, - prodPort: 3000, // The default port that the production server should use - // (gets superseded if process.env.PORT is specified at runtime) + // Full list of options: https://v2.quasar.dev/quasar-cli-vite/developing-cordova-apps/configuring-cordova + cordova: { + // noIosLegacyBuildFlag: true, // uncomment only if you know what you are doing + }, - middlewares: [ - 'render' // keep this as last one - ] - }, + // Full list of options: https://v2.quasar.dev/quasar-cli-vite/developing-capacitor-apps/configuring-capacitor + capacitor: { + hideSplashscreen: true, + }, - // https://v2.quasar.dev/quasar-cli-vite/developing-pwa/configuring-pwa - pwa: { - workboxMode: 'generateSW', // or 'injectManifest' - injectPwaMetaTags: true, - swFilename: 'sw.js', - manifestFilename: 'manifest.json', - useCredentialsForManifestTag: false, - // useFilenameHashes: true, - // extendGenerateSWOptions (cfg) {} - // extendInjectManifestOptions (cfg) {}, - // extendManifestJson (json) {} - // extendPWACustomSWConf (esbuildConf) {} - }, + // Full list of options: https://v2.quasar.dev/quasar-cli-vite/developing-electron-apps/configuring-electron + electron: { + // extendElectronMainConf (esbuildConf) + // extendElectronPreloadConf (esbuildConf) - // Full list of options: https://v2.quasar.dev/quasar-cli-vite/developing-cordova-apps/configuring-cordova - cordova: { - // noIosLegacyBuildFlag: true, // uncomment only if you know what you are doing - }, + // specify the debugging port to use for the Electron app when running in development mode + inspectPort: 5858, - // Full list of options: https://v2.quasar.dev/quasar-cli-vite/developing-capacitor-apps/configuring-capacitor - capacitor: { - hideSplashscreen: true - }, + bundler: "packager", // 'packager' or 'builder' - // Full list of options: https://v2.quasar.dev/quasar-cli-vite/developing-electron-apps/configuring-electron - electron: { - // extendElectronMainConf (esbuildConf) - // extendElectronPreloadConf (esbuildConf) + packager: { + // https://github.com/electron-userland/electron-packager/blob/master/docs/api.md#options + // OS X / Mac App Store + // appBundleId: '', + // appCategoryType: '', + // osxSign: '', + // protocol: 'myapp://path', + // Windows only + // win32metadata: { ... } + }, - // specify the debugging port to use for the Electron app when running in development mode - inspectPort: 5858, + builder: { + // https://www.electron.build/configuration/configuration - bundler: 'packager', // 'packager' or 'builder' + appId: "r2-explorer-dashboard", + }, + }, - packager: { - // https://github.com/electron-userland/electron-packager/blob/master/docs/api.md#options + // Full list of options: https://v2.quasar.dev/quasar-cli-vite/developing-browser-extensions/configuring-bex + bex: { + contentScripts: ["my-content-script"], - // OS X / Mac App Store - // appBundleId: '', - // appCategoryType: '', - // osxSign: '', - // protocol: 'myapp://path', - - // Windows only - // win32metadata: { ... } - }, - - builder: { - // https://www.electron.build/configuration/configuration - - appId: 'r2-explorer-dashboard' - } - }, - - // Full list of options: https://v2.quasar.dev/quasar-cli-vite/developing-browser-extensions/configuring-bex - bex: { - contentScripts: [ - 'my-content-script' - ], - - // extendBexScriptsConf (esbuildConf) {} - // extendBexManifestJson (json) {} - } - } -}); + // extendBexScriptsConf (esbuildConf) {} + // extendBexManifestJson (json) {} + }, +})); diff --git a/packages/dashboard/src/App.vue b/packages/dashboard/src/App.vue index 38442ee..fa3f196 100644 --- a/packages/dashboard/src/App.vue +++ b/packages/dashboard/src/App.vue @@ -3,9 +3,9 @@ diff --git a/packages/dashboard/src/appUtils.js b/packages/dashboard/src/appUtils.js index 7c3e846..c692378 100644 --- a/packages/dashboard/src/appUtils.js +++ b/packages/dashboard/src/appUtils.js @@ -1,257 +1,278 @@ import { api } from "boot/axios"; import { useMainStore } from "stores/main-store"; -export const ROOT_FOLDER = "IA==" // IA== is a space +export const ROOT_FOLDER = "IA=="; // IA== is a space function mapFile(obj, prefix) { - const date = new Date(obj.uploaded) + const date = new Date(obj.uploaded); - return { - ...obj, - hash: encode(obj.key), - nameHash: encode(obj.key.replace(prefix, '')), - name: obj.key.replace(prefix, ''), - lastModified: timeSince(date), - timestamp: date.getTime(), - size: bytesToSize(obj.size), - sizeRaw: obj.size, - type: 'file', - icon: 'article', - color: 'grey', - } + return { + ...obj, + hash: encode(obj.key), + nameHash: encode(obj.key.replace(prefix, "")), + name: obj.key.replace(prefix, ""), + lastModified: timeSince(date), + timestamp: date.getTime(), + size: bytesToSize(obj.size), + sizeRaw: obj.size, + type: "file", + icon: "article", + color: "grey", + }; } export const timeSince = (date) => { - const seconds = Math.floor((new Date() - date) / 1000); + const seconds = Math.floor((new Date() - date) / 1000); - let interval = seconds / 31536000; - let calc; + let interval = seconds / 31536000; + let calc; - if (interval > 1) { - // calc = Math.floor(interval) - // return calc + (calc === 1 ? ' year' : ' years') - return date.toLocaleDateString(); - } - interval = seconds / 2592000; - if (interval > 1) { - // calc = Math.floor(interval) - // return calc + (calc === 1 ? ' month' : ' months') - return date.toLocaleDateString(); - } - interval = seconds / 86400; - if (interval > 1) { - // calc = Math.floor(interval) - // return calc + (calc === 1 ? ' day' : ' days') - return date.toLocaleDateString(); - } - interval = seconds / 3600; - if (interval > 1) { - calc = Math.floor(interval); - return calc + (calc === 1 ? " hour" : " hours"); - } - interval = seconds / 60; - if (interval > 1) { - calc = Math.floor(interval); - return calc + (calc === 1 ? " minute" : " minutes"); - } + if (interval > 1) { + // calc = Math.floor(interval) + // return calc + (calc === 1 ? ' year' : ' years') + return date.toLocaleDateString(); + } + interval = seconds / 2592000; + if (interval > 1) { + // calc = Math.floor(interval) + // return calc + (calc === 1 ? ' month' : ' months') + return date.toLocaleDateString(); + } + interval = seconds / 86400; + if (interval > 1) { + // calc = Math.floor(interval) + // return calc + (calc === 1 ? ' day' : ' days') + return date.toLocaleDateString(); + } + interval = seconds / 3600; + if (interval > 1) { + calc = Math.floor(interval); + return calc + (calc === 1 ? " hour" : " hours"); + } + interval = seconds / 60; + if (interval > 1) { + calc = Math.floor(interval); + return calc + (calc === 1 ? " minute" : " minutes"); + } - calc = Math.floor(interval); - return calc + (calc === 1 ? " second" : " seconds"); + calc = Math.floor(interval); + return calc + (calc === 1 ? " second" : " seconds"); }; export const bytesToSize = (bytes) => { - const sizes = ["Bytes", "KB", "MB", "GB", "TB"]; - if (bytes === 0) return "0 Byte"; - const i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024))); - return Math.round(bytes / Math.pow(1024, i), 2) + " " + sizes[i]; + const sizes = ["Bytes", "KB", "MB", "GB", "TB"]; + if (bytes === 0) return "0 Byte"; + const i = Number.parseInt(Math.floor(Math.log(bytes) / Math.log(1024))); + return `${Math.round(bytes / 1024 ** i, 2)} ${sizes[i]}`; }; export const bytesToMegabytes = (bytes) => { - return Math.round(bytes / Math.pow(1024, 2)); + return Math.round(bytes / 1024 ** 2); }; export const encode = (key) => { - if (key && key !== '/' && key.startsWith('/')) { - // File keys should never start with / - key = key.slice(1) - } - return btoa(unescape(encodeURIComponent(key))); + if (key && key !== "/" && key.startsWith("/")) { + // File keys should never start with / + key = key.slice(1); + } + return btoa(unescape(encodeURIComponent(key))); }; export const decode = (key) => { - return decodeURIComponent(escape(atob(key))); + return decodeURIComponent(escape(atob(key))); }; export const apiHandler = { - createFolder: (key, bucket) => { - return api.post(`/buckets/${bucket}/folder`, { - key: encode(key) - }) - }, - deleteObject: (key, bucket) => { - return api.post(`/buckets/${bucket}/delete`, { - key: encode(key) - }) - }, - downloadFile: (bucket, key, previewConfig, onDownloadProgress, abortControl) => { - const extra = {}; - if (previewConfig.downloadType === "objectUrl" || previewConfig.downloadType === "blob") { - extra.responseType = "arraybuffer"; - } - if (abortControl) { - extra.signal = abortControl.signal; - } - if (onDownloadProgress) { - extra.onDownloadProgress = onDownloadProgress; - } + createFolder: (key, bucket) => { + return api.post(`/buckets/${bucket}/folder`, { + key: encode(key), + }); + }, + deleteObject: (key, bucket) => { + return api.post(`/buckets/${bucket}/delete`, { + key: encode(key), + }); + }, + downloadFile: ( + bucket, + key, + previewConfig, + onDownloadProgress, + abortControl, + ) => { + const extra = {}; + if ( + previewConfig.downloadType === "objectUrl" || + previewConfig.downloadType === "blob" + ) { + extra.responseType = "arraybuffer"; + } + if (abortControl) { + extra.signal = abortControl.signal; + } + if (onDownloadProgress) { + extra.onDownloadProgress = onDownloadProgress; + } - return api.get( - `/buckets/${bucket}/${encode(key)}`, - extra - ); - }, - headFile: async (bucket, key) => { - let prefix = '' - if (key.includes('/')) { - prefix = key.replace(key.split('/').pop(), '') - } + return api.get(`/buckets/${bucket}/${encode(key)}`, extra); + }, + headFile: async (bucket, key) => { + let prefix = ""; + if (key.includes("/")) { + prefix = key.replace(key.split("/").pop(), ""); + } - const resp = await api.get(`/buckets/${bucket}/${encode(key)}/head`); + const resp = await api.get(`/buckets/${bucket}/${encode(key)}/head`); - if (resp.status === 200) { - return mapFile(resp.data, prefix) - } - }, - renameObject: (bucket, oldKey, newKey) => { - return api.post(`/buckets/${bucket}/move`, { - oldKey: encode(oldKey), - newKey: encode(newKey) - }) - }, - updateMetadata: async (bucket, key, metadata) => { - let prefix = '' - if (key.includes('/')) { - prefix = key.replace(key.split('/').pop(), '') - } + if (resp.status === 200) { + return mapFile(resp.data, prefix); + } + }, + renameObject: (bucket, oldKey, newKey) => { + return api.post(`/buckets/${bucket}/move`, { + oldKey: encode(oldKey), + newKey: encode(newKey), + }); + }, + updateMetadata: async (bucket, key, metadata) => { + let prefix = ""; + if (key.includes("/")) { + prefix = key.replace(key.split("/").pop(), ""); + } - const resp = await api.post( - `/buckets/${bucket}/${encode(key)}`, - { - customMetadata: metadata - } - ) + const resp = await api.post(`/buckets/${bucket}/${encode(key)}`, { + customMetadata: metadata, + }); - if (resp.status === 200) { - return mapFile(resp.data, prefix) - } - }, - multipartCreate: (file, key, bucket) => { - return api.post(`/buckets/${bucket}/multipart/create`, null, { - params: { - key: encode(key), - httpMetadata: encode(JSON.stringify({ - contentType: file.type - })) - } - }) - }, - multipartComplete: (file, key, bucket, parts, uploadId) => { - return api.post(`/buckets/${bucket}/multipart/complete`, { - key: encode(key), - uploadId, - parts - }) - }, - multipartUpload: (uploadId, partNumber, bucket, key, chunk, callback) => { - return api.post(`/buckets/${bucket}/multipart/upload`, chunk, { - params: { - key: encode(key), - uploadId, - partNumber - }, - onUploadProgress: callback, - headers: { - 'Content-Type': 'multipart/form-data' - } - }) - }, - uploadObjects: (file, key, bucket, callback) => { - // console.log(key) - return api.post(`/buckets/${bucket}/upload`, file, { - params: { - key: encode(key), - httpMetadata: encode(JSON.stringify({ - contentType: file.type - })) - }, - headers: { - 'Content-Type': 'multipart/form-data' - }, - onUploadProgress: callback - }) - }, - listObjects: async (bucket, prefix, delimiter = '/', cursor = null) => { - return await api.get(`/buckets/${bucket}?include=customMetadata&include=httpMetadata`, { - params: { - delimiter: delimiter, - prefix: prefix && prefix !== '/' ? encode(prefix) : '', - cursor: cursor - } - }) - }, - fetchFile: async (bucket, prefix, delimiter = '/') => { - const mainStore = useMainStore(); - let truncated = true - let cursor = null - let contentFiles = [] - let contentFolders = [] + if (resp.status === 200) { + return mapFile(resp.data, prefix); + } + }, + multipartCreate: (file, key, bucket) => { + return api.post(`/buckets/${bucket}/multipart/create`, null, { + params: { + key: encode(key), + httpMetadata: encode( + JSON.stringify({ + contentType: file.type, + }), + ), + }, + }); + }, + multipartComplete: (file, key, bucket, parts, uploadId) => { + return api.post(`/buckets/${bucket}/multipart/complete`, { + key: encode(key), + uploadId, + parts, + }); + }, + multipartUpload: (uploadId, partNumber, bucket, key, chunk, callback) => { + return api.post(`/buckets/${bucket}/multipart/upload`, chunk, { + params: { + key: encode(key), + uploadId, + partNumber, + }, + onUploadProgress: callback, + headers: { + "Content-Type": "multipart/form-data", + }, + }); + }, + uploadObjects: (file, key, bucket, callback) => { + // console.log(key) + return api.post(`/buckets/${bucket}/upload`, file, { + params: { + key: encode(key), + httpMetadata: encode( + JSON.stringify({ + contentType: file.type, + }), + ), + }, + headers: { + "Content-Type": "multipart/form-data", + }, + onUploadProgress: callback, + }); + }, + listObjects: async (bucket, prefix, delimiter = "/", cursor = null) => { + return await api.get( + `/buckets/${bucket}?include=customMetadata&include=httpMetadata`, + { + params: { + delimiter: delimiter, + prefix: prefix && prefix !== "/" ? encode(prefix) : "", + cursor: cursor, + }, + }, + ); + }, + fetchFile: async (bucket, prefix, delimiter = "/") => { + const mainStore = useMainStore(); + let truncated = true; + let cursor = null; + const contentFiles = []; + const contentFolders = []; - while (truncated) { - const response = await apiHandler.listObjects(bucket, prefix, delimiter, cursor) + while (truncated) { + const response = await apiHandler.listObjects( + bucket, + prefix, + delimiter, + cursor, + ); - truncated = response.data.truncated - cursor = response.data.cursor + truncated = response.data.truncated; + cursor = response.data.cursor; - if (response.data.objects) { - const files = response.data.objects.filter(function(obj) { - return !(obj.key.endsWith('/') && delimiter !== '') && obj.key !== prefix // Remove selected folder when delimiter is defined - }).map((obj) => mapFile(obj, prefix)).filter(obj => { - // Remove hidden files - return !(mainStore.showHiddenFiles !== true && obj.name.startsWith('.')) - }) + if (response.data.objects) { + const files = response.data.objects + .filter((obj) => { + return ( + !(obj.key.endsWith("/") && delimiter !== "") && obj.key !== prefix + ); // Remove selected folder when delimiter is defined + }) + .map((obj) => mapFile(obj, prefix)) + .filter((obj) => { + // Remove hidden files + return !( + mainStore.showHiddenFiles !== true && obj.name.startsWith(".") + ); + }); - for (const f of files) { - contentFiles.push(f) - } - } + for (const f of files) { + contentFiles.push(f); + } + } - if (response.data.delimitedPrefixes) { - const folders = response.data.delimitedPrefixes.map(function (obj) { - return { - name: obj.replace(prefix, ''), - hash: encode(obj.key), - key: obj, - lastModified: '--', - timestamp: 0, - size: '--', - sizeRaw: 0, - type: 'folder', - icon: 'folder', - color: 'orange', - } - }).filter(obj => { - // Remove hidden files - return !(mainStore.showHiddenFiles !== true && obj.name.startsWith('.')) - }) + if (response.data.delimitedPrefixes) { + const folders = response.data.delimitedPrefixes + .map((obj) => ({ + name: obj.replace(prefix, ""), + hash: encode(obj.key), + key: obj, + lastModified: "--", + timestamp: 0, + size: "--", + sizeRaw: 0, + type: "folder", + icon: "folder", + color: "orange", + })) + .filter((obj) => { + // Remove hidden files + return !( + mainStore.showHiddenFiles !== true && obj.name.startsWith(".") + ); + }); - for (const f of folders) { - contentFolders.push(f) - } - } - } + for (const f of folders) { + contentFolders.push(f); + } + } + } - return [ - ...contentFolders, - ...contentFiles - ] - } -} + return [...contentFolders, ...contentFiles]; + }, +}; diff --git a/packages/dashboard/src/boot/auth.js b/packages/dashboard/src/boot/auth.js index 6b9810c..7816136 100644 --- a/packages/dashboard/src/boot/auth.js +++ b/packages/dashboard/src/boot/auth.js @@ -1,14 +1,15 @@ -import { boot } from 'quasar/wrappers'; -import { useAuthStore } from 'stores/auth-store'; +import { boot } from "quasar/wrappers"; +import { useAuthStore } from "stores/auth-store"; import { useMainStore } from "stores/main-store"; -export default boot(async ({router, store}) => { - // Check if theres any auth token stored, if there is, try to fetch or redirect - const authStore = useAuthStore(store); - const authResp = await authStore.CheckLoginInStorage(router); +export default boot(async ({ router, store }) => { + // Check if theres any auth token stored, if there is, try to fetch or redirect + const authStore = useAuthStore(store); + const authResp = await authStore.CheckLoginInStorage(router); - if (authResp === false) { // No auth token stored, try to fetch without auth or redirect - const mainStore = useMainStore(store) - await mainStore.loadServerConfigs(router, true) - } + if (authResp === false) { + // No auth token stored, try to fetch without auth or redirect + const mainStore = useMainStore(store); + await mainStore.loadServerConfigs(router, true); + } }); diff --git a/packages/dashboard/src/boot/axios.js b/packages/dashboard/src/boot/axios.js index c9167d1..5f17374 100644 --- a/packages/dashboard/src/boot/axios.js +++ b/packages/dashboard/src/boot/axios.js @@ -1,5 +1,5 @@ -import { boot } from 'quasar/wrappers' -import axios from 'axios' +import axios from "axios"; +import { boot } from "quasar/wrappers"; // Be careful when using SSR for cross-request state pollution // due to creating a Singleton instance here; @@ -7,22 +7,22 @@ import axios from 'axios' // good idea to move this instance creation inside of the // "export default () => {}" function below (which runs individually // for each client) -let url = window.location.origin -if (process.env.NODE_ENV === 'development') { - url = process.env.VUE_APP_SERVER_URL || 'http://localhost:8787' +let url = window.location.origin; +if (process.env.NODE_ENV === "development") { + url = process.env.VUE_APP_SERVER_URL || "http://localhost:8787"; } -const api = axios.create({ baseURL: `${url}/api` }) +const api = axios.create({ baseURL: `${url}/api` }); export default boot(({ app }) => { - // for use inside Vue files (Options API) through this.$axios and this.$api + // for use inside Vue files (Options API) through this.$axios and this.$api - app.config.globalProperties.$axios = axios - // ^ ^ ^ this will allow you to use this.$axios (for Vue Options API form) - // so you won't necessarily have to import axios in each vue file + app.config.globalProperties.$axios = axios; + // ^ ^ ^ this will allow you to use this.$axios (for Vue Options API form) + // so you won't necessarily have to import axios in each vue file - app.config.globalProperties.$api = api - // ^ ^ ^ this will allow you to use this.$api (for Vue Options API form) - // so you can easily perform requests against your app's API -}) + app.config.globalProperties.$api = api; + // ^ ^ ^ this will allow you to use this.$api (for Vue Options API form) + // so you can easily perform requests against your app's API +}); -export { api } +export { api }; diff --git a/packages/dashboard/src/boot/bus.js b/packages/dashboard/src/boot/bus.js index 5eb99c8..c202561 100644 --- a/packages/dashboard/src/boot/bus.js +++ b/packages/dashboard/src/boot/bus.js @@ -1,12 +1,12 @@ -import { EventBus } from 'quasar' -import { boot } from 'quasar/wrappers' +import { EventBus } from "quasar"; +import { boot } from "quasar/wrappers"; export default boot(({ app }) => { - const bus = new EventBus() + const bus = new EventBus(); - // for Options API - app.config.globalProperties.$bus = bus + // for Options API + app.config.globalProperties.$bus = bus; - // for Composition API - app.provide('bus', bus) -}) + // for Composition API + app.provide("bus", bus); +}); diff --git a/packages/dashboard/src/components/files/CreateFile.vue b/packages/dashboard/src/components/files/CreateFile.vue index 7855b3f..9a32653 100644 --- a/packages/dashboard/src/components/files/CreateFile.vue +++ b/packages/dashboard/src/components/files/CreateFile.vue @@ -24,68 +24,73 @@ diff --git a/packages/dashboard/src/components/files/CreateFolder.vue b/packages/dashboard/src/components/files/CreateFolder.vue index 3624a59..c1080c0 100644 --- a/packages/dashboard/src/components/files/CreateFolder.vue +++ b/packages/dashboard/src/components/files/CreateFolder.vue @@ -24,54 +24,58 @@ diff --git a/packages/dashboard/src/components/files/FileOptions.vue b/packages/dashboard/src/components/files/FileOptions.vue index c2029e6..dacb3fe 100644 --- a/packages/dashboard/src/components/files/FileOptions.vue +++ b/packages/dashboard/src/components/files/FileOptions.vue @@ -33,144 +33,156 @@ diff --git a/packages/dashboard/src/components/preview/logGz.vue b/packages/dashboard/src/components/preview/logGz.vue index 4e16807..697c94c 100644 --- a/packages/dashboard/src/components/preview/logGz.vue +++ b/packages/dashboard/src/components/preview/logGz.vue @@ -8,25 +8,23 @@ import * as fflate from "fflate"; export default { - props: ['filedata'], - data: function () { - return { - data: null - } - }, - mounted() { - const parsedData = new Uint8Array(this.filedata); - const decompressed = fflate.decompressSync(parsedData); + props: ["filedata"], + data: () => ({ + data: null, + }), + mounted() { + const parsedData = new Uint8Array(this.filedata); + const decompressed = fflate.decompressSync(parsedData); - const origText = fflate.strFromU8(decompressed); + const origText = fflate.strFromU8(decompressed); - this.data = origText.split('\n').map(val => { - try { - return JSON.stringify(JSON.parse(val), null, 2) - } catch (e) { - return val - } - }) - } -} + this.data = origText.split("\n").map((val) => { + try { + return JSON.stringify(JSON.parse(val), null, 2); + } catch (e) { + return val; + } + }); + }, +}; diff --git a/packages/dashboard/src/components/utils/DragAndDrop.vue b/packages/dashboard/src/components/utils/DragAndDrop.vue index 920cdac..7f9fbc6 100644 --- a/packages/dashboard/src/components/utils/DragAndDrop.vue +++ b/packages/dashboard/src/components/utils/DragAndDrop.vue @@ -23,296 +23,320 @@