diff --git a/webapp/openapi-playground/mod/openapi/OperationView.tsx b/webapp/openapi-playground/mod/openapi/OperationView.tsx index 4bea8b24..b8f981df 100644 --- a/webapp/openapi-playground/mod/openapi/OperationView.tsx +++ b/webapp/openapi-playground/mod/openapi/OperationView.tsx @@ -5,6 +5,7 @@ import { Box, styled } from "@innoai-tech/vueuikit"; import { ResponseView } from "./ResponseView.tsx"; import { RequestBuilder } from "./RequestBuilder.tsx"; import { Markdown } from "@innoai-tech/vuemarkdown"; +import { DatabaseErContainer } from "./components/DatabaseErView.tsx"; export const OperationView = component$({ operationId: t.string() @@ -87,24 +88,32 @@ export const OperationView = component$({ if (!op) { return null; } + if (op.operationId == "SycDatabaseEr") { + return ( + + {$heading} + {$desc} + + + + + ) + } + return ( {$heading} {$desc} - + {$requestBuilder} - + ); }) @@ -118,6 +127,16 @@ const OperationContainer = styled("div")({ alignItems: "stretch" }); + +const OperationMain = styled("div")({ + flex: 1, + overflow: "hidden", + display: "flex", + flexDirection: "column", + alignItems: "stretch" +}); + + const OperationHeading = styled("div")({ display: "flex", alignItems: "center", diff --git a/webapp/openapi-playground/mod/openapi/components/DatabaseErView.tsx b/webapp/openapi-playground/mod/openapi/components/DatabaseErView.tsx new file mode 100644 index 00000000..758c0562 --- /dev/null +++ b/webapp/openapi-playground/mod/openapi/components/DatabaseErView.tsx @@ -0,0 +1,241 @@ +import { component, component$, rx } from "@innoai-tech/vuekit"; +import type { OperationWithMethodPath } from "../models"; +import { OpenAPIProvider } from "../OpenAPIProvider.tsx"; +import { onMounted } from "vue"; +import { alpha, styled, variant } from "@innoai-tech/vueuikit"; +import { Icon, mdiKey } from "@innoai-tech/vuematerial"; +import { mdiKeyOutline } from "@mdi/js"; + +export type ErDatabase = { + name: string + tables: Record +} + +export type ErTable = { + title?: string + description?: string + columns: Record + constraints: Record +} + +export type ErColumn = { + type: string + title?: string + description?: string + of?: string +} + +export type ErConstraint = { + title?: string + description?: string + columnNames: Array + method?: string + unique?: boolean + primary?: boolean +} + + +export const DatabaseErContainer = component$<{ + op: OperationWithMethodPath +}>((props, { render }) => { + + const openapi$ = OpenAPIProvider.use(); + + onMounted(() => { + openapi$.request(props.op.operationId, {}); + }); + + return rx( + openapi$.response$(props.op.operationId), + render((resp) => { + return ; + }) + ); +}); + +export const DatabaseErView = component<{ + database: ErDatabase +}>((props) => { + return () => { + return ( + + + {props.database.name} + + {Object.keys(props.database.tables).toSorted().map((tableName) => { + const t = props.database.tables[tableName] ?? { columns: {}, constraints: {} }; + + const columns = t.columns; + const constraints = t.constraints; + + return ( + + + + {tableName} + + + + {t.title} + + + {Object.keys(columns).toSorted().map((colName) => { + const col = columns[colName]!; + + return ( + + + {colName} + + {col.of ? ( + + {col.of} + + ) : ( + + {col.type} + + )} + + {col.title} + + + ); + })} + + {Object.entries(constraints).toSorted(([name1, c1], [name2, c2]) => { + if (c2.primary && !c1.primary) { + return 1; + } + + if (!c2.primary && c1.primary) { + return -1; + } + + if (c2.unique && !c1.unique) { + return 1; + } + + if (!c2.unique && c1.unique) { + return -1; + } + + return name1.localeCompare(name2); + }).map(([constraintName, constraint]) => { + + return ( + + + + + {constraintName} + + + ({constraint.columnNames.join(",")}) + + + + ); + })} + + ); + })} + + ); + }; +}); + + +const DatabaseErMain = styled("div")({ + py: 18, + px: 24, + flex: 1, + overflow: "auto" +}); + +const DatabaseErHeader = styled("div")({ + py: 8, + px: 16, + textStyle: "sys.label-large" +}); + + +const DatabaseErTable = styled("details")({ + "& + &": { + mt: 16 + }, + + rounded: "sm", + border: "1px solid", + borderColor: variant("sys.outline-variant", alpha(0.38)), + overflow: "hidden" +}); + +const DatabaseErTableSummary = styled("summary")({ + textStyle: "sys.label-large", + py: 8, + px: 16, + display: "flex", + color: "sys.primary" +}); + + +const DatabaseErTableDef = styled("div")({ + px: 16, + py: 4, + display: "flex", + "&:hover": { + containerStyle: "sys.surface-container-low" + } +}); + + +export const DatabaseErTableColumnName = styled("div")({ + display: "flex", + width: "20vw", + textStyle: "sys.label-small", + font: "code" +}); + + +export const DatabaseErTableColumnComment = styled("div")({ + display: "flex", + textStyle: "sys.label-small", + width: "20vw", + justifyContent: "end" +}); + +export const DatabaseErTableColumnOf = styled("div")({ + flex: 1, + textStyle: "sys.label-small", + font: "code", + color: "sys.primary" +}); + + +export const DatabaseErTableColumnType = styled("div")({ + flex: 1, + textStyle: "sys.label-small" +}); + + +export const DatabaseErTableConstraintName = styled("div")({ + flex: 1, + textStyle: "sys.label-small", + font: "code", + display: "flex", + alignItems: "center", + gap: "1em", + + _primary: { + [`${Icon}`]: { + color: "sys.primary" + } + } +}); + +const Spacer = styled("div")({ + flex: 1 +}); \ No newline at end of file