@canmingir/link 1.2.23 → 1.2.25
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.
- package/package.json +3 -1
- package/src/Platform.jsx +10 -14
- package/src/context/Context.js +98 -0
- package/src/context/reducer.js +590 -10
- package/src/layouts/auth/modern.jsx +2 -2
- package/src/lib/APIDialogAction/APIDialogAction.jsx +109 -0
- package/src/lib/APIDialogAction/index.js +1 -0
- package/src/lib/APIDialogAction/styles.js +6 -0
- package/src/lib/APIParams/APIParams.jsx +57 -0
- package/src/lib/APIParams/index.js +1 -0
- package/src/lib/APIPath/APIPath.jsx +82 -0
- package/src/lib/APIPath/index.js +1 -0
- package/src/lib/APIPath/styles.js +19 -0
- package/src/lib/APITree/APITree.jsx +409 -0
- package/src/lib/APITree/Arrow.jsx +21 -0
- package/src/lib/APITree/DeleteMethodDialog.jsx +41 -0
- package/src/lib/APITree/index.js +1 -0
- package/src/lib/APITree/styles.js +19 -0
- package/src/lib/APITypes/APITypes.jsx +141 -0
- package/src/lib/APITypes/TypeEditor.jsx +46 -0
- package/src/lib/APITypes/TypeList.jsx +180 -0
- package/src/lib/APITypes/index.js +1 -0
- package/src/lib/BlankTreeMessage/BlankTreeMessage.jsx +39 -0
- package/src/lib/BlankTreeMessage/index.js +1 -0
- package/src/lib/DialogTootip/DialogTooltip.jsx +67 -0
- package/src/lib/DialogTootip/index.js +1 -0
- package/src/lib/DialogTootip/styles.js +9 -0
- package/src/lib/NewApiBody/NewAPIBody.jsx +97 -0
- package/src/lib/NewApiBody/ParamView.jsx +38 -0
- package/src/lib/NucDialog/NucDialog.jsx +108 -0
- package/src/lib/NucDialog/index.js +1 -0
- package/src/lib/ParamTable/ParamTable.jsx +133 -0
- package/src/lib/ParamTable/TypeMenu.jsx +102 -0
- package/src/lib/ParamTable/defaults.js +47 -0
- package/src/lib/ParamTable/index.js +1 -0
- package/src/lib/ParamTable/styles.js +12 -0
- package/src/lib/ResourceMenu/AlertMassage.jsx +28 -0
- package/src/lib/ResourceMenu/DeleteResourceDialog.jsx +60 -0
- package/src/lib/ResourceMenu/ResourceMenu.jsx +156 -0
- package/src/lib/ResourceMenu/index.js +1 -0
- package/src/lib/ResourceMenu/styles.js +5 -0
- package/src/lib/Schema/Schema.jsx +204 -0
- package/src/lib/Schema/index.js +1 -0
- package/src/lib/SchemaEditor/SchemaEditor.jsx +258 -0
- package/src/lib/SchemaEditor/SchemaEditor.test.js +193 -0
- package/src/lib/SchemaEditor/SchemaPropertyEditor.jsx +135 -0
- package/src/lib/SchemaEditor/SchemaUtils.js +152 -0
- package/src/lib/SchemaEditor/index.js +1 -0
- package/src/lib/ToggleableMenu/ToggleableMenu.jsx +35 -0
- package/src/lib/ToggleableMenu/index.js +1 -0
- package/src/lib/index.js +14 -0
- package/src/pages/Callback.jsx +2 -4
- package/src/pages/LoginPage.jsx +3 -12
- package/src/stories/APITree.stories.jsx +429 -0
- package/src/stories/FlowChart.stories.jsx +1 -1
- package/src/templates/ActionTemplate.js +24 -0
- package/src/widgets/Login/CognitoLogin.jsx +2 -2
- package/src/widgets/Login/DemoLogin.jsx +1 -1
- package/src/widgets/LoginForm/LoginForm.jsx +8 -3
- package/src/widgets/SettingsDialog.jsx +33 -11
|
@@ -0,0 +1,429 @@
|
|
|
1
|
+
import APIDialogAction from "../lib/APIDialogAction/APIDialogAction";
|
|
2
|
+
import APIParams from "../lib/APIParams/APIParams";
|
|
3
|
+
import APIPath from "../lib/APIPath/APIPath";
|
|
4
|
+
import APITree from "../lib/APITree/APITree";
|
|
5
|
+
import APITypes from "../lib/APITypes/APITypes";
|
|
6
|
+
import CssBaseline from "@mui/material/CssBaseline";
|
|
7
|
+
import NewAPIBody from "../lib/NewApiBody/NewAPIBody";
|
|
8
|
+
import NucDialog from "../lib/NucDialog/NucDialog";
|
|
9
|
+
|
|
10
|
+
import { Box, Divider } from "@mui/material";
|
|
11
|
+
import React, { useEffect, useRef, useState } from "react";
|
|
12
|
+
import { ThemeProvider, createTheme } from "@mui/material/styles";
|
|
13
|
+
import { publish, useEvent } from "@nucleoidai/react-event";
|
|
14
|
+
|
|
15
|
+
const theme = createTheme({
|
|
16
|
+
palette: {
|
|
17
|
+
mode: "dark",
|
|
18
|
+
custom: {
|
|
19
|
+
apiTreeRightClick: "rgba(255, 255, 255, 0.08)",
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
custom: {
|
|
23
|
+
apiTreeItem: {
|
|
24
|
+
fontSize: 12,
|
|
25
|
+
color: "#666",
|
|
26
|
+
fontWeight: "bold",
|
|
27
|
+
backgroundColor: "#fdfdfd",
|
|
28
|
+
border: "1px solid #c3c5c8",
|
|
29
|
+
width: 44,
|
|
30
|
+
borderRadius: 8,
|
|
31
|
+
mt: 1 / 4,
|
|
32
|
+
mb: 1 / 4,
|
|
33
|
+
boxShadow: "1px 1px #b8b8b8",
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
const sampleApi = [
|
|
39
|
+
{
|
|
40
|
+
path: "/",
|
|
41
|
+
method: "GET",
|
|
42
|
+
summary: "Hello World",
|
|
43
|
+
description: "Hello World",
|
|
44
|
+
params: [],
|
|
45
|
+
action: 'function action(req) {\n return { message: "Hello World" };\n}',
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
path: "/items",
|
|
49
|
+
method: "GET",
|
|
50
|
+
summary: "List items",
|
|
51
|
+
description: "List all items",
|
|
52
|
+
params: [{ in: "query", type: "string", required: true, name: "name" }],
|
|
53
|
+
action:
|
|
54
|
+
"function action(req) {\n return Item.filter(i => i.name === req.query.name);\n}",
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
path: "/items",
|
|
58
|
+
method: "POST",
|
|
59
|
+
summary: "Create item",
|
|
60
|
+
description: "Create a new item",
|
|
61
|
+
params: [],
|
|
62
|
+
action:
|
|
63
|
+
"function action(req) {\n return new Item(req.body.name, req.body.barcode);\n}",
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
path: "/items",
|
|
67
|
+
method: "DELETE",
|
|
68
|
+
summary: "Delete item",
|
|
69
|
+
description: "Delete an item",
|
|
70
|
+
params: [],
|
|
71
|
+
action: "function action(req) {\n // delete logic\n}",
|
|
72
|
+
},
|
|
73
|
+
];
|
|
74
|
+
|
|
75
|
+
export default {
|
|
76
|
+
title: "Components/APITree",
|
|
77
|
+
component: APITree,
|
|
78
|
+
parameters: {
|
|
79
|
+
docs: {
|
|
80
|
+
description: {
|
|
81
|
+
component:
|
|
82
|
+
"APITree displays API endpoints in a tree structure grouped by path segments. " +
|
|
83
|
+
"It supports context menus for editing/deleting methods and a resource menu for adding new endpoints.",
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
layout: "centered",
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
const ALL_METHODS = ["GET", "POST", "PUT", "DELETE", "PATCH"];
|
|
91
|
+
|
|
92
|
+
const APIWorkspace = () => {
|
|
93
|
+
const [view, setView] = useState("PARAMS");
|
|
94
|
+
const [dialogKey, setDialogKey] = useState(0);
|
|
95
|
+
|
|
96
|
+
const methodRef = useRef("GET");
|
|
97
|
+
const pathRef = useRef("/");
|
|
98
|
+
const paramsRef = useRef([]);
|
|
99
|
+
const addParams = useRef(null);
|
|
100
|
+
const requestSchemaRef = useRef();
|
|
101
|
+
const responseSchemaRef = useRef();
|
|
102
|
+
const typesRef = useRef({});
|
|
103
|
+
|
|
104
|
+
const [dialog, setDialog] = useState({
|
|
105
|
+
type: null,
|
|
106
|
+
action: null,
|
|
107
|
+
open: false,
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
const [api, setApi] = useState(sampleApi);
|
|
111
|
+
|
|
112
|
+
const [selected] = useEvent("SELECTED_API_CHANGED", {
|
|
113
|
+
path: "/",
|
|
114
|
+
method: "GET",
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
const [types, setTypes] = useState([]);
|
|
118
|
+
|
|
119
|
+
const [typeAdd] = useEvent("API_TYPE_ADD", null);
|
|
120
|
+
const [typeDelete] = useEvent("API_TYPE_DELETE", null);
|
|
121
|
+
const [typeRename] = useEvent("API_TYPE_RENAME", null);
|
|
122
|
+
|
|
123
|
+
const [methodDelete] = useEvent("API_METHOD_DELETE", null);
|
|
124
|
+
const [resourceDelete] = useEvent("API_RESOURCE_DELETE", null);
|
|
125
|
+
const [apiDialogOpen] = useEvent("API_DIALOG_OPEN", null);
|
|
126
|
+
|
|
127
|
+
const isEdit = dialog.type === "method" && dialog.action === "edit";
|
|
128
|
+
const isAddMethod = dialog.type === "method" && dialog.action === "add";
|
|
129
|
+
|
|
130
|
+
const selectedEndpoint = api.find(
|
|
131
|
+
(ep) =>
|
|
132
|
+
ep.path === selected?.path &&
|
|
133
|
+
ep.method?.toLowerCase() === selected?.method?.toLowerCase()
|
|
134
|
+
);
|
|
135
|
+
|
|
136
|
+
useEffect(() => {
|
|
137
|
+
if (!typeAdd) return;
|
|
138
|
+
|
|
139
|
+
setTypes((prev) => {
|
|
140
|
+
const { typeName } = typeAdd;
|
|
141
|
+
if (!typeName) return prev;
|
|
142
|
+
|
|
143
|
+
const exists = prev.some((t) => t.name === typeName);
|
|
144
|
+
if (exists) return prev;
|
|
145
|
+
|
|
146
|
+
return [
|
|
147
|
+
...prev,
|
|
148
|
+
{
|
|
149
|
+
name: typeName,
|
|
150
|
+
schema: {
|
|
151
|
+
name: typeName,
|
|
152
|
+
type: "object",
|
|
153
|
+
properties: [
|
|
154
|
+
{ type: "string", name: "id" },
|
|
155
|
+
{ type: "string", name: "name" },
|
|
156
|
+
],
|
|
157
|
+
},
|
|
158
|
+
},
|
|
159
|
+
];
|
|
160
|
+
});
|
|
161
|
+
}, [typeAdd]);
|
|
162
|
+
|
|
163
|
+
useEffect(() => {
|
|
164
|
+
if (!typeDelete) return;
|
|
165
|
+
|
|
166
|
+
setTypes((prev) => prev.filter((t) => t.name !== typeDelete.typeName));
|
|
167
|
+
}, [typeDelete]);
|
|
168
|
+
|
|
169
|
+
useEffect(() => {
|
|
170
|
+
if (!typeRename) return;
|
|
171
|
+
|
|
172
|
+
setTypes((prev) =>
|
|
173
|
+
prev.map((t) =>
|
|
174
|
+
t.name === typeRename.oldTypeName
|
|
175
|
+
? {
|
|
176
|
+
...t,
|
|
177
|
+
name: typeRename.newTypeName,
|
|
178
|
+
schema: {
|
|
179
|
+
...t.schema,
|
|
180
|
+
name: typeRename.newTypeName,
|
|
181
|
+
},
|
|
182
|
+
}
|
|
183
|
+
: t
|
|
184
|
+
)
|
|
185
|
+
);
|
|
186
|
+
}, [typeRename]);
|
|
187
|
+
|
|
188
|
+
useEffect(() => {
|
|
189
|
+
publish("API_TYPES_CHANGED", { types });
|
|
190
|
+
}, [types]);
|
|
191
|
+
|
|
192
|
+
useEffect(() => {
|
|
193
|
+
publish("API_DATA_CHANGED", api);
|
|
194
|
+
}, [api]);
|
|
195
|
+
|
|
196
|
+
useEffect(() => {
|
|
197
|
+
if (!apiDialogOpen) return;
|
|
198
|
+
|
|
199
|
+
setDialog((prev) => ({
|
|
200
|
+
...prev,
|
|
201
|
+
type: apiDialogOpen.type,
|
|
202
|
+
action: apiDialogOpen.action,
|
|
203
|
+
open: true,
|
|
204
|
+
}));
|
|
205
|
+
}, [apiDialogOpen]);
|
|
206
|
+
|
|
207
|
+
useEffect(() => {
|
|
208
|
+
if (!methodDelete || !selected) return;
|
|
209
|
+
|
|
210
|
+
setApi((prev) =>
|
|
211
|
+
prev.filter(
|
|
212
|
+
(route) =>
|
|
213
|
+
!(
|
|
214
|
+
route.path === selected.path &&
|
|
215
|
+
route.method?.toLowerCase() === selected.method?.toLowerCase()
|
|
216
|
+
)
|
|
217
|
+
)
|
|
218
|
+
);
|
|
219
|
+
}, [methodDelete, selected]);
|
|
220
|
+
|
|
221
|
+
useEffect(() => {
|
|
222
|
+
if (!resourceDelete || !resourceDelete.path) return;
|
|
223
|
+
|
|
224
|
+
const pathToDelete = resourceDelete.path;
|
|
225
|
+
setApi((prev) => prev.filter((ep) => !ep.path.startsWith(pathToDelete)));
|
|
226
|
+
}, [resourceDelete]);
|
|
227
|
+
|
|
228
|
+
useEffect(() => {
|
|
229
|
+
if (!dialog.open) return;
|
|
230
|
+
|
|
231
|
+
setView("PARAMS");
|
|
232
|
+
setDialogKey((k) => k + 1);
|
|
233
|
+
|
|
234
|
+
if (isEdit && selectedEndpoint) {
|
|
235
|
+
methodRef.current = selectedEndpoint.method?.toUpperCase() || "GET";
|
|
236
|
+
pathRef.current = selectedEndpoint.path || "/";
|
|
237
|
+
paramsRef.current = Array.isArray(selectedEndpoint.params)
|
|
238
|
+
? [...selectedEndpoint.params]
|
|
239
|
+
: [];
|
|
240
|
+
} else {
|
|
241
|
+
methodRef.current = "GET";
|
|
242
|
+
pathRef.current = selected?.path || "/";
|
|
243
|
+
paramsRef.current = [];
|
|
244
|
+
}
|
|
245
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
246
|
+
}, [dialog.open]);
|
|
247
|
+
|
|
248
|
+
const usedMethods = api
|
|
249
|
+
.filter((ep) => ep.path === selected?.path)
|
|
250
|
+
.map((ep) => ep.method?.toUpperCase());
|
|
251
|
+
|
|
252
|
+
const allowedMethods = isEdit
|
|
253
|
+
? [selectedEndpoint?.method?.toUpperCase() || "GET"]
|
|
254
|
+
: isAddMethod
|
|
255
|
+
? ALL_METHODS.filter((m) => !usedMethods.includes(m))
|
|
256
|
+
: ALL_METHODS;
|
|
257
|
+
|
|
258
|
+
const basePath = isEdit
|
|
259
|
+
? selectedEndpoint?.path || selected?.path || "/"
|
|
260
|
+
: selected?.path || "/";
|
|
261
|
+
|
|
262
|
+
const isPathDisabled = isAddMethod || isEdit;
|
|
263
|
+
const isMethodDisabled = isEdit;
|
|
264
|
+
|
|
265
|
+
const dialogTitle = isEdit
|
|
266
|
+
? "Edit API Endpoint"
|
|
267
|
+
: isAddMethod
|
|
268
|
+
? "Add Method"
|
|
269
|
+
: "Add Resource";
|
|
270
|
+
|
|
271
|
+
const handleCloseDialog = () =>
|
|
272
|
+
setDialog((prev) => ({
|
|
273
|
+
...prev,
|
|
274
|
+
open: false,
|
|
275
|
+
}));
|
|
276
|
+
|
|
277
|
+
const handleSave = () => {
|
|
278
|
+
if (isEdit) {
|
|
279
|
+
setApi((prev) => {
|
|
280
|
+
const idx = prev.findIndex(
|
|
281
|
+
(ep) =>
|
|
282
|
+
ep.path === selected.path &&
|
|
283
|
+
ep.method?.toLowerCase() === selected.method?.toLowerCase()
|
|
284
|
+
);
|
|
285
|
+
if (idx === -1) return prev;
|
|
286
|
+
|
|
287
|
+
const next = [...prev];
|
|
288
|
+
const current = next[idx];
|
|
289
|
+
|
|
290
|
+
next[idx] = {
|
|
291
|
+
...current,
|
|
292
|
+
request: {
|
|
293
|
+
...(current.request || {}),
|
|
294
|
+
schema: requestSchemaRef.current?.schemaOutput?.() || [],
|
|
295
|
+
},
|
|
296
|
+
response: {
|
|
297
|
+
...(current.response || {}),
|
|
298
|
+
schema: responseSchemaRef.current?.schemaOutput?.() || [],
|
|
299
|
+
},
|
|
300
|
+
params: paramsRef.current,
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
return next;
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
setDialog((prev) => ({ ...prev, open: false }));
|
|
307
|
+
} else {
|
|
308
|
+
const newEndpoint = {
|
|
309
|
+
path: pathRef.current,
|
|
310
|
+
method: methodRef.current,
|
|
311
|
+
request: requestSchemaRef.current?.schemaOutput?.() || {},
|
|
312
|
+
response: responseSchemaRef.current?.schemaOutput?.() || {},
|
|
313
|
+
params: paramsRef.current,
|
|
314
|
+
summary: `${methodRef.current} ${pathRef.current}`,
|
|
315
|
+
description: `API endpoint for ${pathRef.current}`,
|
|
316
|
+
};
|
|
317
|
+
|
|
318
|
+
setApi((prev) => [...prev, newEndpoint]);
|
|
319
|
+
setDialog((prev) => ({ ...prev, open: false }));
|
|
320
|
+
}
|
|
321
|
+
};
|
|
322
|
+
|
|
323
|
+
const handleDelete = () => {
|
|
324
|
+
if (!selected) return;
|
|
325
|
+
setApi((prev) =>
|
|
326
|
+
prev.filter(
|
|
327
|
+
(ep) =>
|
|
328
|
+
!(
|
|
329
|
+
ep.path === selected.path &&
|
|
330
|
+
ep.method?.toLowerCase() === selected.method?.toLowerCase()
|
|
331
|
+
)
|
|
332
|
+
)
|
|
333
|
+
);
|
|
334
|
+
setDialog((prev) => ({ ...prev, open: false }));
|
|
335
|
+
};
|
|
336
|
+
|
|
337
|
+
return (
|
|
338
|
+
<Box sx={{ display: "flex", height: "100%", gap: 2 }}>
|
|
339
|
+
<Box sx={{ width: 280, flexShrink: 0, height: "100%" }}>
|
|
340
|
+
<APITree />
|
|
341
|
+
</Box>
|
|
342
|
+
|
|
343
|
+
<NucDialog
|
|
344
|
+
title={dialogTitle}
|
|
345
|
+
open={dialog.open}
|
|
346
|
+
handleClose={handleCloseDialog}
|
|
347
|
+
maximizedDimensions={{ width: "75rem", height: "60rem" }}
|
|
348
|
+
minimizedDimensions={{ width: "65rem", height: "50rem" }}
|
|
349
|
+
action={
|
|
350
|
+
<APIDialogAction
|
|
351
|
+
view={view}
|
|
352
|
+
setApiDialogView={setView}
|
|
353
|
+
saveApiDialog={handleSave}
|
|
354
|
+
saveDisable={false}
|
|
355
|
+
deleteDisable={!isEdit}
|
|
356
|
+
deleteMethod={handleDelete}
|
|
357
|
+
/>
|
|
358
|
+
}
|
|
359
|
+
>
|
|
360
|
+
<Box
|
|
361
|
+
key={dialogKey}
|
|
362
|
+
sx={{ display: "flex", flexDirection: "column", height: "100%" }}
|
|
363
|
+
>
|
|
364
|
+
<APIPath
|
|
365
|
+
method={allowedMethods[0] || "GET"}
|
|
366
|
+
path={basePath}
|
|
367
|
+
methodRef={methodRef}
|
|
368
|
+
pathRef={pathRef}
|
|
369
|
+
onTypesButtonClick={() => setView("TYPES")}
|
|
370
|
+
allowedMethods={allowedMethods.length ? allowedMethods : ["GET"]}
|
|
371
|
+
isMethodDisabled={isMethodDisabled}
|
|
372
|
+
isPathDisabled={isPathDisabled}
|
|
373
|
+
validatePath={() => {}}
|
|
374
|
+
/>
|
|
375
|
+
<Divider sx={{ my: 2 }} />
|
|
376
|
+
{view === "PARAMS" && (
|
|
377
|
+
<APIParams
|
|
378
|
+
types={types}
|
|
379
|
+
paramsRef={paramsRef}
|
|
380
|
+
addParams={addParams}
|
|
381
|
+
/>
|
|
382
|
+
)}
|
|
383
|
+
{view === "BODY" && (
|
|
384
|
+
<NewAPIBody
|
|
385
|
+
types={types}
|
|
386
|
+
api={{
|
|
387
|
+
path: basePath,
|
|
388
|
+
method: methodRef.current,
|
|
389
|
+
params: paramsRef.current,
|
|
390
|
+
request: selectedEndpoint?.request || { schema: [] },
|
|
391
|
+
response: selectedEndpoint?.response || { schema: [] },
|
|
392
|
+
}}
|
|
393
|
+
requestSchemaRef={requestSchemaRef}
|
|
394
|
+
responseSchemaRef={responseSchemaRef}
|
|
395
|
+
/>
|
|
396
|
+
)}
|
|
397
|
+
{view === "TYPES" && (
|
|
398
|
+
<APITypes tstypes={[]} nuctypes={types} typesRef={typesRef} />
|
|
399
|
+
)}
|
|
400
|
+
</Box>
|
|
401
|
+
</NucDialog>
|
|
402
|
+
</Box>
|
|
403
|
+
);
|
|
404
|
+
};
|
|
405
|
+
|
|
406
|
+
export const APITreeWorkspace = {
|
|
407
|
+
render: () => <APIWorkspace />,
|
|
408
|
+
decorators: [
|
|
409
|
+
(Story) => (
|
|
410
|
+
<ThemeProvider theme={theme}>
|
|
411
|
+
<CssBaseline />
|
|
412
|
+
<div style={{ width: 900, height: 600 }}>
|
|
413
|
+
<Story />
|
|
414
|
+
</div>
|
|
415
|
+
</ThemeProvider>
|
|
416
|
+
),
|
|
417
|
+
],
|
|
418
|
+
parameters: {
|
|
419
|
+
layout: "centered",
|
|
420
|
+
docs: {
|
|
421
|
+
description: {
|
|
422
|
+
story:
|
|
423
|
+
"Full workspace: right-click a path node or click the + FAB to open the ResourceMenu, " +
|
|
424
|
+
"then choose Resource, Method, or Delete. Adding a resource or method opens the API dialog " +
|
|
425
|
+
"where you can configure the path, method, params, and body before saving.",
|
|
426
|
+
},
|
|
427
|
+
},
|
|
428
|
+
},
|
|
429
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
const ActionTemplate = {
|
|
2
|
+
GET: `function action(req) {
|
|
3
|
+
// Implement your GET logic here
|
|
4
|
+
return {};
|
|
5
|
+
}`,
|
|
6
|
+
POST: `function action(req) {
|
|
7
|
+
// Implement your POST logic here
|
|
8
|
+
return {};
|
|
9
|
+
}`,
|
|
10
|
+
PUT: `function action(req) {
|
|
11
|
+
// Implement your PUT logic here
|
|
12
|
+
return {};
|
|
13
|
+
}`,
|
|
14
|
+
DELETE: `function action(req) {
|
|
15
|
+
// Implement your DELETE logic here
|
|
16
|
+
return {};
|
|
17
|
+
}`,
|
|
18
|
+
PATCH: `function action(req) {
|
|
19
|
+
// Implement your PATCH logic here
|
|
20
|
+
return {};
|
|
21
|
+
}`,
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export default ActionTemplate;
|
|
@@ -18,12 +18,17 @@ const handleOAuthLogin = (
|
|
|
18
18
|
};
|
|
19
19
|
|
|
20
20
|
function LoginForm() {
|
|
21
|
-
const { name, project } = config();
|
|
21
|
+
const { name, project, credentials } = config();
|
|
22
22
|
|
|
23
23
|
const [email, setEmail] = useState("");
|
|
24
24
|
const [password, setPassword] = useState("");
|
|
25
25
|
|
|
26
|
-
const
|
|
26
|
+
const providerCheck =
|
|
27
|
+
credentials?.provider === "COGNITO" || credentials?.provider === "DEMO";
|
|
28
|
+
|
|
29
|
+
const hasContent = !providerCheck || !!project.nucleoid;
|
|
30
|
+
|
|
31
|
+
const renderHead = hasContent ? (
|
|
27
32
|
<Stack spacing={2} sx={{ mb: 5 }}>
|
|
28
33
|
<Typography variant="h4">Sign in to {name}</Typography>
|
|
29
34
|
{project.nucleoid && (
|
|
@@ -34,7 +39,7 @@ function LoginForm() {
|
|
|
34
39
|
</Stack>
|
|
35
40
|
)}
|
|
36
41
|
</Stack>
|
|
37
|
-
);
|
|
42
|
+
) : null;
|
|
38
43
|
|
|
39
44
|
const renderForm = (
|
|
40
45
|
<>
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import Iconify from "../components/Iconify";
|
|
2
2
|
import config from "../config/config";
|
|
3
|
-
import pkg from "../../../../../package.json";
|
|
4
3
|
import { useEvent } from "@nucleoidai/react-event";
|
|
5
4
|
import useSettings from "../hooks/useSettings";
|
|
6
5
|
import { useUser } from "../hooks/use-user";
|
|
@@ -29,6 +28,18 @@ import {
|
|
|
29
28
|
import { Button, Dialog, DialogActions, DialogContent } from "@mui/material";
|
|
30
29
|
import React, { useEffect, useState } from "react";
|
|
31
30
|
|
|
31
|
+
let pkg = {
|
|
32
|
+
name: "",
|
|
33
|
+
version: "",
|
|
34
|
+
description: "",
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
try {
|
|
38
|
+
pkg = require("../../../../../../package.json");
|
|
39
|
+
} catch (error) {
|
|
40
|
+
console.error("Failed to load package.json for About tab:", error);
|
|
41
|
+
}
|
|
42
|
+
|
|
32
43
|
function a11yProps(index) {
|
|
33
44
|
return {
|
|
34
45
|
id: `vertical-tab-${index}`,
|
|
@@ -45,6 +56,9 @@ const TabPanel = (props) => {
|
|
|
45
56
|
const SettingsDialogTabs = ({ tabs }) => {
|
|
46
57
|
const [value, setValue] = useState(0);
|
|
47
58
|
|
|
59
|
+
const hasPkgInfo =
|
|
60
|
+
pkg && (pkg.name || pkg.version || pkg.description) ? true : false;
|
|
61
|
+
|
|
48
62
|
const handleChange = (event, newValue) => {
|
|
49
63
|
setValue(newValue);
|
|
50
64
|
};
|
|
@@ -98,18 +112,20 @@ const SettingsDialogTabs = ({ tabs }) => {
|
|
|
98
112
|
sx={{ "& label": { color: "custom.grey" } }}
|
|
99
113
|
{...a11yProps(1)}
|
|
100
114
|
/>
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
115
|
+
{hasPkgInfo && (
|
|
116
|
+
<Tab
|
|
117
|
+
label={"About"}
|
|
118
|
+
sx={{ "& label": { color: "custom.grey" } }}
|
|
119
|
+
{...a11yProps(2)}
|
|
120
|
+
/>
|
|
121
|
+
)}
|
|
106
122
|
{tabs?.map((tab, index) => (
|
|
107
123
|
<Tab
|
|
108
124
|
key={tab.label}
|
|
109
125
|
iconPosition="start"
|
|
110
126
|
label={tab.label}
|
|
111
127
|
sx={{ "& label": { color: "custom.grey" } }}
|
|
112
|
-
{...a11yProps(index + 3)}
|
|
128
|
+
{...a11yProps(index + (hasPkgInfo ? 3 : 2))}
|
|
113
129
|
/>
|
|
114
130
|
))}
|
|
115
131
|
</Tabs>
|
|
@@ -120,11 +136,17 @@ const SettingsDialogTabs = ({ tabs }) => {
|
|
|
120
136
|
<TabPanel value={value} index={1}>
|
|
121
137
|
<Settings />
|
|
122
138
|
</TabPanel>
|
|
123
|
-
|
|
124
|
-
<
|
|
125
|
-
|
|
139
|
+
{hasPkgInfo && (
|
|
140
|
+
<TabPanel value={value} index={2}>
|
|
141
|
+
<About />
|
|
142
|
+
</TabPanel>
|
|
143
|
+
)}
|
|
126
144
|
{tabs?.map((tab, index) => (
|
|
127
|
-
<TabPanel
|
|
145
|
+
<TabPanel
|
|
146
|
+
key={tab.label}
|
|
147
|
+
value={value}
|
|
148
|
+
index={index + (hasPkgInfo ? 3 : 2)}
|
|
149
|
+
>
|
|
128
150
|
<tab.panel />
|
|
129
151
|
</TabPanel>
|
|
130
152
|
))}
|