feat(shared): implemented log view
This commit is contained in:
parent
0a8cedd23f
commit
9ffb4f5261
21 changed files with 316 additions and 279 deletions
|
@ -22,7 +22,7 @@ import { ModalThemePicker, ns as themeNs } from 'shared/components/modal/theme-p
|
|||
import { ModalLocalePicker, ns as localeNs } from 'shared/components/modal/locale-picker.mjs'
|
||||
import { ModalMenu } from 'site/components/navigation/modal-menu.mjs'
|
||||
|
||||
import { NavButton, NavSpacer, colors } from 'shared/components/workbench/header.mjs'
|
||||
import { NavButton, NavSpacer, colors } from 'shared/components/header.mjs'
|
||||
|
||||
export const ns = ['header', 'sections', ...themeNs, ...localeNs]
|
||||
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
import get from 'lodash.get'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import orderBy from 'lodash.orderby'
|
||||
import { freeSewingConfig as conf } from 'shared/config/freesewing.config.mjs'
|
||||
import { useAccount } from 'shared/hooks/use-account.mjs'
|
||||
import { designs } from 'shared/config/designs.mjs'
|
||||
|
@ -104,43 +102,9 @@ const sitePages = (t = false, control = 99) => {
|
|||
return pages
|
||||
}
|
||||
|
||||
const createCrumbs = (path, nav) =>
|
||||
path.map((crumb, i) => {
|
||||
const entry = get(nav, path.slice(0, i + 1), { t: 'no-title', s: path.join('/') })
|
||||
const val = { t: entry.t, s: entry.s }
|
||||
if (entry.o) val.o = entry.o
|
||||
|
||||
return val
|
||||
})
|
||||
|
||||
const createSections = (nav) => {
|
||||
const sections = {}
|
||||
for (const slug of Object.keys(nav)) {
|
||||
const entry = nav[slug]
|
||||
const val = { t: entry.t, s: entry.s }
|
||||
if (entry.o) val.o = entry.o
|
||||
if (!entry.h) sections[slug] = val
|
||||
}
|
||||
|
||||
return orderBy(sections, ['o', 't'])
|
||||
}
|
||||
|
||||
export const useNavigation = ({ path }) => {
|
||||
const { t } = useTranslation(ns)
|
||||
const { account } = useAccount()
|
||||
|
||||
const nav = sitePages(t, account?.control)
|
||||
|
||||
// Create crumbs array
|
||||
const crumbs = createCrumbs(path, nav)
|
||||
const sections = createSections(nav)
|
||||
|
||||
return {
|
||||
crumbs,
|
||||
sections,
|
||||
slug: path.join('/'),
|
||||
nav: path.length > 1 ? get(nav, path[0]) : path.length === 0 ? sections : nav[path[0]],
|
||||
title: crumbs.length > 0 ? crumbs.slice(-1)[0].t : '',
|
||||
siteNav: nav,
|
||||
}
|
||||
return sitePages(t, account.control)
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ const colors = {
|
|||
note: 'primary',
|
||||
tip: 'accent',
|
||||
warning: 'error',
|
||||
error: 'error',
|
||||
fixme: 'warning',
|
||||
link: 'secondary',
|
||||
related: 'info',
|
||||
|
|
|
@ -19,6 +19,7 @@ import { CutView, ns as cutNs } from 'shared/components/workbench/views/cut/inde
|
|||
import { EditView, ns as editNs } from './views/edit/index.mjs'
|
||||
import { TestView, ns as testNs } from 'shared/components/workbench/views/test/index.mjs'
|
||||
import { ExportView, ns as exportNs } from 'shared/components/workbench/views/exporting/index.mjs'
|
||||
import { LogView, ns as logNs } from 'shared/components/workbench/views/logs/index.mjs'
|
||||
|
||||
export const ns = [
|
||||
'account',
|
||||
|
@ -30,6 +31,7 @@ export const ns = [
|
|||
...editNs,
|
||||
...testNs,
|
||||
...exportNs,
|
||||
...logNs,
|
||||
]
|
||||
|
||||
const defaultUi = {
|
||||
|
@ -43,6 +45,7 @@ const views = {
|
|||
export: ExportView,
|
||||
edit: EditView,
|
||||
test: TestView,
|
||||
logs: LogView,
|
||||
}
|
||||
|
||||
const draftViews = ['draft']
|
||||
|
@ -87,6 +90,7 @@ export const Workbench = ({ design, Design, baseSettings, DynamicDocs, from }) =
|
|||
const viewProps = {
|
||||
account,
|
||||
design,
|
||||
view,
|
||||
setView,
|
||||
update,
|
||||
settings,
|
||||
|
@ -127,6 +131,9 @@ export const Workbench = ({ design, Design, baseSettings, DynamicDocs, from }) =
|
|||
// Draft the pattern or die trying
|
||||
try {
|
||||
pattern.draft()
|
||||
const errors = [...pattern.store.logs.error]
|
||||
for (const store of pattern.setStores) errors.push(...store.logs.error)
|
||||
if (errors.length > 0) setView('logs')
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
setError(<ErrorView>{JSON.stringify(error)}</ErrorView>)
|
||||
|
|
|
@ -1,48 +0,0 @@
|
|||
//import { Chevron } from 'shared/components/navigation/primary'
|
||||
|
||||
export const XrayAttributes = ({ attr = false, t }) => {
|
||||
return null
|
||||
// FIXME
|
||||
/*
|
||||
if (!attr || !attr.list || Object.keys(attr.list).length < 1) return null
|
||||
|
||||
return (
|
||||
<Li>
|
||||
<Details>
|
||||
<Summary>
|
||||
<SumDiv>
|
||||
<Deg />
|
||||
Attributes
|
||||
</SumDiv>
|
||||
<Chevron />
|
||||
</Summary>
|
||||
<Ul>
|
||||
{Object.keys(attr.list).map((at) => (
|
||||
<Li key={at}>
|
||||
<Details>
|
||||
<Summary>
|
||||
<SumDiv>
|
||||
<Deg />
|
||||
{at}
|
||||
</SumDiv>
|
||||
<Chevron />
|
||||
</Summary>
|
||||
<Ul>
|
||||
{attr.list[at].map((val) => (
|
||||
<Li key={val}>
|
||||
<NoSumDiv>
|
||||
<Deg />
|
||||
<span>{val === true ? t('app.yes') : val}</span>
|
||||
</NoSumDiv>
|
||||
</Li>
|
||||
))}
|
||||
</Ul>
|
||||
</Details>
|
||||
</Li>
|
||||
))}
|
||||
</Ul>
|
||||
</Details>
|
||||
</Li>
|
||||
)
|
||||
*/
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
export const loadSettingsConfig = (settings) => {
|
||||
export const loadSettingsConfig = (settings, view) => {
|
||||
const uiSettings = {
|
||||
control: {
|
||||
control: 1, // Show when control > 0
|
||||
|
@ -34,6 +34,30 @@ export const loadSettingsConfig = (settings) => {
|
|||
dflt: 0,
|
||||
emoji: '🔬',
|
||||
},
|
||||
view: {
|
||||
control: 3,
|
||||
list: ['draft', 'test', 'print', 'cut', 'save', 'export', 'logs'],
|
||||
dflt: view,
|
||||
emoji: '👀',
|
||||
choiceTitles: {
|
||||
draft: 'draft',
|
||||
test: 'test',
|
||||
print: 'print',
|
||||
cut: 'cut',
|
||||
save: 'save',
|
||||
export: 'export',
|
||||
logs: 'logs',
|
||||
},
|
||||
valueTitles: {
|
||||
draft: 'draft',
|
||||
test: 'test',
|
||||
print: 'print',
|
||||
cut: 'cut',
|
||||
save: 'save',
|
||||
export: 'export',
|
||||
logs: 'logs',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
uiSettings.control.list.forEach(
|
||||
|
|
|
@ -13,13 +13,13 @@ const UiSetting = ({ name, control, ...rest }) => (
|
|||
<MenuItem
|
||||
{...rest}
|
||||
name={name}
|
||||
allowToggle={name !== 'control' && control > 3}
|
||||
allowToggle={!['control', 'view'].includes(name) && control > 3}
|
||||
control={control}
|
||||
/>
|
||||
)
|
||||
|
||||
export const UiSettings = ({ update, ui, control, language, DynamicDocs }) => {
|
||||
const settingsConfig = loadSettingsConfig(ui)
|
||||
export const UiSettings = ({ update, ui, control, language, DynamicDocs, view, setView }) => {
|
||||
const settingsConfig = loadSettingsConfig(ui, view)
|
||||
|
||||
return (
|
||||
<WorkbenchMenu
|
||||
|
@ -37,6 +37,7 @@ export const UiSettings = ({ update, ui, control, language, DynamicDocs }) => {
|
|||
name: 'uiSettings',
|
||||
ns,
|
||||
updateFunc: update.ui,
|
||||
passProps: { view, setView },
|
||||
}}
|
||||
/>
|
||||
)
|
||||
|
|
|
@ -15,8 +15,22 @@ export const ControlSettingInput = (props) => {
|
|||
)
|
||||
}
|
||||
|
||||
const ViewInput = (props) => {
|
||||
const { selection, update } = useControlState()
|
||||
|
||||
props.config.dflt = props.view
|
||||
return (
|
||||
<ListInput
|
||||
{...props}
|
||||
updateFunc={(path, newVal) => props.setView(newVal)}
|
||||
current={props.view}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export const inputs = {
|
||||
renderer: ListInput,
|
||||
inspect: BoolInput,
|
||||
control: ControlSettingInput,
|
||||
view: ViewInput,
|
||||
}
|
||||
|
|
|
@ -1,38 +0,0 @@
|
|||
//import { Chevron } from 'shared/components/navigation/primary.mjs'
|
||||
|
||||
export const ConsoleLog = (props) => null
|
||||
// FIXME
|
||||
/*
|
||||
(
|
||||
<Li>
|
||||
<Details>
|
||||
<Summary>
|
||||
<SumDiv>
|
||||
<Deg />
|
||||
<span>console.log()</span>
|
||||
</SumDiv>
|
||||
<Chevron />
|
||||
</Summary>
|
||||
<Ul>
|
||||
{['designConfig', 'patternConfig', 'gist', 'draft', 'renderProps'].map((it) => (
|
||||
<Li key={it}>
|
||||
<SumButton
|
||||
onClick={() => {
|
||||
if (it === 'designConfig') return console.log(props.design.designConfig)
|
||||
if (it === 'patternConfig') return console.log(props.design.patternConfig)
|
||||
if (it === 'renderProps') return console.log(props.draft.getRenderProps())
|
||||
return console.log(props[it])
|
||||
}}
|
||||
>
|
||||
<SumDiv>
|
||||
<Deg />
|
||||
<span>{it}</span>
|
||||
</SumDiv>
|
||||
</SumButton>
|
||||
</Li>
|
||||
))}
|
||||
</Ul>
|
||||
</Details>
|
||||
</Li>
|
||||
)
|
||||
*/
|
|
@ -1,71 +0,0 @@
|
|||
//import { Chevron } from 'shared/components/navigation/primary'
|
||||
//import { XrayPoint } from './point'
|
||||
//
|
||||
//const MoveLine = ({ op }) => <XrayPoint point={op.to} />
|
||||
//const Curve = ({ op }) => null
|
||||
/*
|
||||
['cp1', 'cp2', 'to'].map((pnt) => (
|
||||
<Li key={pnt}>
|
||||
<Details>
|
||||
<Summary>
|
||||
<SumDiv>
|
||||
<Deg />
|
||||
<span className="font-bold">{pnt}</span>
|
||||
</SumDiv>
|
||||
<Chevron />
|
||||
</Summary>
|
||||
<XrayPoint point={op[pnt]} />
|
||||
</Details>
|
||||
</Li>
|
||||
))
|
||||
*/
|
||||
//const XrayPathOp = ({ op }) => null
|
||||
/*
|
||||
* (
|
||||
<Li>
|
||||
{op.type === 'close' ? (
|
||||
<NoSumDiv>
|
||||
<Deg />
|
||||
<span className="font-bold">{op.type}</span>
|
||||
</NoSumDiv>
|
||||
) : (
|
||||
<Details>
|
||||
<Summary>
|
||||
<SumDiv>
|
||||
<Deg />
|
||||
<span className="font-bold">{op.type}</span>
|
||||
<span>To</span>
|
||||
</SumDiv>
|
||||
<Chevron />
|
||||
</Summary>
|
||||
<Ul>{op.type === 'curve' ? <Curve op={op} /> : <MoveLine op={op} />}</Ul>
|
||||
</Details>
|
||||
)}
|
||||
</Li>
|
||||
)
|
||||
*/
|
||||
export const XrayPathOps = ({ ops = false }) => null
|
||||
/*
|
||||
* {
|
||||
if (!ops || ops.length < 1) return null
|
||||
|
||||
return (
|
||||
<Li>
|
||||
<Details>
|
||||
<Summary>
|
||||
<SumDiv>
|
||||
<Deg />
|
||||
<span className="font-bold">path.ops</span>
|
||||
</SumDiv>
|
||||
<Chevron />
|
||||
</Summary>
|
||||
<Ul>
|
||||
{ops.map((op) => (
|
||||
<XrayPathOp op={op} key={op} />
|
||||
))}
|
||||
</Ul>
|
||||
</Details>
|
||||
</Li>
|
||||
)
|
||||
}
|
||||
*/
|
|
@ -1,35 +0,0 @@
|
|||
//import { formatMm } from 'shared/utils.mjs'
|
||||
//import { XrayAttributes } from './attributes.mjs'
|
||||
//import { XrayPathOps } from './path-ops.mjs'
|
||||
|
||||
export const XrayPath = ({ pathName, partName, draft, units }) => null
|
||||
/*{
|
||||
const path = draft?.parts?.[partName]?.paths?.[pathName]
|
||||
|
||||
if (!path) return null
|
||||
return (
|
||||
<Ul>
|
||||
<XrayAttributes attr={path.attributes} />
|
||||
<Li>
|
||||
<NoSumDiv>
|
||||
<Deg />
|
||||
<span className="font-bold mr-2">path.render =</span>
|
||||
<span>{JSON.stringify(path.render)}</span>
|
||||
</NoSumDiv>
|
||||
</Li>
|
||||
<Li>
|
||||
<NoSumDiv>
|
||||
<Deg />
|
||||
<span className="font-bold mr-2">path.length() =</span>
|
||||
<span
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: formatMm(path.length(), units),
|
||||
}}
|
||||
/>
|
||||
</NoSumDiv>
|
||||
</Li>
|
||||
<XrayPathOps ops={path.ops} />
|
||||
</Ul>
|
||||
)
|
||||
}
|
||||
*/
|
|
@ -1,23 +0,0 @@
|
|||
//import { round } from 'shared/utils'
|
||||
//import { XrayAttributes } from './attributes'
|
||||
|
||||
export const XrayPoint = ({ pointName, partName, draft, t }) => null
|
||||
/*{
|
||||
const point = draft?.parts?.[partName]?.points?.[pointName]
|
||||
|
||||
return point ? (
|
||||
<Ul>
|
||||
{['x', 'y'].map((coord) => (
|
||||
<Li key={coord}>
|
||||
<NoSumDiv>
|
||||
<Deg />
|
||||
<span className="font-bold mr-2">{coord} =</span>
|
||||
<span>{round(point[coord])}</span>
|
||||
</NoSumDiv>
|
||||
</Li>
|
||||
))}
|
||||
<XrayAttributes attr={point.attributes} t={t} />
|
||||
</Ul>
|
||||
) : null
|
||||
}
|
||||
*/
|
|
@ -1,18 +0,0 @@
|
|||
//import { useTranslation } from 'next-i18next'
|
||||
|
||||
export const XrayReset = (props) => null
|
||||
/*{
|
||||
const { t } = useTranslation(['app'])
|
||||
|
||||
return (
|
||||
<Li>
|
||||
<SumButton onClick={() => props.updateGist(['_state', 'xray'], { enabled: true })}>
|
||||
<SumDiv>
|
||||
<Deg />
|
||||
<span>{t(`reset`)}</span>
|
||||
</SumDiv>
|
||||
</SumButton>
|
||||
</Li>
|
||||
)
|
||||
}
|
||||
*/
|
|
@ -16,3 +16,28 @@ inspectYes.t: Enable the inspector
|
|||
inspectYes.d: With the pattern inspector enabled and the React rendering engine selected, we will add interactivity to the pattern to allow you to inspect the various elements that make up the pattern.
|
||||
no: No
|
||||
yes: Yes
|
||||
draft: Draft
|
||||
test: Test
|
||||
print: Print layout
|
||||
cut: Cut Layout
|
||||
save: Save
|
||||
export: Export
|
||||
edit: Edit
|
||||
draft.t: Draft your pattern
|
||||
draft.d: Launches FreeSewing flagship pattern editor, where you can tweak your pattern to your heart's desire
|
||||
test.t: Test your pattern
|
||||
test.d: See how your pattern adapts to changes in options, or measurements
|
||||
print.t: Print Layout
|
||||
print.d: Allows you to arrange your pattern pieces so you can printing your pattern on as little pages as possible
|
||||
cut.t: Cutting layout
|
||||
cut.d: Allows you to arrange your pattern pieces so you can determine exactly how much fabric you need to make it.
|
||||
save.t: Save your pattern
|
||||
save.d: Save the current pattern to your FreeSewing account
|
||||
export.t: Export your pattern
|
||||
export.d: Allows you to export this pattern to a variety of formats
|
||||
logs.t: Pattern logs
|
||||
logs.d: Allows you to browse the pattern logs to see what exactly happened while drafting this pattern
|
||||
edit.t: Hand-edit the pattern settings
|
||||
edit.d: This allows you to hand-edit the pattern settings, giving you full control over how your pattern will be drafted
|
||||
view: View
|
||||
view.d: These are the various views you can pick from. Includes those views available via the navigation bar or menu, and some additional ones
|
||||
|
|
|
@ -5,4 +5,5 @@ export const values = {
|
|||
renderer: ListValue,
|
||||
inspect: ListValue,
|
||||
control: ({ control }) => <Difficulty score={control} color="primary" />,
|
||||
view: ListValue,
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { useState } from 'react'
|
||||
import { useState, useEffect } from 'react'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import { PanZoomPattern as ShowPattern } from 'shared/components/workbench/pan-zoom-pattern.mjs'
|
||||
import { InspectorPattern } from './inspector/pattern.mjs'
|
||||
import { DraftMenu, ns as menuNs } from './menu.mjs'
|
||||
|
@ -16,12 +17,15 @@ export const DraftView = ({
|
|||
language,
|
||||
account,
|
||||
DynamicDocs,
|
||||
setView,
|
||||
view,
|
||||
}) => {
|
||||
// State for inspector
|
||||
const [inspect, setInspect] = useState({
|
||||
show: {},
|
||||
reveal: {},
|
||||
})
|
||||
|
||||
const inspector = {
|
||||
show: (data) => {
|
||||
const newInspect = { ...inspect }
|
||||
|
@ -83,6 +87,8 @@ export const DraftView = ({
|
|||
DynamicDocs,
|
||||
inspector,
|
||||
renderProps,
|
||||
view,
|
||||
setView,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
@ -22,6 +22,8 @@ export const DraftMenu = ({
|
|||
DynamicDocs,
|
||||
inspector = false,
|
||||
renderProps,
|
||||
view,
|
||||
setView,
|
||||
}) => {
|
||||
const control = account.control
|
||||
const menuProps = {
|
||||
|
@ -40,7 +42,7 @@ export const DraftMenu = ({
|
|||
{ui.inspect ? <Inspector {...menuProps} {...{ ui, inspector, renderProps }} /> : null}
|
||||
<DesignOptions {...menuProps} />
|
||||
<CoreSettings {...menuProps} />
|
||||
<UiSettings {...menuProps} ui={ui} />
|
||||
<UiSettings {...menuProps} {...{ ui, view, setView }} />
|
||||
</nav>
|
||||
)
|
||||
}
|
||||
|
|
118
sites/shared/components/workbench/views/logs/errors.mjs
Normal file
118
sites/shared/components/workbench/views/logs/errors.mjs
Normal file
|
@ -0,0 +1,118 @@
|
|||
import { useState } from 'react'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import { NoIcon as ErrorIcon } from 'shared/components/icons.mjs'
|
||||
import { WebLink } from 'shared/components/web-link.mjs'
|
||||
|
||||
const knownVars = [
|
||||
'sa',
|
||||
'Path',
|
||||
'Point',
|
||||
'Snippet',
|
||||
'paths',
|
||||
'points',
|
||||
'snippets',
|
||||
'absoluteOptions',
|
||||
'complete',
|
||||
'measurements',
|
||||
'options',
|
||||
'paperless',
|
||||
'sa',
|
||||
'scale',
|
||||
'context',
|
||||
'getId',
|
||||
'hide',
|
||||
'log',
|
||||
'macro',
|
||||
'setHidden',
|
||||
'store',
|
||||
'unhide',
|
||||
'units',
|
||||
'utils',
|
||||
'Bezier',
|
||||
'part',
|
||||
]
|
||||
|
||||
export const analyzeDraftLogLine = ({ type, line, t }) => {
|
||||
if (type === 'error' && line.stack) return <DraftError err={line} t={t} />
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
const Code = ({ children }) => <code className="font-mono font-bold px-1 rounded">{children}</code>
|
||||
|
||||
const ShowStackButton = ({
|
||||
setDetails,
|
||||
details,
|
||||
t,
|
||||
txt = 'click here to show the stack trace',
|
||||
}) => (
|
||||
<button className="text-secondary font-medium" onClick={() => setDetails(!details)}>
|
||||
{txt}
|
||||
</button>
|
||||
)
|
||||
|
||||
const NotDestructured = ({ missing, err, setDetails, details, t }) => (
|
||||
<div>
|
||||
This most likely means that <Code>{missing}</Code> was not desctructured as a draft method
|
||||
parameter.
|
||||
<br />
|
||||
See{' '}
|
||||
<WebLink
|
||||
href="https://freesewing.dev/reference/api/part/draft"
|
||||
txt="the draft method documentation"
|
||||
/>{' '}
|
||||
or <ShowStackButton {...{ setDetails, details, t }} />.
|
||||
</div>
|
||||
)
|
||||
|
||||
const DesignsVarUndefined = ({ missing, err, t }) => (
|
||||
<div key={missing}>
|
||||
We were unable to draft this pattern because <Code>{missing}</Code> is undefined in{' '}
|
||||
<Code>{err.stack.split('\n')[0].split('/designs/').pop()}</Code>
|
||||
</div>
|
||||
)
|
||||
|
||||
const OtherVarUndefined = ({ missing, err, t }) => (
|
||||
<div key={missing}>
|
||||
The <Code>{missing}</Code> variable is undefined.
|
||||
<br />
|
||||
Check <Code>{stack[0]}</Code> for details or <ShowStackButton {...{ setDetails, details, t }} />
|
||||
.
|
||||
</div>
|
||||
)
|
||||
|
||||
const DraftError = ({ err, t }) => {
|
||||
const [details, setDetails] = useState(false)
|
||||
const data = []
|
||||
const stack = err.stack.split('\n')
|
||||
// Leave this here, it's intentional. We log the error to you can inpect it.
|
||||
console.log(err)
|
||||
|
||||
const msg = err.toString()
|
||||
if (err.name === 'ReferenceError') {
|
||||
if (err.message.includes('is not defined')) {
|
||||
const missing = err.message.split(' ').shift()
|
||||
if (stack[0].includes('/designs/')) {
|
||||
data.push(<DesignsVarUndefined {...{ err, missing, t }} />)
|
||||
if (knownVars.includes(missing))
|
||||
data.push(<NotDestructured key="nd" {...{ details, setDetails, err, missing, t }} />)
|
||||
} else data.push(<OtherVarUndefined {...{ err, missing, t }} />)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{data}
|
||||
{details ? (
|
||||
<>
|
||||
<h6>{t('stackTrace')}</h6>
|
||||
<ol className="list list-inside list-decimal text-sm font-mono">
|
||||
{stack.map((line, i) => (
|
||||
<li key={i}>{line}</li>
|
||||
))}
|
||||
</ol>
|
||||
</>
|
||||
) : null}
|
||||
</>
|
||||
)
|
||||
}
|
95
sites/shared/components/workbench/views/logs/index.mjs
Normal file
95
sites/shared/components/workbench/views/logs/index.mjs
Normal file
|
@ -0,0 +1,95 @@
|
|||
import { useTranslation } from 'next-i18next'
|
||||
import { analyzeDraftLogLine } from './errors.mjs'
|
||||
|
||||
export const ns = ['logs']
|
||||
|
||||
const colors = {
|
||||
error: 'error',
|
||||
warning: 'warning',
|
||||
info: 'secondary',
|
||||
debug: 'base',
|
||||
}
|
||||
|
||||
const DraftLogEntry = ({ type, line, t }) => {
|
||||
// Some lines are arrays, handle each entry individually
|
||||
if (Array.isArray(line))
|
||||
return line.reverse().map((l, key) => <DraftLogEntry line={l} {...{ t, type, key }} />)
|
||||
|
||||
let title = 'Unsure how to treat this error'
|
||||
const data = []
|
||||
|
||||
// Simple error string
|
||||
if (typeof line === 'string') title = line
|
||||
if (typeof line === 'object') {
|
||||
data.push(analyzeDraftLogLine({ type, line, t }))
|
||||
title = line.toString()
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={`relative my-2 bg-${colors[type]} bg-opacity-5 -ml-4 -mr-4 sm:ml-0 sm:mr-0`}>
|
||||
<div
|
||||
className={`
|
||||
lg:border-0 lg:border-l-4 px-4
|
||||
shadow text-base border-${colors[type]}
|
||||
flex flex-col items-start
|
||||
`}
|
||||
>
|
||||
<div className={`flex flex-row gap-1 py-1`}>
|
||||
<span className={`hidden lg:block font-bold uppercase text-${colors[type]}`}>{type}</span>
|
||||
<span className={`hidden lg:block font-bold text-${colors[type]}`}>|</span>
|
||||
<span className="font-medium px-2 lg:px-0">{title}</span>
|
||||
</div>
|
||||
<div className="popout-content pl-2">{data}</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const DraftLogs = ({ type, t, lines = [] }) =>
|
||||
lines.length > 0 ? (
|
||||
<>
|
||||
<h3>{t(type)}</h3>
|
||||
{lines.reverse().map((line, key) => (
|
||||
<DraftLogEntry {...{ type, key, line, t }} />
|
||||
))}
|
||||
</>
|
||||
) : null
|
||||
|
||||
const extractLogs = (pattern) => {
|
||||
const logs = {}
|
||||
for (const type of ['error', 'warning', 'info', 'debug']) {
|
||||
logs[type] = [...pattern.store.logs[type]]
|
||||
for (const store of pattern.setStores) logs[type].push(...store.logs[type])
|
||||
}
|
||||
|
||||
return logs
|
||||
}
|
||||
|
||||
export const LogView = ({
|
||||
pattern,
|
||||
patternConfig,
|
||||
settings,
|
||||
ui,
|
||||
update,
|
||||
language,
|
||||
account,
|
||||
DynamicDocs,
|
||||
}) => {
|
||||
const { t } = useTranslation(ns)
|
||||
|
||||
try {
|
||||
pattern.draft(settings)
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
}
|
||||
const logs = extractLogs(pattern)
|
||||
|
||||
return (
|
||||
<div className="max-w-4xl mx-auto px-4 pb-8">
|
||||
<h1>{t('logs')}</h1>
|
||||
{Object.entries(logs).map(([type, lines], key) => (
|
||||
<DraftLogs {...{ type, lines, t, key }} />
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
11
sites/shared/components/workbench/views/logs/logs.en.yaml
Normal file
11
sites/shared/components/workbench/views/logs/logs.en.yaml
Normal file
|
@ -0,0 +1,11 @@
|
|||
logs: Logs
|
||||
error: Error messages
|
||||
warning: Warning messages
|
||||
info: Info messages
|
||||
debug: Debug messages
|
||||
seeLinkOrClick: See {{ link }} or { click }
|
||||
notDesctructured: This most likely means that { var } was not desctructured as a draft method parameter.
|
||||
designVarUndefined: We were unable to draft this pattern because { var } is undefined in { file }
|
||||
otherVarUndefined: The { var } variable is undefined.
|
||||
checkForDetailsOrClick: Check { file } for details or { click }.
|
||||
stacktrace: Stack trace
|
|
@ -255,8 +255,9 @@ export const nsMerge = (...args) => {
|
|||
const ns = new Set()
|
||||
for (const arg of args) {
|
||||
if (typeof arg === 'string') ns.add(arg)
|
||||
else if (Array.isArray(arg)) ns.add(nsMerge(...arg))
|
||||
else console.log('Unexpected namespect type:', { arg })
|
||||
else if (Array.isArray(arg)) {
|
||||
for (const el of nsMerge(...arg)) ns.add(el)
|
||||
} else console.log('Unexpected namespect type:', { arg })
|
||||
}
|
||||
|
||||
return [...ns]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue