diff --git a/.changelog/361.feature.md b/.changelog/361.feature.md new file mode 100644 index 00000000..1175b273 --- /dev/null +++ b/.changelog/361.feature.md @@ -0,0 +1 @@ +Add initial ERC-8004 support diff --git a/src/backend/api.ts b/src/backend/api.ts index 31a281af..8ee3d754 100644 --- a/src/backend/api.ts +++ b/src/backend/api.ts @@ -20,6 +20,7 @@ import { toast } from 'sonner' import { isMachineRemoved } from '../components/MachineStatusIcon/isMachineRemoved.ts' import { trackEvent } from 'fathom-client' import { getOasisAddressBytesFromEvm } from '../utils/helpers.ts' +import { addRofl8004ServiceToCompose, hasRofl8004ServiceSecrets } from '../utils/rofl-8004.ts' const BACKEND_URL = import.meta.env.VITE_ROFL_APP_BACKEND @@ -432,7 +433,12 @@ export function useCreateAndDeployApp() { const manifest = yaml.stringify( fillTemplate(roflTemplateYaml, appData.metadata!, build, network, appId, address), ) - const compose = template.yaml.compose + + let compose = template.yaml.compose + if (hasRofl8004ServiceSecrets(appData)) { + compose = addRofl8004ServiceToCompose(template.yaml.compose, appData) + } + console.log('Build?') setCurrentStep('building') diff --git a/src/components/CodeDisplay/index.tsx b/src/components/CodeDisplay/index.tsx index 28b4da37..73384f18 100644 --- a/src/components/CodeDisplay/index.tsx +++ b/src/components/CodeDisplay/index.tsx @@ -15,14 +15,26 @@ const MonacoEditor = lazy(async () => { try { const monaco = await import('monaco-editor') const monacoReact = await import('@monaco-editor/react') + window.MonacoEnvironment = { - getWorker() { + getWorker(_, label) { + // JSON worker + if (label === 'json') { + return new Worker( + new URL( + '../../../node_modules/monaco-editor/esm/vs/language/json/json.worker.js', + import.meta.url, + ), + { type: 'module' }, + ) + } return new Worker( new URL('../../../node_modules/monaco-editor/esm/vs/editor/editor.worker.js', import.meta.url), { type: 'module' }, ) }, } + monacoReact.loader.config({ monaco }) return monacoReact @@ -43,6 +55,7 @@ type CodeDisplayProps = { onChange?: (value: string | undefined) => void // CSS white-space set in index.css for proper placeholder rendering placeholder?: string + language?: 'yaml' | 'json' } export const CodeDisplay: FC = ({ @@ -51,6 +64,7 @@ export const CodeDisplay: FC = ({ readOnly = true, onChange, placeholder, + language = 'yaml', }) => { const editorRef = useRef(null) const monacoInstanceRef = useRef(null) @@ -130,6 +144,25 @@ export const CodeDisplay: FC = ({ monacoInstance.editor.setModelMarkers(model, 'highlightYamlErrors', markers) } + const highlightJsonErrors = (newData: string | undefined) => { + const monacoInstance = monacoInstanceRef.current + if (!monacoInstance || !editorRef.current || newData === undefined) { + return + } + const model = editorRef.current.getModel() + if (!model) return + + const markers: monaco.editor.IMarkerData[] = [] + + try { + JSON.parse(newData) + } catch (e) { + console.warn(e) + } + + monacoInstance.editor.setModelMarkers(model, 'highlightJsonErrors', markers) + } + const handleEditorDidMount = ( editor: monaco.editor.IStandaloneCodeEditor, monacoInstance: typeof monaco, @@ -140,7 +173,13 @@ export const CodeDisplay: FC = ({ } const handleEditorChange = (newData: string | undefined) => { - if (!readOnly) highlightYamlErrors(newData) + if (!readOnly) { + if (language === 'yaml') { + highlightYamlErrors(newData) + } else if (language === 'json') { + highlightJsonErrors(newData) + } + } highlightErrorLogs(newData) @@ -152,7 +191,7 @@ export const CodeDisplay: FC = ({ }> } - language="yaml" + language={language} value={data} theme="customTheme" beforeMount={handleEditorWillMount} diff --git a/src/components/InputFormField/index.tsx b/src/components/InputFormField/index.tsx index a0485534..2d2a8071 100644 --- a/src/components/InputFormField/index.tsx +++ b/src/components/InputFormField/index.tsx @@ -4,7 +4,13 @@ import { Input } from '@oasisprotocol/ui-library/src/components/ui/input' import { Textarea } from '@oasisprotocol/ui-library/src/components/ui/textarea' import { Label } from '@oasisprotocol/ui-library/src/components/ui/label' import { Button } from '@oasisprotocol/ui-library/src/components/ui/button' -import { Eye, EyeOff } from 'lucide-react' +import { Eye, EyeOff, Info } from 'lucide-react' +import { + Tooltip, + TooltipContent, + TooltipTrigger, + TooltipProvider, +} from '@oasisprotocol/ui-library/src/components/ui/tooltip' type InputFormFieldProps = { control: Control @@ -14,6 +20,7 @@ type InputFormFieldProps = { type?: 'input' | 'password' | 'number' | 'textarea' disabled?: boolean min?: number + info?: string } export const InputFormField = ({ @@ -24,6 +31,7 @@ export const InputFormField = ({ type = 'input', disabled = false, min, + info, }: InputFormFieldProps): ReactNode => { const [showPassword, setShowPassword] = useState(false) @@ -40,7 +48,21 @@ export const InputFormField = ({ return (
- {label && } + {label && ( +
+ + {info && ( + + + + + + {info} + + + )} +
+ )} ({ )}
) : ( -