From b8cd39b27ae4efbe0a920939680ab9beb97e9ee6 Mon Sep 17 00:00:00 2001 From: srijitcoder Date: Wed, 20 Nov 2024 16:26:09 +0530 Subject: [PATCH 1/3] feat: added upload image and video to editor --- public/config.js | 150 +++++++++++++++++++++ src/api/index.js | 5 + src/components/file/CreateFile.vue | 91 ++++++------- src/methods/file-edit-view/post-message.js | 8 +- 4 files changed, 206 insertions(+), 48 deletions(-) diff --git a/public/config.js b/public/config.js index cd4451a..b38d778 100644 --- a/public/config.js +++ b/public/config.js @@ -12,6 +12,153 @@ globalThis.ghConfig = { }, }; +// Shared upload functionality +const handleFileUpload = async (file, editor, fileType, insertTemplate) => { + // Check if file is correct type + if (!file.type.startsWith(fileType + '/')) { + alert(`Please select a ${fileType} file`); + return; + } + + // Check file size (10MB = 10 * 1024 * 1024 bytes) + if (file.size > 10 * 1024 * 1024) { + alert('File size must be less than 10MB'); + return; + } + + // Create a FormData object to hold the file data + const formData = new FormData(); + formData.append('file', file); + + window.parent.postMessage({ + type: 'EDITOR_FILE_UPLOADING' + }, "*"); + + // Convert file to base64 + const reader = new FileReader(); + const base64Promise = new Promise((resolve) => { + reader.onload = () => { + const base64 = reader.result.split(',')[1]; + resolve(base64); + }; + }); + reader.readAsDataURL(file); + const base64Content = await base64Promise; + + try { + // Get PR number from URL path + const pathParts = window.location.pathname.split('/'); + const prNumber = pathParts[1]; // Get PR number like "62" + + // Get session details to get branch info + const token = await globalThis.ghConfig.config.auth; + const owner = globalThis.ghConfig.config.username; + const repo = globalThis.ghConfig.config.repo; + + // Get PR details to get branch ref + const prResponse = await fetch(`https://api.github.com/repos/${owner}/${repo}/pulls/${prNumber}`, { + headers: { + 'Authorization': `token ${token}`, + 'Accept': 'application/vnd.github.v3+json' + } + }); + + if (!prResponse.ok) { + throw new Error(`Failed to get PR details`); + } + + const prData = await prResponse.json(); + const branchRef = prData.head.ref; + + const branchOwner = prData.head.repo.owner.login; + const repoName = prData.head.repo.name; + + // Upload file to branch + const timestamp = Date.now(); + const fileName = file.name.replace(/[^a-zA-Z0-9\s.-]/g, '').replace(/\s+/g, '-').replace(/\.([^.]*)$/, `-${timestamp}.$1`); + const uploadResponse = await fetch(`https://api.github.com/repos/${branchOwner}/${repoName}/contents/assets/${fileName}`, { + method: 'PUT', + headers: { + 'Authorization': `token ${token}`, + 'Accept': 'application/vnd.github.v3+json', + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + message: `Upload ${fileType} ${file.name}`, + content: base64Content, + branch: branchRef + }) + }); + + if (!uploadResponse.ok) { + throw new Error(`Failed to upload ${fileType}`); + } + + const uploadData = await uploadResponse.json(); + const fileUrl = uploadData.content.download_url; + + // Insert using provided template + editor.codemirror.getDoc().setValue( + editor.codemirror.getDoc().getValue() + insertTemplate(fileUrl) + ); + + } catch (error) { + if(fileType === 'image') { + editor.codemirror.getDoc().setValue( + editor.codemirror.getDoc().getValue() + insertTemplate(reader.result) + ); + } else { + alert('Failed to upload file'); + } + } + + window.parent.postMessage({ + type: 'EDITOR_FILE_UPLOADED' + }, "*"); +}; + +const insertImageTool = { + name: "Attach Image", + action: customFunction = (editor) => { + let input = document.createElement('input'); + input.type = 'file'; + input.onchange = async e => { + console.log(globalThis.ghConfig); + const file = e.target.files[0]; + await handleFileUpload( + file, + editor, + 'image', + (url) => `\n![](${url})` + ); + }; + input.click(); + }, + className: "fa fa-image", + title: "Attach Image", +}; + +const insertVideoTool = { + name: "Attach Video", + action: customFunction = (editor) => { + let input = document.createElement('input'); + input.type = 'file'; + input.onchange = async e => { + console.log(globalThis.ghConfig); + const file = e.target.files[0]; + await handleFileUpload( + file, + editor, + 'video', + (url) => `\n` + ); + }; + input.click(); + }, + className: "fa fa-video-camera", + title: "Attach Video", +}; + globalThis.schemaMap = [ { path: "/eo-missions/catalog.json", @@ -75,6 +222,9 @@ globalThis.schemaMap = [ "unordered-list", "ordered-list", "link", + "|", + insertImageTool, + insertVideoTool ], spellChecker: false, }, diff --git a/src/api/index.js b/src/api/index.js index dac97e2..e13f983 100644 --- a/src/api/index.js +++ b/src/api/index.js @@ -26,6 +26,11 @@ export async function initOctokit() { const username = config.githubOwner || import.meta.env.VUE_APP_GITHUB_OWNER; const repo = config.githubRepo || import.meta.env.VUE_APP_GITHUB_REPO; + globalThis.ghConfig = { + ...config, + config: { auth, username, repo }, + }; + const octokit = new Octokit({ auth }); const { data } = await octokit.rest.users.getAuthenticated(); diff --git a/src/components/file/CreateFile.vue b/src/components/file/CreateFile.vue index b3f39a7..824b9cd 100644 --- a/src/components/file/CreateFile.vue +++ b/src/components/file/CreateFile.vue @@ -186,60 +186,57 @@ const getSelectedFileFolder = (name) => { + + diff --git a/src/methods/file-edit-view/post-message.js b/src/methods/file-edit-view/post-message.js index 3779872..cfad9da 100644 --- a/src/methods/file-edit-view/post-message.js +++ b/src/methods/file-edit-view/post-message.js @@ -1,4 +1,4 @@ -import { updateSchemaDefaults } from "@/helpers/index.js"; +import { updateSchemaDefaults, useLoader } from "@/helpers/index.js"; import isEqual from "lodash.isequal"; import { initEOXJSONFormMethod } from "@/methods/file-edit-view/init-eox-jsonform.js"; @@ -18,6 +18,8 @@ export function addPostMessageEventMethod({ jsonFormInstance, isSchemaBased, }) { + const loader = useLoader(); + let loaderInstance = null; window.addEventListener("message", function (event) { if ( event.data && @@ -31,5 +33,9 @@ export function addPostMessageEventMethod({ } } } + if (event.data && event.data.type === "EDITOR_FILE_UPLOADING") + loaderInstance = loader.show(); + if (event.data && event.data.type === "EDITOR_FILE_UPLOADED") + loaderInstance?.hide(); }); } From cd1f1b01c4cddaada171bb450b82bd259b8fa4e0 Mon Sep 17 00:00:00 2001 From: srijitcoder Date: Wed, 20 Nov 2024 16:34:41 +0530 Subject: [PATCH 2/3] chores: path added to upload --- public/config.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/public/config.js b/public/config.js index b38d778..3140339 100644 --- a/public/config.js +++ b/public/config.js @@ -12,6 +12,8 @@ globalThis.ghConfig = { }, }; +const PATH_TO_UPLOAD = 'assets'; + // Shared upload functionality const handleFileUpload = async (file, editor, fileType, insertTemplate) => { // Check if file is correct type @@ -76,7 +78,7 @@ const handleFileUpload = async (file, editor, fileType, insertTemplate) => { // Upload file to branch const timestamp = Date.now(); const fileName = file.name.replace(/[^a-zA-Z0-9\s.-]/g, '').replace(/\s+/g, '-').replace(/\.([^.]*)$/, `-${timestamp}.$1`); - const uploadResponse = await fetch(`https://api.github.com/repos/${branchOwner}/${repoName}/contents/assets/${fileName}`, { + const uploadResponse = await fetch(`https://api.github.com/repos/${branchOwner}/${repoName}/contents/${PATH_TO_UPLOAD}/${fileName}`, { method: 'PUT', headers: { 'Authorization': `token ${token}`, From e5e1a4ffc88e70aa9231c8e82698ce38d894f550 Mon Sep 17 00:00:00 2001 From: srijitcoder Date: Thu, 21 Nov 2024 13:15:41 +0530 Subject: [PATCH 3/3] fix: fiel url through commit sha --- public/config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/config.js b/public/config.js index 3140339..5b8451b 100644 --- a/public/config.js +++ b/public/config.js @@ -97,7 +97,7 @@ const handleFileUpload = async (file, editor, fileType, insertTemplate) => { } const uploadData = await uploadResponse.json(); - const fileUrl = uploadData.content.download_url; + const fileUrl = `https://raw.githubusercontent.com/${owner}/${repo}/${uploadData.commit.sha}/${PATH_TO_UPLOAD}/${fileName}`; // Insert using provided template editor.codemirror.getDoc().setValue(