diff --git a/packages/freesewing.shared/components/workbench/draft/index.js b/packages/freesewing.shared/components/workbench/draft/index.js index 35d8183bb17..c6dee39d21e 100644 --- a/packages/freesewing.shared/components/workbench/draft/index.js +++ b/packages/freesewing.shared/components/workbench/draft/index.js @@ -1,8 +1,13 @@ +import { useState } from 'react' import SvgWrapper from './svg-wrapper' import Error from './error.js' +import Popout from 'shared/components/popout.js' +import Robot from 'shared/components/robot/index.js' const LabDraft = props => { - const { app, draft, pattern, gist, updateGist, unsetGist } = props + const { app, draft, pattern, gist, updateGist, unsetGist, feedback } = props + + const [share, setShare] = useState(false) if (!draft) return null if (gist?.renderer === 'svg') { @@ -24,17 +29,66 @@ const LabDraft = props => { return } + // Handle broken drafts + let error = null + if (patternProps.events.error.length > 0) { + error = ( + +
+
+

Got {patternProps.events.error.length} problems and a stitch ain't one

+

Don't be alarmed, but we ran into some trouble while drafting this pattern.

+

Help us make FreeSewing better

+

+ If you like puzzles, you can try to figure out what went wrong: +

+
    +
  • + Check the +
  • +
  • Check the partially rendered pattern below to see which areas are problematic
  • +
+

+ Alternatively, you can escalate this. Which means that: +

+
    +
  • + We will compile a crash report that contains everything needed to recreate this problem +
  • +
  • + We will include personal data such as your username, + email address and measurements +
  • +
  • + We will share this report and the data in it with FreeSewing's bughunters team +
  • +
+
+ +
+

+ +

+ +
+ +
+
+ ) + } + console.log(patternProps) + return ( -
- -
+ <> + {error} + + ) } diff --git a/packages/freesewing.shared/components/workbench/draft/part/index.js b/packages/freesewing.shared/components/workbench/draft/part/index.js index 0a9ada65894..883f9a5350a 100644 --- a/packages/freesewing.shared/components/workbench/draft/part/index.js +++ b/packages/freesewing.shared/components/workbench/draft/part/index.js @@ -1,8 +1,32 @@ +import React from 'react' import Path from '../path' import Point from '../point' import Snippet from '../snippet' import { getProps } from '../utils' +class ErrorBoundary extends React.Component { + constructor(props) { + super(props); + this.state = { hasError: false }; + } + + static getDerivedStateFromError(error) { + console.log(error) + return { hasError: true } + } + componentDidCatch(error, errorInfo) { + console.log(error, errorInfo) + } + render() { + if (this.state.hasError) { + console.log('in error boundary', props) + return Something went wrong. + } + + return this.props.children + } +} + const XrayPart = props => { // Don't bother if this is the only part on display if (props.gist.only && props.gist.only.length === 1) return null @@ -38,44 +62,53 @@ const Part = props => { ) : null return ( - - {grid} - { - props.gist?._state?.xray?.enabled && - props.gist?._state?.xray?.reveal?.[partName] - && - } - {Object.keys(part.paths).map((pathName) => ( - - ))} - {Object.keys(props.part.points).map((pointName) => ( - - ))} - {Object.keys(props.part.snippets).map((snippetName) => ( - - ))} - {focus} - + + {grid} + { + props.gist?._state?.xray?.enabled && + props.gist?._state?.xray?.reveal?.[partName] + && + } + {Object.keys(part.paths).map((pathName) => ( + + ))} + {Object.keys(props.part.points).map((pointName) => ( + + ))} + {Object.keys(props.part.snippets).map((snippetName) => ( + + ))} + {focus} + ) } +/* + + + */ export default Part diff --git a/packages/freesewing.shared/components/workbench/draft/path/index.js b/packages/freesewing.shared/components/workbench/draft/path/index.js index a5525391f57..23089794394 100644 --- a/packages/freesewing.shared/components/workbench/draft/path/index.js +++ b/packages/freesewing.shared/components/workbench/draft/path/index.js @@ -1,3 +1,4 @@ +import React from 'react' import TextOnPath from '../text-on-path' import { getProps } from '../utils' @@ -21,9 +22,15 @@ const Path = props => { if (!path.render) return null const output = [] const pathId = 'path-' + partName + '-' + pathName - output.push( - - ) + let d = '' + try { d = path.asPathstring() } + catch (err) { + // Bail out + console.log(`Failed to generate pathstring for path ${pathId} in part ${partName}`, err) + return null + } + + output.push() if (path.attributes.get('data-text')) output.push() if (props.gist._state?.xray?.enabled) output.push() diff --git a/packages/freesewing.shared/components/workbench/draft/svg-wrapper.js b/packages/freesewing.shared/components/workbench/draft/svg-wrapper.js index 1bbad0802e3..fb3124f3df8 100644 --- a/packages/freesewing.shared/components/workbench/draft/svg-wrapper.js +++ b/packages/freesewing.shared/components/workbench/draft/svg-wrapper.js @@ -40,14 +40,10 @@ const SvgWrapper = props => { {Object.keys(patternProps.parts).map((name) => ( - ))} diff --git a/packages/freesewing.shared/components/workbench/layout/draft.js b/packages/freesewing.shared/components/workbench/layout/draft.js index 504138d706d..577535b99de 100644 --- a/packages/freesewing.shared/components/workbench/layout/draft.js +++ b/packages/freesewing.shared/components/workbench/layout/draft.js @@ -152,7 +152,7 @@ const Part = props => { const partLayout= layout.parts[name] // Don't just assume this makes sense - if (typeof layout.parts[name].move?.x === 'undefined') return null + if (typeof layout.parts?.[name]?.move?.x === 'undefined') return null // Use a ref for direct DOM manipulation const partRef = useRef(null) diff --git a/packages/freesewing.shared/components/workbench/preload.js b/packages/freesewing.shared/components/workbench/preload.js index b6108397087..48325f043fb 100644 --- a/packages/freesewing.shared/components/workbench/preload.js +++ b/packages/freesewing.shared/components/workbench/preload.js @@ -15,7 +15,7 @@ const preload = { if (result.data.files['pattern.yaml'].content) { let g = yaml.load(result.data.files['pattern.yaml'].content) if (g.design !== pattern.config.name) return [ - false, `You tried loading a configuration for ${g.design} into a ${design} development environment` + false, `You tried loading a configuration for ${g.design} into a ${pattern.config.name} development environment` ] return g diff --git a/packages/freesewing.shared/components/wrappers/workbench.js b/packages/freesewing.shared/components/wrappers/workbench.js index 0bc2b470180..12e4f6e74c8 100644 --- a/packages/freesewing.shared/components/wrappers/workbench.js +++ b/packages/freesewing.shared/components/wrappers/workbench.js @@ -1,4 +1,4 @@ -import { useEffect } from 'react' +import { useEffect, useState } from 'react' import useLocalStorage from 'shared/hooks/useLocalStorage.js' import Layout from 'shared/components/layouts/default' import Menu from 'shared/components/workbench/menu/index.js' @@ -62,6 +62,7 @@ const WorkbenchWrapper = ({ app, pattern, preload=false, from=false }) => { // State for gist const [gist, setGist] = useLocalStorage(`${pattern.config.name}_gist`, defaultGist(pattern, app.locale)) + const [messages, setMessages] = useState([]) // If we don't have the required measurements, // force view to measurements @@ -76,7 +77,7 @@ const WorkbenchWrapper = ({ app, pattern, preload=false, from=false }) => { useEffect(async () => { if (preload && from && preloaders[from]) { const g = await preloaders[from](preload, pattern) - // FIXME: Continue here + setGist({ ...gist, ...g.settings }) } }, [preload, from]) @@ -91,6 +92,17 @@ const WorkbenchWrapper = ({ app, pattern, preload=false, from=false }) => { unset(newGist, path) setGist(newGist) } + // Helper methods to handle messages + const feedback = { + add: msg => { + const newMsgs = [...messages] + if (Array.isArray(msg)) newMsgs.push(...msg) + else newMsgs.push(msg) + setMessages(newMsgs) + }, + set: setMessages, + clear: () => setMessages([]), + } // Generate the draft here so we can pass it down let draft = false @@ -107,7 +119,7 @@ const WorkbenchWrapper = ({ app, pattern, preload=false, from=false }) => { } // Props to pass down - const componentProps = { app, pattern, gist, updateGist, unsetGist, setGist, draft } + const componentProps = { app, pattern, gist, updateGist, unsetGist, setGist, draft, feedback } // Required props for layout const layoutProps = { app: app, @@ -121,6 +133,7 @@ const WorkbenchWrapper = ({ app, pattern, preload=false, from=false }) => { : views.welcome return + {messages} }