diff --git a/sites/backend/src/models/pattern.mjs b/sites/backend/src/models/pattern.mjs
index b52aebbaee2..c1a59aad22c 100644
--- a/sites/backend/src/models/pattern.mjs
+++ b/sites/backend/src/models/pattern.mjs
@@ -2,6 +2,7 @@ import { log } from '../utils/log.mjs'
import { capitalize } from '../utils/index.mjs'
import { setPatternAvatar } from '../utils/sanity.mjs'
import yaml from 'js-yaml'
+import { SetModel } from './set.mjs'
export function PatternModel(tools) {
this.config = tools.config
@@ -11,6 +12,7 @@ export function PatternModel(tools) {
this.rbac = tools.rbac
this.encryptedFields = ['data', 'img', 'name', 'notes', 'settings']
this.clear = {} // For holding decrypted data
+ this.Set = new SetModel(tools)
return this
}
@@ -218,8 +220,8 @@ PatternModel.prototype.reveal = async function () {
}
if (this.record.cset.measies) this.record.cset.measies = JSON.parse(this.record.cset.measies)
}
- if (this.record.set) {
- if (this.record.set.measies) this.record.set.measies = JSON.parse(this.record.set.measies)
+ if (this.record?.set) {
+ this.record.set = this.Set.revealSet(this.record.set)
}
return this
diff --git a/sites/org/pages/patterns/[id]/edit.mjs b/sites/org/pages/patterns/[id]/edit.mjs
new file mode 100644
index 00000000000..27784f46253
--- /dev/null
+++ b/sites/org/pages/patterns/[id]/edit.mjs
@@ -0,0 +1,77 @@
+// Hooks
+import { useEffect, useState } from 'react'
+import { useAccount } from 'shared/hooks/use-account.mjs'
+import { useBackend } from 'shared/hooks/use-backend.mjs'
+import { useDesign } from 'shared/hooks/use-design.mjs'
+// Dependencies
+import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
+// Components
+import { PageWrapper, ns as pageNs } from 'shared/components/wrappers/page.mjs'
+import { Workbench, ns as wbNs } from 'shared/components/workbench/index.mjs'
+import { WorkbenchLayout } from 'site/components/layouts/workbench.mjs'
+import { Null } from 'shared/components/null.mjs'
+import { DynamicOrgDocs as DynamicDocs } from 'site/components/dynamic-org-docs.mjs'
+
+// Translation namespaces used on this page
+const namespaces = [...new Set(['aaron', ...wbNs, ...pageNs])]
+
+const EditPatternPage = ({ page, id }) => {
+ // State
+ const [pattern, setPattern] = useState(false)
+
+ // Hooks
+ const { token } = useAccount()
+ const backend = useBackend(token)
+ const Design = useDesign(pattern?.design)
+
+ // Effect
+ useEffect(() => {
+ const getPattern = async () => {
+ const result = await backend.getPattern(id)
+ if (result.success) setPattern(result.data.pattern)
+ }
+ // Guard against loops as the backend object is recreated on each render
+ if (pattern === false) getPattern()
+ else if (pattern.id && pattern.id !== id) getPattern()
+ }, [id, pattern.id, backend])
+
+ const baseSettings = pattern
+ ? {
+ ...pattern.settings,
+ measurements: pattern.set ? pattern.set.measies : pattern.cset.measies,
+ }
+ : null
+
+ return (
+
+
+
+ )
+}
+
+export default EditPatternPage
+
+export async function getStaticProps({ locale, params }) {
+ return {
+ props: {
+ ...(await serverSideTranslations(locale, namespaces)),
+ id: Number(params.id),
+ page: {
+ locale,
+ path: ['new', 'pattern', 'aaron', 'set', params.id],
+ title: '',
+ },
+ },
+ }
+}
+
+export async function getStaticPaths() {
+ return {
+ paths: [],
+ fallback: true,
+ }
+}
diff --git a/sites/shared/components/account/account.en.yaml b/sites/shared/components/account/account.en.yaml
index b96ff74d343..6b6dce5f9b1 100644
--- a/sites/shared/components/account/account.en.yaml
+++ b/sites/shared/components/account/account.en.yaml
@@ -25,7 +25,7 @@ img: Profile image
username: Username
compare: Metricset Comparison
consent: Consent & Privacy
-control: Power versus Simplicity
+control: User Experience
imperial: Units
units: Units
apikeys: API Keys
@@ -97,7 +97,7 @@ control4d: Reveals all features, keeps handrails and safety checks.
control5t: Get out of my way
control5d: Reveals all features, removes all handrails and safety checks.
controlShowMore: Show more options
-controlTitle: What do you prefer?
+controlTitle: Which user experience do you prefer?
# img
imgTitle: How about a picture?
imgDragAndDropImageHere: Drag and drop an image here
diff --git a/sites/shared/components/account/control.mjs b/sites/shared/components/account/control.mjs
index 13bcdbda03f..274aebf0e0a 100644
--- a/sites/shared/components/account/control.mjs
+++ b/sites/shared/components/account/control.mjs
@@ -13,7 +13,7 @@ import { ContinueButton } from 'shared/components/buttons/continue-button.mjs'
export const ns = ['account', 'toast']
-export const ControlSettings = ({ title = false, welcome = false }) => {
+export const ControlSettings = ({ title = false, welcome = false, noBack = false }) => {
// Context
const { startLoading, stopLoading } = useContext(LoadingContext)
@@ -50,25 +50,16 @@ export const ControlSettings = ({ title = false, welcome = false }) => {
return (
{title ?
{t('controlTitle')}
: null}
- {[1, 2, 3, 4, 5].map((val) => {
- if (selection === 1 && val > 2) return null
- if (selection === 2 && val > 3) return null
- if (selection === 3 && val > 4) return null
- if (selection === 5 && val < 4) return null
- else
- return (
-
-
- {selection === 1 && val === 2 ? t('showMore') : t(`control${val}t`)}
-
- {selection > 1 ? (
-
- {t(`control${val}d`)}
-
- ) : null}
-
- )
- })}
+ {[1, 2, 3, 4, 5].map((val) => (
+
+ {t(`control${val}t`)}
+ {selection > 1 ? (
+
+ {t(`control${val}d`)}
+
+ ) : null}
+
+ ))}
{welcome ? (
<>
@@ -86,7 +77,7 @@ export const ControlSettings = ({ title = false, welcome = false }) => {
>
) : null}
>
- ) : (
+ ) : noBack ? null : (
)}
diff --git a/sites/shared/components/account/patterns.mjs b/sites/shared/components/account/patterns.mjs
index 2594e0e43b7..3c0df83c239 100644
--- a/sites/shared/components/account/patterns.mjs
+++ b/sites/shared/components/account/patterns.mjs
@@ -625,7 +625,6 @@ export const Patterns = ({ standAlone = false }) => {
{t('createANewPattern')}
{standAlone ? null : }
- {JSON.stringify(patterns, null, 2)}
)
}
diff --git a/sites/shared/components/account/shared.mjs b/sites/shared/components/account/shared.mjs
index 4f79baff7c4..986e0a24f95 100644
--- a/sites/shared/components/account/shared.mjs
+++ b/sites/shared/components/account/shared.mjs
@@ -3,7 +3,7 @@ import Link from 'next/link'
import { useTranslation } from 'next-i18next'
import {
CogIcon,
- ControlIcon,
+ FingerprintIcon as ControlIcon,
NewsletterIcon,
UnitsIcon,
CompareIcon,
diff --git a/sites/shared/components/modal/spinner.mjs b/sites/shared/components/modal/spinner.mjs
new file mode 100644
index 00000000000..c45d24a44f4
--- /dev/null
+++ b/sites/shared/components/modal/spinner.mjs
@@ -0,0 +1,8 @@
+import { ModalWrapper } from 'shared/components/wrappers/modal.mjs'
+import { Spinner } from 'shared/components/spinner.mjs'
+
+export const ModalSpinner = ({ color = 'warning' }) => (
+
+
+
+)
diff --git a/sites/shared/components/workbench/header.mjs b/sites/shared/components/workbench/header.mjs
index d5370844461..bbb6c3f641c 100644
--- a/sites/shared/components/workbench/header.mjs
+++ b/sites/shared/components/workbench/header.mjs
@@ -11,7 +11,7 @@ import {
ClearIcon,
CodeIcon,
CutIcon,
- HelpIcon,
+ FingerprintIcon,
MenuIcon,
OptionsIcon,
PrintIcon,
@@ -20,6 +20,8 @@ import {
import { Ribbon } from 'shared/components/ribbon.mjs'
import Link from 'next/link'
import { ModalMenu } from 'site/components/navigation/modal-menu.mjs'
+import { ModalWrapper } from 'shared/components/wrappers/modal.mjs'
+import { ControlSettings } from 'shared/components/account/control.mjs'
export const ns = ['workbench', 'sections']
@@ -150,8 +152,19 @@ const NavIcons = ({ setModal, setView, view }) => {
-
-
+
+ setModal(
+
+
+
+
+ )
+ }
+ >
+
>
)
diff --git a/sites/shared/components/workbench/index.mjs b/sites/shared/components/workbench/index.mjs
index 926394f02fa..ec3a5c603dc 100644
--- a/sites/shared/components/workbench/index.mjs
+++ b/sites/shared/components/workbench/index.mjs
@@ -10,17 +10,12 @@ import { objUpdate } from 'shared/utils.mjs'
// Components
import { WorkbenchHeader } from './header.mjs'
import { ErrorView } from 'shared/components/error/view.mjs'
+import { ModalSpinner } from 'shared/components/modal/spinner.mjs'
// Views
import { DraftView, ns as draftNs } from 'shared/components/workbench/views/draft/index.mjs'
import { SaveView, ns as saveNs } from 'shared/components/workbench/views/save/index.mjs'
-export const ns = ['workbench', ...draftNs, ...saveNs]
-
-const loadDefaultSettings = ({ locale = 'en', units = 'metric' }) => ({
- units,
- locale,
- embed: true,
-})
+export const ns = ['account', 'workbench', ...draftNs, ...saveNs]
const defaultUi = {
renderer: 'react',
@@ -28,31 +23,32 @@ const defaultUi = {
const draftViews = ['draft', 'test']
-export const Workbench = ({ design, Design, set = false, DynamicDocs = false }) => {
+export const Workbench = ({ design, Design, baseSettings, DynamicDocs, from }) => {
// Hooks
const { t, i18n } = useTranslation(ns)
const { language } = i18n
const { account } = useAccount()
- const defaultSettings = loadDefaultSettings({
- units: account.imperial ? 'imperial' : 'metric',
- locale: language,
- })
- if (set) defaultSettings.measurements = set.measies
-
// State
const [view, setView] = useView()
- const [settings, setSettings] = useState({ ...defaultSettings, embed: true })
- const [ui, setUi] = useState({ ...defaultUi })
+ const [settings, setSettings] = useState({ ...baseSettings, embed: true })
+ const [ui, setUi] = useState(defaultUi)
const [error, setError] = useState(false)
- // Effects
+ // Effect
useEffect(() => {
- if (set.measies) update.settings('measurements', set.measies)
- }, [set])
+ // Force re-render when baseSettings changes. Required when they are loaded async.
+ setSettings({ ...baseSettings, embed: true })
+ }, [baseSettings])
- // Don't bother without a set or Design
- if (!set || !Design) return null
+ // Helper methods for settings/ui updates
+ const update = {
+ settings: (path, val) => setSettings(objUpdate({ ...settings }, path, val)),
+ ui: (path, val) => setUi(objUpdate({ ...ui }, path, val)),
+ }
+
+ // Don't bother without a Design
+ if (!Design) return
// Short-circuit errors early
if (error)
@@ -62,13 +58,7 @@ export const Workbench = ({ design, Design, set = false, DynamicDocs = false })
{error}
>
)
-
- // Helper methods for settings/ui updates
- const update = {
- settings: (path, val) => setSettings(objUpdate({ ...settings }, path, val)),
- ui: (path, val) => setUi(objUpdate({ ...ui }, path, val)),
- }
-
+ console.log(baseSettings)
// Deal with each view
const viewProps = {
account,
@@ -108,7 +98,7 @@ export const Workbench = ({ design, Design, set = false, DynamicDocs = false })
}
// Save view
- else if (view === 'save') viewContent =
+ else if (view === 'save') viewContent =
return (
<>
diff --git a/sites/shared/components/workbench/menus/core-settings/index.mjs b/sites/shared/components/workbench/menus/core-settings/index.mjs
index e0e10620272..65fc99e180e 100644
--- a/sites/shared/components/workbench/menus/core-settings/index.mjs
+++ b/sites/shared/components/workbench/menus/core-settings/index.mjs
@@ -146,7 +146,7 @@ export const Setting = ({
return (
}
title={}
buttons={buttons}
@@ -167,26 +167,27 @@ export const CoreSettings = ({
language,
account,
DynamicDocs,
+ control,
}) => {
// FIXME: Update this namespace
const { t } = useTranslation(['i18n', 'core-settings', design])
const { setModal } = useContext(ModalContext)
+ // For the simplest experience, not core settings are shown at all
+ if (control < 2) return null
+
const settingsConfig = loadSettingsConfig({
language,
- control: account.control,
+ control,
sabool: settings.sabool,
parts: patternConfig.draftOrder,
})
- // Default control level is 2 (in case people are not logged in)
- const control = account.control || 2
const loadDocs = DynamicDocs
? (evt, setting = false) => {
evt.stopPropagation()
let path = `site/draft/core-settings`
if (setting) path += `/${setting}`
- console.log(path)
setModal(
@@ -210,19 +211,20 @@ export const CoreSettings = ({
)
return (
-
- {t('core-settings:coreSettings.t')}
-
-
- }
- openTitle={t('core-settings:coreSettings')}
- openButtons={openButtons}
- >
- {t('core-settings:coreSettings.d')}
+ <>
+
+ {control > 4 ? (
+
+ ) : (
+ <>
+
+
+ {t('core-settings:coreSettings')}
+
+
{t('core-settings:coreSettings.d')}
+ >
+ )}
+
{Object.keys(settingsConfig)
.filter((name) => settingsConfig[name].control <= control)
.map((name) => (
@@ -236,6 +238,6 @@ export const CoreSettings = ({
units={settings.units}
/>
))}
-
+ >
)
}
diff --git a/sites/shared/components/workbench/menus/design-options/index.mjs b/sites/shared/components/workbench/menus/design-options/index.mjs
index 6ead8300753..ec39c848507 100644
--- a/sites/shared/components/workbench/menus/design-options/index.mjs
+++ b/sites/shared/components/workbench/menus/design-options/index.mjs
@@ -173,8 +173,14 @@ export const DesignOptionGroup = ({
Option,
t,
loadDocs,
+ topLevel = false,
}) => (
- } openTitle={t(group)}>
+ }
+ openTitle={t(group)}
+ >
{Object.entries(options).map(([option, type]) =>
typeof type === 'string' ? (