diff --git a/electron/components/file.js b/electron/components/file.js index 8df05420d05b17f202ab73e94ec0538677fbd8a3..071e25116aa4dcec38dbc1dcd38d4dc09fa977ce 100644 --- a/electron/components/file.js +++ b/electron/components/file.js @@ -184,6 +184,13 @@ const writeProjectData = async function (workdir, data) { fs.writeFileSync(path.join(workdir, 'project.json'), data); }; +/** + * Write the epoc data to the content.json file in workdir + */ +const writeEpocData = async function (workdir, data) { + fs.writeFileSync(path.join(workdir, 'content.json'), data); +}; + /** * Copy the imported file to the workdir * @param {string} workdir @@ -238,6 +245,7 @@ module.exports = { saveAsEpocProject, exportProject, writeProjectData, + writeEpocData, readProjectData, copyFileToWorkdir, cleanAllWorkdir diff --git a/electron/components/ipc.js b/electron/components/ipc.js index ff03ff9e901e8214abe4a8de84d568185b2b76ea..a169d7614b7021b2f5fdeeac1be6b87f21d3b15b 100644 --- a/electron/components/ipc.js +++ b/electron/components/ipc.js @@ -2,7 +2,7 @@ const { ipcMain } = require('electron'); const path = require('path'); const store = require('./store'); const { runPreview } = require('./preview'); -const { getRecentFiles, pickEpocProject, openEpocProject, newEpocProject, saveEpocProject, exportProject, writeProjectData, readProjectData, copyFileToWorkdir } = require('./file'); +const { getRecentFiles, pickEpocProject, openEpocProject, newEpocProject, saveEpocProject, exportProject, writeProjectData, writeEpocData, readProjectData, copyFileToWorkdir } = require('./file'); /** * Setup ipc listeners that are received from renderer process @@ -66,6 +66,10 @@ const setupIpcListener = function (targetWindow) { await writeProjectData(store.state.currentProject.workdir, data); }); + ipcMain.on('writeEpocData', async (event, data) => { + await writeEpocData(store.state.currentProject.workdir, data); + }); + ipcMain.on('importFile', async (event, filepath) => { sendToFrontend(targetWindow, 'fileImported', await copyFileToWorkdir(store.state.currentProject.workdir, filepath)); }); diff --git a/electron/electron.js b/electron/electron.js index 842e200f21cce48b8e80e75a09629f1ba989467d..e8245e97027460f60c1fe53a96ded8e873511ad8 100644 --- a/electron/electron.js +++ b/electron/electron.js @@ -60,7 +60,7 @@ app.whenReady().then(() => { }; session.defaultSession.webRequest.onBeforeRequest(filter, (details, callback) => { - if (details.url.indexOf('assets/') !== -1) { + if (mainWindow.webContents.id === details.webContents.id && details.url.indexOf('assets/') !== -1) { const filepath = details.url.split('assets/')[1]; return callback({ redirectURL: `assets://assets/${filepath}` }); diff --git a/src/features/forms/FormPanel.vue b/src/features/forms/FormPanel.vue index a7d5892aff8fc4d6f96a5fcf285c6b315439bd39..a90fce00842869809e261c1bcfca7f03ff95de1c 100644 --- a/src/features/forms/FormPanel.vue +++ b/src/features/forms/FormPanel.vue @@ -11,7 +11,7 @@ function actionOnForm(action: string) { switch (action) { case 'delete': editorStore.deleteElement(editorStore.openedNodeId); - projectService.saveProjectData(); + projectService.writeProjectData(); break; } } diff --git a/src/features/forms/components/GenericField.vue b/src/features/forms/components/GenericField.vue index 5dacb23161506b8e91877bc52acfc2a75453e95a..67f403166919bc8130df08f3270841ae7ce6e3c6 100644 --- a/src/features/forms/components/GenericField.vue +++ b/src/features/forms/components/GenericField.vue @@ -20,7 +20,7 @@ const node = editorStore.openedParentId ? findNode(editorStore.openedParentId) : function onInput(value, id) { node.data.formValues[id] = value; - projectService.saveProjectData(); + projectService.writeProjectData(); } function onRepeatInput(value, id) { @@ -52,7 +52,7 @@ function onRepeatInput(value, id) { node.data.formValues[id][value.index][value.id] = value.value; } } - projectService.saveProjectData(); + projectService.writeProjectData(); } </script> diff --git a/src/shared/classes/epoc-v1.ts b/src/shared/classes/epoc-v1.ts new file mode 100644 index 0000000000000000000000000000000000000000..dcdd623ab28496b3080f84618882891c5ac21ebe --- /dev/null +++ b/src/shared/classes/epoc-v1.ts @@ -0,0 +1,64 @@ +import { Assessment, Chapter, Content, Epoc, html, Parameters, uid } from '@epoc/epoc-specs/dist/v1'; +import { Question } from '@epoc/epoc-specs/dist/v1/question'; +import { Author } from '@epoc/epoc-specs/dist/v1/author'; + +export class EpocV1 implements Epoc { + id: string; + title: string; + image: string; + objectives: string[]; + summary: html; + teaser: string; + thumbnail: string; + version: string; + certificateScore: number; + download: string; + lastModif: string; + chaptersCount: number; + assessmentsCount: number; + authors:Author[]; + parameters: Parameters; + chapters: Record<uid, Chapter>; + contents: Record<uid, Content>; + questions: Record<uid, Question>; + + constructor( + id: string, title: string, image: string, objectives: string[], summary: html, teaser: string, + thumbnail: string, version: string, certificateScore: number, authors: Author[], + chapterParameter: string + ) { + this.id = id; + this.title = title; + this.image = image; + this.objectives = objectives; + this.summary = summary; + this.teaser = teaser; + this.thumbnail = thumbnail; + this.version = version; + this.certificateScore = certificateScore; + this.authors = authors; + this.parameters = { + chapterParameter + }; + this.chapters = {}; + this.contents = {}; + this.questions = {}; + this.chaptersCount = 0; + this.assessmentsCount = 0; + this.download = ''; + } + + addChapter(id: uid, chapter: Chapter) { + this.chapters[id] = chapter; + } + + addContent(id, chapterId, content) { + this.questions[id] = content; + this.chapters[chapterId].contents.push(id); + } + + addDuestion(id, contentId, question) { + this.questions[id] = question; + (this.contents[contentId] as Assessment).questions.push(id); + } +} \ No newline at end of file diff --git a/src/shared/data/form.data.ts b/src/shared/data/form.data.ts index 14d76d7424898edb1dd17cc1c19bdba8f3b15cd2..b2989228797d7041ec8fc92035cf4d7b79375219 100644 --- a/src/shared/data/form.data.ts +++ b/src/shared/data/form.data.ts @@ -191,6 +191,68 @@ export const epocForm: Form = { } ] }, + { + name: 'Auteurs', + inputs: [ + { + id: 'authors', + label: 'Auteur', + type: 'repeat', + value: '', + inputs: [ + { + id: 'name', + type: 'text', + label: 'Nom', + placeholder: 'Préom nom', + value: '' + }, + { + id: 'image', + type: 'file', + label: 'Image', + placeholder: 'Ajouter une image', + value: '', + accept: '.png,.jpg,.jpeg,.gif,.bmp,.svg,.webp' + }, + { + id: 'title', + type: 'text', + label: 'Titre', + placeholder: 'Chercheuse à l\'Inria', + value: '', + }, + { + id: 'description', + type: 'ql-editor', + label: '', + placeholder: 'Description', + value: '' + } + ] + } + ] + }, + { + name: 'Objectifs', + inputs: [ + { + id: 'objectives', + label: 'Objectif', + type: 'repeat', + value: '', + inputs: [ + { + id: '', + type: 'textarea', + label: '', + placeholder: 'Saisissez un objectif ...', + value: '' + } + ] + } + ] + }, { name: 'Paramètres :', inputs : [ diff --git a/src/shared/services/editor.service.ts b/src/shared/services/editor.service.ts index 4ef4bc518ea3e8876d99fe78189d9fff23e9ecc4..cfe519bfdea73ffe037996018f3d420479ca00b3 100644 --- a/src/shared/services/editor.service.ts +++ b/src/shared/services/editor.service.ts @@ -2,7 +2,6 @@ import { ApiInterface } from '@/src/shared/interfaces/api.interface'; import { router } from '@/src/router'; import { useEditorStore, useProjectStore } from '@/src/shared/stores'; import { ePocProject } from '@/src/shared/interfaces'; -import { projectService } from './project.service'; import { createToaster } from '@meforma/vue-toaster'; const toaster = createToaster({ @@ -139,7 +138,6 @@ function openEpocProject(project): void { function saveEpocProject(): void { editorStore.saving = true; api.send('saveEpocProject'); - projectService.createContentJSON(); } function runPreview(): void { diff --git a/src/shared/services/project.service.ts b/src/shared/services/project.service.ts index bf92b07daa7e24f5e83d202f4e149d0da7ae0f07..907c0f319c5745eb952c4fd467b73b1acd466dc4 100644 --- a/src/shared/services/project.service.ts +++ b/src/shared/services/project.service.ts @@ -1,16 +1,19 @@ import { ApiInterface } from '@/src/shared/interfaces/api.interface'; import { useProjectStore } from '../stores'; -import { getConnectedEdges, useVueFlow } from '@vue-flow/core'; +import { getConnectedEdges, GraphNode, useVueFlow } from '@vue-flow/core'; +import { EpocV1 } from '@/src/shared/classes/epoc-v1'; declare const api: ApiInterface; const { toObject, onNodesChange, nodes, edges, findNode } = useVueFlow({ id: 'main' }); const projectStore = useProjectStore(); -function saveProjectData(): void { +function writeProjectData(): void { debounceFunction(500, () => { const data = JSON.stringify(toObject()); + const content = JSON.stringify(createContentJSON()); api.send('writeProjectData', data); + api.send('writeEpocData', content); }); } @@ -32,116 +35,70 @@ const debounceFunction = function (delay, cb) { }; onNodesChange(() => { - saveProjectData(); + writeProjectData(); }); -function createContentJSON() { - // const content = {}; - // content['chapters'] = {}; - // content['contents'] = {}; - // const startingNode = nodes.value.filter((node) => { return node.type === 'epoc' || node.type === 'chapter';}); - // startingNode.forEach((node) => { - // if(node.type === 'epoc') { - // const inputs = node.data.form.fields[0].inputs; - // content['lastModif'] = new Date().toISOString(); - // content['title'] = inputs[0].value; - // content['image']= inputs[2].value; - // content['thumbnail'] = inputs[3].value; - // content['teaser'] = inputs[4].value; - // content['summary'] = inputs[5].value; - // content['id'] = inputs[6].value; - // content['edition'] = inputs[7].value; - // content['parameters'] = { - // 'chapterParameters': inputs[1].value - // }; - - // //TODO - // content['author'] = {}; - // content['certificateScore'] = 0; - // content['plugins'] = []; - // } - // if(node.type === 'chapter') { - // const chapter = {}; - // const titleInputs = node.data.form.fields[0].inputs; - // chapter['title'] = titleInputs[0].value; - // const objectiveInputs = node.data.form.fields[1].inputs; - // const objectives = []; - // for(const objective of objectiveInputs) { - // objectives.push(objective.inputs[0].value); - // } - // chapter['objective'] = objectives; - - // chapter['contents'] = []; - - // let nextEdge = getNextEdge(node); - // while (nextEdge) { - // const nextNode = findNode(nextEdge.target); - // chapter['contents'].push(nextNode.data.contentId); - - // const type = identifyTemplate(nextNode); - // const element = {}; - // if(type === 'video') { - // const titleInput = nextNode.data.form.fields[0].inputs[0].value; - // const summaryInput = nextNode.data.elements[0].form.fields[0].inputs[1].value; - - // element['type'] = 'video'; - // element['title'] = titleInput; - // element['summary'] = summaryInput; - - // //TODO - // element['source'] = ''; - // element['subtitles'] = []; - // element['transcript'] = ''; - // element['poster'] = ''; - - // } else if(type === 'text') { - // const titleInput = nextNode.data.form.fields[0].inputs[0].value; - // const htmlInput = nextNode.data.elements[0].form.fields[0].inputs[0].value; - - // element['type'] = 'html'; - // element['title'] = titleInput; - // element['html'] = htmlInput; - - // } else { - // const question = {}; - // const element = nextNode.data.elements[0]; - // question['type'] = element.action.type; - - // const fields = element.form.fields; - - // question['score'] = fields[0].inputs[1].value; - // question['statement'] = fields[0].inputs[0].value; - // question[''] - - // console.log('question:',question); - // console.log('node:', nextNode); - // } - // content['contents'][nextNode.data.contentId] = element; - - // nextEdge = getNextEdge(nextNode); - // } - // content['chapters'][node.data.contentId] = chapter; - // } - // }); - // console.log('content:', JSON.stringify(content)); +function createContentJSON() : EpocV1 { + + const epocNode = nodes.value.find((node) => { return node.type === 'epoc'; }); + const chapterNodes = nodes.value.filter((node) => { return node.type === 'chapter'; }); + + const ePocValues = epocNode.data.formValues; + + const epoc = new EpocV1( + ePocValues.id || 'E000XX', + ePocValues.title || 'Title', + ePocValues.image || '', + ePocValues.objectives || [], + ePocValues.summary || '', + ePocValues.teaser || '', + ePocValues.thumbnail || '', + ePocValues.version || new Date().getFullYear(), + ePocValues.certificateScore || 0, + ePocValues.authors || {}, + ePocValues.chapterParameter + ); + + console.log(epoc); + + chapterNodes.forEach(chapter => { + console.log(chapter.data); + const chapterValues = chapter.data.formValues; + epoc.addChapter(chapter.data.contentId, { + title: chapterValues.title || '', + image: chapterValues.image || '', + objectives: chapterValues.objectives || [], + contents: [] + }); + let nextNode = getNextNode(chapter); + while (nextNode) { + console.log(nextNode.data); + const chapterValues = chapter.data.formValues; + epoc.addChapter(chapter.data.contentId, { + title: chapterValues.title || '', + image: chapterValues.image || '', + objectives: chapterValues.objectives || [], + contents: [] + }); + nextNode = getNextNode(nextNode); + } + }); + + + return epoc; } -function getNextEdge(node) { +function getNextNode(node) { const edge = getConnectedEdges([node], edges.value).filter((edge) => edge.source === node.id)[0]; - return edge ? { target: edge.target, source: edge.source } : null; + return edge ? getNodeById(edge.target) : null; } -function identifyTemplate(node) { - if(node.data.type !== 'template'){ - return null; - } else { - return node.data.elements[0].action.type; - } +function getNodeById(id) : GraphNode { + return nodes.value.find((node) => { return node.id === id; }); } export const projectService = { importFile, - saveProjectData, - createContentJSON, + writeProjectData }; \ No newline at end of file