@backstage/plugin-config-schema 0.1.34 → 0.1.35-next.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,32 @@
1
1
  # @backstage/plugin-config-schema
2
2
 
3
+ ## 0.1.35-next.1
4
+
5
+ ### Patch Changes
6
+
7
+ - c3fa90e184: Updated dependency `zen-observable` to `^0.10.0`.
8
+ - Updated dependencies
9
+ - @backstage/core-components@0.12.1-next.1
10
+ - @backstage/core-plugin-api@1.1.1-next.1
11
+ - @backstage/types@1.0.2-next.1
12
+ - @backstage/config@1.0.5-next.1
13
+ - @backstage/errors@1.1.4-next.1
14
+ - @backstage/theme@0.2.16
15
+
16
+ ## 0.1.35-next.0
17
+
18
+ ### Patch Changes
19
+
20
+ - 3280711113: Updated dependency `msw` to `^0.49.0`.
21
+ - 19356df560: Updated dependency `zen-observable` to `^0.9.0`.
22
+ - Updated dependencies
23
+ - @backstage/core-components@0.12.1-next.0
24
+ - @backstage/core-plugin-api@1.1.1-next.0
25
+ - @backstage/types@1.0.2-next.0
26
+ - @backstage/config@1.0.5-next.0
27
+ - @backstage/errors@1.1.4-next.0
28
+ - @backstage/theme@0.2.16
29
+
3
30
  ## 0.1.34
4
31
 
5
32
  ### Patch Changes
