Skip to content

Commit

Permalink
Public interface changes
Browse files Browse the repository at this point in the history
  • Loading branch information
riccardo-forina committed Nov 20, 2024
1 parent 65574ba commit 31b561c
Show file tree
Hide file tree
Showing 7 changed files with 137 additions and 51 deletions.
51 changes: 47 additions & 4 deletions packages/test-app/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,18 @@ import cssWorker from "monaco-editor/esm/vs/language/css/css.worker?worker";
import htmlWorker from "monaco-editor/esm/vs/language/html/html.worker?worker";
import tsWorker from "monaco-editor/esm/vs/language/typescript/ts.worker?worker";
import { worker } from "./rpc.ts";
import { useCallback, useState } from "react";
// import * as worker from "../../ui/src/OpenApiEditorWorker.ts";
import { useCallback, useRef, useState } from "react";
import {
Button,
Flex,
FlexItem,
PageSection,
Switch,
TextArea,
Title,
} from "@patternfly/react-core";
import { fromPromise } from "xstate";

self.MonacoEnvironment = {
getWorker(_, label) {
Expand All @@ -42,21 +46,57 @@ self.MonacoEnvironment = {
loader.config({ monaco });

function App() {
const [state, send] = useMachine(appMachine, { input: { spec: undefined } });
const [state, send] = useMachine(
appMachine.provide({
actors: {
parseSpec: fromPromise(async ({ input }) => {
if (input.spec) {
await worker.parseOasSchema(input.spec);
return true;
}
return false;
}),
},
}),
{ input: { spec: undefined } }
);
const [captureChanges, setCaptureChanges] = useState(true);
const [output, setOutput] = useState("");

const asYamlRef = useRef<(() => Promise<string>) | null>(null);

const onDocumentChange: OpenApiEditorProps["onDocumentChange"] = useCallback(
({ asJson, asYaml }) => {
console.log("DOCUMENT_CHANGE");
// this should be run in a debounce
if (captureChanges) {
asYaml().then((v) => setOutput(v.substring(0, 1000)));
asYaml().then((v) => {
setOutput(v.substring(0, 1000));
});
}
asYamlRef.current = asYaml;
},
[captureChanges]
[]
);

const onSaveClick = useCallback(async () => {
if (asYamlRef.current) {
const value = await asYamlRef.current();
setOutput(value);
send({
type: "SPEC",
content: `
{
"openapi": "3.0.3",
"info": {
"title": "Sample API"
}
}
`,
});
}
}, [send]);

switch (true) {
case state.matches("idle"):
return (
Expand Down Expand Up @@ -97,6 +137,9 @@ function App() {
</PageSection>
<PageSection variant={"secondary"}>
<Flex>
<FlexItem>
<Button onClick={onSaveClick}>Save and update</Button>
</FlexItem>
<Title headingLevel={"h6"}>
<Switch
isChecked={captureChanges}
Expand Down
14 changes: 7 additions & 7 deletions packages/test-app/src/AppMachine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export const appMachine = setup({
},
actors: {
checkPreviousSession: fromPromise<Context, Input>(({ input }) =>
Input(input),
Input(input)
),
parseSpec: fromPromise<boolean, Input>(({ input }) => ParseSpec(input)),
},
Expand Down Expand Up @@ -78,12 +78,6 @@ export const appMachine = setup({
previousWorkAvailable: {},
invalidSpec: {},
},
on: {
SPEC: {
target: "parsing",
actions: assign(({ event }) => ({ spec: event.content })),
},
},
},
parsing: {
initial: "parsing",
Expand Down Expand Up @@ -114,4 +108,10 @@ export const appMachine = setup({
},
parsed: {},
},
on: {
SPEC: {
target: ".parsing",
actions: assign(({ event }) => ({ spec: event.content })),
},
},
});
10 changes: 4 additions & 6 deletions packages/ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
"lib"
],
"peerDependencies": {
"@apicurio/data-models": "^1.1.28",
"@patternfly/patternfly": "^6.0.0",
"@patternfly/react-code-editor": "^6.0.0",
"@patternfly/react-core": "^6.0.0",
Expand All @@ -24,11 +23,9 @@
"monaco-editor": "*",
"monaco-yaml": "*",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"xstate": "^5.18.2"
"react-dom": "^18.3.1"
},
"devDependencies": {
"@apicurio/data-models": "^1.1.28",
"@eslint/js": "^9.8.0",
"@patternfly/patternfly": "^6.0.0",
"@patternfly/react-code-editor": "^6.0.0",
Expand All @@ -52,14 +49,15 @@
"rimraf": "^6.0.0",
"typescript": "^5.5.3",
"typescript-eslint": "^8.0.0",
"vite": "^5.4.0",
"xstate": "^5.18.2"
"vite": "^5.4.0"
},
"packageManager": "[email protected]",
"dependencies": {
"@apicurio/data-models": "^1.1.28",
"lodash": "^4.17.21",
"react-markdown": "^9.0.1",
"remark-gfm": "^4.0.0",
"xstate": "^5.18.2",
"yaml": "^2.6.0"
}
}
25 changes: 23 additions & 2 deletions packages/ui/src/OpenApiEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ export type OpenApiEditorProps = {
asYaml: () => Promise<string>;
asJson: () => Promise<string>;
}) => void;
enableViewer?: boolean;
enableDesigner?: boolean;
enableSource?: boolean;
};

export const OpenApiEditorMachineContext =
Expand All @@ -101,6 +104,9 @@ export function OpenApiEditor({
undoChange,
redoChange,
onDocumentChange,
enableViewer = true,
enableDesigner = true,
enableSource = true,
}: OpenApiEditorProps) {
const containerRef = useRef<HTMLDivElement | null>(null);

Expand Down Expand Up @@ -230,13 +236,25 @@ export function OpenApiEditor({
ref={containerRef}
id={"editor-container"}
>
<Editor />
<Editor
enableViewer={enableViewer}
enableDesigner={enableDesigner}
enableSource={enableSource}
/>
</div>
</OpenApiEditorMachineContext.Provider>
);
}

function Editor() {
function Editor({
enableViewer,
enableDesigner,
enableSource,
}: {
enableViewer: boolean;
enableDesigner?: boolean;
enableSource: boolean;
}) {
const {
isSavingSlowly,
showNavigation,
Expand Down Expand Up @@ -286,6 +304,9 @@ function Editor() {
label={label}
view={view}
canGoBack={selectedNode.type !== "root"}
enableViewer={enableViewer}
enableDesigner={enableDesigner}
enableSource={enableSource}
/>
<Drawer
isExpanded={showNavigation}
Expand Down
20 changes: 13 additions & 7 deletions packages/ui/src/OpenApiEditorWorker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,9 @@ function getNavigationDataTypes(filter = ""): NavigationDataType[] {
});
}

export function getDocumentNavigation(filter = ""): DocumentNavigation {
export async function getDocumentNavigation(
filter = ""
): Promise<DocumentNavigation> {
return {
paths: getNavigationPaths(filter),
responses: getNavigationResponses(filter),
Expand Down Expand Up @@ -190,7 +192,7 @@ function securitySchemes(): DM.SecurityScheme[] {
}
}

export function parseOasSchema(schema: string) {
export async function parseOasSchema(schema: string) {
try {
document = DM.Library.readDocumentFromJSONString(schema) as DM.OasDocument;
otEngine = new DM.OtEngine(document);
Expand All @@ -202,7 +204,7 @@ export function parseOasSchema(schema: string) {
}
}

export function getPathSnapshot(node: NodePath): DocumentPath {
export async function getPathSnapshot(node: NodePath): Promise<DocumentPath> {
const path = resolveNode(node.nodePath);

if (document.is3xDocument()) {
Expand Down Expand Up @@ -233,7 +235,9 @@ export function getPathSnapshot(node: NodePath): DocumentPath {
}
}

export function getDataTypeSnapshot(node: NodeDataType): DocumentDataType {
export async function getDataTypeSnapshot(
node: NodeDataType
): Promise<DocumentDataType> {
const schema = resolveNode(node.nodePath) as DM.OasSchema;

const description = schema.description;
Expand Down Expand Up @@ -292,7 +296,9 @@ export function getDataTypeSnapshot(node: NodeDataType): DocumentDataType {
};
}

export function getResponseSnapshot(node: NodeResponse): DocumentResponse {
export async function getResponseSnapshot(
node: NodeResponse
): Promise<DocumentResponse> {
const response = resolveNode(node.nodePath);

if (document.is3xDocument()) {
Expand All @@ -308,7 +314,7 @@ export function getResponseSnapshot(node: NodeResponse): DocumentResponse {
}
}

export function getDocumentRootSnapshot(): DocumentRoot {
export async function getDocumentRootSnapshot(): Promise<DocumentRoot> {
console.log("getDocumentRootSnapshot");
return {
title: document.info.title,
Expand Down Expand Up @@ -400,7 +406,7 @@ export async function getEditorState(filter: string): Promise<EditorModel> {

return {
documentTitle: document.info.title,
navigation: getDocumentNavigation(filter),
navigation: await getDocumentNavigation(filter),
canUndo,
canRedo,
validationProblems: validationProblems.map((v): Validation => {
Expand Down
62 changes: 37 additions & 25 deletions packages/ui/src/components/EditorToolbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ export type EditorToolbarProps = {
canGoBack: boolean;
onBack: () => void;
onViewChange: (view: EditorToolbarView) => void;
enableViewer: boolean;
enableDesigner?: boolean;
enableSource: boolean;
};
export function EditorToolbar({
title,
Expand All @@ -39,6 +42,9 @@ export function EditorToolbar({
canGoBack,
onBack,
onViewChange,
enableViewer,
enableDesigner,
enableSource,
}: EditorToolbarProps) {
const { low, medium, high } = OpenApiEditorMachineContext.useSelector(
({ context }) => {
Expand Down Expand Up @@ -113,7 +119,7 @@ export function EditorToolbar({
</>
)}
</ToolbarGroup>
<ToolbarGroup align={{ lg: "alignEnd" }} style={{ maxWidth: "30%" }}>
<ToolbarGroup align={{ lg: "alignEnd" }} style={{ maxWidth: "50%" }}>
<ToolbarItem>
<UndoRedo />
</ToolbarItem>
Expand All @@ -122,30 +128,36 @@ export function EditorToolbar({
<ToolbarItem variant={"separator"} />
<ToolbarItem>
<ToggleGroup aria-label="View selector">
<ToggleGroupItem
text="Visualize"
buttonId="toggle-visualize"
isSelected={view === "visualize"}
onChange={() => {
onViewChange("visualize");
}}
/>
<ToggleGroupItem
text="Design"
buttonId="toggle-designer"
isSelected={view === "design"}
onChange={() => {
onViewChange("design");
}}
/>
<ToggleGroupItem
text="Source"
buttonId="toggle-yaml"
isSelected={view === "code"}
onChange={() => {
onViewChange("code");
}}
/>
{enableViewer && (
<ToggleGroupItem
text="Visualize"
buttonId="toggle-visualize"
isSelected={view === "visualize"}
onChange={() => {
onViewChange("visualize");
}}
/>
)}
{enableDesigner && (
<ToggleGroupItem
text="Design"
buttonId="toggle-designer"
isSelected={view === "design"}
onChange={() => {
onViewChange("design");
}}
/>
)}
{enableSource && (
<ToggleGroupItem
text="Source"
buttonId="toggle-yaml"
isSelected={view === "code"}
onChange={() => {
onViewChange("code");
}}
/>
)}
</ToggleGroup>
</ToolbarItem>
</>
Expand Down
6 changes: 6 additions & 0 deletions packages/ui/src/components/NodeHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ export function NodeHeader({
label,
view,
canGoBack,
enableViewer,
enableDesigner,
enableSource,
}: { title?: ReactNode; label?: ReactNode; canGoBack: boolean } & Omit<
EditorToolbarProps,
"onViewChange" | "onBack"
Expand All @@ -20,6 +23,9 @@ export function NodeHeader({
label={label}
title={title ?? <Skeleton className={classes.skeleton} />}
view={view}
enableViewer={enableViewer}
enableDesigner={enableDesigner}
enableSource={enableSource}
onViewChange={(view) => {
switch (view) {
case "visualize":
Expand Down

0 comments on commit 31b561c

Please sign in to comment.