1
0
Fork 0

feat: EditSettings view

This commit is contained in:
joostdecock 2025-02-23 12:31:52 +01:00
parent 9ab297a471
commit a50e3ca50e
8 changed files with 406 additions and 150 deletions

View file

@ -238,9 +238,11 @@ collection:
'@freesewing/snapseries': *freesewing
react:
_:
"@codemirror/lang-yaml": "^6.1.2"
"@uiw/react-codemirror": "^4.23.8"
d3-drag: "3.0.0"
d3-selection: "3.0.0"
diff: "^7.0.0"
file-saver: "^2.0.5"
"highlight.js": "^11.11.1"
html-react-parser: "^5.2.2"
@ -248,11 +250,13 @@ react:
jotai-location: "^0.5.5"
luxon: "^3.5.0"
pdfkit: "^0.16.0"
react-diff-viewer-continued: "^4.0.5"
react-dropzone: "^14.3.5"
react-zoom-pan-pinch: "^3.7.0"
svg-to-pdfkit: "^0.1.8"
use-local-storage-state: "^19.5.0"
web-worker: "^1.5.0"
yaml: "^2.7.0"
peer:
react: &react "^19.0.0"
utils:

View file

@ -81,6 +81,7 @@ packageJson:
"./components/Control": "./components/Control/index.mjs"
"./components/CopyToClipboardButton": "./components/CopyToClipboardButton/index.mjs"
"./components/Design": "./components/Design/index.mjs"
"./components/DiffViewer": "./components/DiffViewer/index.mjs"
"./components/Docusaurus": "./components/Docusaurus/index.mjs"
"./components/Editor": "./components/Editor/index.mjs"
"./components/Heading": "./components/Heading/index.mjs"
@ -120,6 +121,7 @@ packageJson:
"./hooks/useDesign": "./hooks/useDesign/index.mjs"
"./hooks/useDesignTranslation": "./hooks/useDesignTranslation/index.mjs"
"./hooks/useSelection": "./hooks/useSelection/index.mjs"
"./hooks/useStateObject": "./hooks/useStateObject/index.mjs"
# Lib
"./lib/RestClient": "./lib/RestClient/index.mjs"
"./lib/logoPath": "./components/Logo/path.mjs"

268
package-lock.json generated
View file

