@malloy-publisher/sdk 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/.eslintrc +36 -0
  2. package/.prettierrc +4 -0
  3. package/README.md +1 -0
  4. package/openapitools.json +7 -0
  5. package/package.json +63 -0
  6. package/src/assets/img/spinner.svg +43 -0
  7. package/src/client/.openapi-generator/FILES +9 -0
  8. package/src/client/.openapi-generator/VERSION +1 -0
  9. package/src/client/.openapi-generator-ignore +23 -0
  10. package/src/client/api.ts +1170 -0
  11. package/src/client/base.ts +86 -0
  12. package/src/client/common.ts +150 -0
  13. package/src/client/configuration.ts +110 -0
  14. package/src/client/git_push.sh +57 -0
  15. package/src/client/index.ts +18 -0
  16. package/src/components/DOMElement/DOMElement.tsx +19 -0
  17. package/src/components/DOMElement/index.ts +1 -0
  18. package/src/components/Model/Model.tsx +110 -0
  19. package/src/components/Model/ModelCell.tsx +175 -0
  20. package/src/components/Model/index.ts +1 -0
  21. package/src/components/Notebook/Notebook.tsx +82 -0
  22. package/src/components/Notebook/NotebookCell.tsx +194 -0
  23. package/src/components/Notebook/index.ts +1 -0
  24. package/src/components/Package/Config.tsx +99 -0
  25. package/src/components/Package/Databases.tsx +75 -0
  26. package/src/components/Package/FileTreeView.tsx +224 -0
  27. package/src/components/Package/Models.tsx +77 -0
  28. package/src/components/Package/Package.tsx +78 -0
  29. package/src/components/Package/index.ts +1 -0
  30. package/src/components/Project/About.tsx +56 -0
  31. package/src/components/Project/Packages.tsx +105 -0
  32. package/src/components/Project/Project.tsx +26 -0
  33. package/src/components/Project/index.ts +1 -0
  34. package/src/components/QueryResult/QueryResult.tsx +84 -0
  35. package/src/components/QueryResult/index.ts +1 -0
  36. package/src/components/RenderedResult/RenderedResult.tsx +38 -0
  37. package/src/components/highlighter.ts +649 -0
  38. package/src/components/index.ts +5 -0
  39. package/src/components/styles.ts +21 -0
  40. package/src/index.ts +1 -0
  41. package/src/react-app-env.d.ts +73 -0
  42. package/tsconfig.json +34 -0
  43. package/vite.config.ts +31 -0
