From f210de0e13a933f3752ef532f1359d347d188eee Mon Sep 17 00:00:00 2001 From: Samuele de Tomasi Date: Sat, 17 Jul 2021 15:53:17 +0200 Subject: [PATCH] Added FileSystem.ts and fixed todo section --- electron/IPC/fileSystem.ts | 113 +++++++++++++ electron/configureDev.ts | 1 + electron/index.ts | 11 +- electron/mainWindow.ts | 14 +- electron/preload.ts | 5 +- package.json | 2 +- svelte/src/hooks.ts | 23 --- .../{ => lib}/components/InfoElectron.svelte | 0 .../src/{ => lib}/components/Version.svelte | 0 svelte/src/{ => lib}/components/tab.svelte | 0 svelte/src/lib/form.ts | 69 ++++---- svelte/src/routes/help/index.svelte | 2 +- svelte/src/routes/help/tab/renderer.svelte | 4 +- svelte/src/routes/todos/[uid].json.ts | 16 -- svelte/src/routes/todos/_api.ts | 48 ------ svelte/src/routes/todos/index.json.ts | 30 ---- svelte/src/routes/todos/index.svelte | 158 +++++++++--------- 17 files changed, 262 insertions(+), 234 deletions(-) create mode 100644 electron/IPC/fileSystem.ts delete mode 100644 svelte/src/hooks.ts rename svelte/src/{ => lib}/components/InfoElectron.svelte (100%) rename svelte/src/{ => lib}/components/Version.svelte (100%) rename svelte/src/{ => lib}/components/tab.svelte (100%) delete mode 100644 svelte/src/routes/todos/[uid].json.ts delete mode 100644 svelte/src/routes/todos/_api.ts delete mode 100644 svelte/src/routes/todos/index.json.ts diff --git a/electron/IPC/fileSystem.ts b/electron/IPC/fileSystem.ts new file mode 100644 index 0000000..d8b68c1 --- /dev/null +++ b/electron/IPC/fileSystem.ts @@ -0,0 +1,113 @@ +import { SendChannels } from "./General/channelsInterface"; +import IPC from "./General/IPC"; +import { app, BrowserWindow } from "electron"; +import { access, writeFile, mkdir, readFile } from 'fs/promises'; +import path from "path"; + + +const nameAPI = "fileSystem"; + +// to Main +const validSendChannel: SendChannels = { + "readFile": readFileTodos, + "saveFile": saveFile +}; + +// from Main +const validReceiveChannel: string[] = [ + "getFile" +]; + +const fileSystem = new IPC ({ + nameAPI, + validSendChannel, + validReceiveChannel +}); + +export default fileSystem; + +async function readFileTodos(mainWindow: BrowserWindow, event: Electron.IpcMainEvent, fileName: any) { + const fileExists = await checkFileTodosExists(fileName); + if (!fileExists) { + await createDir(); + const data = `[]`; + await writeTodos(fileName, data); + } + const todos = await loadTodos(fileName); + mainWindow.webContents.send("getFile", todos); +} + +async function saveFile(mainWindow: BrowserWindow, event: Electron.IpcMainEvent, data: { fileName: string, todo: string }) { + const { fileName, todo } = {...data}; + console.log(fileName); + console.log(todo); + + const fileExists = await checkFileTodosExists(fileName); + if (!fileExists) { + await createDir(); + } + await writeTodos(fileName, todo); +} + +async function checkFileTodosExists(fileName:string) { + const userData = app.getPath('userData'); + const pathFile = path.join(userData, 'todos' ,fileName); + try { + await access(pathFile); + return true; + } catch (error) { + console.log("DOES NOT exist:", pathFile); + console.error(error); + return false; + } +} + +async function writeTodos(fileName: string, data: string) { + const userData = app.getPath('userData'); + const pathFile = path.join(userData, 'todos' ,fileName); + try { + await writeFile(pathFile, data); + } catch (error) { + console.log("await writeFile(pathFile, data);", pathFile); + console.error(error); + } +} + +async function createDir() { + const userData = app.getPath('userData'); + const pathDir = path.join(userData, 'todos'); + let dirExists = false; + try { + await access(pathDir); + dirExists = true; + } catch (error) { + // The check failed + console.log("DOES NOT exist:", pathDir); + console.error(error); + dirExists = false; + } + + if (!dirExists) { + try { + await mkdir(pathDir); + } catch (error) { + console.log(" await mkdir(pathDir);", pathDir); + console.error(error); + } + } +} + + +async function loadTodos(fileName: string) { + const userData = app.getPath('userData'); + const pathDir = path.join(userData, 'todos', fileName); + let result = []; + try { + const rawData = await readFile(pathDir, 'utf-8'); + result = JSON.parse(rawData); + } catch (err) { + console.error(err); + } + + return result; +} \ No newline at end of file diff --git a/electron/configureDev.ts b/electron/configureDev.ts index f1eba83..348f9d1 100644 --- a/electron/configureDev.ts +++ b/electron/configureDev.ts @@ -43,6 +43,7 @@ class ConfigureDev { _build_Dist() { exec("npm run svelte:build"); } _watch_Dist() { require("electron-reload")(path.join(__dirname, "www")); } _serve_Dist() { + // this.loadURL = serve({ directory: pathOnDisk, scheme: "html" }); this.loadURL = serve({ directory: "dist/www" }); } diff --git a/electron/index.ts b/electron/index.ts index e6ef963..504b7bd 100644 --- a/electron/index.ts +++ b/electron/index.ts @@ -4,6 +4,7 @@ import Main from "./mainWindow"; import systemInfo from './IPC/systemInfo'; import updaterInfo from './IPC/updaterInfo'; +import fileSystem from './IPC/fileSystem'; const developerOptions = { isInProduction: true, // true if is in production @@ -12,6 +13,12 @@ const developerOptions = { watchSvelteBuild: false, // true when you want to watch build svelte }; +/* + testing svelte side: isInProduction: false, serveSvelteDev: true, buildSvelteDev:false, watchSvelteBuild: false + testing only electron side: isInProduction: true, serveSvelteDev: false, buildSvelteDev:false, watchSvelteBuild: false + testing both side: isInProduction: true, serveSvelteDev: false, buildSvelteDev:true, watchSvelteBuild: true +*/ + const windowSettings = { title: "MEMENTO - SvelteKit, Electron, TypeScript", width: 854, @@ -23,8 +30,8 @@ let main = new Main(windowSettings, developerOptions); main.onEvent.on("window-created", async () => { systemInfo.initIpcMain(ipcMain, main.window); updaterInfo.initIpcMain(ipcMain, main.window); - + fileSystem.initIpcMain(ipcMain, main.window); + updaterInfo.initAutoUpdater(autoUpdater, main.window); - }); diff --git a/electron/mainWindow.ts b/electron/mainWindow.ts index 1319b45..d4bb10f 100644 --- a/electron/mainWindow.ts +++ b/electron/mainWindow.ts @@ -66,9 +66,19 @@ class Main { }); if (this.configDev.isLocalHost()) { - await window.loadURL("http://localhost:3000/"); + try { + await window.loadURL("http://localhost:3000/"); + } catch (error) { + console.log(`ERROR: window.loadURL("http://localhost:3000/");`) + console.log(error) + } } else if (this.configDev.isElectronServe()) { - await this.configDev.loadURL(window); + try { + await this.configDev.loadURL(window); + } catch (error) { + console.log(`this.configDev.loadURL(window);`) + console.log(error) + } } window.show(); diff --git a/electron/preload.ts b/electron/preload.ts index 07c5214..c6ad3bd 100644 --- a/electron/preload.ts +++ b/electron/preload.ts @@ -1,6 +1,7 @@ import { generateContextBridge } from "./IPC/General/contextBridge" -import systemInfo from "./IPC/systemInfo"; +import systemInfo from './IPC/systemInfo'; import updaterInfo from './IPC/updaterInfo'; +import fileSystem from './IPC/fileSystem'; -generateContextBridge([systemInfo, updaterInfo]); +generateContextBridge([systemInfo, updaterInfo, fileSystem]); diff --git a/package.json b/package.json index d93cb79..cbcb1c2 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "Memento: how to use Svelte with Electron and TypeScript", "author": "Samuele de Tomasi ", "license": "MIT", - "version": "0.0.2", + "version": "0.0.3", "main": "dist/index.js", "scripts": { "nodemon": "nodemon", diff --git a/svelte/src/hooks.ts b/svelte/src/hooks.ts deleted file mode 100644 index df8b96c..0000000 --- a/svelte/src/hooks.ts +++ /dev/null @@ -1,23 +0,0 @@ -import cookie from 'cookie'; -import { v4 as uuid } from '@lukeed/uuid'; -import type { Handle } from '@sveltejs/kit'; - -export const handle: Handle = async ({ request, resolve }) => { - const cookies = cookie.parse(request.headers.cookie || ''); - request.locals.userid = cookies.userid || uuid(); - - // TODO https://github.com/sveltejs/kit/issues/1046 - if (request.query.has('_method')) { - request.method = request.query.get('_method').toUpperCase(); - } - - const response = await resolve(request); - - if (!cookies.userid) { - // if this is the first time the user has visited this app, - // set a cookie so that we recognise them when they return - response.headers['set-cookie'] = `userid=${request.locals.userid}; Path=/; HttpOnly`; - } - - return response; -}; diff --git a/svelte/src/components/InfoElectron.svelte b/svelte/src/lib/components/InfoElectron.svelte similarity index 100% rename from svelte/src/components/InfoElectron.svelte rename to svelte/src/lib/components/InfoElectron.svelte diff --git a/svelte/src/components/Version.svelte b/svelte/src/lib/components/Version.svelte similarity index 100% rename from svelte/src/components/Version.svelte rename to svelte/src/lib/components/Version.svelte diff --git a/svelte/src/components/tab.svelte b/svelte/src/lib/components/tab.svelte similarity index 100% rename from svelte/src/components/tab.svelte rename to svelte/src/lib/components/tab.svelte diff --git a/svelte/src/lib/form.ts b/svelte/src/lib/form.ts index c52e923..a99f449 100644 --- a/svelte/src/lib/form.ts +++ b/svelte/src/lib/form.ts @@ -12,42 +12,51 @@ export function enhance( result: (res: Response, form: HTMLFormElement) => void; } ) { - let current_token: {}; async function handle_submit(e: Event) { - const token = (current_token = {}); - e.preventDefault(); - + console.log("HANDLE_SUBMIT"); + console.log(e); + const formData = new FormData(form); + console.log(formData); + console.log(form); const body = new FormData(form); - if (pending) pending(body, form); + console.log(body); + console.log(form.action); + // const token = (current_token = {}); - try { - const res = await fetch(form.action, { - method: form.method, - headers: { - accept: 'application/json' - }, - body - }); - - if (token !== current_token) return; - - if (res.ok) { - result(res, form); - } else if (error) { - error(res, null, form); - } else { - console.error(await res.text()); - } - } catch (e) { - if (error) { - error(null, e, form); - } else { - throw e; - } - } + // e.preventDefault(); + + // const body = new FormData(form); + + // if (pending) pending(body, form); + + // try { + // const res = await fetch(form.action, { + // method: form.method, + // headers: { + // accept: 'application/json' + // }, + // body + // }); + + // if (token !== current_token) return; + + // if (res.ok) { + // result(res, form); + // } else if (error) { + // error(res, null, form); + // } else { + // console.error(await res.text()); + // } + // } catch (e) { + // if (error) { + // error(null, e, form); + // } else { + // throw e; + // } + // } } form.addEventListener('submit', handle_submit); diff --git a/svelte/src/routes/help/index.svelte b/svelte/src/routes/help/index.svelte index d1534f5..97b068c 100644 --- a/svelte/src/routes/help/index.svelte +++ b/svelte/src/routes/help/index.svelte @@ -1,6 +1,6 @@
diff --git a/svelte/src/routes/todos/[uid].json.ts b/svelte/src/routes/todos/[uid].json.ts deleted file mode 100644 index 17891fa..0000000 --- a/svelte/src/routes/todos/[uid].json.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { api } from './_api'; -import type { RequestHandler } from '@sveltejs/kit'; -import type { Locals } from '$lib/types'; - -// PATCH /todos/:uid.json -export const patch: RequestHandler = async (request) => { - return api(request, `todos/${request.locals.userid}/${request.params.uid}`, { - text: request.body.get('text'), - done: request.body.has('done') ? !!request.body.get('done') : undefined - }); -}; - -// DELETE /todos/:uid.json -export const del: RequestHandler = async (request) => { - return api(request, `todos/${request.locals.userid}/${request.params.uid}`); -}; diff --git a/svelte/src/routes/todos/_api.ts b/svelte/src/routes/todos/_api.ts deleted file mode 100644 index 2319c18..0000000 --- a/svelte/src/routes/todos/_api.ts +++ /dev/null @@ -1,48 +0,0 @@ -import type { Request } from '@sveltejs/kit'; -import type { Locals } from '$lib/types'; - -/* - This module is used by the /todos.json and /todos/[uid].json - endpoints to make calls to api.svelte.dev, which stores todos - for each user. The leading underscore indicates that this is - a private module, _not_ an endpoint — visiting /todos/_api - will net you a 404 response. - - (The data on the todo app will expire periodically; no - guarantees are made. Don't use it to organise your life.) -*/ - -const base = 'https://api.svelte.dev'; - -export async function api(request: Request, resource: string, data?: {}) { - // user must have a cookie set - if (!request.locals.userid) { - return { status: 401 }; - } - - const res = await fetch(`${base}/${resource}`, { - method: request.method, - headers: { - 'content-type': 'application/json' - }, - body: data && JSON.stringify(data) - }); - - // if the request came from a
submission, the browser's default - // behaviour is to show the URL corresponding to the form's "action" - // attribute. in those cases, we want to redirect them back to the - // /todos page, rather than showing the response - if (res.ok && request.method !== 'GET' && request.headers.accept !== 'application/json') { - return { - status: 303, - headers: { - location: '/todos' - } - }; - } - - return { - status: res.status, - body: await res.json() - }; -} diff --git a/svelte/src/routes/todos/index.json.ts b/svelte/src/routes/todos/index.json.ts deleted file mode 100644 index 57d68a9..0000000 --- a/svelte/src/routes/todos/index.json.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { api } from './_api'; -import type { RequestHandler } from '@sveltejs/kit'; -import type { Locals } from '$lib/types'; - -// GET /todos.json -export const get: RequestHandler = async (request) => { - // request.locals.userid comes from src/hooks.js - const response = await api(request, `todos/${request.locals.userid}`); - - if (response.status === 404) { - // user hasn't created a todo list. - // start with an empty array - return { body: [] }; - } - - return response; -}; - -// POST /todos.json -export const post: RequestHandler = async (request) => { - const response = await api(request, `todos/${request.locals.userid}`, { - // because index.svelte posts a FormData object, - // request.body is _also_ a (readonly) FormData - // object, which allows us to get form data - // with the `body.get(key)` method - text: request.body.get('text') - }); - - return response; -}; diff --git a/svelte/src/routes/todos/index.svelte b/svelte/src/routes/todos/index.svelte index 02e575c..f7e47b2 100644 --- a/svelte/src/routes/todos/index.svelte +++ b/svelte/src/routes/todos/index.svelte @@ -1,27 +1,23 @@ - --> @@ -53,20 +96,8 @@