@@ -0,0 +1,495 @@
1
+ import React, { createContext, useContext, useRef, useEffect, useMemo } from 'react';
2
+ import useObservable from 'react-use/lib/useObservable';
3
+ import { configSchemaApiRef } from '../index.esm.js';
4
+ import 'zen-observable';
5
+ import '@backstage/errors';
6
+ import { makeStyles, Chip, Box, Divider, Typography, Paper, Table, TableBody, TableRow, TableCell, withStyles, createStyles, alpha } from '@material-ui/core';
7
+ import ChevronRightIcon from '@material-ui/icons/ChevronRight';
8
+ import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
9
+ import { TreeItem, TreeView } from '@material-ui/lab';
10
+ import { Page, Header, Content, Progress } from '@backstage/core-components';
11
+ import { useApi } from '@backstage/core-plugin-api';
12
+
13
+ class ScrollTargetsForwarder {
14
+ constructor() {
15
+ this.listeners = /* @__PURE__ */ new Map();
16
+ }
17
+ setScrollListener(id, listener) {
18
+ this.listeners.set(id, listener);
19
+ return () => {
20
+ if (this.listeners.get(id) === listener) {
21
+ this.listeners.delete(id);
22
+ }
23
+ };
24
+ }
25
+ scrollTo(id) {
26
+ var _a;
27
+ (_a = this.listeners.get(id)) == null ? void 0 : _a();
28
+ }
29
+ }
30
+ const ScrollTargetsContext = createContext(
31
+ void 0
32
+ );
33
+ function ScrollTargetsProvider({ children }) {
34
+ return /* @__PURE__ */ React.createElement(
35
+ ScrollTargetsContext.Provider,
36
+ {
37
+ value: new ScrollTargetsForwarder(),
38
+ children
39
+ }
40
+ );
41
+ }
42
+ function useScrollTargets() {
43
+ return useContext(ScrollTargetsContext);
44
+ }
45
+
46
+ function titleVariant(depth) {
47
+ if (depth <= 1) {
48
+ return "h2";
49
+ } else if (depth === 2) {
50
+ return "h3";
51
+ } else if (depth === 3) {
52
+ return "h4";
53
+ } else if (depth === 4) {
54
+ return "h5";
55
+ }
56
+ return "h6";
57
+ }
58
+ const useChildViewStyles = makeStyles((theme) => ({
59
+ title: {
60
+ marginBottom: 0
61
+ },
62
+ chip: {
63
+ marginLeft: theme.spacing(1),
64
+ marginRight: 0,
65
+ marginBottom: 0
66
+ }
67
+ }));
68
+ function ChildView({
69
+ path,
70
+ depth,
71
+ schema,
72
+ required,
73
+ lastChild
74
+ }) {
75
+ const classes = useChildViewStyles();
76
+ const titleRef = useRef(null);
77
+ const scroll = useScrollTargets();
78
+ useEffect(() => {
79
+ return scroll == null ? void 0 : scroll.setScrollListener(path, () => {
80
+ var _a;
81
+ (_a = titleRef.current) == null ? void 0 : _a.scrollIntoView({ behavior: "smooth" });
82
+ });
83
+ }, [scroll, path]);
84
+ const chips = new Array();
85
+ const chipProps = { size: "small", classes: { root: classes.chip } };
86
+ if (required) {
87
+ chips.push(
88
+ /* @__PURE__ */ React.createElement(Chip, { label: "required", color: "default", key: "required", ...chipProps })
89
+ );
90
+ }
91
+ const visibility = schema == null ? void 0 : schema.visibility;
92
+ if (visibility === "frontend") {
93
+ chips.push(
94
+ /* @__PURE__ */ React.createElement(Chip, { label: "frontend", color: "primary", key: "visibility", ...chipProps })
95
+ );
96
+ } else if (visibility === "secret") {
97
+ chips.push(
98
+ /* @__PURE__ */ React.createElement(Chip, { label: "secret", color: "secondary", key: "visibility", ...chipProps })
99
+ );
100
+ }
101
+ return /* @__PURE__ */ React.createElement(Box, { paddingBottom: lastChild ? 4 : 8, display: "flex", flexDirection: "row" }, /* @__PURE__ */ React.createElement(Divider, { orientation: "vertical", flexItem: true }), /* @__PURE__ */ React.createElement(Box, { paddingLeft: 2, flex: 1 }, /* @__PURE__ */ React.createElement(
102
+ Box,
103
+ {
104
+ display: "flex",
105
+ flexDirection: "row",
106
+ marginBottom: 2,
107
+ alignItems: "center"
108
+ },
109
+ /* @__PURE__ */ React.createElement(
110
+ Typography,
111
+ {
112
+ ref: titleRef,
113
+ variant: titleVariant(depth),
114
+ classes: { root: classes.title }
115
+ },
116
+ path
117
+ ),
118
+ chips.length > 0 && /* @__PURE__ */ React.createElement(Box, { marginLeft: 1 }),
119
+ chips
120
+ ), schema && /* @__PURE__ */ React.createElement(SchemaView, { path, depth, schema })));
121
+ }
122
+
123
+ function MetadataViewRow({ label, text, data }) {
124
+ if (text === void 0 && data === void 0) {
125
+ return null;
126
+ }
127
+ return /* @__PURE__ */ React.createElement(TableRow, null, /* @__PURE__ */ React.createElement(TableCell, { style: { width: 160 } }, /* @__PURE__ */ React.createElement(Typography, { variant: "body1", noWrap: true, style: { fontWeight: 900 } }, label)), /* @__PURE__ */ React.createElement(TableCell, null, /* @__PURE__ */ React.createElement(Typography, { variant: "body1" }, data ? JSON.stringify(data) : text)));
128
+ }
129
+ function MetadataView({ schema }) {
130
+ return /* @__PURE__ */ React.createElement(Paper, { variant: "outlined", square: true, style: { width: "100%" } }, /* @__PURE__ */ React.createElement(Table, { size: "small" }, /* @__PURE__ */ React.createElement(TableBody, null, /* @__PURE__ */ React.createElement(MetadataViewRow, { label: "Type", data: schema.type }), /* @__PURE__ */ React.createElement(MetadataViewRow, { label: "Allowed values", data: schema.enum }), schema.additionalProperties === true && /* @__PURE__ */ React.createElement(MetadataViewRow, { label: "Additional Properties", text: "true" }), schema.additionalItems === true && /* @__PURE__ */ React.createElement(MetadataViewRow, { label: "Additional Items", text: "true" }), /* @__PURE__ */ React.createElement(MetadataViewRow, { label: "Format", text: schema.format }), /* @__PURE__ */ React.createElement(
131
+ MetadataViewRow,
132
+ {
133
+ label: "Pattern",
134
+ text: schema.pattern && String(schema.pattern)
135
+ }
136
+ ), /* @__PURE__ */ React.createElement(MetadataViewRow, { label: "Minimum", data: schema.minimum }), /* @__PURE__ */ React.createElement(MetadataViewRow, { label: "Maximum", data: schema.maximum }), /* @__PURE__ */ React.createElement(
137
+ MetadataViewRow,
138
+ {
139
+ label: "Exclusive minimum",
140
+ data: schema.exclusiveMinimum
141
+ }
142
+ ), /* @__PURE__ */ React.createElement(
143
+ MetadataViewRow,
144
+ {
145
+ label: "Exclusive maximum",
146
+ data: schema.exclusiveMaximum
147
+ }
148
+ ), /* @__PURE__ */ React.createElement(MetadataViewRow, { label: "Multiple of", data: schema.multipleOf }), /* @__PURE__ */ React.createElement(
149
+ MetadataViewRow,
150
+ {
151
+ label: "Maximum number of items",
152
+ data: schema.maxItems
153
+ }
154
+ ), /* @__PURE__ */ React.createElement(
155
+ MetadataViewRow,
156
+ {
157
+ label: "Minimum number of items",
158
+ data: schema.minItems
159
+ }
160
+ ), /* @__PURE__ */ React.createElement(
161
+ MetadataViewRow,
162
+ {
163
+ label: "Maximum number of properties",
164
+ data: schema.maxProperties
165
+ }
166
+ ), /* @__PURE__ */ React.createElement(
167
+ MetadataViewRow,
168
+ {
169
+ label: "Minimum number of properties",
170
+ data: schema.minProperties
171
+ }
172
+ ), /* @__PURE__ */ React.createElement(MetadataViewRow, { label: "Maximum Length", data: schema.maxLength }), /* @__PURE__ */ React.createElement(MetadataViewRow, { label: "Minimum Length", data: schema.minLength }), /* @__PURE__ */ React.createElement(
173
+ MetadataViewRow,
174
+ {
175
+ label: "Items must be unique",
176
+ data: schema.uniqueItems
177
+ }
178
+ ))));
179
+ }
180
+
181
+ function ArrayView({ path, depth, schema }) {
182
+ const itemDepth = depth + 1;
183
+ const itemPath = path ? `${path}[]` : "[]";
184
+ const itemSchema = schema.items;
185
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Box, { marginBottom: 4 }, schema.description && /* @__PURE__ */ React.createElement(Box, { marginBottom: 4 }, /* @__PURE__ */ React.createElement(Typography, { variant: "body1" }, schema.description)), /* @__PURE__ */ React.createElement(MetadataView, { schema })), /* @__PURE__ */ React.createElement(Typography, { variant: "overline" }, "Items"), /* @__PURE__ */ React.createElement(
186
+ ChildView,
187
+ {
188
+ lastChild: true,
189
+ path: itemPath,
190
+ depth: itemDepth,
191
+ schema: itemSchema
192
+ }
193
+ ), schema.additionalItems && schema.additionalItems !== true && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Typography, { variant: "overline" }, "Additional Items"), /* @__PURE__ */ React.createElement(
194
+ ChildView,
195
+ {
196
+ path: itemPath,
197
+ depth: itemDepth,
198
+ schema: schema.additionalItems,
199
+ lastChild: true
200
+ }
201
+ )));
202
+ }
203
+
204
+ function MatchView({
205
+ path,
206
+ depth,
207
+ schema,
208
+ label
209
+ }) {
210
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Typography, { variant: "overline" }, label), schema.map((optionSchema, index) => /* @__PURE__ */ React.createElement(
211
+ ChildView,
212
+ {
213
+ key: index,
214
+ path: `${path}/${index + 1}`,
215
+ depth: depth + 1,
216
+ schema: optionSchema,
217
+ lastChild: index === schema.length - 1
218
+ }
219
+ )));
220
+ }
221
+
222
+ function isRequired(name, required) {
223
+ if (required === true) {
224
+ return true;
225
+ }
226
+ if (Array.isArray(required)) {
227
+ return required.includes(name);
228
+ }
229
+ return false;
230
+ }
231
+ function ObjectView({ path, depth, schema }) {
232
+ var _a, _b;
233
+ const properties = Object.entries((_a = schema.properties) != null ? _a : {});
234
+ const patternProperties = Object.entries((_b = schema.patternProperties) != null ? _b : {});
235
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, depth > 0 && /* @__PURE__ */ React.createElement(Box, { marginBottom: 4 }, schema.description && /* @__PURE__ */ React.createElement(Box, { marginBottom: 4 }, /* @__PURE__ */ React.createElement(Typography, { variant: "body1" }, schema.description)), /* @__PURE__ */ React.createElement(MetadataView, { schema })), properties.length > 0 && /* @__PURE__ */ React.createElement(React.Fragment, null, depth > 0 && /* @__PURE__ */ React.createElement(Typography, { variant: "overline" }, "Properties"), properties.map(([name, propSchema], index) => /* @__PURE__ */ React.createElement(
236
+ ChildView,
237
+ {
238
+ key: name,
239
+ path: path ? `${path}.${name}` : name,
240
+ depth: depth + 1,
241
+ schema: propSchema,
242
+ lastChild: index === properties.length - 1,
243
+ required: isRequired(name, schema.required)
244
+ }
245
+ ))), patternProperties.length > 0 && /* @__PURE__ */ React.createElement(React.Fragment, null, depth > 0 && /* @__PURE__ */ React.createElement(Typography, { variant: "overline" }, "Pattern Properties"), patternProperties.map(([name, propSchema], index) => /* @__PURE__ */ React.createElement(
246
+ ChildView,
247
+ {
248
+ key: name,
249
+ path: path ? `${path}.<${name}>` : name,
250
+ depth: depth + 1,
251
+ schema: propSchema,
252
+ lastChild: index === patternProperties.length - 1,
253
+ required: isRequired(name, schema.required)
254
+ }
255
+ ))), schema.additionalProperties && schema.additionalProperties !== true && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Typography, { variant: "overline" }, "Additional Properties"), /* @__PURE__ */ React.createElement(
256
+ ChildView,
257
+ {
258
+ path: `${path}.*`,
259
+ depth: depth + 1,
260
+ schema: schema.additionalProperties,
261
+ lastChild: true
262
+ }
263
+ )));
264
+ }
265
+
266
+ function ScalarView({ schema }) {
267
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, schema.description && /* @__PURE__ */ React.createElement(Box, { marginBottom: 4 }, /* @__PURE__ */ React.createElement(Typography, { variant: "body1" }, schema.description)), /* @__PURE__ */ React.createElement(MetadataView, { schema }));
268
+ }
269
+
270
+ function SchemaView(props) {
271
+ const { schema } = props;
272
+ if (schema.anyOf) {
273
+ return /* @__PURE__ */ React.createElement(
274
+ MatchView,
275
+ {
276
+ ...props,
277
+ schema: schema.anyOf,
278
+ label: "Any of the following"
279
+ }
280
+ );
281
+ }
282
+ if (schema.oneOf) {
283
+ return /* @__PURE__ */ React.createElement(
284
+ MatchView,
285
+ {
286
+ ...props,
287
+ schema: schema.oneOf,
288
+ label: "One of the following"
289
+ }
290
+ );
291
+ }
292
+ if (schema.allOf) {
293
+ return /* @__PURE__ */ React.createElement(
294
+ MatchView,
295
+ {
296
+ ...props,
297
+ schema: schema.allOf,
298
+ label: "All of the following"
299
+ }
300
+ );
301
+ }
302
+ switch (schema.type) {
303
+ case "array":
304
+ return /* @__PURE__ */ React.createElement(ArrayView, { ...props });
305
+ case "object":
306
+ case void 0:
307
+ return /* @__PURE__ */ React.createElement(ObjectView, { ...props });
308
+ default:
309
+ return /* @__PURE__ */ React.createElement(ScalarView, { ...props });
310
+ }
311
+ }
312
+
313
+ const StyledTreeItem = withStyles(
314
+ (theme) => createStyles({
315
+ label: {
316
+ userSelect: "none"
317
+ },
318
+ group: {
319
+ marginLeft: 7,
320
+ paddingLeft: theme.spacing(1),
321
+ borderLeft: `1px solid ${alpha(theme.palette.text.primary, 0.15)}`
322
+ }
323
+ })
324
+ )((props) => /* @__PURE__ */ React.createElement(TreeItem, { ...props }));
325
+ function createSchemaBrowserItems(expanded, schema, path = "", depth = 0) {
326
+ let matchArr;
327
+ if (schema.anyOf) {
328
+ matchArr = schema.anyOf;
329
+ } else if (schema.oneOf) {
330
+ matchArr = schema.oneOf;
331
+ } else if (schema.allOf) {
332
+ matchArr = schema.allOf;
333
+ }
334
+ if (matchArr) {
335
+ return matchArr.map((childSchema, index) => {
336
+ const childPath = `${path}/${index + 1}`;
337
+ if (depth > 0)
338
+ expanded.push(childPath);
339
+ return /* @__PURE__ */ React.createElement(
340
+ StyledTreeItem,
341
+ {
342
+ key: childPath,
343
+ nodeId: childPath,
344
+ label: `<Option ${index + 1}>`
345
+ },
346
+ createSchemaBrowserItems(
347
+ expanded,
348
+ childSchema,
349
+ childPath,
350
+ depth + 1
351
+ )
352
+ );
353
+ });
354
+ }
355
+ switch (schema.type) {
356
+ case "array": {
357
+ const childPath = `${path}[]`;
358
+ if (depth > 0)
359
+ expanded.push(childPath);
360
+ return /* @__PURE__ */ React.createElement(StyledTreeItem, { nodeId: childPath, label: "[]" }, schema.items && createSchemaBrowserItems(
361
+ expanded,
362
+ schema.items,
363
+ childPath,
364
+ depth + 1
365
+ ));
366
+ }
367
+ case "object":
368
+ case void 0: {
369
+ const children = [];
370
+ if (schema.properties) {
371
+ children.push(
372
+ ...Object.entries(schema.properties).map(([name, childSchema]) => {
373
+ const childPath = path ? `${path}.${name}` : name;
374
+ if (depth > 0)
375
+ expanded.push(childPath);
376
+ return /* @__PURE__ */ React.createElement(StyledTreeItem, { key: childPath, nodeId: childPath, label: name }, createSchemaBrowserItems(
377
+ expanded,
378
+ childSchema,
379
+ childPath,
380
+ depth + 1
381
+ ));
382
+ })
383
+ );
384
+ }
385
+ if (schema.patternProperties) {
386
+ children.push(
387
+ ...Object.entries(schema.patternProperties).map(
388
+ ([name, childSchema]) => {
389
+ const childPath = `${path}.<${name}>`;
390
+ if (depth > 0)
391
+ expanded.push(childPath);
392
+ return /* @__PURE__ */ React.createElement(
393
+ StyledTreeItem,
394
+ {
395
+ key: childPath,
396
+ nodeId: childPath,
397
+ label: `<${name}>`
398
+ },
399
+ createSchemaBrowserItems(
400
+ expanded,
401
+ childSchema,
402
+ childPath,
403
+ depth + 1
404
+ )
405
+ );
406
+ }
407
+ )
408
+ );
409
+ }
410
+ if (schema.additionalProperties && schema.additionalProperties !== true) {
411
+ const childPath = `${path}.*`;
412
+ if (depth > 0)
413
+ expanded.push(childPath);
414
+ children.push(
415
+ /* @__PURE__ */ React.createElement(StyledTreeItem, { key: childPath, nodeId: childPath, label: "*" }, createSchemaBrowserItems(
416
+ expanded,
417
+ schema.additionalProperties,
418
+ childPath,
419
+ depth + 1
420
+ ))
421
+ );
422
+ }
423
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, children);
424
+ }
425
+ default:
426
+ return null;
427
+ }
428
+ }
429
+ function SchemaBrowser({ schema }) {
430
+ const scroll = useScrollTargets();
431
+ const expandedRef = useRef([]);
432
+ const data = useMemo(() => {
433
+ const expanded = new Array();
434
+ const items = createSchemaBrowserItems(expanded, schema);
435
+ return { items, expanded };
436
+ }, [schema]);
437
+ if (!scroll) {
438
+ throw new Error("No scroll handler available");
439
+ }
440
+ const handleToggle = (_event, expanded) => {
441
+ expandedRef.current = expanded;
442
+ };
443
+ const handleSelect = (_event, nodeId) => {
444
+ if (expandedRef.current.includes(nodeId)) {
445
+ scroll.scrollTo(nodeId);
446
+ }
447
+ };
448
+ return /* @__PURE__ */ React.createElement(
449
+ TreeView,
450
+ {
451
+ defaultExpanded: data.expanded,
452
+ defaultCollapseIcon: /* @__PURE__ */ React.createElement(ExpandMoreIcon, null),
453
+ defaultExpandIcon: /* @__PURE__ */ React.createElement(ChevronRightIcon, null),
454
+ onNodeToggle: handleToggle,
455
+ onNodeSelect: handleSelect
456
+ },
457
+ data.items
458
+ );
459
+ }
460
+
461
+ const SchemaViewer = ({ schema }) => {
462
+ return /* @__PURE__ */ React.createElement(Box, { flex: "1", position: "relative" }, /* @__PURE__ */ React.createElement(
463
+ Box,
464
+ {
465
+ clone: true,
466
+ position: "absolute",
467
+ display: "flex",
468
+ flexDirection: "row",
469
+ flexWrap: "nowrap",
470
+ maxHeight: "100%"
471
+ },
472
+ /* @__PURE__ */ React.createElement(Paper, { elevation: 3 }, /* @__PURE__ */ React.createElement(ScrollTargetsProvider, null, /* @__PURE__ */ React.createElement(Box, { padding: 1, overflow: "auto", width: 300 }, /* @__PURE__ */ React.createElement(SchemaBrowser, { schema })), /* @__PURE__ */ React.createElement(Box, { flex: "1", overflow: "auto" }, /* @__PURE__ */ React.createElement(SchemaView, { schema, path: "", depth: 0 }))))
473
+ ));
474
+ };
475
+
476
+ const ConfigSchemaPage = () => {
477
+ const configSchemaApi = useApi(configSchemaApiRef);
478
+ const schemaResult = useObservable(
479
+ useMemo(() => configSchemaApi.schema$(), [configSchemaApi])
480
+ );
481
+ let content;
482
+ if (schemaResult) {
483
+ if (schemaResult.schema) {
484
+ content = /* @__PURE__ */ React.createElement(SchemaViewer, { schema: schemaResult.schema });
485
+ } else {
486
+ content = /* @__PURE__ */ React.createElement(Typography, { variant: "h4" }, "No configuration schema available");
487
+ }
488
+ } else {
489
+ content = /* @__PURE__ */ React.createElement(Progress, null);
490
+ }
491
+ return /* @__PURE__ */ React.createElement(Page, { themeId: "tool" }, /* @__PURE__ */ React.createElement(Header, { title: "Configuration Reference" }), /* @__PURE__ */ React.createElement(Content, { stretch: true }, content));
492
+ };
493
+
494
+ export { ConfigSchemaPage };
495
+ //# sourceMappingURL=index-66fc5938.esm.js.map