@ -23951,6 +23951,21 @@
"@lezer/common": "^1.1.0"
}
},
"node_modules/@codemirror/lang-yaml": {
"version": "6.1.2",
"resolved": "https://registry.npmjs.org/@codemirror/lang-yaml/-/lang-yaml-6.1.2.tgz",
"integrity": "sha512-dxrfG8w5Ce/QbT7YID7mWZFKhdhsaTNOYjOkSIMt1qmC4VQnXSDSYVHHHn8k6kJUfIhtLo8t1JJgltlxWdsITw==",
"license": "MIT",
"dependencies": {
"@codemirror/autocomplete": "^6.0.0",
"@codemirror/language": "^6.0.0",
"@codemirror/state": "^6.0.0",
"@lezer/common": "^1.2.0",
"@lezer/highlight": "^1.2.0",
"@lezer/lr": "^1.0.0",
"@lezer/yaml": "^1.0.0"
}
},
"node_modules/@codemirror/language": {
"version": "6.10.8",
"resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.10.8.tgz",
@ -26309,6 +26324,188 @@
"tslib": "^2.4.0"
}
},
"node_modules/@emotion/babel-plugin": {
"version": "11.13.5",
"resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.13.5.tgz",
"integrity": "sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==",
"license": "MIT",
"dependencies": {
"@babel/helper-module-imports": "^7.16.7",
"@babel/runtime": "^7.18.3",
"@emotion/hash": "^0.9.2",
"@emotion/memoize": "^0.9.0",
"@emotion/serialize": "^1.3.3",
"babel-plugin-macros": "^3.1.0",
"convert-source-map": "^1.5.0",
"escape-string-regexp": "^4.0.0",
"find-root": "^1.1.0",
"source-map": "^0.5.7",
"stylis": "4.2.0"
}
},
"node_modules/@emotion/babel-plugin/node_modules/babel-plugin-macros": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz",
"integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.12.5",
"cosmiconfig": "^7.0.0",
"resolve": "^1.19.0"
},
"engines": {
"node": ">=10",
"npm": ">=6"
}
},
"node_modules/@emotion/babel-plugin/node_modules/convert-source-map": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
"integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==",
"license": "MIT"
},
"node_modules/@emotion/babel-plugin/node_modules/cosmiconfig": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz",
"integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==",
"license": "MIT",
"dependencies": {
"@types/parse-json": "^4.0.0",
"import-fresh": "^3.2.1",
"parse-json": "^5.0.0",
"path-type": "^4.0.0",
"yaml": "^1.10.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/@emotion/babel-plugin/node_modules/source-map": {
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
"integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==",
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/@emotion/babel-plugin/node_modules/yaml": {
"version": "1.10.2",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
"integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
"license": "ISC",
"engines": {
"node": ">= 6"
}
},
"node_modules/@emotion/cache": {
"version": "11.14.0",
"resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.14.0.tgz",
"integrity": "sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==",
"license": "MIT",
"dependencies": {
"@emotion/memoize": "^0.9.0",
"@emotion/sheet": "^1.4.0",
"@emotion/utils": "^1.4.2",
"@emotion/weak-memoize": "^0.4.0",
"stylis": "4.2.0"
}
},
"node_modules/@emotion/css": {
"version": "11.13.5",
"resolved": "https://registry.npmjs.org/@emotion/css/-/css-11.13.5.tgz",
"integrity": "sha512-wQdD0Xhkn3Qy2VNcIzbLP9MR8TafI0MJb7BEAXKp+w4+XqErksWR4OXomuDzPsN4InLdGhVe6EYcn2ZIUCpB8w==",
"license": "MIT",
"dependencies": {
"@emotion/babel-plugin": "^11.13.5",
"@emotion/cache": "^11.13.5",
"@emotion/serialize": "^1.3.3",
"@emotion/sheet": "^1.4.0",
"@emotion/utils": "^1.4.2"
}
},
"node_modules/@emotion/hash": {
"version": "0.9.2",
"resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz",
"integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==",
"license": "MIT"
},
"node_modules/@emotion/memoize": {
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz",
"integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==",
"license": "MIT"
},
"node_modules/@emotion/react": {
"version": "11.14.0",
"resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.14.0.tgz",
"integrity": "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.18.3",
"@emotion/babel-plugin": "^11.13.5",
"@emotion/cache": "^11.14.0",
"@emotion/serialize": "^1.3.3",
"@emotion/use-insertion-effect-with-fallbacks": "^1.2.0",
"@emotion/utils": "^1.4.2",
"@emotion/weak-memoize": "^0.4.0",
"hoist-non-react-statics": "^3.3.1"
},
"peerDependencies": {
"react": ">=16.8.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@emotion/serialize": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.3.tgz",
"integrity": "sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==",
"license": "MIT",
"dependencies": {
"@emotion/hash": "^0.9.2",
"@emotion/memoize": "^0.9.0",
"@emotion/unitless": "^0.10.0",
"@emotion/utils": "^1.4.2",
"csstype": "^3.0.2"
}
},
"node_modules/@emotion/sheet": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz",
"integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==",
"license": "MIT"
},
"node_modules/@emotion/unitless": {
"version": "0.10.0",
"resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.10.0.tgz",
"integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==",
"license": "MIT"
},
"node_modules/@emotion/use-insertion-effect-with-fallbacks": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.2.0.tgz",
"integrity": "sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==",
"license": "MIT",
"peerDependencies": {
"react": ">=16.8.0"
}
},
"node_modules/@emotion/utils": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.2.tgz",
"integrity": "sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==",
"license": "MIT"
},
"node_modules/@emotion/weak-memoize": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz",
"integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==",
"license": "MIT"
},
"node_modules/@eslint-community/eslint-utils": {
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz",
@ -27721,6 +27918,17 @@
"@lezer/common": "^1.0.0"
}
},
"node_modules/@lezer/yaml": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@lezer/yaml/-/yaml-1.0.3.tgz",
"integrity": "sha512-GuBLekbw9jDBDhGur82nuwkxKQ+a3W5H0GfaAthDXcAu+XdpS43VlnxA9E9hllkpSP5ellRDKjLLj7Lu9Wr6xA==",
"license": "MIT",
"dependencies": {
"@lezer/common": "^1.2.0",
"@lezer/highlight": "^1.0.0",
"@lezer/lr": "^1.4.0"
}
},
"node_modules/@marijn/find-cluster-break": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@marijn/find-cluster-break/-/find-cluster-break-1.0.2.tgz",
@ -34097,6 +34305,12 @@
"node": ">=8"
}
},
"node_modules/classnames": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz",
"integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==",
"license": "MIT"
},
"node_modules/clean-css": {
"version": "5.3.3",
"resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.3.tgz",
@ -37368,7 +37582,6 @@
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz",
"integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==",
"dev": true,
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.3.1"
@ -39868,6 +40081,12 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/find-root": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz",
"integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==",
"license": "MIT"
},
"node_modules/find-up": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-7.0.0.tgz",
@ -48070,6 +48289,12 @@
"node": ">= 4.0.0"
}
},
"node_modules/memoize-one": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz",
"integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==",
"license": "MIT"
},
"node_modules/meow": {
"version": "12.1.1",
"resolved": "https://registry.npmjs.org/meow/-/meow-12.1.1.tgz",
@ -54643,6 +54868,26 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/react-diff-viewer-continued": {
"version": "4.0.5",
"resolved": "https://registry.npmjs.org/react-diff-viewer-continued/-/react-diff-viewer-continued-4.0.5.tgz",
"integrity": "sha512-L43gIPdhHgu1MYdip4vNqAt5s2JLICKe2/RyGUr2ohAxfhYaH1+QZ6vBO0qgo4xGBhE3jmvbOA/swq4/gdS/0g==",
"license": "MIT",
"dependencies": {
"@emotion/css": "^11.13.5",
"@emotion/react": "^11.14.0",
"classnames": "^2.5.1",
"diff": "^5.2.0",
"memoize-one": "^6.0.0"
},
"engines": {
"node": ">= 16"
},
"peerDependencies": {
"react": "^15.3.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
"react-dom": "^15.3.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
}
},
"node_modules/react-dom": {
"version": "19.0.0",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.0.0.tgz",
@ -57881,6 +58126,12 @@
"postcss": "^8.4.31"
}
},
"node_modules/stylis": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz",
"integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==",
"license": "MIT"
},
"node_modules/sucrase": {
"version": "3.35.0",
"resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz",
@ -61968,9 +62219,11 @@
"version": "3.3.0-rc.1",
"license": "MIT",
"dependencies": {
"@codemirror/lang-yaml": "^6.1.2",
"@uiw/react-codemirror": "^4.23.8",
"d3-drag": "3.0.0",
"d3-selection": "3.0.0",
"diff": "^7.0.0",
"file-saver": "^2.0.5",
"highlight.js": "^11.11.1",
"html-react-parser": "^5.2.2",
@ -61978,11 +62231,13 @@
"jotai-location": "^0.5.5",
"luxon": "^3.5.0",
"pdfkit": "^0.16.0",
"react-diff-viewer-continued": "^4.0.5",
"react-dropzone": "^14.3.5",
"react-zoom-pan-pinch": "^3.7.0",
"svg-to-pdfkit": "^0.1.8",
"use-local-storage-state": "^19.5.0",
"web-worker": "^1.5.0"
"web-worker": "^1.5.0",
"yaml": "^2.7.0"
},
"devDependencies": {},
"engines": {
@ -61996,6 +62251,15 @@
"react": "^19.0.0"
}
},
"packages/react/node_modules/diff": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/diff/-/diff-7.0.0.tgz",
"integrity": "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==",
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.3.1"
}
},
"packages/rehype-highlight-lines": {
"version": "3.3.0-rc.1",
"extraneous": true,

View file

@ -0,0 +1,8 @@
import React from 'react'
import { diffWords, diffJson } from 'diff'
import ReactDiffViewer from 'react-diff-viewer-continued'
export const diffJSON = (from, to) => diffJson(from, to)
export const diffCheck = (from, to) => diffWords(from, to)
export const DiffViewer = (props) => <ReactDiffViewer {...props} />

View file

@ -1,14 +1,26 @@
// Dependencies
import { linkClasses, horFlexClasses, patternUrlFromState } from '@freesewing/utils'
import { linkClasses, horFlexClasses, patternUrlFromState, clone } from '@freesewing/utils'
import { exportTypes, handleExport } from '../../lib/export/index.mjs'
import yaml from 'yaml'
// Hooks
import React, { useState } from 'react'
import { useStateObject } from '@freesewing/react/hooks/useStateObject'
// Components
import { H1, H2, H3, H5 } from '@freesewing/react/components/Heading'
import { H1, H2, H3, H4, H5 } from '@freesewing/react/components/Heading'
import { Popout } from '@freesewing/react/components/Popout'
import { DiffViewer, diffCheck } from '@freesewing/react/components/DiffViewer'
import { HeaderMenu } from '../HeaderMenu.mjs'
import { EditIcon, CodeIcon, TipIcon, PrintIcon } from '@freesewing/react/components/Icon'
import {
ResetIcon,
OkIcon,
EditIcon,
ExpandIcon,
CodeIcon,
TipIcon,
PrintIcon,
} from '@freesewing/react/components/Icon'
import CodeMirror from '@uiw/react-codemirror'
import { yaml as yamlLang } from '@codemirror/lang-yaml'
/**
* This is the editSettings view
@ -20,13 +32,20 @@ import CodeMirror from '@uiw/react-codemirror'
*/
export const EditSettingsView = (props) => {
const [settings, setSettings] = useState(props.state.settings)
const { state, config, update } = props
return (
<>
<HeaderMenu state={state} {...{ config, update }} />
<div className="tw-m-auto tw-mt-8 tw-max-w-2xl tw-px-4 tw-mb-8">
<H1>Documenation</H1>
<PrimedSettingsEditor {...props} {...{ runningSettings, dconf }} />
<div className="tw-m-auto tw-mt-8 tw-max-w-4xl tw-px-4 tw-mb-8">
<H1>Edit settings by hand</H1>
<p className="tw-mb-4">
You can hand-edit your pattern settings below.
<br />
The changes will not take effect until you click the <b>Apply changes</b> button at the
bottom.
</p>
<PrimedSettingsEditor {...props} />
</div>
</>
)
@ -39,70 +58,38 @@ export const PrimedSettingsEditor = (props) => {
/*
* Destructure props
*/
const { runningSettings } = props
const { state } = props
/*
* React state
*/
/* eslint-disable-next-line no-unused-vars */
const [mSettings, update, setMSettings] = useStateObject(runningSettings) // Holds the settings
const [validationReport, setValidationReport] = useState(false) // Holds the validatino report
const [settings, update, setSettings] = useStateObject(state.settings) // Holds the settings
const [showDelta, setShowDelta] = useState(false)
const [deployOngoing, setDeployOngoing] = useState(false)
const [doValidate, setDoValidate] = useState(false)
const [kiosk, setKiosk] = useState(false)
const [localJson, setLocalJson] = useState(JSON.stringify(runningSettings, null, 2)) // Holds the settings as JSON
const [localYaml, setLocalYaml] = useState(yaml.stringify(runningSettings)) // Holds the settings as YAML
const [localYaml, setLocalYaml] = useState(yaml.stringify(state.settings)) // Holds the settings as YAML
/*
* Method to revert to running settings
* Method to revert to the settings in the editor state
*/
const revert = () => setMSettings(cloneAsPojo(runningSettings))
/*
* API client
*/
const { api } = useApi()
/*
* Loading context
*/
const { setLoadingStatus } = useContext(LoadingStatusContext)
/*
* Helper method to deploy the settings
*/
const deploy = async () => {
setLoadingStatus([true, 'Uploading settings'])
setDeployOngoing(true)
const result = await api.deploy(mSettings)
return result[1] === 204
? setLoadingStatus([true, 'Settings updated', true, true])
: setLoadingStatus([true, `Unable to deploy the settings`, true, false])
const revert = () => {
setSettings(clone(state.settings))
setLocalYaml(yaml.stringify(state.settings))
}
if (!mSettings.cluster) return null
/*
* Method to save to the settings into the editor state
*/
const save = () => {
props.update.state('settings', yaml.parse(localYaml))
}
if (!settings) return null
/*
* Handle settings delta
*/
const delta =
diffCheck(yaml.stringify(runningSettings), yaml.stringify(mSettings)).length > 1 ? true : false
if (deployOngoing)
return (
<>
<Box color="success">
<div className="flex flex-row items-center gap-2 text-success-content">
<div className="w-6 h-6">
<OkIcon className="w-6 h-6 text-success-content" stroke={4} />
</div>
Settings are being deployed
</div>
</Box>
<p>Please wait as Morio applies the new settings.</p>
</>
)
diffCheck(yaml.stringify(state.settings), yaml.stringify(settings)).length > 1 ? true : false
const onChangeYaml = (input) => {
let newSettings
@ -110,122 +97,59 @@ export const PrimedSettingsEditor = (props) => {
newSettings = yaml.parse(input)
if (newSettings) {
setLocalYaml(input)
setMSettings(newSettings)
setSettings(newSettings)
}
} catch (err) {
// This is fine
}
}
const onChangeJson = (input) => {
let newSettings
try {
newSettings = JSON.parse(input)
if (newSettings) {
setLocalJson(input)
setMSettings(newSettings)
}
} catch (err) {
console.log(err)
// This is fine
}
}
return (
<>
{mSettings.preseed?.base ? (
<Popout warning>
<h5>These settings are preseeded</h5>
<p>
This Morio deployment uses preseeded settings. This means the settings are loaded from a
remote system, typically a version control system like GitLab or GitHub.
</p>
<p>
While you <b>can</b> update the settings here, those settings will be lost next time
Morio is reseeded.
<br />
You probably should <b>update the preseeded setting instead</b>.
</p>
</Popout>
) : null}
{doValidate ? (
<CodeMirror
value={localYaml}
height="50vh"
onChange={onChangeYaml}
extensions={[yamlLang()]}
/>
{delta ? (
<>
<ShowSettingsValidation
{...{
api,
deploy,
mSettings,
setLoadingStatus,
setValidationReport,
validationReport,
}}
/>
<p className="text-right w-full">
<H4>You have made changes</H4>
<p>Your settings have been edited, and are now different from the editor settings.</p>
<div className="tw-grid tw-grid-cols-1 lg:tw-grid-cols-3 tw-gap-2 tw-w-full">
<button
className="btn btn-primary btn-outline btn-s btn-sm"
onClick={() => setDoValidate(false)}
className="tw-daisy-btn tw-daisy-btn-primary tw-daisy-btn-outline"
onClick={() => setShowDelta(!showDelta)}
>
<NoteIcon /> Back to editor
{showDelta ? 'Hide' : 'Show'} Changes
</button>
</p>
</>
) : (
<div className={kiosk ? 'absolute top-12 left-0 w-screen h-screen z-50 bg-base-100' : ''}>
<Tabs tabs="YAML, JSON">
<Tab id="json" name="test" label="As YAML">
<CodeMirror
value={localYaml}
height={kiosk ? '90vh' : '70vh'}
onChange={onChangeYaml}
/>
</Tab>
<Tab id="yaml" label="As JSON">
<CodeMirror
value={localJson}
height={kiosk ? '90vh' : '70vh'}
extensions={[jsonLang()]}
onChange={onChangeJson}
/>
</Tab>
</Tabs>
<div className="my-2 w-full flex flex-row flex-wrap items-center gap-2 justify-center">
<button
className="btn btn-primary btn-outline flex flex-row items-center gap-2"
onClick={() => setKiosk(!kiosk)}
className="tw-daisy-btn tw-daisy-btn-primary tw-flex tw-flex-row tw-items-center tw-justify-between"
onClick={save}
>
<ExpandIcon /> {kiosk ? 'Collapse' : 'Expand'}
<OkIcon stroke={3} />
Save Settings
</button>
<button className="btn btn-primary" onClick={() => setDoValidate(true)}>
Validate Settings
<button
className="tw-daisy-btn tw-daisy-btn-error tw-daisy-btn-outline tw-flex tw-flex-row tw-items-center tw-justify-between"
onClick={revert}
>
<ResetIcon />
Revert Settings
</button>
</div>
</div>
)}
{!doValidate && delta ? (
<Popout note>
<h4>You have made changes that are yet to be deployed</h4>
<p>The settings have been edited, and are now different from the deployed settings.</p>
{showDelta ? (
<div className="my-4 w-full overflow-scroll">
<div className="tw-my-4 tw-w-full tw-overflow-scroll">
<DiffViewer
from={yaml.stringify(runningSettings)}
to={yaml.stringify(mSettings)}
oldValue={yaml.stringify(state.settings)}
newValue={yaml.stringify(settings)}
extraLinesSurroundingDiff="1"
fromTitle="Currently deployed settings"
toTitle="Your edits"
/>
</div>
) : null}
<div className="flex flex-row flex-wrap gap-2 justify-end w-full">
<button className="btn btn-warning btn-ghost" onClick={revert}>
Revert to Running Settings
</button>
<button
className="btn btn-primary btn-outline"
onClick={() => setShowDelta(!showDelta)}
>
{showDelta ? 'Hide' : 'Show'} Settings Delta
</button>
</div>
</Popout>
</>
) : null}
</>
)

View file

@ -105,7 +105,7 @@ export const viewLabels = {
t: 'Export Pattern',
d: 'Export this pattern into a variety of formats',
},
edit: {
editSettings: {
t: 'Edit settings by hand',
d: "Throw caution to the wind, and hand-edit the pattern's settings",
},

View file

@ -0,0 +1,48 @@
import React, { useState } from 'react'
import set from 'lodash/set.js'
import unset from 'lodash/unset.js'
/*
* Helper method to handle object updates
*
* This is a wrapper around lodash.set() with extra support for unsetting data.
*
* @param {object} obj - The object to update
* @param {array|string} path - The path to the property to update either as an array or string in dot notation
* @param {mixed} val - The value to set. If the value holds the string 'unset' the property will be removed
*
* @return {object} obj - The mutated object
*/
export const objUpdate = (obj = {}, path, val = undefined) => {
if (val === undefined) {
if (Array.isArray(path) && Array.isArray(path[0])) {
for (const [ipath, ival = undefined] of path) {
if (ival === undefined) unset(obj, ipath)
else set(obj, ipath, ival)
}
} else unset(obj, path)
} else set(obj, path, val)
return obj
}
/*
* This hooks provides an React state update with an
* update method that allows us to set deeply nested
* properties.
*/
export const useStateObject = (dflt = {}) => {
const [obj, setObj] = useState(dflt)
const replace = (val) => setObj(val)
const update = (path, val, altObj = false) => {
const newObj = altObj ? { ...altObj } : { ...obj }
objUpdate(newObj, path, val)
setObj(newObj)
return newObj
}
return [obj, update, replace]
}

View file

@ -34,6 +34,7 @@
"./components/Control": "./components/Control/index.mjs",
"./components/CopyToClipboardButton": "./components/CopyToClipboardButton/index.mjs",
"./components/Design": "./components/Design/index.mjs",
"./components/DiffViewer": "./components/DiffViewer/index.mjs",
"./components/Docusaurus": "./components/Docusaurus/index.mjs",
"./components/Editor": "./components/Editor/index.mjs",
"./components/Heading": "./components/Heading/index.mjs",
@ -71,6 +72,7 @@
"./hooks/useDesign": "./hooks/useDesign/index.mjs",
"./hooks/useDesignTranslation": "./hooks/useDesignTranslation/index.mjs",
"./hooks/useSelection": "./hooks/useSelection/index.mjs",
"./hooks/useStateObject": "./hooks/useStateObject/index.mjs",
"./lib/RestClient": "./lib/RestClient/index.mjs",
"./lib/logoPath": "./components/Logo/path.mjs"
},
@ -82,9 +84,11 @@
"react": "^19.0.0"
},
"dependencies": {
"@codemirror/lang-yaml": "^6.1.2",
"@uiw/react-codemirror": "^4.23.8",
"d3-drag": "3.0.0",
"d3-selection": "3.0.0",
"diff": "^7.0.0",
"file-saver": "^2.0.5",
"highlight.js": "^11.11.1",
"html-react-parser": "^5.2.2",
@ -92,11 +96,13 @@
"jotai-location": "^0.5.5",
"luxon": "^3.5.0",
"pdfkit": "^0.16.0",
"react-diff-viewer-continued": "^4.0.5",
"react-dropzone": "^14.3.5",
"react-zoom-pan-pinch": "^3.7.0",
"svg-to-pdfkit": "^0.1.8",
"use-local-storage-state": "^19.5.0",
"web-worker": "^1.5.0"
"web-worker": "^1.5.0",
"yaml": "^2.7.0"
},
"devDependencies": {},
"files": [