Todos

- { - const created = await res.json(); - todos = [...todos, created]; - - form.reset(); - } - }} - > - + + {#each todos as todo (todo.uid)} @@ -76,41 +107,22 @@ transition:scale|local={{ start: 0.7 }} animate:flip={{ duration: 200 }} > -
{ - todo.done = !!data.get('done'); - }, - result: patch - }} - > + toggleDone(todo.uid)}>
@@ -213,15 +225,7 @@ opacity: 1; } - .save { - position: absolute; - right: 0; - opacity: 0; - background-image: url("data:image/svg+xml,%3Csvg width='24' height='24' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M20.5 2H3.5C2.67158 2 2 2.67157 2 3.5V20.5C2 21.3284 2.67158 22 3.5 22H20.5C21.3284 22 22 21.3284 22 20.5V3.5C22 2.67157 21.3284 2 20.5 2Z' fill='%23676778' stroke='%23676778' stroke-width='1.5' stroke-linejoin='round'/%3E%3Cpath d='M17 2V11H7.5V2H17Z' fill='white' stroke='white' stroke-width='1.5' stroke-linejoin='round'/%3E%3Cpath d='M13.5 5.5V7.5' stroke='%23676778' stroke-width='1.5' stroke-linecap='round'/%3E%3Cpath d='M5.99844 2H18.4992' stroke='%23676778' stroke-width='1.5' stroke-linecap='round'/%3E%3C/svg%3E%0A"); - } - - .todo input:focus + .save, - .save:focus { + .todo input:focus { transition: opacity 0.2s; opacity: 1; }