@@ -0,0 +1,175 @@
1
+ import React from "react";
2
+ import {
3
+ styled,
4
+ Collapse,
5
+ CardActions,
6
+ Card,
7
+ CardContent,
8
+ Divider,
9
+ Stack,
10
+ Typography,
11
+ Tooltip,
12
+ IconButton,
13
+ } from "@mui/material";
14
+ import { QueryResult } from "../QueryResult";
15
+ import AnalyticsOutlinedIcon from "@mui/icons-material/AnalyticsOutlined";
16
+ import ShareOutlinedIcon from "@mui/icons-material/ShareOutlined";
17
+ import ContentCopyIcon from "@mui/icons-material/ContentCopy";
18
+ import { useEffect } from "react";
19
+ import { highlight } from "../highlighter";
20
+
21
+ const StyledCard = styled(Card)({
22
+ display: "flex",
23
+ flexDirection: "column",
24
+ height: "100%",
25
+ });
26
+
27
+ interface ModelCellProps {
28
+ server: string;
29
+ packageName: string;
30
+ modelPath: string;
31
+ sourceName?: string;
32
+ queryName: string;
33
+ }
34
+
35
+ export function ModelCell({
36
+ server,
37
+ packageName,
38
+ modelPath,
39
+ sourceName,
40
+ queryName,
41
+ }: ModelCellProps) {
42
+ const [resultsExpanded, setResultsExpanded] = React.useState(false);
43
+ const [sharingExpanded, setSharingExpanded] = React.useState(false);
44
+ const [highlightedEmbedCode, setHighlightedEmbedCode] =
45
+ React.useState<string>();
46
+ useEffect(() => {
47
+ highlight(
48
+ getQueryResultCodeSnippet(
49
+ server,
50
+ packageName,
51
+ modelPath,
52
+ sourceName,
53
+ queryName,
54
+ ),
55
+ "typescript",
56
+ ).then((code) => {
57
+ setHighlightedEmbedCode(code);
58
+ });
59
+ }, [server, packageName, modelPath, sourceName, queryName]);
60
+
61
+ return (
62
+ <>
63
+ <StyledCard
64
+ variant="outlined"
65
+ sx={{
66
+ padding: "0px 10px 0px 10px",
67
+ borderRadius: "0px",
68
+ }}
69
+ >
70
+ <Stack
71
+ sx={{
72
+ display: "flex",
73
+ flexDirection: "row",
74
+ justifyContent: "space-between",
75
+ width: "100%",
76
+ }}
77
+ >
78
+ <Typography
79
+ variant="subtitle2"
80
+ sx={{ mt: "auto", mb: "auto" }}
81
+ >{`View > ${queryName}`}</Typography>
82
+ <CardActions sx={{ padding: "0px" }}>
83
+ <Tooltip
84
+ title={resultsExpanded ? "Hide Results" : "Show Results"}
85
+ >
86
+ <IconButton
87
+ size="small"
88
+ onClick={() => {
89
+ setResultsExpanded(!resultsExpanded);
90
+ }}
91
+ >
92
+ <AnalyticsOutlinedIcon />
93
+ </IconButton>
94
+ </Tooltip>
95
+ <Tooltip
96
+ title={sharingExpanded ? "Hide Sharing" : "Show Sharing"}
97
+ >
98
+ <IconButton
99
+ size="small"
100
+ onClick={() => {
101
+ setSharingExpanded(!sharingExpanded);
102
+ }}
103
+ >
104
+ <ShareOutlinedIcon />
105
+ </IconButton>
106
+ </Tooltip>
107
+ </CardActions>
108
+ </Stack>
109
+ <Collapse in={sharingExpanded} timeout="auto" unmountOnExit>
110
+ <Divider sx={{ mb: "10px" }} />
111
+ <Stack
112
+ sx={{
113
+ p: "10px",
114
+ borderRadius: 0,
115
+ flexDirection: "row",
116
+ justifyContent: "space-between",
117
+ }}
118
+ >
119
+ <Typography
120
+ fontSize="12px"
121
+ sx={{ fontSize: "12px", "& .line": { textWrap: "wrap" } }}
122
+ >
123
+ <div
124
+ className="content"
125
+ dangerouslySetInnerHTML={{
126
+ __html: highlightedEmbedCode,
127
+ }}
128
+ />
129
+ </Typography>
130
+ <Tooltip title="View Code">
131
+ <IconButton
132
+ sx={{ width: "24px", height: "24px" }}
133
+ onClick={() => {
134
+ navigator.clipboard.writeText(
135
+ getQueryResultCodeSnippet(
136
+ server,
137
+ packageName,
138
+ modelPath,
139
+ sourceName,
140
+ queryName,
141
+ ),
142
+ );
143
+ }}
144
+ >
145
+ <ContentCopyIcon />
146
+ </IconButton>
147
+ </Tooltip>
148
+ </Stack>
149
+ </Collapse>
150
+ <Collapse in={resultsExpanded} timeout="auto" unmountOnExit>
151
+ <Divider sx={{ mb: "10px" }} />
152
+ <CardContent>
153
+ <QueryResult
154
+ server={server}
155
+ packageName={packageName}
156
+ modelPath={modelPath}
157
+ sourceName={sourceName}
158
+ queryName={queryName}
159
+ />
160
+ </CardContent>
161
+ </Collapse>
162
+ </StyledCard>
163
+ </>
164
+ );
165
+ }
166
+
167
+ function getQueryResultCodeSnippet(
168
+ server: string,
169
+ packageName: string,
170
+ modelPath: string,
171
+ sourceName: string,
172
+ queryName: string,
173
+ ): string {
174
+ return `<QueryResult server="${server}" packageName="${packageName}" modelPath="${modelPath}" sourceName="${sourceName}" queryName="${queryName}"/>`;
175
+ }
@@ -0,0 +1 @@
1
+ export { default as Model } from "./Model";
@@ -0,0 +1,82 @@
1
+ import { Configuration, ModelsApi } from "../../client";
2
+ import axios from "axios";
3
+ import Stack from "@mui/material/Stack";
4
+ import { NotebookCell } from "./NotebookCell";
5
+ import { Typography } from "@mui/material";
6
+ import { useQuery, QueryClient } from "@tanstack/react-query";
7
+
8
+ axios.defaults.baseURL = "http://localhost:4000";
9
+ const modelsApi = new ModelsApi(new Configuration());
10
+ const queryClient = new QueryClient();
11
+
12
+ interface NotebookProps {
13
+ server?: string;
14
+ packageName: string;
15
+ notebookPath: string;
16
+ versionId?: string;
17
+ }
18
+
19
+ export default function Notebook({
20
+ server,
21
+ packageName,
22
+ notebookPath,
23
+ versionId,
24
+ }: NotebookProps) {
25
+ const {
26
+ data: notebook,
27
+ isSuccess,
28
+ isError,
29
+ error,
30
+ } = useQuery(
31
+ {
32
+ queryKey: [server, packageName, notebookPath, versionId],
33
+ queryFn: () =>
34
+ modelsApi.getModel(packageName, notebookPath, versionId, {
35
+ baseURL: server,
36
+ withCredentials: true,
37
+ }),
38
+ retry: false,
39
+ },
40
+ queryClient,
41
+ );
42
+
43
+ return (
44
+ <Stack spacing={1} component="section">
45
+ {!isSuccess && !isError && (
46
+ <Typography variant="body2" sx={{ p: "10px", m: "auto" }}>
47
+ Fetching Notebook...
48
+ </Typography>
49
+ )}
50
+ {isSuccess &&
51
+ notebook.data.notebookCells?.map((cell, index) => (
52
+ <NotebookCell
53
+ cell={cell}
54
+ modelDef={notebook.data.modelDef}
55
+ dataStyles={notebook.data.dataStyles}
56
+ queryResultCodeSnippet={getQueryResultCodeSnippet(
57
+ server,
58
+ packageName,
59
+ notebookPath,
60
+ cell.text,
61
+ )}
62
+ key={index}
63
+ />
64
+ ))}
65
+ {isError && (
66
+ <Typography variant="body2" sx={{ p: "10px", m: "auto" }}>
67
+ {`${packageName} > ${notebookPath} > ${versionId} - ${error.message}`}
68
+ </Typography>
69
+ )}
70
+ </Stack>
71
+ );
72
+ }
73
+
74
+ function getQueryResultCodeSnippet(
75
+ server: string,
76
+ packageName: string,
77
+ modelPath: string,
78
+ query: string,
79
+ ): string {
80
+ const queryResultsString = `<QueryResult server="${server}" packageName="${packageName}" modelPath="${modelPath}" query="${query}"/>`;
81
+ return queryResultsString.replace(/\n/g, "");
82
+ }
@@ -0,0 +1,194 @@
1
+ import React from "react";
2
+ import { Suspense, lazy } from "react";
3
+ import {
4
+ Stack,
5
+ Collapse,
6
+ CardActions,
7
+ CardContent,
8
+ IconButton,
9
+ Tooltip,
10
+ } from "@mui/material";
11
+ import { StyledCard, StyledCardContent } from "../styles";
12
+ import Markdown from "markdown-to-jsx";
13
+ import { NotebookCell as ClientNotebookCell } from "../../client";
14
+ import { Typography } from "@mui/material";
15
+ import { Divider } from "@mui/material";
16
+ import ContentCopyIcon from "@mui/icons-material/ContentCopy";
17
+ import { highlight } from "../highlighter";
18
+ import { useEffect } from "react";
19
+ import CodeIcon from "@mui/icons-material/Code";
20
+ import ShareIcon from "@mui/icons-material/ShareOutlined";
21
+
22
+ const RenderedResult = lazy(() => import("../RenderedResult/RenderedResult"));
23
+
24
+ interface NotebookCellProps {
25
+ cell: ClientNotebookCell;
26
+ modelDef: string;
27
+ dataStyles: string;
28
+ queryResultCodeSnippet: string;
29
+ }
30
+
31
+ export function NotebookCell({
32
+ cell,
33
+ modelDef,
34
+ dataStyles,
35
+ queryResultCodeSnippet,
36
+ }: NotebookCellProps) {
37
+ const [codeExpanded, setCodeExpanded] = React.useState<boolean>(false);
38
+ const [sharingExpanded, setSharingExpanded] = React.useState<boolean>(false);
39
+ const [highlightedMalloyCode, setHighlightedMalloyCode] =
40
+ React.useState<string>();
41
+ const [highlightedEmbedCode, setHighlightedEmbedCode] =
42
+ React.useState<string>();
43
+ useEffect(() => {
44
+ if (cell.type === "code")
45
+ highlight(cell.text, "malloy").then((code) => {
46
+ setHighlightedMalloyCode(code);
47
+ });
48
+ }, [cell]);
49
+
50
+ useEffect(() => {
51
+ highlight(queryResultCodeSnippet, "typescript").then((code) => {
52
+ setHighlightedEmbedCode(code);
53
+ });
54
+ }, [queryResultCodeSnippet]);
55
+
56
+ return (
57
+ (cell.type === "markdown" && (
58
+ <StyledCard variant="outlined" sx={{ border: 0 }}>
59
+ <StyledCardContent>
60
+ <Markdown>{cell.text}</Markdown>
61
+ </StyledCardContent>
62
+ </StyledCard>
63
+ )) ||
64
+ (cell.type === "code" && (
65
+ <StyledCard variant="outlined">
66
+ <Stack
67
+ sx={{ flexDirection: "row", justifyContent: "space-between" }}
68
+ >
69
+ <Typography variant="overline" sx={{ ml: "10px" }}>
70
+ Code {cell.queryResult && "+ Results"} Cell
71
+ </Typography>
72
+ <Stack>
73
+ <CardActions
74
+ sx={{
75
+ padding: "0px 10px 0px 10px",
76
+ mb: "auto",
77
+ mt: "auto",
78
+ }}
79
+ >
80
+ <Tooltip title={codeExpanded ? "Hide Code" : "View Code"}>
81
+ <IconButton
82
+ size="small"
83
+ onClick={() => {
84
+ setCodeExpanded(!codeExpanded);
85
+ }}
86
+ >
87
+ <CodeIcon />
88
+ </IconButton>
89
+ </Tooltip>
90
+ {cell.queryResult && (
91
+ <Tooltip
92
+ title={
93
+ sharingExpanded ? "Hide Sharing" : "View Sharing"
94
+ }
95
+ >
96
+ <IconButton
97
+ size="small"
98
+ onClick={() => {
99
+ setSharingExpanded(!sharingExpanded);
100
+ }}
101
+ >
102
+ <ShareIcon />
103
+ </IconButton>
104
+ </Tooltip>
105
+ )}
106
+ </CardActions>
107
+ </Stack>
108
+ </Stack>
109
+ <Collapse in={codeExpanded} timeout="auto" unmountOnExit>
110
+ <Divider />
111
+ <Stack
112
+ sx={{
113
+ p: "10px",
114
+ borderRadius: 0,
115
+ flexDirection: "row",
116
+ justifyContent: "space-between",
117
+ }}
118
+ >
119
+ <Typography
120
+ sx={{ fontSize: "12px", "& .line": { textWrap: "wrap" } }}
121
+ >
122
+ <div
123
+ className="content"
124
+ dangerouslySetInnerHTML={{
125
+ __html: highlightedMalloyCode,
126
+ }}
127
+ />
128
+ </Typography>
129
+ <Tooltip title="View Code">
130
+ <IconButton
131
+ sx={{ width: "24px", height: "24px" }}
132
+ onClick={() => {
133
+ navigator.clipboard.writeText(cell.text);
134
+ }}
135
+ >
136
+ <ContentCopyIcon />
137
+ </IconButton>
138
+ </Tooltip>
139
+ </Stack>
140
+ </Collapse>
141
+ <Collapse in={sharingExpanded} timeout="auto" unmountOnExit>
142
+ <Divider />
143
+ <Stack
144
+ sx={{
145
+ p: "10px",
146
+ borderRadius: 0,
147
+ flexDirection: "row",
148
+ justifyContent: "space-between",
149
+ }}
150
+ >
151
+ <Typography
152
+ sx={{
153
+ fontSize: "12px",
154
+ "& .line": { textWrap: "wrap" },
155
+ }}
156
+ >
157
+ <div
158
+ dangerouslySetInnerHTML={{
159
+ __html: highlightedEmbedCode,
160
+ }}
161
+ />
162
+ </Typography>
163
+ <Tooltip title="View Code">
164
+ <IconButton
165
+ sx={{ width: "24px", height: "24px" }}
166
+ onClick={() => {
167
+ navigator.clipboard.writeText(
168
+ queryResultCodeSnippet,
169
+ );
170
+ }}
171
+ >
172
+ <ContentCopyIcon />
173
+ </IconButton>
174
+ </Tooltip>
175
+ </Stack>
176
+ </Collapse>
177
+ {cell.queryResult && (
178
+ <>
179
+ <Divider sx={{ mb: "10px" }} />
180
+ <CardContent>
181
+ <Suspense fallback="Loading malloy...">
182
+ <RenderedResult
183
+ modelDef={modelDef}
184
+ queryResult={cell.queryResult}
185
+ dataStyles={dataStyles}
186
+ />
187
+ </Suspense>
188
+ </CardContent>
189
+ </>
190
+ )}
191
+ </StyledCard>
192
+ ))
193
+ );
194
+ }
@@ -0,0 +1 @@
1
+ export { default as Notebook } from "./Notebook";
@@ -0,0 +1,99 @@
1
+ import ErrorIcon from "@mui/icons-material/ErrorOutlined";
2
+ import {
3
+ Box,
4
+ Divider,
5
+ List,
6
+ ListItem,
7
+ ListItemText,
8
+ Typography,
9
+ } from "@mui/material";
10
+ import { QueryClient, useQuery } from "@tanstack/react-query";
11
+ import axios from "axios";
12
+ import { Configuration, PackagesApi } from "../../client";
13
+ import { StyledCard, StyledCardContent } from "../styles";
14
+
15
+ axios.defaults.baseURL = "http://localhost:4000";
16
+ const packagesApi = new PackagesApi(new Configuration());
17
+ const queryClient = new QueryClient();
18
+
19
+ interface PackageProps {
20
+ server?: string;
21
+ packageName: string;
22
+ versionId?: string;
23
+ }
24
+
25
+ export default function Package({
26
+ server,
27
+ packageName,
28
+ versionId,
29
+ }: PackageProps) {
30
+ const { data, isSuccess, isError, error } = useQuery(
31
+ {
32
+ queryKey: ["package", server, packageName, versionId],
33
+ queryFn: () =>
34
+ packagesApi.getPackage(packageName, versionId, {
35
+ baseURL: server,
36
+ withCredentials: true,
37
+ }),
38
+ retry: false,
39
+ },
40
+ queryClient,
41
+ );
42
+
43
+ return (
44
+ <StyledCard variant="outlined" sx={{ padding: "10px", width: "100%" }}>
45
+ <StyledCardContent>
46
+ <Typography variant="overline" fontWeight="bold">
47
+ Package Config
48
+ </Typography>
49
+ <Divider />
50
+ <Box
51
+ sx={{
52
+ mt: "10px",
53
+ maxHeight: "300px",
54
+ overflowY: "auto",
55
+ }}
56
+ >
57
+ <List dense={true} disablePadding={true}>
58
+ <ListItem dense={true} disablePadding={true}>
59
+ <ListItemText primary="Name" secondary={packageName} />
60
+ </ListItem>
61
+ {!isSuccess && !isError && (
62
+ <Typography variant="body2" sx={{ p: "20px", m: "auto" }}>
63
+ Fethching Package Metadata...
64
+ </Typography>
65
+ )}
66
+ {isSuccess &&
67
+ ((data.data && (
68
+ <ListItem dense={true} disablePadding={true}>
69
+ <ListItemText
70
+ primary="Description"
71
+ secondary={data.data.description}
72
+ />
73
+ </ListItem>
74
+ )) || (
75
+ <ListItem
76
+ disablePadding={true}
77
+ dense={true}
78
+ sx={{ mt: "20px" }}
79
+ >
80
+ <ErrorIcon
81
+ sx={{
82
+ color: "grey.600",
83
+ mr: "10px",
84
+ }}
85
+ />
86
+ <ListItemText primary={"No package manifest"} />
87
+ </ListItem>
88
+ ))}
89
+ {isError && (
90
+ <Typography variant="body2" sx={{ p: "10px", m: "auto" }}>
91
+ {`${packageName} > ${versionId} - ${error.message}`}
92
+ </Typography>
93
+ )}
94
+ </List>
95
+ </Box>
96
+ </StyledCardContent>
97
+ </StyledCard>
98
+ );
99
+ }
@@ -0,0 +1,75 @@
1
+ import { Box, Divider, Typography } from "@mui/material";
2
+ import { QueryClient, useQuery } from "@tanstack/react-query";
3
+ import axios from "axios";
4
+ import { Configuration, DatabasesApi } from "../../client";
5
+ import { StyledCard, StyledCardContent } from "../styles";
6
+ import { FileTreeView } from "./FileTreeView";
7
+
8
+ axios.defaults.baseURL = "http://localhost:4000";
9
+ const databasesApi = new DatabasesApi(new Configuration());
10
+ const queryClient = new QueryClient();
11
+
12
+ const DEFAULT_EXPANDED_FOLDERS = ["data/"];
13
+
14
+ interface PackageProps {
15
+ server?: string;
16
+ packageName: string;
17
+ versionId?: string;
18
+ }
19
+
20
+ export default function Package({
21
+ server,
22
+ packageName,
23
+ versionId,
24
+ }: PackageProps) {
25
+ const { data, isSuccess, isError, error } = useQuery(
26
+ {
27
+ queryKey: ["databases", server, packageName, versionId],
28
+ queryFn: () =>
29
+ databasesApi.listDatabases(packageName, versionId, {
30
+ baseURL: server,
31
+ withCredentials: true,
32
+ }),
33
+ retry: false,
34
+ },
35
+ queryClient,
36
+ );
37
+
38
+ return (
39
+ <StyledCard variant="outlined" sx={{ padding: "10px", width: "100%" }}>
40
+ <StyledCardContent>
41
+ <Typography variant="overline" fontWeight="bold">
42
+ Embedded Databases
43
+ </Typography>
44
+ <Divider />
45
+ <Box
46
+ sx={{
47
+ mt: "10px",
48
+ maxHeight: "300px",
49
+ overflowY: "auto",
50
+ }}
51
+ >
52
+ {!isSuccess && !isError && (
53
+ <Typography variant="body2" sx={{ p: "20px", m: "auto" }}>
54
+ Fetching Databases...
55
+ </Typography>
56
+ )}
57
+ {isSuccess && data.data.length > 0 && (
58
+ <FileTreeView
59
+ items={data.data}
60
+ defaultExpandedItems={DEFAULT_EXPANDED_FOLDERS}
61
+ />
62
+ )}
63
+ {isSuccess && data.data.length === 0 && (
64
+ <Typography variant="body2">No Embedded Databases</Typography>
65
+ )}
66
+ {isError && (
67
+ <Typography variant="body2" sx={{ p: "10px", m: "auto" }}>
68
+ {`${packageName} > ${versionId} - ${error.message}`}
69
+ </Typography>
70
+ )}
71
+ </Box>
72
+ </StyledCardContent>
73
+ </StyledCard>
74
+ );
75
+ }