From 82e2b1742f9c6156c51b0d3707155873c63d4d80 Mon Sep 17 00:00:00 2001 From: SrGooglo Date: Thu, 15 May 2025 09:59:42 +0000 Subject: [PATCH 01/10] Improve image card style --- packages/app/src/pages/auth/index.less | 207 ++++++++++++++----------- 1 file changed, 116 insertions(+), 91 deletions(-) diff --git a/packages/app/src/pages/auth/index.less b/packages/app/src/pages/auth/index.less index 5578423f..df634b3f 100755 --- a/packages/app/src/pages/auth/index.less +++ b/packages/app/src/pages/auth/index.less @@ -1,137 +1,162 @@ .login-page { - display: flex; - flex-direction: column; + display: flex; + flex-direction: column; - justify-content: center; + justify-content: center; - align-items: center; + align-items: center; - width: 100vw; - height: 100vh; + width: 100vw; + height: 100vh; - font-family: "Space Grotesk", sans-serif; + font-family: "Space Grotesk", sans-serif; - .background { - position: absolute; + .background { + position: absolute; - z-index: 10; + z-index: 10; - top: 0; - left: 0; + top: 0; + left: 0; - width: 100vw; - height: 100vh; + width: 100vw; + height: 100vh; - svg { - margin: 0; + svg { + margin: 0; - opacity: 0; + opacity: 0; - animation: opacityIn 3s ease-in-out 0s forwards; - } + animation: opacityIn 3s ease-in-out 0s forwards; + } - background-image: radial-gradient(rgba(var(--layout-background-contrast), 0.3) 1px, transparent 0), - radial-gradient(rgba(var(--layout-background-contrast), 0.3) 1px, transparent 0); + background-image: + radial-gradient( + rgba(var(--layout-background-contrast), 0.3) 1px, + transparent 0 + ), + radial-gradient( + rgba(var(--layout-background-contrast), 0.3) 1px, + transparent 0 + ); - background-position: 0 0, - 25px 25px; - background-size: 50px 50px; - } + background-position: + 0 0, + 25px 25px; + background-size: 50px 50px; + } +} - .wrapper { - position: relative; - z-index: 15; +@wrapper-img-width: 250px; - display: flex; - flex-direction: row; +.wrapper { + position: relative; + z-index: 15; - width: 55vw; - min-width: 700px; - max-width: 800px; + display: flex; + flex-direction: row; - overflow: hidden; + width: 55vw; + min-width: 700px; + max-width: 800px; - height: 50vh; - min-height: 500px; - max-height: 500px; + height: 50vh; + min-height: 500px; + max-height: 500px; - transition: all 250ms ease-in-out; + background-color: var(--background-color-accent); + border: 3px solid var(--border-color); - background-color: var(--background-color-accent); + border-radius: 12px; - border: 1px solid var(--border-color); + transition: all 250ms ease-in-out; - border-radius: 12px; + overflow: hidden; - .wrapper_background { - height: 100%; + .wrapper_background { + position: absolute; - min-width: 250px; - width: 250px; + left: 0; + top: 0; - border-radius: 12px; + height: 100%; - background-position: center; - background-size: cover; - background-repeat: no-repeat; - } + width: calc(@wrapper-img-width + 10px); + min-width: calc(@wrapper-img-width + 10px); - .content { - display: flex; - flex-direction: column; + background-position: center; + background-size: cover; + background-repeat: no-repeat; - align-items: center; - justify-content: center; + z-index: 1; + } - width: 100%; + .content { + position: absolute; + display: flex; + flex-direction: column; - min-width: 420px; + right: 0; - gap: 20px; + align-items: center; + justify-content: center; - padding: 40px; + width: calc(100% - @wrapper-img-width); + min-width: 420px; - .content_header { - height: 70px; + height: 100%; - img { - width: 100%; - height: 100%; - } - } + gap: 20px; + padding: 40px; - .actions { - display: flex; - flex-direction: column; + outline: 3px solid var(--border-color-solid); + border-radius: 12px; - align-items: center; - justify-content: center; + background-color: var(--background-color-accent); + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.09); - width: 100%; + z-index: 2; - gap: 15px; + .content_header { + height: 70px; - .ant-btn { - width: 100%; + img { + width: 100%; + height: 100%; + } + } - font-weight: 500; - letter-spacing: -0.6px; + .actions { + display: flex; + flex-direction: column; - &:last-child { - margin-bottom: 0; - } - } - } - } - } + align-items: center; + justify-content: center; + + width: 100%; + + gap: 15px; + + .ant-btn { + width: 100%; + + font-weight: 500; + letter-spacing: -0.6px; + + &:last-child { + margin-bottom: 0; + } + } + } + } } @keyframes opacityIn { - from { - opacity: 0; - } + from { + opacity: 0; + } - to { - opacity: 1; - } -} \ No newline at end of file + to { + opacity: 1; + } +} From 8b241e9ee0452ba3b38e18efb0e58c7525194bfa Mon Sep 17 00:00:00 2001 From: SrGooglo Date: Thu, 15 May 2025 10:01:37 +0000 Subject: [PATCH 02/10] Change classnames --- packages/app/src/pages/auth/index.jsx | 6 +++--- packages/app/src/pages/auth/index.less | 14 +++++++------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/app/src/pages/auth/index.jsx b/packages/app/src/pages/auth/index.jsx index 6efef997..e1e23e50 100755 --- a/packages/app/src/pages/auth/index.jsx +++ b/packages/app/src/pages/auth/index.jsx @@ -54,9 +54,9 @@ const AuthPage = (props) => { -
+
{ }} /> -
+
{React.createElement( keyToComponents[activeKey] ?? keyToComponents["selector"], diff --git a/packages/app/src/pages/auth/index.less b/packages/app/src/pages/auth/index.less index df634b3f..5ee5438a 100755 --- a/packages/app/src/pages/auth/index.less +++ b/packages/app/src/pages/auth/index.less @@ -47,9 +47,9 @@ } } -@wrapper-img-width: 250px; +@login-page-card-img-width: 250px; -.wrapper { +.login-page-card { position: relative; z-index: 15; @@ -73,7 +73,7 @@ overflow: hidden; - .wrapper_background { + &__background { position: absolute; left: 0; @@ -81,8 +81,8 @@ height: 100%; - width: calc(@wrapper-img-width + 10px); - min-width: calc(@wrapper-img-width + 10px); + width: calc(@login-page-card-img-width + 10px); + min-width: calc(@login-page-card-img-width + 10px); background-position: center; background-size: cover; @@ -91,7 +91,7 @@ z-index: 1; } - .content { + &__content { position: absolute; display: flex; flex-direction: column; @@ -101,7 +101,7 @@ align-items: center; justify-content: center; - width: calc(100% - @wrapper-img-width); + width: calc(100% - @login-page-card-img-width); min-width: 420px; height: 100%; From 270ac23a4634643983a348bfa45cd34a2f637851 Mon Sep 17 00:00:00 2001 From: SrGooglo Date: Thu, 15 May 2025 13:03:24 +0000 Subject: [PATCH 03/10] added solid border color --- packages/app/config/defaultTheme.json | 152 +++++++++++++------------- 1 file changed, 77 insertions(+), 75 deletions(-) diff --git a/packages/app/config/defaultTheme.json b/packages/app/config/defaultTheme.json index ccfdfa75..62a76546 100755 --- a/packages/app/config/defaultTheme.json +++ b/packages/app/config/defaultTheme.json @@ -1,76 +1,78 @@ { - "defaultVars": { - "fontScale": "1", - "backgroundBlur": "10px", - "colorPrimary": "#ff6064", - "app-color": "#ff6064", - "danger-color": "#ff6064", - "backgroundColorTransparency": "0.8", - "backgroundImage": "", - "fontFamily": "'Noto Sans', sans-serif", - "layoutMargin": "unset", - "layoutPadding": "20px 20px 20px 20px", - "borderRadius": "8px", - "text-color-white": "#d2d2d2", - "text-color-black": "#000000", - "page-transition-duration": "150ms", - "backgroundSize": "cover", - "backgroundPosition": "center", - "backgroundRepeat": "no-repeat", - "backgroundAttachment": "fixed", - "top-bar-height": "52px", - "bottom-bar-height": "80px", - "compact-mode": false - }, - "defaultVariant": "dark", - "variants": { - "light": { - "bg_color_1": "255, 255, 255", - "bg_color_2": "200, 200, 200", - "bg_color_3": "150, 150, 150", - "bg_color_4": "100, 100, 100", - "bg_color_5": "45, 45, 45", - "bg_color_6": "0, 0, 0", - "text-color": "var(--text-color-black)", - "svg-color": "var(--text-color)", - "disabled-color": "#d2d2d2", - "layoutBackgroundColor": "255, 255, 255", - "layout-background-contrast": "38, 38, 38", - "background-color-primary": "#ffffff", - "background-color-primary-2": "#f0f0f0", - "shadow-color": "#4b4b4b7c", - "background-color-accent-values": "240, 242, 245", - "background-color-accent": "#f0f2f5", - "background-color-contrast": "#4b4b4b", - "border-color": "rgba(75, 75, 75, 0.2)", - "sidebar-background-color": "var(--background-color-accent)", - "sidedrawer-background-color": "var(--background-color-accent)" - }, - "dark": { - "bg_color_1": "38, 38, 38", - "bg_color_2": "65, 65, 65", - "bg_color_3": "90, 90, 90", - "bg_color_4": "115, 115, 115", - "bg_color_5": "140, 140, 140", - "bg_color_6": "165, 165, 165", - "text-color": "var(--text-color-white)", - "svg-color": "var(--text-color)", - "disabled-color": "#4b4b4b", - "shadow-color": "#1010107c", - "layoutBackgroundColor": "38, 38, 38", - "layout-background-contrast": "255, 255, 255", - "background-color-primary": "#262626", - "background-color-primary-2": "#2c2c2c", - "background-color-accent-values": "53, 53, 53", - "background-color-accent": "#353535", - "background-color-contrast": "#ffffff", - "background_disabled": "#0A0A0A", - "border-color": "rgba(170, 170, 170, 0.2)", - "header-text-color": "#d2d2d2", - "button-background-color": "var(--colorPrimary)", - "button-text-color": "var(--background-color-contrast)", - "sidebar-background-color": "var(--background-color-accent)", - "sidedrawer-background-color": "var(--background-color-accent)" - } - } -} \ No newline at end of file + "defaultVars": { + "fontScale": "1", + "backgroundBlur": "10px", + "colorPrimary": "#ff6064", + "app-color": "#ff6064", + "danger-color": "#ff6064", + "backgroundColorTransparency": "0.8", + "backgroundImage": "", + "fontFamily": "'Noto Sans', sans-serif", + "layoutMargin": "unset", + "layoutPadding": "20px 20px 20px 20px", + "borderRadius": "8px", + "text-color-white": "#d2d2d2", + "text-color-black": "#000000", + "page-transition-duration": "150ms", + "backgroundSize": "cover", + "backgroundPosition": "center", + "backgroundRepeat": "no-repeat", + "backgroundAttachment": "fixed", + "top-bar-height": "52px", + "bottom-bar-height": "80px", + "compact-mode": false + }, + "defaultVariant": "dark", + "variants": { + "light": { + "bg_color_1": "255, 255, 255", + "bg_color_2": "200, 200, 200", + "bg_color_3": "150, 150, 150", + "bg_color_4": "100, 100, 100", + "bg_color_5": "45, 45, 45", + "bg_color_6": "0, 0, 0", + "text-color": "var(--text-color-black)", + "svg-color": "var(--text-color)", + "disabled-color": "#d2d2d2", + "layoutBackgroundColor": "255, 255, 255", + "layout-background-contrast": "38, 38, 38", + "background-color-primary": "#ffffff", + "background-color-primary-2": "#f0f0f0", + "shadow-color": "#4b4b4b7c", + "background-color-accent-values": "240, 242, 245", + "background-color-accent": "#f0f2f5", + "background-color-contrast": "#4b4b4b", + "border-color": "rgba(75, 75, 75, 0.2)", + "border-color-solid": "#b3b3b3", + "sidebar-background-color": "var(--background-color-accent)", + "sidedrawer-background-color": "var(--background-color-accent)" + }, + "dark": { + "bg_color_1": "38, 38, 38", + "bg_color_2": "65, 65, 65", + "bg_color_3": "90, 90, 90", + "bg_color_4": "115, 115, 115", + "bg_color_5": "140, 140, 140", + "bg_color_6": "165, 165, 165", + "text-color": "var(--text-color-white)", + "svg-color": "var(--text-color)", + "disabled-color": "#4b4b4b", + "shadow-color": "#1010107c", + "layoutBackgroundColor": "38, 38, 38", + "layout-background-contrast": "255, 255, 255", + "background-color-primary": "#262626", + "background-color-primary-2": "#2c2c2c", + "background-color-accent-values": "53, 53, 53", + "background-color-accent": "#353535", + "background-color-contrast": "#ffffff", + "background_disabled": "#0A0A0A", + "border-color": "rgba(170, 170, 170, 0.2)", + "border-color-solid": "#4c4c4c", + "header-text-color": "#d2d2d2", + "button-background-color": "var(--colorPrimary)", + "button-text-color": "var(--background-color-contrast)", + "sidebar-background-color": "var(--background-color-accent)", + "sidedrawer-background-color": "var(--background-color-accent)" + } + } +} From 464bb901e4adccb5149231a1f745067a372cf4f7 Mon Sep 17 00:00:00 2001 From: SrGooglo Date: Thu, 15 May 2025 13:03:58 +0000 Subject: [PATCH 04/10] Use comty.js file uploads --- .../app/src/classes/ChunkedUpload/index.js | 237 ------------------ .../ReleaseEditor/tabs/Tracks/index.jsx | 38 ++- .../app/src/components/PostCreator/index.jsx | 25 +- .../app/src/components/UploadButton/index.jsx | 27 +- .../cores/remoteStorage/remoteStorage.core.js | 117 --------- .../app/src/utils/queuedUploadFile/index.js | 46 ++++ 6 files changed, 85 insertions(+), 405 deletions(-) delete mode 100644 packages/app/src/classes/ChunkedUpload/index.js delete mode 100755 packages/app/src/cores/remoteStorage/remoteStorage.core.js create mode 100644 packages/app/src/utils/queuedUploadFile/index.js diff --git a/packages/app/src/classes/ChunkedUpload/index.js b/packages/app/src/classes/ChunkedUpload/index.js deleted file mode 100644 index 22cc95cb..00000000 --- a/packages/app/src/classes/ChunkedUpload/index.js +++ /dev/null @@ -1,237 +0,0 @@ -import { EventBus } from "@ragestudio/vessel" - -export default class ChunkedUpload { - constructor(params) { - const { - endpoint, - file, - headers = {}, - splitChunkSize = 1024 * 1024 * 10, - maxRetries = 3, - delayBeforeRetry = 5, - } = params - - if (!endpoint) { - throw new Error("Missing endpoint") - } - - if ((!file) instanceof File) { - throw new Error("Invalid or missing file") - } - - if (typeof headers !== "object") { - throw new Error("Invalid headers") - } - - if (splitChunkSize <= 0) { - throw new Error("Invalid splitChunkSize") - } - - this.chunkCount = 0 - this.retriesCount = 0 - - this.splitChunkSize = splitChunkSize - this.totalChunks = Math.ceil(file.size / splitChunkSize) - - this.maxRetries = maxRetries - this.delayBeforeRetry = delayBeforeRetry - this.offline = this.paused = false - - this.endpoint = endpoint - this.file = file - this.headers = { - ...headers, - "uploader-original-name": encodeURIComponent(file.name), - "uploader-file-id": this.getFileUID(file), - "uploader-chunks-total": this.totalChunks, - "chunk-size": splitChunkSize, - "cache-control": "no-cache", - connection: "keep-alive", - } - - this.setupListeners() - this.nextSend() - - console.debug("[Uploader] Created", { - splitChunkSize: splitChunkSize, - totalChunks: this.totalChunks, - totalSize: file.size, - fileName: file.name, - fileType: file.type, - }) - } - - _reader = new FileReader() - events = new EventBus() - - setupListeners() { - window.addEventListener( - "online", - () => - !this.offline && - ((this.offline = false), - this.events.emit("online"), - this.nextSend()), - ) - window.addEventListener( - "offline", - () => ((this.offline = true), this.events.emit("offline")), - ) - } - - getFileUID(file) { - return ( - Math.floor(Math.random() * 100000000) + - Date.now() + - file.size + - "_tmp" - ) - } - - loadChunk() { - return new Promise((resolve) => { - const start = this.chunkCount * this.splitChunkSize - const end = Math.min(start + this.splitChunkSize, this.file.size) - - this._reader.onload = () => { - resolve( - new Blob([this._reader.result], { - type: "application/octet-stream", - }), - ) - } - this._reader.readAsArrayBuffer(this.file.slice(start, end)) - }) - } - - async sendChunk() { - console.log(`[UPLOADER] Sending chunk ${this.chunkCount}`, { - currentChunk: this.chunkCount, - totalChunks: this.totalChunks, - chunk: this.chunk, - }) - - try { - const res = await fetch(this.endpoint, { - method: "POST", - headers: { - ...this.headers, - "uploader-chunk-number": this.chunkCount, - }, - body: this.chunk, - }) - - return res - } catch (error) { - this.manageRetries() - } - } - - manageRetries() { - if (++this.retriesCount < this.maxRetries) { - setTimeout(() => this.nextSend(), this.delayBeforeRetry * 1000) - - this.events.emit("fileRetry", { - message: `Retrying chunk ${this.chunkCount}`, - chunk: this.chunkCount, - retriesLeft: this.retries - this.retriesCount, - }) - } else { - this.events.emit("error", { - message: `No more retries for chunk ${this.chunkCount}`, - }) - } - } - - async nextSend() { - if (this.paused || this.offline) { - return null - } - - this.chunk = await this.loadChunk() - - try { - const res = await this.sendChunk() - - if (![200, 201, 204].includes(res.status)) { - // failed!! - return this.manageRetries() - } - - const data = await res.json() - - console.log(`[UPLOADER] Chunk ${this.chunkCount} sent`) - - this.chunkCount = this.chunkCount + 1 - - if (this.chunkCount < this.totalChunks) { - this.nextSend() - } - - // check if is the last chunk, if so, handle sse events - if (this.chunkCount === this.totalChunks) { - if (data.sseChannelId || data.sseUrl) { - this.waitOnSSE(data) - } else { - this.events.emit("finish", data) - } - } - - this.events.emit("progress", { - percent: Math.round((100 / this.totalChunks) * this.chunkCount), - state: "Uploading", - }) - } catch (error) { - this.events.emit("error", error) - } - } - - togglePause() { - this.paused = !this.paused - - if (!this.paused) { - return this.nextSend() - } - } - - waitOnSSE(data) { - // temporal solution until comty.js manages this - const url = `${app.cores.api.client().mainOrigin}/upload/sse_events/${data.sseChannelId}` - - console.log(`[UPLOADER] Connecting to SSE channel >`, url) - const eventSource = new EventSource(url) - - eventSource.onerror = (error) => { - this.events.emit("error", error) - eventSource.close() - } - - eventSource.onopen = () => { - console.log(`[UPLOADER] SSE channel opened`) - } - - eventSource.onmessage = (event) => { - // parse json - const messageData = JSON.parse(event.data) - - console.log(`[UPLOADER] SSE Event >`, messageData) - - if (messageData.event === "done") { - this.events.emit("finish", messageData.result) - eventSource.close() - } - - if (messageData.event === "error") { - this.events.emit("error", messageData.result) - eventSource.close() - } - - if (messageData.state) { - this.events.emit("progress", { - percent: messageData.percent, - state: messageData.state, - }) - } - } - } -} diff --git a/packages/app/src/components/MusicStudio/ReleaseEditor/tabs/Tracks/index.jsx b/packages/app/src/components/MusicStudio/ReleaseEditor/tabs/Tracks/index.jsx index 4f36d67b..14c2c29d 100644 --- a/packages/app/src/components/MusicStudio/ReleaseEditor/tabs/Tracks/index.jsx +++ b/packages/app/src/components/MusicStudio/ReleaseEditor/tabs/Tracks/index.jsx @@ -1,9 +1,10 @@ import React from "react" import * as antd from "antd" -import classnames from "classnames" -import { DragDropContext, Droppable } from "react-beautiful-dnd" import { createSwapy } from "swapy" +import queuedUploadFile from "@utils/queuedUploadFile" +import FilesModel from "@models/files" + import TrackManifest from "@cores/player/classes/TrackManifest" import { Icons } from "@components/Icons" @@ -209,14 +210,14 @@ class TracksManager extends React.Component { console.log( `[${trackManifest.uid}] Founded cover, uploading...`, ) + const coverFile = new File( [trackManifest._coverBlob], "cover.jpg", { type: trackManifest._coverBlob.type }, ) - const coverUpload = - await app.cores.remoteStorage.uploadFile(coverFile) + const coverUpload = await FilesModel.upload(coverFile) trackManifest.cover = coverUpload.url } @@ -243,25 +244,16 @@ class TracksManager extends React.Component { } uploadToStorage = async (req) => { - const response = await app.cores.remoteStorage - .uploadFile(req.file, { - onProgress: this.handleTrackFileUploadProgress, - headers: { - transformations: "a-dash", - }, - }) - .catch((error) => { - console.error(error) - antd.message.error(error) - - req.onError(error) - - return false - }) - - if (response) { - req.onSuccess(response) - } + await queuedUploadFile(req.file, { + onFinish: (file, response) => { + req.onSuccess(response) + }, + onError: req.onError, + onProgress: this.handleTrackFileUploadProgress, + headers: { + transformations: "a-dash", + }, + }) } handleTrackFileUploadProgress = async (file, progress) => { diff --git a/packages/app/src/components/PostCreator/index.jsx b/packages/app/src/components/PostCreator/index.jsx index 89ca7b61..ba44a55e 100755 --- a/packages/app/src/components/PostCreator/index.jsx +++ b/packages/app/src/components/PostCreator/index.jsx @@ -10,6 +10,7 @@ import { Icons } from "@components/Icons" import Poll from "@components/Poll" import clipboardEventFileToFile from "@utils/clipboardEventFileToFile" +import queuedUploadFile from "@utils/queuedUploadFile" import PostModel from "@models/post" import SearchModel from "@models/search" @@ -195,22 +196,14 @@ export default class PostCreator extends React.Component { uploadFile = async (req) => { this.toggleUploaderVisibility(false) - const request = await app.cores.remoteStorage - .uploadFile(req.file) - .catch((error) => { - console.error(error) - antd.message.error(error) - - req.onError(error) - - return false - }) - - if (request) { - console.log(`Upload done >`, request) - - return req.onSuccess(request) - } + await queuedUploadFile(req.file, { + onFinish: (file, response) => { + req.onSuccess(response) + }, + onError: (file, response) => { + req.onError(response) + }, + }) } removeAttachment = (file_uid) => { diff --git a/packages/app/src/components/UploadButton/index.jsx b/packages/app/src/components/UploadButton/index.jsx index 90ca59e4..2fee6122 100755 --- a/packages/app/src/components/UploadButton/index.jsx +++ b/packages/app/src/components/UploadButton/index.jsx @@ -1,12 +1,13 @@ import React from "react" import { Upload, Progress } from "antd" import classnames from "classnames" +import queuedUploadFile from "@utils/queuedUploadFile" import { Icons } from "@components/Icons" import "./index.less" -export default (props) => { +const UploadButton = (props) => { const [uploading, setUploading] = React.useState(false) const [progress, setProgress] = React.useState(null) @@ -40,17 +41,7 @@ export default (props) => { handleOnStart(req.file.uid, req.file) - await app.cores.remoteStorage.uploadFile(req.file, { - headers: props.headers, - onProgress: (file, progress) => { - setProgress(progress) - handleOnProgress(file.uid, progress) - }, - onError: (file, error) => { - setProgress(null) - handleOnError(file.uid, error) - setUploading(false) - }, + await queuedUploadFile(req.file, { onFinish: (file, response) => { if (typeof props.ctx?.onUpdateItem === "function") { props.ctx.onUpdateItem(response.url) @@ -67,6 +58,16 @@ export default (props) => { setProgress(null) }, 1000) }, + onError: (file, error) => { + setProgress(null) + handleOnError(file.uid, error) + setUploading(false) + }, + onProgress: (file, progress) => { + setProgress(progress) + handleOnProgress(file.uid, progress) + }, + headers: props.headers, }) } @@ -106,3 +107,5 @@ export default (props) => { ) } + +export default UploadButton diff --git a/packages/app/src/cores/remoteStorage/remoteStorage.core.js b/packages/app/src/cores/remoteStorage/remoteStorage.core.js deleted file mode 100755 index 3cca026c..00000000 --- a/packages/app/src/cores/remoteStorage/remoteStorage.core.js +++ /dev/null @@ -1,117 +0,0 @@ -import { Core } from "@ragestudio/vessel" - -import ChunkedUpload from "@classes/ChunkedUpload" -import SessionModel from "@models/session" - -export default class RemoteStorage extends Core { - static namespace = "remoteStorage" - static depends = ["api", "tasksQueue"] - - public = { - uploadFile: this.uploadFile, - getFileHash: this.getFileHash, - binaryArrayToFile: this.binaryArrayToFile, - } - - binaryArrayToFile(bin, filename) { - const { format, data } = bin - - const filenameExt = format.split("/")[1] - filename = `${filename}.${filenameExt}` - - const byteArray = new Uint8Array(data) - const blob = new Blob([byteArray], { type: data.type }) - - return new File([blob], filename, { - type: format, - }) - } - - async getFileHash(file) { - const buffer = await file.arrayBuffer() - const hash = await crypto.subtle.digest("SHA-256", buffer) - const hashArray = Array.from(new Uint8Array(hash)) - const hashHex = hashArray - .map((b) => b.toString(16).padStart(2, "0")) - .join("") - - return hashHex - } - - async uploadFile( - file, - { - onProgress = () => {}, - onFinish = () => {}, - onError = () => {}, - service = "standard", - headers = {}, - } = {}, - ) { - return await new Promise((_resolve, _reject) => { - const fn = async () => - new Promise((resolve, reject) => { - const uploader = new ChunkedUpload({ - endpoint: `${app.cores.api.client().mainOrigin}/upload/chunk`, - splitChunkSize: 5 * 1024 * 1024, - file: file, - service: service, - headers: { - ...headers, - "provider-type": service, - Authorization: `Bearer ${SessionModel.token}`, - }, - }) - - uploader.events.on("error", ({ message }) => { - this.console.error("[Uploader] Error", message) - - app.cores.notifications.new( - { - title: "Could not upload file", - description: message, - }, - { - type: "error", - }, - ) - - if (typeof onError === "function") { - onError(file, message) - } - - reject(message) - _reject(message) - }) - - uploader.events.on("progress", (data) => { - if (typeof onProgress === "function") { - onProgress(file, data) - } - }) - - uploader.events.on("finish", (data) => { - this.console.debug("[Uploader] Finish", data) - - app.cores.notifications.new( - { - title: "File uploaded", - }, - { - type: "success", - }, - ) - - if (typeof onFinish === "function") { - onFinish(file, data) - } - - resolve(data) - _resolve(data) - }) - }) - - app.cores.tasksQueue.appendToQueue(`upload_${file.name}`, fn) - }) - } -} diff --git a/packages/app/src/utils/queuedUploadFile/index.js b/packages/app/src/utils/queuedUploadFile/index.js new file mode 100644 index 00000000..3f73d879 --- /dev/null +++ b/packages/app/src/utils/queuedUploadFile/index.js @@ -0,0 +1,46 @@ +import FilesModel from "@models/files" + +export default (file, options) => { + if (!app.cores.tasksQueue) { + throw new Error("Missing tasksQueue") + } + + return app.cores.tasksQueue.appendToQueue( + `upload_${file.name}`, + async () => { + await FilesModel.upload(file, { + ...options, + onError: (file, error) => { + app.cores.notifications.new( + { + title: "Could not upload file", + description: error.message, + }, + { + type: "error", + }, + ) + + if (typeof options.onError === "function") { + options.onError(file, error) + } + }, + onFinish: (file, data) => { + app.cores.notifications.new( + { + title: "File uploaded", + description: `[${file.name}] uploaded successfully!`, + }, + { + type: "success", + }, + ) + + if (typeof options.onFinish === "function") { + options.onFinish(file, data) + } + }, + }) + }, + ) +} From 2731fd7b4ee845d00efb8acdc310b6b2561a0fdb Mon Sep 17 00:00:00 2001 From: SrGooglo Date: Thu, 15 May 2025 13:04:06 +0000 Subject: [PATCH 05/10] remove unused core --- packages/app/src/cores/sync/sync.core.js | 34 ------------------------ 1 file changed, 34 deletions(-) delete mode 100755 packages/app/src/cores/sync/sync.core.js diff --git a/packages/app/src/cores/sync/sync.core.js b/packages/app/src/cores/sync/sync.core.js deleted file mode 100755 index 5ed2b0ac..00000000 --- a/packages/app/src/cores/sync/sync.core.js +++ /dev/null @@ -1,34 +0,0 @@ -import { Core } from "@ragestudio/vessel" -import SyncModel from "comty.js/models/sync" - -export default class SyncCore extends Core { - static namespace = "sync" - static dependencies = ["api", "settings"] - - activeLinkedServices = {} - - services = { - - } - - public = { - getActiveLinkedServices: function () { - return this.activeLinkedServices - }.bind(this), - services: this.services, - } - - events = { - "app.initialization.start": async () => { - const activeServices = await SyncModel.getLinkedServices().catch((error) => { - this.console.error(error) - return null - }) - - if (activeServices) { - this.console.log(`Active services`, activeServices) - this.activeLinkedServices = activeServices - } - } - } -} \ No newline at end of file From 79b8ecc98f8ba72a9b1932310b7dbb9a6da16f98 Mon Sep 17 00:00:00 2001 From: SrGooglo Date: Thu, 15 May 2025 13:04:09 +0000 Subject: [PATCH 06/10] format --- .../src/cores/tasksQueue/tasksQueue.core.js | 137 +++++++++--------- 1 file changed, 71 insertions(+), 66 deletions(-) diff --git a/packages/app/src/cores/tasksQueue/tasksQueue.core.js b/packages/app/src/cores/tasksQueue/tasksQueue.core.js index 4327ad25..99241c87 100755 --- a/packages/app/src/cores/tasksQueue/tasksQueue.core.js +++ b/packages/app/src/cores/tasksQueue/tasksQueue.core.js @@ -2,90 +2,95 @@ import { Core } from "@ragestudio/vessel" import { Observable } from "object-observer" export default class TasksQueue extends Core { - static depends = ["settings"] + static depends = ["settings"] - static namespace = "tasksQueue" + static namespace = "tasksQueue" - static get maxRunningTasks() { - return app.cores.settings.get("tasks.maxRunningTasks") ?? 3 - } + static get maxRunningTasks() { + return app.cores.settings.get("tasks.maxRunningTasks") ?? 3 + } - public = { - appendToQueue: this.appendToQueue.bind(this), - processTasks: this.processTasks.bind(this), - } + public = { + appendToQueue: this.appendToQueue.bind(this), + processTasks: this.processTasks.bind(this), + } - taskQueue = Observable.from([]) + taskQueue = Observable.from([]) - runningTasksIds = Observable.from([]) + runningTasksIds = Observable.from([]) - processTasks() { - if (this.runningTasksIds.length >= TasksQueue.maxRunningTasks ?? 1) { - this.console.log("We are already running the maximum number of tasks") - return false - } + processTasks() { + if (this.runningTasksIds.length >= TasksQueue.maxRunningTasks ?? 1) { + this.console.log( + "We are already running the maximum number of tasks", + ) + return false + } - // check if there are new tasks in the queue and move them to the tasks array with the maximum number of tasks can be run - if (this.taskQueue.length === 0) { - this.console.log("No tasks in the queue") - return false - } + // check if there are new tasks in the queue and move them to the tasks array with the maximum number of tasks can be run + if (this.taskQueue.length === 0) { + this.console.log("No tasks in the queue") + return false + } - let tasks = this.taskQueue.splice(0, TasksQueue.maxRunningTasks ?? 1) + let tasks = this.taskQueue.splice(0, TasksQueue.maxRunningTasks ?? 1) - tasks = tasks.filter((task) => task) + tasks = tasks.filter((task) => task) - const promises = tasks.map(async (task) => { - if (typeof task.fn !== "function") { - throw new Error("Task must be a function") - } + const promises = tasks.map(async (task) => { + if (typeof task.fn !== "function") { + throw new Error("Task must be a function") + } - if (typeof task.id === "undefined") { - throw new Error("Task id is required") - } + if (typeof task.id === "undefined") { + throw new Error("Task id is required") + } - // add the task to the running tasks array - this.runningTasksIds.push(task.id) + // add the task to the running tasks array + this.runningTasksIds.push(task.id) - const taskResult = await task.fn() - .catch((error) => { - // delete the task from the running tasks array - this.runningTasksIds = this.runningTasksIds.filter((runningTaskId) => runningTaskId !== task.id) + const taskResult = await task.fn().catch((error) => { + // delete the task from the running tasks array + this.runningTasksIds = this.runningTasksIds.filter( + (runningTaskId) => runningTaskId !== task.id, + ) - // propagate the error through an exception - throw error - }) + // propagate the error through an exception + throw error + }) - // delete the task from the running tasks array - this.runningTasksIds = this.runningTasksIds.filter((runningTaskId) => runningTaskId !== task.id) + // delete the task from the running tasks array + this.runningTasksIds = this.runningTasksIds.filter( + (runningTaskId) => runningTaskId !== task.id, + ) - return taskResult - }) + return taskResult + }) - Promise.all(promises) - .then((res) => { - this.processTasks() - }) - .catch((error) => { - this.console.error(error) - this.processTasks() - }) - } + Promise.all(promises) + .then((res) => { + this.processTasks() + }) + .catch((error) => { + this.console.error(error) + this.processTasks() + }) + } - appendToQueue(taskId, task) { - if (!taskId) { - throw new Error("Task id is required") - } + appendToQueue(taskId, task) { + if (!taskId) { + throw new Error("Task id is required") + } - if (Array.isArray(task)) { - throw new Error("Task must be a function") - } + if (Array.isArray(task)) { + throw new Error("Task must be a function") + } - this.taskQueue.unshift({ - id: taskId, - fn: task, - }) + this.taskQueue.unshift({ + id: taskId, + fn: task, + }) - this.processTasks() - } -} \ No newline at end of file + this.processTasks() + } +} From da7a21a4abc9d53905b257c0ae92ad05aecee40e Mon Sep 17 00:00:00 2001 From: SrGooglo Date: Thu, 15 May 2025 13:04:34 +0000 Subject: [PATCH 07/10] added basic eslint config --- packages/app/eslint.config.js | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 packages/app/eslint.config.js diff --git a/packages/app/eslint.config.js b/packages/app/eslint.config.js new file mode 100644 index 00000000..e52a61a5 --- /dev/null +++ b/packages/app/eslint.config.js @@ -0,0 +1,17 @@ +import js from "@eslint/js" +import globals from "globals" +import pluginReact from "eslint-plugin-react" +import { defineConfig } from "eslint/config" + +export default defineConfig([ + { + files: ["**/*.{js,mjs,cjs,jsx}"], + plugins: { js }, + extends: ["js/recommended"], + }, + { + files: ["**/*.{js,mjs,cjs,jsx}"], + languageOptions: { globals: globals.browser }, + }, + pluginReact.configs.flat.recommended, +]) From 48bd4a3b699240e2d1cd32860ec237efd3afd847 Mon Sep 17 00:00:00 2001 From: SrGooglo Date: Thu, 15 May 2025 13:04:41 +0000 Subject: [PATCH 08/10] bump deps --- packages/app/package.json | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/app/package.json b/packages/app/package.json index fe225cb5..c526f188 100755 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -11,7 +11,8 @@ "build": "vite build", "preview": "vite preview", "release": "node ./scripts/release.js", - "postinstall": "./scripts/postinstall.sh" + "postinstall": "./scripts/postinstall.sh", + "eslint": "eslint" }, "dependencies": { "@ant-design/icons": "^5.4.0", @@ -33,7 +34,7 @@ "axios": "^1.7.7", "bear-react-carousel": "^4.0.10-alpha.0", "classnames": "2.3.1", - "comty.js": "^0.65.5", + "comty.js": "^0.66.0", "d3": "^7.9.0", "dashjs": "^5.0.0", "dompurify": "^3.0.0", @@ -79,9 +80,13 @@ "vite": "^6.2.6" }, "devDependencies": { + "@eslint/js": "^9.26.0", "@octokit/rest": "^21.1.1", "7zip-min": "1.4.3", "dotenv": "16.0.3", - "form-data": "^4.0.0" + "eslint": "^9.26.0", + "eslint-plugin-react": "^7.37.5", + "form-data": "^4.0.0", + "globals": "^16.1.0" } } From d238481547009795e8670fba979c3297dd81c63b Mon Sep 17 00:00:00 2001 From: SrGooglo Date: Thu, 15 May 2025 13:05:06 +0000 Subject: [PATCH 09/10] update deps & submodules --- comty.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/comty.js b/comty.js index 94c8d738..fe5cb1a9 160000 --- a/comty.js +++ b/comty.js @@ -1 +1 @@ -Subproject commit 94c8d7383e84a2de4b193d27adfcb1baa4163f68 +Subproject commit fe5cb1a9a275444abd7307bbd8a4e7c68221369b From 6f1c3fbc559ad61f28d8f76e2b3a4a75766bcf6d Mon Sep 17 00:00:00 2001 From: SrGooglo Date: Thu, 15 May 2025 13:05:48 +0000 Subject: [PATCH 10/10] bump version --- packages/app/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/app/package.json b/packages/app/package.json index c526f188..6ad6d9a2 100755 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -1,6 +1,6 @@ { "name": "@comty/app", - "version": "1.41.0@alpha", + "version": "1.42.0@alpha", "license": "ComtyLicense", "main": "electron/main", "type": "module",