From c1315b3512078e513865293e3af267b8f9f2d561 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Tue, 13 Oct 2026 12:34:51 -0500 Subject: [PATCH 01/32] Update Download endpoint to export four shapes of Markdown files Restructures PDF download into an Export menu containing the PDF export and 4 Markdown Options Slightly tweaks tests Effectively moves the api.mergeBrewText to helpers. I think this makes more sense. Changes the download extension from txt to 'md`. The Commonmark, TOML, and JSON exports are the same with the frontmatter in a slightly different shape. These were selected based on lightweight research into Markdown Frontmatter. If specific formats - such as Obsidian - are different enough in terms of formatting the frontmatter or desired metadata content, this is fairly easy --- client/homebrew/navbar/print.navitem.jsx | 29 ++++++++++++- .../pages/basePages/editPage/editorPage.jsx | 2 +- client/homebrew/pages/sharePage/sharePage.jsx | 2 +- server/homebrew.api.js | 26 +----------- server/homebrew.api.spec.js | 10 ++--- server/page-routes.js | 16 ++++++-- shared/helpers.js | 41 ++++++++++++++++++- 7 files changed, 89 insertions(+), 37 deletions(-) diff --git a/client/homebrew/navbar/print.navitem.jsx b/client/homebrew/navbar/print.navitem.jsx index ff2d75d67..b500c24d6 100644 --- a/client/homebrew/navbar/print.navitem.jsx +++ b/client/homebrew/navbar/print.navitem.jsx @@ -2,7 +2,12 @@ import React, { useState, useEffect } from 'react'; import Nav from './nav.jsx'; import { printCurrentBrew } from '@shared/helpers.js'; -export default function(){ +const processShareId = (brew)=>{ + + return brew.googleId && !brew.stubbed ? brew.googleId + brew.shareId : brew.shareId; +}; + +export default ({ currentBrew })=>{ const [printing, setPrinting] = useState(false); // listen for print cycle events to display "loading" message since it can take some time. @@ -19,7 +24,27 @@ export default function(){ const handlePrintPrepFinished = ()=>{ setPrinting(false); }; - return + if(currentBrew?.shareId) return + + export + + + {printing ? 'loading' : 'get PDF'} + + + Markdown + + + Markdown (TOML) + + + Markdown (JSON) + + + Markdown (Homebrewery) + + ; + else return {printing ? 'loading' : 'get PDF'} ; }; diff --git a/client/homebrew/pages/basePages/editPage/editorPage.jsx b/client/homebrew/pages/basePages/editPage/editorPage.jsx index b9fb34597..718aab442 100644 --- a/client/homebrew/pages/basePages/editPage/editorPage.jsx +++ b/client/homebrew/pages/basePages/editPage/editorPage.jsx @@ -372,7 +372,7 @@ const EditorPage = (props)=>{ {(pageName == 'editPage') && renderAutoSaveButton()} } - + {(pageName == 'editPage') && } diff --git a/client/homebrew/pages/sharePage/sharePage.jsx b/client/homebrew/pages/sharePage/sharePage.jsx index 002844c2c..42a9c4241 100644 --- a/client/homebrew/pages/sharePage/sharePage.jsx +++ b/client/homebrew/pages/sharePage/sharePage.jsx @@ -117,7 +117,7 @@ const SharePage = (props)=>{ view {renderEditLink()} - + download diff --git a/server/homebrew.api.js b/server/homebrew.api.js index aa1f1f84a..8702ec42b 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -10,7 +10,7 @@ import asyncHandler from 'express-async-handler'; import { nanoid } from 'nanoid'; import { makePatches, applyPatches, stringifyPatches, parsePatch } from '@sanity/diff-match-patch'; import { md5 } from 'hash-wasm'; -import { splitTextStyleAndMetadata, +import { splitTextStyleAndMetadata, transformFrontmatter, brewSnippetsToJSON, debugTextMismatch } from '../shared/helpers.js'; import checkClientVersion from './middleware/check-client-version.js'; import dbCheck from './middleware/dbCheck.js'; @@ -209,29 +209,7 @@ const api = { return res.status(200).send(brew.style); }, mergeBrewText : (brew)=>{ - let text = brew.text; - if(brew.style !== undefined) { - text = `\`\`\`css\n` + - `${brew.style || ''}\n` + - `\`\`\`\n\n` + - `${text}`; - } - const metadata = _.pick(brew, ['title', 'description', 'tags', 'renderer', 'theme']); - const snippetsArray = brewSnippetsToJSON('brew_snippets', brew.snippets, null, false).snippets; - metadata.snippets = snippetsArray.length > 0 ? snippetsArray : undefined; - metadata.bleedSize = { top: brew?.bleedSize?.top, bottom: brew?.bleedSize?.bottom, inner: brew?.bleedSize?.inner, outer: brew?.bleedSize?.outer }; - metadata.safetySpace = { top: brew?.safetySpace?.top, bottom: brew?.safetySpace?.bottom, outer: brew?.safetySpace?.outer, inner: brew?.safetySpace?.inner }; - metadata.trimSize = { width: brew?.trimSize?.width, height: brew?.trimSize?.height }; - metadata.columns = brew?.columns; - metadata.columnGutter = brew?.columnGutter; - metadata.license = brew?.license; - metadata.legalAuthors = brew?.legalAuthors; - - text = `\`\`\`metadata\n` + - `${yaml.dump(metadata)}\n` + - `\`\`\`\n\n` + - `${text}`; - return text; + return transformFrontmatter(brew); }, getGoodBrewTitle : (text)=>{ const tokens = hbfm.marked.lexer(text); diff --git a/server/homebrew.api.spec.js b/server/homebrew.api.spec.js index 8bda5407b..b4337e6fc 100644 --- a/server/homebrew.api.spec.js +++ b/server/homebrew.api.spec.js @@ -499,8 +499,6 @@ description: this is a description tags: - something - fun -renderer: v3 -theme: phb bleedSize: top: .125in bottom: .125in @@ -518,6 +516,8 @@ columns: '2' columnGutter: .125in license: None legalAuthors: '' +renderer: v3 +theme: phb \`\`\` @@ -554,7 +554,7 @@ brew`); width : '8.5in', height : '11in', }, - }); + }, 'hb'); expect(result).toEqual(`\`\`\`metadata title: some title @@ -562,8 +562,6 @@ description: this is a description tags: - something - fun -renderer: v3 -theme: phb bleedSize: top: .125in bottom: .125in @@ -581,6 +579,8 @@ columns: '2' columnGutter: .125in license: None legalAuthors: '' +renderer: v3 +theme: phb \`\`\` diff --git a/server/page-routes.js b/server/page-routes.js index 85436d2bc..49879391e 100644 --- a/server/page-routes.js +++ b/server/page-routes.js @@ -15,7 +15,7 @@ import fs from 'fs'; import dbCheck from './middleware/dbCheck.js'; import sanitizeFilename from 'sanitize-filename'; import { DEFAULT_BREW } from './brewDefaults.js'; -import { splitTextStyleAndMetadata } from '../shared/helpers.js'; +import { splitTextStyleAndMetadata, transformFrontmatter } from '../shared/helpers.js'; import GoogleActions from './googleActions.js'; import api from './homebrew.api.js'; @@ -135,9 +135,19 @@ export default function pageRoutes({ }); //Download brew source page - app.get('/download/:id', asyncHandler(getBrew('share')), (req, res)=>{ + app.get('/download/:format/:id', asyncHandler(getBrew('share')), async (req, res)=>{ + const markdownFormats = { + hb : 'homebrewery', + cm : 'commonmark', + toml : 'toml', + json : 'json' + }; + const { brew } = req; + + const lastBrew = brew.text; sanitizeBrew(brew, 'share'); + brew.text = await transformFrontmatter(brew, req.params.format); const prefix = 'HB - '; const encodeRFC3986ValueChars = (str)=>{ @@ -152,7 +162,7 @@ export default function pageRoutes({ res.set({ 'Cache-Control' : 'no-cache', 'Content-Type' : 'text/plain', - 'Content-Disposition' : `attachment; filename*=UTF-8''${encodeRFC3986ValueChars(fileName)}.txt` + 'Content-Disposition' : `attachment; filename*=UTF-8''${encodeRFC3986ValueChars(fileName)}.${markdownFormats[req.params.format]}.md` }); res.status(200).send(brew.text); }); diff --git a/shared/helpers.js b/shared/helpers.js index d20687843..6d8180ae1 100644 --- a/shared/helpers.js +++ b/shared/helpers.js @@ -114,6 +114,44 @@ const splitTextStyleAndMetadata = (brew)=>{ if(typeof brew.tags === 'string') brew.tags = brew.tags ? [brew.tags] : []; }; +const transformFrontmatter = (brew, format = 'hb')=>{ + const markdownFormats = { + hb : '```metadata', + cm : '---', + toml : '+++', + json : ';;;' + }; + + let text = brew.text; + if((brew.style !== undefined) && (format == 'hb')) { + text = `\`\`\`css\n` + + `${brew.style || ''}\n` + + `\`\`\`\n\n` + + `${text}`; + } + const metadata = _.pick(brew, ['title', 'description', 'tags']); + if(format == 'hb') { + const snippetsArray = brewSnippetsToJSON('brew_snippets', brew.snippets, null, false).snippets; + metadata.snippets = snippetsArray.length > 0 ? snippetsArray : undefined; + metadata.bleedSize = { top: brew?.bleedSize?.top, bottom: brew?.bleedSize?.bottom, inner: brew?.bleedSize?.inner, outer: brew?.bleedSize?.outer }; + metadata.safetySpace = { top: brew?.safetySpace?.top, bottom: brew?.safetySpace?.bottom, outer: brew?.safetySpace?.outer, inner: brew?.safetySpace?.inner }; + metadata.trimSize = { width: brew?.trimSize?.width, height: brew?.trimSize?.height }; + metadata.columns = brew?.columns; + metadata.columnGutter = brew?.columnGutter; + metadata.license = brew?.license; + metadata.legalAuthors = brew?.legalAuthors; + metadata.renderer = brew.renderer; + metadata.theme = brew.theme; + } + + text = `${markdownFormats[format]}\n` + + `${format != 'json' ? yaml.dump(metadata) : JSON.stringify(metadata)}\n` + + `${markdownFormats[format].slice(0, 3)}\n\n` + + `${text}`; + + return text; +}; + const printCurrentBrew = async ()=>{ if(window.typeof !== 'undefined') { // fire a custom event for the print cycle @@ -230,5 +268,6 @@ export { fetchThemeBundle, brewSnippetsToJSON, debugTextMismatch, - yamlSnippetsToText + yamlSnippetsToText, + transformFrontmatter }; From 8e40f809c1ef2e2caa6dcd87b2dd12f7299dfa45 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Tue, 13 Oct 2026 12:39:16 -0500 Subject: [PATCH 02/32] Rebuild #4994 without added Brotli files for tests --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 6f1269f97..0f76d8fe7 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "test:api-unit:css": "jest \"server/.*.spec.js\" -t \"Get CSS\" --verbose", "test:api-unit:notifications": "jest \"server/.*.spec.js\" -t \"Notifications\" --verbose", "test:content-negotiation": "jest \"server/middleware/.*.spec.js\" --verbose", + "test:static-content": "jest \"tests/routes/static-content.test.js\" --verbose", "test:coverage": "jest --coverage --silent --runInBand", "test:dev": "jest --verbose --watch", "test:basic": "jest tests/markdown/basic.test.js --verbose", From 34b5b559a7fdc09e7132a3f9f21f94cf397ef79d Mon Sep 17 00:00:00 2001 From: David Bolack Date: Tue, 13 Oct 2026 12:42:10 -0500 Subject: [PATCH 03/32] Add updated test files Staged brotli tests left in place in case full evaluation desired. --- tests/routes/static-content.test.js | 39 +++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 tests/routes/static-content.test.js diff --git a/tests/routes/static-content.test.js b/tests/routes/static-content.test.js new file mode 100644 index 000000000..13e6ed44e --- /dev/null +++ b/tests/routes/static-content.test.js @@ -0,0 +1,39 @@ +import supertest from 'supertest'; +import createApp from '../../server/app.js'; + +let app; +let request; + +beforeAll(async ()=>{ + app = await createApp(); + request = supertest.agent(app).set('X-Forwarded-Proto', 'https'); +}); + +// Commenting out brotli serving tests until such time as a decision is made about verifying. + +describe('Tests for static assets and cache settings', ()=>{ + // it('Test Brotli compressed CSS file', async ()=>{ + // const results = await request.get('/fonts/fonts/fonts.css.br'); + // expect(results.header['content-type']).toBe('application/octet-stream'); + // expect(results.header['cache-control']).toBe('public, max-age: 43200, must-revalidate'); + // }); + + // it('Test Brotli encrypted font file', async ()=>{ + // const results = await request.get('/fonts/fonts/open-sans-latin-400-normal.woff2.br'); + // expect(results.header['content-type']).toBe('application/octet-stream'); + // expect(results.header['cache-control']).toBe('public, max-age=2592000, must-revalidate'); + // }); + + it('Test regular CSS file', async ()=>{ + const results = await request.get('/fonts/fonts/fonts.css'); + expect(results.header['content-type']).toBe('text/css; charset=utf-8'); + expect(results.header['cache-control']).toBe('public, max-age: 43200, must-revalidate'); + }); + + it('Test regular font file', async ()=>{ + const results = await request.get('/fonts/fonts/open-sans-latin-400-normal.woff2'); + expect(results.header['content-type']).toBe('font/woff2'); + expect(results.header['cache-control']).toBe('public, max-age=2592000, must-revalidate'); + }); + +}); \ No newline at end of file From 991655a05fe3159cb9bc84ecd4b604244cce9642 Mon Sep 17 00:00:00 2001 From: David Bolack Date: Tue, 13 Oct 2026 13:10:35 -0500 Subject: [PATCH 04/32] Remove files changed from incorrect base --- client/homebrew/navbar/print.navitem.jsx | 29 +------------ .../pages/basePages/editPage/editorPage.jsx | 2 +- client/homebrew/pages/sharePage/sharePage.jsx | 2 +- package.json | 1 - server/homebrew.api.js | 26 +++++++++++- server/homebrew.api.spec.js | 10 ++--- server/page-routes.js | 16 ++------ shared/helpers.js | 41 +------------------ 8 files changed, 37 insertions(+), 90 deletions(-) diff --git a/client/homebrew/navbar/print.navitem.jsx b/client/homebrew/navbar/print.navitem.jsx index b500c24d6..ff2d75d67 100644 --- a/client/homebrew/navbar/print.navitem.jsx +++ b/client/homebrew/navbar/print.navitem.jsx @@ -2,12 +2,7 @@ import React, { useState, useEffect } from 'react'; import Nav from './nav.jsx'; import { printCurrentBrew } from '@shared/helpers.js'; -const processShareId = (brew)=>{ - - return brew.googleId && !brew.stubbed ? brew.googleId + brew.shareId : brew.shareId; -}; - -export default ({ currentBrew })=>{ +export default function(){ const [printing, setPrinting] = useState(false); // listen for print cycle events to display "loading" message since it can take some time. @@ -24,27 +19,7 @@ export default ({ currentBrew })=>{ const handlePrintPrepFinished = ()=>{ setPrinting(false); }; - if(currentBrew?.shareId) return - - export - - - {printing ? 'loading' : 'get PDF'} - - - Markdown - - - Markdown (TOML) - - - Markdown (JSON) - - - Markdown (Homebrewery) - - ; - else return + return {printing ? 'loading' : 'get PDF'} ; }; diff --git a/client/homebrew/pages/basePages/editPage/editorPage.jsx b/client/homebrew/pages/basePages/editPage/editorPage.jsx index 718aab442..b9fb34597 100644 --- a/client/homebrew/pages/basePages/editPage/editorPage.jsx +++ b/client/homebrew/pages/basePages/editPage/editorPage.jsx @@ -372,7 +372,7 @@ const EditorPage = (props)=>{ {(pageName == 'editPage') && renderAutoSaveButton()} } - + {(pageName == 'editPage') && } diff --git a/client/homebrew/pages/sharePage/sharePage.jsx b/client/homebrew/pages/sharePage/sharePage.jsx index 42a9c4241..002844c2c 100644 --- a/client/homebrew/pages/sharePage/sharePage.jsx +++ b/client/homebrew/pages/sharePage/sharePage.jsx @@ -117,7 +117,7 @@ const SharePage = (props)=>{ view {renderEditLink()} - + download diff --git a/package.json b/package.json index 0f76d8fe7..6f1269f97 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,6 @@ "test:api-unit:css": "jest \"server/.*.spec.js\" -t \"Get CSS\" --verbose", "test:api-unit:notifications": "jest \"server/.*.spec.js\" -t \"Notifications\" --verbose", "test:content-negotiation": "jest \"server/middleware/.*.spec.js\" --verbose", - "test:static-content": "jest \"tests/routes/static-content.test.js\" --verbose", "test:coverage": "jest --coverage --silent --runInBand", "test:dev": "jest --verbose --watch", "test:basic": "jest tests/markdown/basic.test.js --verbose", diff --git a/server/homebrew.api.js b/server/homebrew.api.js index 8702ec42b..aa1f1f84a 100644 --- a/server/homebrew.api.js +++ b/server/homebrew.api.js @@ -10,7 +10,7 @@ import asyncHandler from 'express-async-handler'; import { nanoid } from 'nanoid'; import { makePatches, applyPatches, stringifyPatches, parsePatch } from '@sanity/diff-match-patch'; import { md5 } from 'hash-wasm'; -import { splitTextStyleAndMetadata, transformFrontmatter, +import { splitTextStyleAndMetadata, brewSnippetsToJSON, debugTextMismatch } from '../shared/helpers.js'; import checkClientVersion from './middleware/check-client-version.js'; import dbCheck from './middleware/dbCheck.js'; @@ -209,7 +209,29 @@ const api = { return res.status(200).send(brew.style); }, mergeBrewText : (brew)=>{ - return transformFrontmatter(brew); + let text = brew.text; + if(brew.style !== undefined) { + text = `\`\`\`css\n` + + `${brew.style || ''}\n` + + `\`\`\`\n\n` + + `${text}`; + } + const metadata = _.pick(brew, ['title', 'description', 'tags', 'renderer', 'theme']); + const snippetsArray = brewSnippetsToJSON('brew_snippets', brew.snippets, null, false).snippets; + metadata.snippets = snippetsArray.length > 0 ? snippetsArray : undefined; + metadata.bleedSize = { top: brew?.bleedSize?.top, bottom: brew?.bleedSize?.bottom, inner: brew?.bleedSize?.inner, outer: brew?.bleedSize?.outer }; + metadata.safetySpace = { top: brew?.safetySpace?.top, bottom: brew?.safetySpace?.bottom, outer: brew?.safetySpace?.outer, inner: brew?.safetySpace?.inner }; + metadata.trimSize = { width: brew?.trimSize?.width, height: brew?.trimSize?.height }; + metadata.columns = brew?.columns; + metadata.columnGutter = brew?.columnGutter; + metadata.license = brew?.license; + metadata.legalAuthors = brew?.legalAuthors; + + text = `\`\`\`metadata\n` + + `${yaml.dump(metadata)}\n` + + `\`\`\`\n\n` + + `${text}`; + return text; }, getGoodBrewTitle : (text)=>{ const tokens = hbfm.marked.lexer(text); diff --git a/server/homebrew.api.spec.js b/server/homebrew.api.spec.js index b4337e6fc..8bda5407b 100644 --- a/server/homebrew.api.spec.js +++ b/server/homebrew.api.spec.js @@ -499,6 +499,8 @@ description: this is a description tags: - something - fun +renderer: v3 +theme: phb bleedSize: top: .125in bottom: .125in @@ -516,8 +518,6 @@ columns: '2' columnGutter: .125in license: None legalAuthors: '' -renderer: v3 -theme: phb \`\`\` @@ -554,7 +554,7 @@ brew`); width : '8.5in', height : '11in', }, - }, 'hb'); + }); expect(result).toEqual(`\`\`\`metadata title: some title @@ -562,6 +562,8 @@ description: this is a description tags: - something - fun +renderer: v3 +theme: phb bleedSize: top: .125in bottom: .125in @@ -579,8 +581,6 @@ columns: '2' columnGutter: .125in license: None legalAuthors: '' -renderer: v3 -theme: phb \`\`\` diff --git a/server/page-routes.js b/server/page-routes.js index 49879391e..85436d2bc 100644 --- a/server/page-routes.js +++ b/server/page-routes.js @@ -15,7 +15,7 @@ import fs from 'fs'; import dbCheck from './middleware/dbCheck.js'; import sanitizeFilename from 'sanitize-filename'; import { DEFAULT_BREW } from './brewDefaults.js'; -import { splitTextStyleAndMetadata, transformFrontmatter } from '../shared/helpers.js'; +import { splitTextStyleAndMetadata } from '../shared/helpers.js'; import GoogleActions from './googleActions.js'; import api from './homebrew.api.js'; @@ -135,19 +135,9 @@ export default function pageRoutes({ }); //Download brew source page - app.get('/download/:format/:id', asyncHandler(getBrew('share')), async (req, res)=>{ - const markdownFormats = { - hb : 'homebrewery', - cm : 'commonmark', - toml : 'toml', - json : 'json' - }; - + app.get('/download/:id', asyncHandler(getBrew('share')), (req, res)=>{ const { brew } = req; - - const lastBrew = brew.text; sanitizeBrew(brew, 'share'); - brew.text = await transformFrontmatter(brew, req.params.format); const prefix = 'HB - '; const encodeRFC3986ValueChars = (str)=>{ @@ -162,7 +152,7 @@ export default function pageRoutes({ res.set({ 'Cache-Control' : 'no-cache', 'Content-Type' : 'text/plain', - 'Content-Disposition' : `attachment; filename*=UTF-8''${encodeRFC3986ValueChars(fileName)}.${markdownFormats[req.params.format]}.md` + 'Content-Disposition' : `attachment; filename*=UTF-8''${encodeRFC3986ValueChars(fileName)}.txt` }); res.status(200).send(brew.text); }); diff --git a/shared/helpers.js b/shared/helpers.js index 6d8180ae1..d20687843 100644 --- a/shared/helpers.js +++ b/shared/helpers.js @@ -114,44 +114,6 @@ const splitTextStyleAndMetadata = (brew)=>{ if(typeof brew.tags === 'string') brew.tags = brew.tags ? [brew.tags] : []; }; -const transformFrontmatter = (brew, format = 'hb')=>{ - const markdownFormats = { - hb : '```metadata', - cm : '---', - toml : '+++', - json : ';;;' - }; - - let text = brew.text; - if((brew.style !== undefined) && (format == 'hb')) { - text = `\`\`\`css\n` + - `${brew.style || ''}\n` + - `\`\`\`\n\n` + - `${text}`; - } - const metadata = _.pick(brew, ['title', 'description', 'tags']); - if(format == 'hb') { - const snippetsArray = brewSnippetsToJSON('brew_snippets', brew.snippets, null, false).snippets; - metadata.snippets = snippetsArray.length > 0 ? snippetsArray : undefined; - metadata.bleedSize = { top: brew?.bleedSize?.top, bottom: brew?.bleedSize?.bottom, inner: brew?.bleedSize?.inner, outer: brew?.bleedSize?.outer }; - metadata.safetySpace = { top: brew?.safetySpace?.top, bottom: brew?.safetySpace?.bottom, outer: brew?.safetySpace?.outer, inner: brew?.safetySpace?.inner }; - metadata.trimSize = { width: brew?.trimSize?.width, height: brew?.trimSize?.height }; - metadata.columns = brew?.columns; - metadata.columnGutter = brew?.columnGutter; - metadata.license = brew?.license; - metadata.legalAuthors = brew?.legalAuthors; - metadata.renderer = brew.renderer; - metadata.theme = brew.theme; - } - - text = `${markdownFormats[format]}\n` + - `${format != 'json' ? yaml.dump(metadata) : JSON.stringify(metadata)}\n` + - `${markdownFormats[format].slice(0, 3)}\n\n` + - `${text}`; - - return text; -}; - const printCurrentBrew = async ()=>{ if(window.typeof !== 'undefined') { // fire a custom event for the print cycle @@ -268,6 +230,5 @@ export { fetchThemeBundle, brewSnippetsToJSON, debugTextMismatch, - yamlSnippetsToText, - transformFrontmatter + yamlSnippetsToText }; From c32ca98e093e47d1e65d3116c1e9519bd39c10d0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 Oct 2026 03:26:11 +0000 Subject: [PATCH 05/32] Bump the prod-dependencies group across 1 directory with 7 updates Bumps the prod-dependencies group with 7 updates in the / directory: | Package | From | To | | --- | --- | --- | | [express](https://github.com/expressjs/express) | `5.2.1` | `5.3.0` | | [js-yaml](https://github.com/nodeca/js-yaml) | `5.4.3` | `5.5.0` | | [mongoose](https://github.com/Automattic/mongoose) | `9.11.1` | `9.11.2` | | [node](https://github.com/aredridel/node-bin-gen) | `26.11.1` | `26.12.0` | | [prettier](https://github.com/prettier/prettier) | `3.9.9` | `3.9.10` | | [react](https://github.com/react/react/tree/HEAD/packages/react) | `19.3.0` | `19.3.1` | | [react-dom](https://github.com/react/react/tree/HEAD/packages/react-dom) | `19.3.0` | `19.3.1` | Updates `express` from 5.2.1 to 5.3.0 - [Release notes](https://github.com/expressjs/express/releases) - [Changelog](https://github.com/expressjs/express/blob/master/History.md) - [Commits](https://github.com/expressjs/express/compare/v5.2.1...v5.3.0) Updates `js-yaml` from 5.4.3 to 5.5.0 - [Changelog](https://github.com/nodeca/js-yaml/blob/master/CHANGELOG.md) - [Commits](https://github.com/nodeca/js-yaml/compare/5.4.3...5.5.0) Updates `mongoose` from 9.11.1 to 9.11.2 - [Release notes](https://github.com/Automattic/mongoose/releases) - [Changelog](https://github.com/Automattic/mongoose/blob/master/CHANGELOG.md) - [Commits](https://github.com/Automattic/mongoose/compare/9.11.1...9.11.2) Updates `node` from 26.11.1 to 26.12.0 - [Commits](https://github.com/aredridel/node-bin-gen/commits) Updates `prettier` from 3.9.9 to 3.9.10 - [Release notes](https://github.com/prettier/prettier/releases) - [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md) - [Commits](https://github.com/prettier/prettier/compare/3.9.9...3.9.10) Updates `react` from 19.3.0 to 19.3.1 - [Release notes](https://github.com/react/react/releases) - [Changelog](https://github.com/react/react/blob/main/CHANGELOG.md) - [Commits](https://github.com/react/react/commits/v19.3.1/packages/react) Updates `react-dom` from 19.3.0 to 19.3.1 - [Release notes](https://github.com/react/react/releases) - [Changelog](https://github.com/react/react/blob/main/CHANGELOG.md) - [Commits](https://github.com/react/react/commits/v19.3.1/packages/react-dom) --- updated-dependencies: - dependency-name: express dependency-version: 5.3.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: prod-dependencies - dependency-name: js-yaml dependency-version: 5.5.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: prod-dependencies - dependency-name: mongoose dependency-version: 9.11.2 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: prod-dependencies - dependency-name: node dependency-version: 26.12.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: prod-dependencies - dependency-name: prettier dependency-version: 3.9.10 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: prod-dependencies - dependency-name: react dependency-version: 19.3.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: prod-dependencies - dependency-name: react-dom dependency-version: 19.3.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: prod-dependencies ... Signed-off-by: dependabot[bot] --- package-lock.json | 111 ++++++++++++++++++++++++---------------------- package.json | 14 +++--- 2 files changed, 66 insertions(+), 59 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0e4277d3a..dd2c214fb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -38,27 +38,27 @@ "cors": "^2.8.5", "create-react-class": "^15.7.0", "dedent": "^1.7.2", - "express": "^5.1.0", + "express": "^5.3.0", "express-async-handler": "^1.2.0", "express-static-gzip": "3.0.2", "fflate": "^0.8.3", "fs-extra": "^11.4.1", "hash-wasm": "^4.12.0", "idb-keyval": "^6.2.5", - "js-yaml": "^5.4.3", + "js-yaml": "^5.5.0", "jwt-simple": "^0.5.6", "less": "^4.9.1", "lodash": "^4.18.1", "marked-hbfm": "^1.0.1", "markedLegacy": "npm:marked@^0.3.19", "moment": "^2.31.0", - "mongoose": "^9.11.1", + "mongoose": "^9.11.2", "nanoid": "6.0.2", "nconf": "^0.13.0", - "node": "^26.11.1", - "prettier": "^3.9.9", - "react": "^19.3.0", - "react-dom": "^19.3.0", + "node": "^26.12.0", + "prettier": "^3.9.10", + "react": "^19.3.1", + "react-dom": "^19.3.1", "react-frame-component": "^5.3.2", "react-router": "^8.4.0", "sanitize-filename": "1.6.4", @@ -6375,9 +6375,9 @@ "license": "MIT" }, "node_modules/content-disposition": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.1.0.tgz", - "integrity": "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-2.0.1.tgz", + "integrity": "sha512-e+H0ZXHSWYrENhQzw1LPuP4oF5MzVKmDU6d3hxlvaPEYLLg62MxtQNPRx4SYSuYJSBUgnQIG4HIN2tEtNv7Dog==", "license": "MIT", "engines": { "node": ">=18" @@ -7531,15 +7531,15 @@ "license": "MIT" }, "node_modules/express": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", - "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/express/-/express-5.3.0.tgz", + "integrity": "sha512-qCqy1xSoaugxOD4IVHb1ZWdkvCF2W3aE2okKouWj8VwJ+ztskSiXoBnCSJqfKT+cVPJhuJqe9YLbY425+Zh00g==", "license": "MIT", "dependencies": { "accepts": "^2.0.0", - "body-parser": "^2.2.1", - "content-disposition": "^1.0.0", - "content-type": "^1.0.5", + "body-parser": "^2.3.0", + "content-disposition": "^2.0.1", + "content-type": "^2.0.0", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", @@ -7555,14 +7555,14 @@ "on-finished": "^2.4.1", "once": "^1.4.0", "parseurl": "^1.3.3", - "proxy-addr": "^2.0.7", - "qs": "^6.14.0", + "proxy-addr": "^2.0.8", + "qs": "^6.16.0", "range-parser": "^1.2.1", "router": "^2.2.0", "send": "^1.1.0", "serve-static": "^2.2.0", "statuses": "^2.0.1", - "type-is": "^2.0.1", + "type-is": "^2.1.0", "vary": "^1.1.2" }, "engines": { @@ -7590,15 +7590,6 @@ "serve-static": "^2.2.0" } }, - "node_modules/express/node_modules/content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, "node_modules/express/node_modules/cookie-signature": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", @@ -10867,9 +10858,9 @@ "license": "MIT" }, "node_modules/js-yaml": { - "version": "5.4.3", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-5.4.3.tgz", - "integrity": "sha512-yzzNtgczwgoVHNigCyKTXcQJU4Y8t/ikU4UxXW0BvrLfHTGWZhsNcOT2s/a7vn81/4KqVnNmHjaUEPlvWnNwVw==", + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-5.5.0.tgz", + "integrity": "sha512-paNr4LFIFPjeeSmwNYdrb8FafLLG/Cr2Af3GjbsHJ5CxIjH4r0c2emlmRdAtpPAieP1gRVzk6buBbVP5gBMGAg==", "funding": [ { "type": "github", @@ -10882,12 +10873,28 @@ ], "license": "MIT", "dependencies": { - "argparse": "^2.0.1" + "argparse": "^3.0.3" }, "bin": { "js-yaml": "bin/js-yaml.mjs" } }, + "node_modules/js-yaml/node_modules/argparse": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-3.0.3.tgz", + "integrity": "sha512-Sn98ftV3KfsO8xfLPHG6oT8y+b0yvbrLgZjgPDXsharNY15tTAjqIsIju4S32nl6/iEUNNE4v+yL2Zhm8ooP3w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], + "license": "PSF-2.0" + }, "node_modules/jsdom": { "version": "30.1.2", "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-30.1.2.tgz", @@ -11054,9 +11061,9 @@ } }, "node_modules/kareem": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/kareem/-/kareem-3.4.0.tgz", - "integrity": "sha512-JAKhnR4S027v/8949QXNInRskgETCg9rFUMi1VjhGbjX+XltCAAEFcXykkSocNkom1kc66EMJfjWvhj87BDQKg==", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/kareem/-/kareem-3.4.1.tgz", + "integrity": "sha512-UlgCAFNAdk/HLSsbfkmbH8pJqpEN52Ek8RG53Ys1i3Q3gbCQruSrWpplZlgIGyDHX/LNoLW97ei3OG43s7UhUA==", "license": "Apache-2.0", "engines": { "node": ">=18.0.0" @@ -11886,13 +11893,13 @@ } }, "node_modules/mongoose": { - "version": "9.11.1", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-9.11.1.tgz", - "integrity": "sha512-fVtjTVACOtAb0PjDDF+O5NebcEJy5JpAH+AXk16/5i36w38YkW6MZ+KWV54bdIOJFymDz1VjjA5Xg6L2QfjQjQ==", + "version": "9.11.2", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-9.11.2.tgz", + "integrity": "sha512-hFkl/2dccpD58coRAya3a/ht8ooAx9YPLzBfxVX9bEsgcrjsNkvuWQe8gplGfDdmzpw2RfFX1IB/G8PiFwyvwg==", "license": "MIT", "dependencies": { "@standard-schema/spec": "^1.1.0", - "kareem": "3.4.0", + "kareem": "3.4.1", "mongodb": "~7.7", "mpath": "0.9.0", "mquery": "6.0.0", @@ -12131,9 +12138,9 @@ } }, "node_modules/node": { - "version": "26.11.1", - "resolved": "https://registry.npmjs.org/node/-/node-26.11.1.tgz", - "integrity": "sha512-KimXTKFoiWoakmW/7c2B3EFwZYrAjTjllg7kKSIQAQ7Ai+gRkkIoCrtrURJDrql+6hLshRWvZUmhkbE+JfKkFw==", + "version": "26.12.0", + "resolved": "https://registry.npmjs.org/node/-/node-26.12.0.tgz", + "integrity": "sha512-/P4rDRs4lOBFW0UUDb1Yuy02aDd9oh/RHZfl3haBnatqUcDnY0np4fo9EgK7zhX09bzZ/uroJfyzW+Tgo5kyiA==", "hasInstallScript": true, "license": "MIT", "dependencies": { @@ -12833,9 +12840,9 @@ } }, "node_modules/prettier": { - "version": "3.9.9", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.9.9.tgz", - "integrity": "sha512-Z/CJHIkdujO/OtN7nXUii0Rf3VT5SRuhjBA82Xvu2XhBUgX3nhP67T0LHceBdQLex7OOFGTox+Q5Yg8Jk2Qivg==", + "version": "3.9.10", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.9.10.tgz", + "integrity": "sha512-skGHTH1Yb9QvaTC4hWnRTzEYtCpApF0UMBPz+t/0ZPzP8ihefo/btKd+QA7pUE0fEwA1SbS/NmhyEcstdXOIdA==", "license": "MIT", "bin": { "prettier": "bin/prettier.cjs" @@ -13085,24 +13092,24 @@ } }, "node_modules/react": { - "version": "19.3.0", - "resolved": "https://registry.npmjs.org/react/-/react-19.3.0.tgz", - "integrity": "sha512-E8LUcbtBWt20bbl2YoHfx4ZDBdxVTfOKtCZn9cDSJ4l6/nuoApcpIBcj47t2wZoVX8g2ZHuMHbiShgCR1T5Sog==", + "version": "19.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-19.3.1.tgz", + "integrity": "sha512-QNhWdt7nrgVWWQG58QuGsAR3jv3Hbe4mb4vz7w2csnHavciZJgda1CPNaldF6eVxv90ud3jUXpKlHL69gO38yw==", "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/react-dom": { - "version": "19.3.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.3.0.tgz", - "integrity": "sha512-JDk8dgif51OjFoDE70+OT9ICyYr+69HlmihNwp1+Nsfbna3t5sIiCa9ZJktDmQ4/1b/rn26hIAR2uYXDMr5r0Q==", + "version": "19.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.3.1.tgz", + "integrity": "sha512-Y0bARz53lhEC1NMCASs0/j+faB/zqt3R8hpvg1e8+61ZVJ4UL0UdC4cBbXfZMcIuhrfgeILTLe+ZeBCavQPtKQ==", "license": "MIT", "dependencies": { "scheduler": "^0.28.0" }, "peerDependencies": { - "react": "^19.3.0" + "react": "^19.3.1" } }, "node_modules/react-frame-component": { diff --git a/package.json b/package.json index 6f1269f97..facfe3b3d 100644 --- a/package.json +++ b/package.json @@ -115,27 +115,27 @@ "cors": "^2.8.5", "create-react-class": "^15.7.0", "dedent": "^1.7.2", - "express": "^5.1.0", + "express": "^5.3.0", "express-async-handler": "^1.2.0", "express-static-gzip": "3.0.2", "fflate": "^0.8.3", "fs-extra": "^11.4.1", "hash-wasm": "^4.12.0", "idb-keyval": "^6.2.5", - "js-yaml": "^5.4.3", + "js-yaml": "^5.5.0", "jwt-simple": "^0.5.6", "less": "^4.9.1", "lodash": "^4.18.1", "marked-hbfm": "^1.0.1", "markedLegacy": "npm:marked@^0.3.19", "moment": "^2.31.0", - "mongoose": "^9.11.1", + "mongoose": "^9.11.2", "nanoid": "6.0.2", "nconf": "^0.13.0", - "node": "^26.11.1", - "prettier": "^3.9.9", - "react": "^19.3.0", - "react-dom": "^19.3.0", + "node": "^26.12.0", + "prettier": "^3.9.10", + "react": "^19.3.1", + "react-dom": "^19.3.1", "react-frame-component": "^5.3.2", "react-router": "^8.4.0", "sanitize-filename": "1.6.4", From 86866c9dd2cabb114737d8410e6a8af32867fef8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Losada=20Hern=C3=A1ndez?= Date: Mon, 19 Oct 2026 12:59:12 +0200 Subject: [PATCH 06/32] refactor uipage to be functional --- .../homebrew/pages/basePages/uiPage/uiPage.jsx | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/client/homebrew/pages/basePages/uiPage/uiPage.jsx b/client/homebrew/pages/basePages/uiPage/uiPage.jsx index 400dbb28e..bd16b85e5 100644 --- a/client/homebrew/pages/basePages/uiPage/uiPage.jsx +++ b/client/homebrew/pages/basePages/uiPage/uiPage.jsx @@ -1,7 +1,4 @@ import './uiPage.less'; -import React from 'react'; -import createReactClass from 'create-react-class'; - import Nav from '../../../navbar/nav.jsx'; import Navbar from '../../../navbar/navbar.jsx'; import NewBrewItem from '../../../navbar/newbrew.navitem.jsx'; @@ -10,15 +7,12 @@ import RecentNavItems from '../../../navbar/recent.navitem.jsx'; const { both: RecentNavItem } = RecentNavItems; import Account from '../../../navbar/account.navitem.jsx'; +const UIPage = ({brew, children})=>{ -const UIPage = createReactClass({ - displayName : 'UIPage', - - render : function(){ - return
+ return
- {this.props.brew.title} + {brew?.title} @@ -30,10 +24,9 @@ const UIPage = createReactClass({
- {this.props.children} + {children}
; - } -}); +}; export default UIPage; From eaa23f51fc97552ae0ca861cabf7556eedefe120 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Losada=20Hern=C3=A1ndez?= Date: Mon, 19 Oct 2026 13:00:57 +0200 Subject: [PATCH 07/32] lint --- .../pages/basePages/uiPage/uiPage.jsx | 36 +++++++++---------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/client/homebrew/pages/basePages/uiPage/uiPage.jsx b/client/homebrew/pages/basePages/uiPage/uiPage.jsx index bd16b85e5..9fa7e08bb 100644 --- a/client/homebrew/pages/basePages/uiPage/uiPage.jsx +++ b/client/homebrew/pages/basePages/uiPage/uiPage.jsx @@ -7,26 +7,22 @@ import RecentNavItems from '../../../navbar/recent.navitem.jsx'; const { both: RecentNavItem } = RecentNavItems; import Account from '../../../navbar/account.navitem.jsx'; -const UIPage = ({brew, children})=>{ +const UIPage = ({ brew, children })=>
+ + + {brew?.title} + + + + + + + + - return
- - - {brew?.title} - - - - - - - - - - -
- {children} -
-
; -}; +
+ {children} +
+
; export default UIPage; From 8cb852263564effa6cdf08d975ec0b5e5011c5d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Losada=20Hern=C3=A1ndez?= Date: Mon, 19 Oct 2026 13:17:08 +0200 Subject: [PATCH 08/32] refactor to functional --- .../editor/metadataEditor/metadataEditor.jsx | 304 +++++++++--------- 1 file changed, 149 insertions(+), 155 deletions(-) diff --git a/client/homebrew/editor/metadataEditor/metadataEditor.jsx b/client/homebrew/editor/metadataEditor/metadataEditor.jsx index a14eb3f09..af357f4c0 100644 --- a/client/homebrew/editor/metadataEditor/metadataEditor.jsx +++ b/client/homebrew/editor/metadataEditor/metadataEditor.jsx @@ -1,6 +1,6 @@ /* eslint-disable max-lines */ import '../uiEditor.less'; -import React from 'react'; +import React, {useState, useEffect} from 'react'; import createReactClass from 'create-react-class'; import _ from 'lodash'; import request from '../../utils/request-middleware.js'; @@ -18,48 +18,37 @@ const callIfExists = (val, fn, ...args)=>{ } }; -const MetadataEditor = createReactClass({ - displayName : 'MetadataEditor', - getDefaultProps : function() { - return { - metadata : { - editId : null, - shareId : null, - title : '', - description : '', - thumbnail : '', - tags : [], - published : false, - authors : [], - renderer : 'legacy', - theme : '5ePHB', - lang : 'en' - }, - - onChange : ()=>{}, - reportError : ()=>{} - }; +const MetadataEditor = ({ + metadata = { + editId: null, + shareId: null, + title: '', + description: '', + thumbnail: '', + tags: [], + published: false, + authors: [], + renderer: 'legacy', + theme: '5ePHB', + lang: 'en', }, - getInitialState : function(){ - return { - isOwner : global.account?.username && global.account?.username === this.props.metadata?.authors[0], - showThumbnail : true - }; - }, + onChange = () => {}, + reportError = () => {}, + +}, ...props) => { + const [isOwner, setIsOwner] = useState(global.account?.username && global.account?.username === metadata?.authors[0]); + const [showThumbnail, setShowThumbnail] = useState(true); - toggleThumbnailDisplay : function(){ - this.setState({ - showThumbnail : !this.state.showThumbnail - }); - }, - renderThumbnail : function(){ - if(!this.state.showThumbnail) return; - return ; - }, - - handleFieldChange : function(name, e){ + const toggleThumbnailDisplay = ()=>{ + setShowThumbnail(!showThumbnail); + }; + const renderThumbnail = ()=>{ + if(!showThumbnail) return; + return ; + }; + const handleFieldChange = (name, e)=>{ // load validation rules, and check input value against them const inputRules = validations[name] ?? []; const validationErr = inputRules.map((rule)=>rule(e.target.value)).filter(Boolean); @@ -72,8 +61,8 @@ const MetadataEditor = createReactClass({ // if no validation rules, save to props if(validationErr.length === 0){ callIfExists(e.target, 'setCustomValidity', ''); - this.props.onChange({ - ...this.props.metadata, + onChange({ + ...metadata, [name] : e.target.value }); return true; @@ -86,45 +75,39 @@ const MetadataEditor = createReactClass({ debouncedReportValidity(e.target, errMessage); return false; } - }, - - handleRenderer : function(renderer, e){ + }; + const handleRenderer = (renderer, e)=>{ if(e.target.checked){ - this.props.metadata.renderer = renderer; + metadata.renderer = renderer; if(renderer == 'legacy') - this.props.metadata.theme = '5ePHB'; + metadata.theme = '5ePHB'; } - this.props.onChange(this.props.metadata, 'renderer'); - }, - - handlePublish : function(val){ - this.props.onChange({ - ...this.props.metadata, + onChange(metadata, 'renderer'); + }; + const handlePublish = (val)=>{ + onChange({ + ...metadata, published : val }); - }, + }; + const handleTheme = (theme)=>{ + metadata.renderer = theme.renderer; + metadata.theme = theme.path; - handleTheme : function(theme){ - this.props.metadata.renderer = theme.renderer; - this.props.metadata.theme = theme.path; - - this.props.onChange(this.props.metadata, 'theme'); - }, - - handleThemeWritein : function(e) { + onChange(metadata, 'theme'); + }; + const handleThemeWritein = (e) =>{ const shareId = e.target.value.split('/').pop(); //Extract just the ID if a URL was pasted in - this.props.metadata.theme = shareId; + metadata.theme = shareId; - this.props.onChange(this.props.metadata, 'theme'); - }, - - handleLanguage : function(languageCode){ - this.props.metadata.lang = languageCode; - this.props.onChange(this.props.metadata); - }, - - handleDelete : function(){ - if(this.props.metadata.authors && this.props.metadata.authors.length <= 1){ + onChange(metadata, 'theme'); + }; + const handleLanguage = (languageCode)=>{ + metadata.lang = languageCode; + onChange(metadata); + }; + const handleDelete = ()=>{ + if(metadata.authors && metadata.authors.length <= 1){ if(!confirm('Are you sure you want to delete this brew? Because you are the only owner of this brew, the document will be deleted permanently.')) return; if(!confirm('Are you REALLY sure? You will not be able to recover the document.')) return; } else { @@ -132,54 +115,50 @@ const MetadataEditor = createReactClass({ if(!confirm('Are you REALLY sure? You will lose editor access to this document.')) return; } - request.delete(`/api/${this.props.metadata.googleId ?? ''}${this.props.metadata.editId}`) + request.delete(`/api/${metadata.googleId ?? ''}${metadata.editId}`) .send() .end((err, res)=>{ if(err) { - this.props.reportError(err); + reportError(err); } else { window.location.href = '/'; } }); - }, - - handleDeleteAuthor : function(author){ + }; + const handleDeleteAuthor = (author)=>{ if(!confirm('Are you sure you want to remove this author? They will lose all edit access to this brew, and it will dissapear from their userpage.')) return; - if(!this.props.metadata.authors.includes(author)) return; - this.props.onChange({ - ...this.props.metadata, - authors : this.props.metadata.authors.filter((a)=>a !== author) + if(!metadata.authors.includes(author)) return; + onChange({ + ...metadata, + authors : metadata.authors.filter((a)=>a !== author) }); - }, - - renderPublish : function(){ - if(this.props.metadata.published){ - return