@backstage/plugin-scaffolder 1.30.1 → 1.31.0-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 +46 -4
- package/dist/alpha/components/TemplateEditorPage/{CustomFieldPlaygroud.esm.js → CustomFieldPlayground.esm.js} +3 -3
- package/dist/alpha/components/TemplateEditorPage/CustomFieldPlayground.esm.js.map +1 -0
- package/dist/alpha/components/TemplateEditorPage/TemplateEditorToolbar.esm.js +24 -2
- package/dist/alpha/components/TemplateEditorPage/TemplateEditorToolbar.esm.js.map +1 -1
- package/dist/alpha/components/TemplateEditorPage/TemplateFormPreviewer.esm.js +1 -1
- package/dist/alpha/components/TemplateEditorPage/TemplateFormPreviewer.esm.js.map +1 -1
- package/dist/alpha/components/TemplateListPage/TemplateListPage.esm.js +4 -2
- package/dist/alpha/components/TemplateListPage/TemplateListPage.esm.js.map +1 -1
- package/dist/alpha/plugin.esm.js +4 -3
- package/dist/alpha/plugin.esm.js.map +1 -1
- package/dist/alpha.d.ts +23 -0
- package/dist/api.esm.js +1 -1
- package/dist/api.esm.js.map +1 -1
- package/dist/components/ActionsPage/ActionsPage.esm.js +4 -2
- package/dist/components/ActionsPage/ActionsPage.esm.js.map +1 -1
- package/dist/components/FileBrowser/FileBrowser.esm.js +3 -3
- package/dist/components/FileBrowser/FileBrowser.esm.js.map +1 -1
- package/dist/components/ListTasksPage/ListTasksPage.esm.js +4 -2
- package/dist/components/ListTasksPage/ListTasksPage.esm.js.map +1 -1
- package/dist/components/RenderSchema/RenderSchema.esm.js.map +1 -1
- package/dist/components/Router/Router.esm.js +9 -1
- package/dist/components/Router/Router.esm.js.map +1 -1
- package/dist/components/TemplatingExtensionsPage/TemplateFilters.esm.js +132 -0
- package/dist/components/TemplatingExtensionsPage/TemplateFilters.esm.js.map +1 -0
- package/dist/components/TemplatingExtensionsPage/TemplateGlobals.esm.js +168 -0
- package/dist/components/TemplatingExtensionsPage/TemplateGlobals.esm.js.map +1 -0
- package/dist/components/TemplatingExtensionsPage/TemplatingExtensionsPage.esm.js +250 -0
- package/dist/components/TemplatingExtensionsPage/TemplatingExtensionsPage.esm.js.map +1 -0
- package/dist/components/TemplatingExtensionsPage/functionArgs.esm.js +19 -0
- package/dist/components/TemplatingExtensionsPage/functionArgs.esm.js.map +1 -0
- package/dist/components/TemplatingExtensionsPage/navigation.esm.js +24 -0
- package/dist/components/TemplatingExtensionsPage/navigation.esm.js.map +1 -0
- package/dist/components/fields/EntityPicker/EntityPicker.esm.js +4 -1
- package/dist/components/fields/EntityPicker/EntityPicker.esm.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/plugin.esm.js +3 -2
- package/dist/plugin.esm.js.map +1 -1
- package/dist/routes.esm.js +6 -1
- package/dist/routes.esm.js.map +1 -1
- package/dist/translation.esm.js +37 -0
- package/dist/translation.esm.js.map +1 -1
- package/package.json +22 -22
- package/dist/alpha/components/TemplateEditorPage/CustomFieldPlaygroud.esm.js.map +0 -1
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
|
|
2
|
+
import { MarkdownContent } from '@backstage/core-components';
|
|
3
|
+
import Accordion from '@material-ui/core/Accordion';
|
|
4
|
+
import AccordionDetails from '@material-ui/core/AccordionDetails';
|
|
5
|
+
import AccordionSummary from '@material-ui/core/AccordionSummary';
|
|
6
|
+
import Box from '@material-ui/core/Box';
|
|
7
|
+
import Typography from '@material-ui/core/Typography';
|
|
8
|
+
import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
|
|
9
|
+
import classNames from 'classnames';
|
|
10
|
+
import React, { useState } from 'react';
|
|
11
|
+
import { RenderSchema } from '../RenderSchema/RenderSchema.esm.js';
|
|
12
|
+
import { ScaffolderUsageExamplesTable } from '../ScaffolderUsageExamplesTable/ScaffolderUsageExamplesTable.esm.js';
|
|
13
|
+
import { inspectFunctionArgSchema } from './functionArgs.esm.js';
|
|
14
|
+
import { renderFragment } from './navigation.esm.js';
|
|
15
|
+
|
|
16
|
+
const FilterDetailContent = ({
|
|
17
|
+
t,
|
|
18
|
+
classes,
|
|
19
|
+
name,
|
|
20
|
+
filter
|
|
21
|
+
}) => {
|
|
22
|
+
const expanded = useState({});
|
|
23
|
+
if (!Object.keys(filter).length) {
|
|
24
|
+
return /* @__PURE__ */ jsx(Typography, { style: { fontStyle: "italic" }, children: t("templatingExtensions.content.filters.metadataAbsent") });
|
|
25
|
+
}
|
|
26
|
+
const schema = filter.schema;
|
|
27
|
+
const partialSchemaRenderContext = {
|
|
28
|
+
classes,
|
|
29
|
+
expanded,
|
|
30
|
+
headings: [/* @__PURE__ */ jsx(Typography, { variant: "h6", component: "h4" })]
|
|
31
|
+
};
|
|
32
|
+
return /* @__PURE__ */ jsxs(React.Fragment, { children: [
|
|
33
|
+
filter.description && /* @__PURE__ */ jsx(MarkdownContent, { content: filter.description }),
|
|
34
|
+
/* @__PURE__ */ jsxs(Box, { pb: 2, children: [
|
|
35
|
+
/* @__PURE__ */ jsx(Typography, { variant: "h5", component: "h3", children: t("templatingExtensions.content.filters.schema.input") }),
|
|
36
|
+
/* @__PURE__ */ jsx(
|
|
37
|
+
RenderSchema,
|
|
38
|
+
{
|
|
39
|
+
strategy: "root",
|
|
40
|
+
context: {
|
|
41
|
+
parentId: `${name}.input`,
|
|
42
|
+
...partialSchemaRenderContext
|
|
43
|
+
},
|
|
44
|
+
schema: schema?.input ?? {}
|
|
45
|
+
}
|
|
46
|
+
)
|
|
47
|
+
] }),
|
|
48
|
+
schema?.arguments?.length && /* @__PURE__ */ jsxs(Box, { pb: 2, children: [
|
|
49
|
+
/* @__PURE__ */ jsx(Typography, { variant: "h5", component: "h3", children: t("templatingExtensions.content.filters.schema.arguments") }),
|
|
50
|
+
schema.arguments.map((arg, i) => {
|
|
51
|
+
const [argSchema, required] = inspectFunctionArgSchema(arg);
|
|
52
|
+
return /* @__PURE__ */ jsxs(React.Fragment, { children: [
|
|
53
|
+
/* @__PURE__ */ jsx(
|
|
54
|
+
"div",
|
|
55
|
+
{
|
|
56
|
+
className: classNames({ [classes.argRequired]: required }),
|
|
57
|
+
children: /* @__PURE__ */ jsx(Typography, { variant: "h6", component: "h4", children: `[${i}]` })
|
|
58
|
+
}
|
|
59
|
+
),
|
|
60
|
+
/* @__PURE__ */ jsx(
|
|
61
|
+
RenderSchema,
|
|
62
|
+
{
|
|
63
|
+
strategy: "root",
|
|
64
|
+
context: {
|
|
65
|
+
parentId: `${name}.arg${i}`,
|
|
66
|
+
...partialSchemaRenderContext,
|
|
67
|
+
headings: [/* @__PURE__ */ jsx(Typography, { variant: "h6", component: "h5" })]
|
|
68
|
+
},
|
|
69
|
+
schema: argSchema
|
|
70
|
+
}
|
|
71
|
+
)
|
|
72
|
+
] }, i);
|
|
73
|
+
})
|
|
74
|
+
] }, `${name}.args`),
|
|
75
|
+
/* @__PURE__ */ jsxs(Box, { pb: 2, children: [
|
|
76
|
+
/* @__PURE__ */ jsx(Typography, { variant: "h5", component: "h3", children: t("templatingExtensions.content.filters.schema.output") }),
|
|
77
|
+
/* @__PURE__ */ jsx(
|
|
78
|
+
RenderSchema,
|
|
79
|
+
{
|
|
80
|
+
strategy: "root",
|
|
81
|
+
context: {
|
|
82
|
+
parentId: `${name}.output`,
|
|
83
|
+
...partialSchemaRenderContext
|
|
84
|
+
},
|
|
85
|
+
schema: schema?.output ?? {}
|
|
86
|
+
}
|
|
87
|
+
)
|
|
88
|
+
] }),
|
|
89
|
+
filter.examples && /* @__PURE__ */ jsxs(Accordion, { children: [
|
|
90
|
+
/* @__PURE__ */ jsx(AccordionSummary, { expandIcon: /* @__PURE__ */ jsx(ExpandMoreIcon, {}), children: /* @__PURE__ */ jsx(Typography, { variant: "h5", component: "h3", children: t("templatingExtensions.content.filters.examples") }) }),
|
|
91
|
+
/* @__PURE__ */ jsx(AccordionDetails, { children: /* @__PURE__ */ jsx(Box, { pb: 2, children: /* @__PURE__ */ jsx(ScaffolderUsageExamplesTable, { examples: filter.examples }) }) })
|
|
92
|
+
] })
|
|
93
|
+
] }, `${name}.detail`);
|
|
94
|
+
};
|
|
95
|
+
const TemplateFilters = ({
|
|
96
|
+
t,
|
|
97
|
+
classes,
|
|
98
|
+
filters,
|
|
99
|
+
baseLink,
|
|
100
|
+
selectedItem
|
|
101
|
+
}) => {
|
|
102
|
+
if (selectedItem && selectedItem.kind !== "filter") {
|
|
103
|
+
return /* @__PURE__ */ jsx(Fragment, {});
|
|
104
|
+
}
|
|
105
|
+
if (!Object.keys(filters).length) {
|
|
106
|
+
return /* @__PURE__ */ jsx("div", { "data-testid": "no-filters", children: t("templatingExtensions.content.filters.notAvailable") });
|
|
107
|
+
}
|
|
108
|
+
return /* @__PURE__ */ jsx("div", { "data-testid": "filters", children: Object.entries(
|
|
109
|
+
selectedItem ? { [selectedItem.name]: filters[selectedItem.name] } : filters
|
|
110
|
+
).map(([name, filter]) => {
|
|
111
|
+
const fragment = renderFragment({ kind: "filter", name });
|
|
112
|
+
return /* @__PURE__ */ jsxs(Box, { pb: 4, "data-testid": name, children: [
|
|
113
|
+
/* @__PURE__ */ jsx(
|
|
114
|
+
Typography,
|
|
115
|
+
{
|
|
116
|
+
id: fragment,
|
|
117
|
+
variant: "h4",
|
|
118
|
+
component: "h2",
|
|
119
|
+
className: classes.code,
|
|
120
|
+
children: name
|
|
121
|
+
}
|
|
122
|
+
),
|
|
123
|
+
React.cloneElement(baseLink, {
|
|
124
|
+
to: `${baseLink.props.to}#${fragment}`
|
|
125
|
+
}),
|
|
126
|
+
/* @__PURE__ */ jsx(FilterDetailContent, { ...{ t, classes, name, filter } })
|
|
127
|
+
] }, name);
|
|
128
|
+
}) });
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
export { TemplateFilters };
|
|
132
|
+
//# sourceMappingURL=TemplateFilters.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TemplateFilters.esm.js","sources":["../../../src/components/TemplatingExtensionsPage/TemplateFilters.tsx"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { Link, MarkdownContent } from '@backstage/core-components';\nimport {\n ListTemplatingExtensionsResponse,\n TemplateFilter,\n} from '@backstage/plugin-scaffolder-react';\nimport Accordion from '@material-ui/core/Accordion';\nimport AccordionDetails from '@material-ui/core/AccordionDetails';\nimport AccordionSummary from '@material-ui/core/AccordionSummary';\nimport Box from '@material-ui/core/Box';\nimport { ClassNameMap } from '@material-ui/core/styles/withStyles';\nimport Typography from '@material-ui/core/Typography';\nimport ExpandMoreIcon from '@material-ui/icons/ExpandMore';\nimport classNames from 'classnames';\nimport React, { ReactElement, useState } from 'react';\nimport { scaffolderTranslationRef } from '../../translation';\nimport { Expanded, RenderSchema, SchemaRenderContext } from '../RenderSchema';\nimport { ScaffolderUsageExamplesTable } from '../ScaffolderUsageExamplesTable';\nimport { inspectFunctionArgSchema } from './functionArgs';\nimport { Extension, renderFragment } from './navigation';\nimport { StyleClasses, TranslationMessages } from './types';\n\nconst FilterDetailContent = ({\n t,\n classes,\n name,\n filter,\n}: {\n t: TranslationMessages<typeof scaffolderTranslationRef>;\n classes: ClassNameMap;\n name: string;\n filter: TemplateFilter;\n}) => {\n const expanded = useState<Expanded>({});\n if (!Object.keys(filter).length) {\n return (\n <Typography style={{ fontStyle: 'italic' }}>\n {t('templatingExtensions.content.filters.metadataAbsent')}\n </Typography>\n );\n }\n const schema = filter.schema;\n const partialSchemaRenderContext: Omit<SchemaRenderContext, 'parentId'> = {\n classes,\n expanded,\n headings: [<Typography variant=\"h6\" component=\"h4\" />],\n };\n return (\n <React.Fragment key={`${name}.detail`}>\n {filter.description && <MarkdownContent content={filter.description} />}\n <Box pb={2}>\n <Typography variant=\"h5\" component=\"h3\">\n {t('templatingExtensions.content.filters.schema.input')}\n </Typography>\n <RenderSchema\n strategy=\"root\"\n context={{\n parentId: `${name}.input`,\n ...partialSchemaRenderContext,\n }}\n schema={schema?.input ?? {}}\n />\n </Box>\n {schema?.arguments?.length && (\n <Box key={`${name}.args`} pb={2}>\n <Typography variant=\"h5\" component=\"h3\">\n {t('templatingExtensions.content.filters.schema.arguments')}\n </Typography>\n {schema.arguments.map((arg, i) => {\n const [argSchema, required] = inspectFunctionArgSchema(arg);\n\n return (\n <React.Fragment key={i}>\n <div\n className={classNames({ [classes.argRequired]: required })}\n >\n <Typography variant=\"h6\" component=\"h4\">\n {`[${i}]`}\n </Typography>\n </div>\n <RenderSchema\n strategy=\"root\"\n context={{\n parentId: `${name}.arg${i}`,\n ...partialSchemaRenderContext,\n headings: [<Typography variant=\"h6\" component=\"h5\" />],\n }}\n schema={argSchema}\n />\n </React.Fragment>\n );\n })}\n </Box>\n )}\n <Box pb={2}>\n <Typography variant=\"h5\" component=\"h3\">\n {t('templatingExtensions.content.filters.schema.output')}\n </Typography>\n <RenderSchema\n strategy=\"root\"\n context={{\n parentId: `${name}.output`,\n ...partialSchemaRenderContext,\n }}\n schema={schema?.output ?? {}}\n />\n </Box>\n {filter.examples && (\n <Accordion>\n <AccordionSummary expandIcon={<ExpandMoreIcon />}>\n <Typography variant=\"h5\" component=\"h3\">\n {t('templatingExtensions.content.filters.examples')}\n </Typography>\n </AccordionSummary>\n <AccordionDetails>\n <Box pb={2}>\n <ScaffolderUsageExamplesTable examples={filter.examples} />\n </Box>\n </AccordionDetails>\n </Accordion>\n )}\n </React.Fragment>\n );\n};\n\nexport const TemplateFilters = ({\n t,\n classes,\n filters,\n baseLink,\n selectedItem,\n}: {\n t: TranslationMessages<typeof scaffolderTranslationRef>;\n classes: StyleClasses;\n filters: ListTemplatingExtensionsResponse['filters'];\n baseLink: ReactElement<Parameters<typeof Link>[0]>;\n selectedItem: Extension | null;\n}) => {\n if (selectedItem && selectedItem.kind !== 'filter') {\n return <></>;\n }\n if (!Object.keys(filters).length) {\n return (\n <div data-testid=\"no-filters\">\n {t('templatingExtensions.content.filters.notAvailable')}\n </div>\n );\n }\n return (\n <div data-testid=\"filters\">\n {Object.entries(\n selectedItem\n ? { [selectedItem.name]: filters[selectedItem.name] }\n : filters,\n ).map(([name, filter]) => {\n const fragment = renderFragment({ kind: 'filter', name });\n return (\n <Box pb={4} key={name} data-testid={name}>\n <Typography\n id={fragment}\n variant=\"h4\"\n component=\"h2\"\n className={classes.code}\n >\n {name}\n </Typography>\n {React.cloneElement(baseLink, {\n to: `${baseLink.props.to}#${fragment}`,\n })}\n <FilterDetailContent {...{ t, classes, name, filter }} />\n </Box>\n );\n })}\n </div>\n );\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
|
|
2
|
+
import { MarkdownContent, CodeSnippet } from '@backstage/core-components';
|
|
3
|
+
import Accordion from '@material-ui/core/Accordion';
|
|
4
|
+
import AccordionDetails from '@material-ui/core/AccordionDetails';
|
|
5
|
+
import AccordionSummary from '@material-ui/core/AccordionSummary';
|
|
6
|
+
import Box from '@material-ui/core/Box';
|
|
7
|
+
import Typography from '@material-ui/core/Typography';
|
|
8
|
+
import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
|
|
9
|
+
import classNames from 'classnames';
|
|
10
|
+
import React, { useState } from 'react';
|
|
11
|
+
import { RenderSchema } from '../RenderSchema/RenderSchema.esm.js';
|
|
12
|
+
import { ScaffolderUsageExamplesTable } from '../ScaffolderUsageExamplesTable/ScaffolderUsageExamplesTable.esm.js';
|
|
13
|
+
import { inspectFunctionArgSchema } from './functionArgs.esm.js';
|
|
14
|
+
import { renderFragment } from './navigation.esm.js';
|
|
15
|
+
|
|
16
|
+
const FunctionDetailContent = ({
|
|
17
|
+
classes,
|
|
18
|
+
name,
|
|
19
|
+
fn,
|
|
20
|
+
t
|
|
21
|
+
}) => {
|
|
22
|
+
const expanded = useState({});
|
|
23
|
+
if (!Object.keys(fn).length) {
|
|
24
|
+
return /* @__PURE__ */ jsx(Typography, { style: { fontStyle: "italic" }, children: t("templatingExtensions.content.functions.notAvailable") });
|
|
25
|
+
}
|
|
26
|
+
const schema = fn.schema;
|
|
27
|
+
const partialSchemaRenderContext = {
|
|
28
|
+
classes,
|
|
29
|
+
expanded,
|
|
30
|
+
headings: [/* @__PURE__ */ jsx(Typography, { variant: "h6", component: "h4" })]
|
|
31
|
+
};
|
|
32
|
+
return /* @__PURE__ */ jsxs(React.Fragment, { children: [
|
|
33
|
+
fn.description && /* @__PURE__ */ jsx(MarkdownContent, { content: fn.description }),
|
|
34
|
+
schema?.arguments?.length && /* @__PURE__ */ jsxs(Box, { pb: 2, children: [
|
|
35
|
+
/* @__PURE__ */ jsx(Typography, { variant: "h5", component: "h3", children: t("templatingExtensions.content.functions.schema.arguments") }),
|
|
36
|
+
schema.arguments.map((arg, i) => {
|
|
37
|
+
const [argSchema, required] = inspectFunctionArgSchema(arg);
|
|
38
|
+
return /* @__PURE__ */ jsxs(React.Fragment, { children: [
|
|
39
|
+
/* @__PURE__ */ jsx(
|
|
40
|
+
"div",
|
|
41
|
+
{
|
|
42
|
+
className: classNames({ [classes.argRequired]: required }),
|
|
43
|
+
children: /* @__PURE__ */ jsx(
|
|
44
|
+
Typography,
|
|
45
|
+
{
|
|
46
|
+
variant: "h6",
|
|
47
|
+
component: "h4",
|
|
48
|
+
children: `[${i}]`
|
|
49
|
+
}
|
|
50
|
+
)
|
|
51
|
+
}
|
|
52
|
+
),
|
|
53
|
+
/* @__PURE__ */ jsx(
|
|
54
|
+
RenderSchema,
|
|
55
|
+
{
|
|
56
|
+
strategy: "root",
|
|
57
|
+
context: {
|
|
58
|
+
parentId: `${name}.arg${i}`,
|
|
59
|
+
...partialSchemaRenderContext,
|
|
60
|
+
headings: [/* @__PURE__ */ jsx(Typography, { variant: "h6", component: "h5" })]
|
|
61
|
+
},
|
|
62
|
+
schema: argSchema
|
|
63
|
+
}
|
|
64
|
+
)
|
|
65
|
+
] }, i);
|
|
66
|
+
})
|
|
67
|
+
] }, `${name}.args`),
|
|
68
|
+
/* @__PURE__ */ jsxs(Box, { pb: 2, children: [
|
|
69
|
+
/* @__PURE__ */ jsx(Typography, { variant: "h5", component: "h3", children: t("templatingExtensions.content.functions.schema.output") }),
|
|
70
|
+
/* @__PURE__ */ jsx(
|
|
71
|
+
RenderSchema,
|
|
72
|
+
{
|
|
73
|
+
strategy: "root",
|
|
74
|
+
context: {
|
|
75
|
+
parentId: `${name}.output`,
|
|
76
|
+
...partialSchemaRenderContext
|
|
77
|
+
},
|
|
78
|
+
schema: schema?.output ?? {}
|
|
79
|
+
}
|
|
80
|
+
)
|
|
81
|
+
] }),
|
|
82
|
+
fn.examples && /* @__PURE__ */ jsxs(Accordion, { children: [
|
|
83
|
+
/* @__PURE__ */ jsx(AccordionSummary, { expandIcon: /* @__PURE__ */ jsx(ExpandMoreIcon, {}), children: /* @__PURE__ */ jsx(Typography, { variant: "h5", component: "h3", children: t("templatingExtensions.content.functions.examples") }) }),
|
|
84
|
+
/* @__PURE__ */ jsx(AccordionDetails, { children: /* @__PURE__ */ jsx(Box, { pb: 2, children: /* @__PURE__ */ jsx(ScaffolderUsageExamplesTable, { examples: fn.examples }) }) })
|
|
85
|
+
] })
|
|
86
|
+
] }, `${name}.detail`);
|
|
87
|
+
};
|
|
88
|
+
const TemplateGlobalFunctions = ({
|
|
89
|
+
classes,
|
|
90
|
+
functions,
|
|
91
|
+
t,
|
|
92
|
+
baseLink,
|
|
93
|
+
selectedItem
|
|
94
|
+
}) => {
|
|
95
|
+
if (selectedItem && selectedItem.kind !== "function") {
|
|
96
|
+
return /* @__PURE__ */ jsx(Fragment, {});
|
|
97
|
+
}
|
|
98
|
+
if (!Object.keys(functions).length) {
|
|
99
|
+
return /* @__PURE__ */ jsx("div", { "data-testid": "no-functions", children: t("templatingExtensions.content.functions.notAvailable") });
|
|
100
|
+
}
|
|
101
|
+
return /* @__PURE__ */ jsx("div", { "data-testid": "functions", children: Object.entries(
|
|
102
|
+
selectedItem ? { [selectedItem.name]: functions[selectedItem.name] } : functions
|
|
103
|
+
).map(([name, fn]) => {
|
|
104
|
+
const fragment = renderFragment({ kind: "function", name });
|
|
105
|
+
return /* @__PURE__ */ jsxs(Box, { pb: 4, "data-testid": name, children: [
|
|
106
|
+
/* @__PURE__ */ jsx(
|
|
107
|
+
Typography,
|
|
108
|
+
{
|
|
109
|
+
id: fragment,
|
|
110
|
+
variant: "h4",
|
|
111
|
+
component: "h2",
|
|
112
|
+
className: classes.code,
|
|
113
|
+
children: name
|
|
114
|
+
}
|
|
115
|
+
),
|
|
116
|
+
React.cloneElement(baseLink, {
|
|
117
|
+
to: `${baseLink.props.to}#${fragment}`
|
|
118
|
+
}),
|
|
119
|
+
/* @__PURE__ */ jsx(FunctionDetailContent, { ...{ classes, name, fn, t } })
|
|
120
|
+
] }, name);
|
|
121
|
+
}) });
|
|
122
|
+
};
|
|
123
|
+
const TemplateGlobalValues = ({
|
|
124
|
+
classes,
|
|
125
|
+
t,
|
|
126
|
+
values,
|
|
127
|
+
baseLink,
|
|
128
|
+
selectedItem
|
|
129
|
+
}) => {
|
|
130
|
+
if (selectedItem && selectedItem.kind !== "value") {
|
|
131
|
+
return /* @__PURE__ */ jsx(Fragment, {});
|
|
132
|
+
}
|
|
133
|
+
if (!Object.keys(values).length) {
|
|
134
|
+
return /* @__PURE__ */ jsx("div", { "data-testid": "no-values", children: t("templatingExtensions.content.values.notAvailable") });
|
|
135
|
+
}
|
|
136
|
+
return /* @__PURE__ */ jsx("div", { "data-testid": "values", children: Object.entries(
|
|
137
|
+
selectedItem ? { [selectedItem.name]: values[selectedItem.name] } : values
|
|
138
|
+
).map(([name, gv]) => {
|
|
139
|
+
const fragment = renderFragment({ kind: "value", name });
|
|
140
|
+
return /* @__PURE__ */ jsxs(Box, { pb: 4, "data-testid": name, children: [
|
|
141
|
+
/* @__PURE__ */ jsx(
|
|
142
|
+
Typography,
|
|
143
|
+
{
|
|
144
|
+
id: fragment,
|
|
145
|
+
variant: "h4",
|
|
146
|
+
component: "h2",
|
|
147
|
+
className: classes.code,
|
|
148
|
+
children: name
|
|
149
|
+
}
|
|
150
|
+
),
|
|
151
|
+
React.cloneElement(baseLink, {
|
|
152
|
+
to: `${baseLink.props.to}#${fragment}`
|
|
153
|
+
}),
|
|
154
|
+
gv.description && /* @__PURE__ */ jsx(MarkdownContent, { content: gv.description }),
|
|
155
|
+
/* @__PURE__ */ jsx(Box, { padding: 1, "data-testid": `${name}.value`, children: /* @__PURE__ */ jsx(
|
|
156
|
+
CodeSnippet,
|
|
157
|
+
{
|
|
158
|
+
text: JSON.stringify(gv.value, null, 2),
|
|
159
|
+
showCopyCodeButton: true,
|
|
160
|
+
language: "json"
|
|
161
|
+
}
|
|
162
|
+
) })
|
|
163
|
+
] }, name);
|
|
164
|
+
}) });
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
export { TemplateGlobalFunctions, TemplateGlobalValues };
|
|
168
|
+
//# sourceMappingURL=TemplateGlobals.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TemplateGlobals.esm.js","sources":["../../../src/components/TemplatingExtensionsPage/TemplateGlobals.tsx"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { CodeSnippet, Link, MarkdownContent } from '@backstage/core-components';\nimport {\n ListTemplatingExtensionsResponse,\n TemplateGlobalFunction,\n} from '@backstage/plugin-scaffolder-react';\nimport Accordion from '@material-ui/core/Accordion';\nimport AccordionDetails from '@material-ui/core/AccordionDetails';\nimport AccordionSummary from '@material-ui/core/AccordionSummary';\nimport Box from '@material-ui/core/Box';\nimport { ClassNameMap } from '@material-ui/core/styles/withStyles';\nimport Typography from '@material-ui/core/Typography';\nimport ExpandMoreIcon from '@material-ui/icons/ExpandMore';\nimport classNames from 'classnames';\nimport React, { ReactElement, useState } from 'react';\nimport { scaffolderTranslationRef } from '../../translation';\nimport { Expanded, RenderSchema, SchemaRenderContext } from '../RenderSchema';\nimport { ScaffolderUsageExamplesTable } from '../ScaffolderUsageExamplesTable';\nimport { inspectFunctionArgSchema } from './functionArgs';\nimport { Extension, renderFragment } from './navigation';\nimport { TranslationMessages } from './types';\n\nconst FunctionDetailContent = ({\n classes,\n name,\n fn,\n t,\n}: {\n classes: ClassNameMap;\n name: string;\n fn: TemplateGlobalFunction;\n t: TranslationMessages<typeof scaffolderTranslationRef>;\n}) => {\n const expanded = useState<Expanded>({});\n if (!Object.keys(fn).length) {\n return (\n <Typography style={{ fontStyle: 'italic' }}>\n {t('templatingExtensions.content.functions.notAvailable')}\n </Typography>\n );\n }\n const schema = fn.schema;\n const partialSchemaRenderContext: Omit<SchemaRenderContext, 'parentId'> = {\n classes,\n expanded,\n headings: [<Typography variant=\"h6\" component=\"h4\" />],\n };\n return (\n <React.Fragment key={`${name}.detail`}>\n {fn.description && <MarkdownContent content={fn.description} />}\n {schema?.arguments?.length && (\n <Box key={`${name}.args`} pb={2}>\n <Typography variant=\"h5\" component=\"h3\">\n {t('templatingExtensions.content.functions.schema.arguments')}\n </Typography>\n {schema.arguments.map((arg, i) => {\n const [argSchema, required] = inspectFunctionArgSchema(arg);\n\n return (\n <React.Fragment key={i}>\n <div\n className={classNames({ [classes.argRequired]: required })}\n >\n <Typography\n variant=\"h6\"\n component=\"h4\"\n >{`[${i}]`}</Typography>\n </div>\n <RenderSchema\n strategy=\"root\"\n context={{\n parentId: `${name}.arg${i}`,\n ...partialSchemaRenderContext,\n headings: [<Typography variant=\"h6\" component=\"h5\" />],\n }}\n schema={argSchema}\n />\n </React.Fragment>\n );\n })}\n </Box>\n )}\n <Box pb={2}>\n <Typography variant=\"h5\" component=\"h3\">\n {t('templatingExtensions.content.functions.schema.output')}\n </Typography>\n <RenderSchema\n strategy=\"root\"\n context={{\n parentId: `${name}.output`,\n ...partialSchemaRenderContext,\n }}\n schema={schema?.output ?? {}}\n />\n </Box>\n {fn.examples && (\n <Accordion>\n <AccordionSummary expandIcon={<ExpandMoreIcon />}>\n <Typography variant=\"h5\" component=\"h3\">\n {t('templatingExtensions.content.functions.examples')}\n </Typography>\n </AccordionSummary>\n <AccordionDetails>\n <Box pb={2}>\n <ScaffolderUsageExamplesTable examples={fn.examples} />\n </Box>\n </AccordionDetails>\n </Accordion>\n )}\n </React.Fragment>\n );\n};\n\nexport const TemplateGlobalFunctions = ({\n classes,\n functions,\n t,\n baseLink,\n selectedItem,\n}: {\n classes: ClassNameMap;\n functions: ListTemplatingExtensionsResponse['globals']['functions'];\n t: TranslationMessages<typeof scaffolderTranslationRef>;\n baseLink: ReactElement<Parameters<typeof Link>[0]>;\n selectedItem: Extension | null;\n}) => {\n if (selectedItem && selectedItem.kind !== 'function') {\n return <></>;\n }\n if (!Object.keys(functions).length) {\n return (\n <div data-testid=\"no-functions\">\n {t('templatingExtensions.content.functions.notAvailable')}\n </div>\n );\n }\n return (\n <div data-testid=\"functions\">\n {Object.entries(\n selectedItem\n ? { [selectedItem.name]: functions[selectedItem.name] }\n : functions,\n ).map(([name, fn]) => {\n const fragment = renderFragment({ kind: 'function', name });\n return (\n <Box pb={4} key={name} data-testid={name}>\n <Typography\n id={fragment}\n variant=\"h4\"\n component=\"h2\"\n className={classes.code}\n >\n {name}\n </Typography>\n {React.cloneElement(baseLink, {\n to: `${baseLink.props.to}#${fragment}`,\n })}\n <FunctionDetailContent {...{ classes, name, fn, t }} />\n </Box>\n );\n })}\n </div>\n );\n};\n\nexport const TemplateGlobalValues = ({\n classes,\n t,\n values,\n baseLink,\n selectedItem,\n}: {\n classes: ClassNameMap;\n t: TranslationMessages<typeof scaffolderTranslationRef>;\n values: ListTemplatingExtensionsResponse['globals']['values'];\n baseLink: ReactElement<Parameters<typeof Link>[0]>;\n selectedItem: Extension | null;\n}) => {\n if (selectedItem && selectedItem.kind !== 'value') {\n return <></>;\n }\n if (!Object.keys(values).length) {\n return (\n <div data-testid=\"no-values\">\n {t('templatingExtensions.content.values.notAvailable')}\n </div>\n );\n }\n return (\n <div data-testid=\"values\">\n {Object.entries(\n selectedItem\n ? { [selectedItem.name]: values[selectedItem.name] }\n : values,\n ).map(([name, gv]) => {\n const fragment = renderFragment({ kind: 'value', name });\n return (\n <Box pb={4} key={name} data-testid={name}>\n <Typography\n id={fragment}\n variant=\"h4\"\n component=\"h2\"\n className={classes.code}\n >\n {name}\n </Typography>\n {React.cloneElement(baseLink, {\n to: `${baseLink.props.to}#${fragment}`,\n })}\n {gv.description && <MarkdownContent content={gv.description} />}\n <Box padding={1} data-testid={`${name}.value`}>\n <CodeSnippet\n text={JSON.stringify(gv.value, null, 2)}\n showCopyCodeButton\n language=\"json\"\n />\n </Box>\n </Box>\n );\n })}\n </div>\n );\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
2
|
+
import { useRouteRef, useApi } from '@backstage/core-plugin-api';
|
|
3
|
+
import { editRouteRef, scaffolderListTaskRouteRef, rootRouteRef, actionsRouteRef, templatingExtensionsRouteRef } from '../../routes.esm.js';
|
|
4
|
+
import { makeStyles } from '@material-ui/core/styles';
|
|
5
|
+
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
|
|
6
|
+
import { scaffolderTranslationRef } from '../../translation.esm.js';
|
|
7
|
+
import { Page, Header, Content, Progress, ErrorPanel, EmptyState, Link } from '@backstage/core-components';
|
|
8
|
+
import { scaffolderApiRef } from '@backstage/plugin-scaffolder-react';
|
|
9
|
+
import { ScaffolderPageContextMenu } from '@backstage/plugin-scaffolder-react/alpha';
|
|
10
|
+
import Box from '@material-ui/core/Box';
|
|
11
|
+
import InputAdornment from '@material-ui/core/InputAdornment';
|
|
12
|
+
import ListItemText from '@material-ui/core/ListItemText';
|
|
13
|
+
import Tab from '@material-ui/core/Tab';
|
|
14
|
+
import Tabs from '@material-ui/core/Tabs';
|
|
15
|
+
import TextField from '@material-ui/core/TextField';
|
|
16
|
+
import AllInclusiveIcon from '@material-ui/icons/AllInclusive';
|
|
17
|
+
import FilterListIcon from '@material-ui/icons/FilterList';
|
|
18
|
+
import FunctionsIcon from '@material-ui/icons/Functions';
|
|
19
|
+
import LinkIcon from '@material-ui/icons/Link';
|
|
20
|
+
import SearchIcon from '@material-ui/icons/Search';
|
|
21
|
+
import Autocomplete from '@material-ui/lab/Autocomplete';
|
|
22
|
+
import { useState, useEffect, useMemo } from 'react';
|
|
23
|
+
import { useNavigate } from 'react-router-dom';
|
|
24
|
+
import useAsync from 'react-use/esm/useAsync';
|
|
25
|
+
import { parseFragment, listTemplatingExtensions } from './navigation.esm.js';
|
|
26
|
+
import { TemplateFilters } from './TemplateFilters.esm.js';
|
|
27
|
+
import { TemplateGlobalFunctions, TemplateGlobalValues } from './TemplateGlobals.esm.js';
|
|
28
|
+
|
|
29
|
+
const useStyles = makeStyles((theme) => ({
|
|
30
|
+
code: {
|
|
31
|
+
fontFamily: "Menlo, monospace",
|
|
32
|
+
padding: theme.spacing(1),
|
|
33
|
+
backgroundColor: theme.palette.type === "dark" ? theme.palette.grey[700] : theme.palette.grey[300],
|
|
34
|
+
display: "inline-block",
|
|
35
|
+
borderRadius: 5,
|
|
36
|
+
border: `1px solid ${theme.palette.grey[500]}`,
|
|
37
|
+
position: "relative"
|
|
38
|
+
},
|
|
39
|
+
codeRequired: {
|
|
40
|
+
"&::after": {
|
|
41
|
+
position: "absolute",
|
|
42
|
+
content: '"*"',
|
|
43
|
+
top: 0,
|
|
44
|
+
right: theme.spacing(0.5),
|
|
45
|
+
fontWeight: "bolder",
|
|
46
|
+
color: theme.palette.error.light
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
argRequired: {
|
|
50
|
+
position: "relative",
|
|
51
|
+
"& > *": {
|
|
52
|
+
display: "inline",
|
|
53
|
+
position: "relative",
|
|
54
|
+
"&::after": {
|
|
55
|
+
position: "absolute",
|
|
56
|
+
content: '"*"',
|
|
57
|
+
top: 0,
|
|
58
|
+
right: theme.spacing(-1),
|
|
59
|
+
fontWeight: "bolder",
|
|
60
|
+
color: theme.palette.error.light
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
link: {
|
|
65
|
+
paddingLeft: theme.spacing(1),
|
|
66
|
+
cursor: "pointer"
|
|
67
|
+
},
|
|
68
|
+
tabs: {
|
|
69
|
+
display: "block",
|
|
70
|
+
minHeight: "initial",
|
|
71
|
+
overflow: "initial"
|
|
72
|
+
}
|
|
73
|
+
}));
|
|
74
|
+
const TemplatingExtensionsPageContent = ({
|
|
75
|
+
linkLocal
|
|
76
|
+
}) => {
|
|
77
|
+
const api = useApi(scaffolderApiRef);
|
|
78
|
+
const classes = useStyles();
|
|
79
|
+
const { t } = useTranslationRef(scaffolderTranslationRef);
|
|
80
|
+
const { loading, value, error } = useAsync(async () => {
|
|
81
|
+
if (api.listTemplatingExtensions) {
|
|
82
|
+
return api.listTemplatingExtensions();
|
|
83
|
+
}
|
|
84
|
+
console.warn(
|
|
85
|
+
"listTemplatingExtensions is not implemented in the scaffolderApi; please make sure to implement this method."
|
|
86
|
+
);
|
|
87
|
+
return Promise.resolve({
|
|
88
|
+
filters: {},
|
|
89
|
+
globals: { functions: {}, values: {} }
|
|
90
|
+
});
|
|
91
|
+
}, [api]);
|
|
92
|
+
const [tab, selectTab] = useState("filter");
|
|
93
|
+
const [selectedItem, setSelectedItem] = useState(null);
|
|
94
|
+
const [input, setInput] = useState("");
|
|
95
|
+
const handleTab = (_event, kind) => {
|
|
96
|
+
if (selectedItem?.kind !== kind) {
|
|
97
|
+
setSelectedItem(null);
|
|
98
|
+
setInput("");
|
|
99
|
+
}
|
|
100
|
+
selectTab(kind);
|
|
101
|
+
};
|
|
102
|
+
const selectItem = (item) => {
|
|
103
|
+
setSelectedItem(item);
|
|
104
|
+
if (item) {
|
|
105
|
+
selectTab(item.kind);
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
useEffect(() => {
|
|
109
|
+
if (value && window.location.hash) {
|
|
110
|
+
try {
|
|
111
|
+
selectTab(parseFragment(window.location.hash.substring(1)).kind);
|
|
112
|
+
document.querySelector(window.location.hash)?.scrollIntoView();
|
|
113
|
+
} catch (e) {
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}, [value]);
|
|
117
|
+
const extensionKinds = useMemo(
|
|
118
|
+
() => ({
|
|
119
|
+
filter: {
|
|
120
|
+
icon: /* @__PURE__ */ jsx(FilterListIcon, {}),
|
|
121
|
+
label: t("templatingExtensions.content.filters.title")
|
|
122
|
+
},
|
|
123
|
+
function: {
|
|
124
|
+
icon: /* @__PURE__ */ jsx(FunctionsIcon, {}),
|
|
125
|
+
label: t("templatingExtensions.content.functions.title")
|
|
126
|
+
},
|
|
127
|
+
value: {
|
|
128
|
+
icon: /* @__PURE__ */ jsx(AllInclusiveIcon, {}),
|
|
129
|
+
label: t("templatingExtensions.content.values.title")
|
|
130
|
+
}
|
|
131
|
+
}),
|
|
132
|
+
[t]
|
|
133
|
+
);
|
|
134
|
+
const templatingExtensionsLink = useRouteRef(templatingExtensionsRouteRef);
|
|
135
|
+
if (loading) {
|
|
136
|
+
return /* @__PURE__ */ jsx(Progress, {});
|
|
137
|
+
}
|
|
138
|
+
if (error || !value) {
|
|
139
|
+
return /* @__PURE__ */ jsxs("div", { "data-testid": "empty", children: [
|
|
140
|
+
error && /* @__PURE__ */ jsx(ErrorPanel, { error }),
|
|
141
|
+
/* @__PURE__ */ jsx(
|
|
142
|
+
EmptyState,
|
|
143
|
+
{
|
|
144
|
+
missing: "info",
|
|
145
|
+
title: t("templatingExtensions.content.emptyState.title"),
|
|
146
|
+
description: t("templatingExtensions.content.emptyState.description")
|
|
147
|
+
}
|
|
148
|
+
)
|
|
149
|
+
] });
|
|
150
|
+
}
|
|
151
|
+
const { filters, globals } = value;
|
|
152
|
+
const baseLink = /* @__PURE__ */ jsx(
|
|
153
|
+
Link,
|
|
154
|
+
{
|
|
155
|
+
className: classes.link,
|
|
156
|
+
to: templatingExtensionsLink(),
|
|
157
|
+
...linkLocal ? {} : { target: "_blank", rel: "noopener noreferrer" },
|
|
158
|
+
children: /* @__PURE__ */ jsx(LinkIcon, {})
|
|
159
|
+
}
|
|
160
|
+
);
|
|
161
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
162
|
+
/* @__PURE__ */ jsx(
|
|
163
|
+
Autocomplete,
|
|
164
|
+
{
|
|
165
|
+
renderInput: (params) => /* @__PURE__ */ jsx(
|
|
166
|
+
TextField,
|
|
167
|
+
{
|
|
168
|
+
...params,
|
|
169
|
+
"aria-label": t(
|
|
170
|
+
"templatingExtensions.content.searchFieldPlaceholder"
|
|
171
|
+
),
|
|
172
|
+
placeholder: t(
|
|
173
|
+
"templatingExtensions.content.searchFieldPlaceholder"
|
|
174
|
+
),
|
|
175
|
+
variant: "outlined",
|
|
176
|
+
InputProps: {
|
|
177
|
+
...params.InputProps,
|
|
178
|
+
startAdornment: /* @__PURE__ */ jsx(InputAdornment, { position: "start", children: /* @__PURE__ */ jsx(SearchIcon, {}) })
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
),
|
|
182
|
+
getOptionLabel: (option) => option.name,
|
|
183
|
+
getOptionSelected: (lhs, rhs) => lhs === rhs,
|
|
184
|
+
options: listTemplatingExtensions(value),
|
|
185
|
+
groupBy: (option) => option.kind,
|
|
186
|
+
renderGroup: (params) => /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
187
|
+
/* @__PURE__ */ jsxs(Box, { display: "flex", alignItems: "center", children: [
|
|
188
|
+
extensionKinds[params.group].icon,
|
|
189
|
+
/* @__PURE__ */ jsx(Box, { sx: { ml: 1 }, children: extensionKinds[params.group].label })
|
|
190
|
+
] }),
|
|
191
|
+
/* @__PURE__ */ jsx("ul", { children: params.children })
|
|
192
|
+
] }),
|
|
193
|
+
renderOption: (option) => /* @__PURE__ */ jsx(ListItemText, { primary: option.name }),
|
|
194
|
+
onChange: (_event, option) => {
|
|
195
|
+
selectItem(option);
|
|
196
|
+
},
|
|
197
|
+
inputValue: input,
|
|
198
|
+
onInputChange: (_event, s) => setInput(s),
|
|
199
|
+
loading,
|
|
200
|
+
fullWidth: true,
|
|
201
|
+
clearOnEscape: true
|
|
202
|
+
}
|
|
203
|
+
),
|
|
204
|
+
/* @__PURE__ */ jsx(Tabs, { value: tab, onChange: handleTab, centered: true, className: classes.tabs, children: Object.entries(extensionKinds).map(([k, v]) => /* @__PURE__ */ jsx(Tab, { value: k, ...v }, k)) }),
|
|
205
|
+
tab === "filter" && /* @__PURE__ */ jsx(TemplateFilters, { ...{ baseLink, t, classes, filters, selectedItem } }),
|
|
206
|
+
tab === "function" && /* @__PURE__ */ jsx(
|
|
207
|
+
TemplateGlobalFunctions,
|
|
208
|
+
{
|
|
209
|
+
functions: globals.functions,
|
|
210
|
+
...{ baseLink, t, classes, selectedItem }
|
|
211
|
+
}
|
|
212
|
+
),
|
|
213
|
+
tab === "value" && /* @__PURE__ */ jsx(
|
|
214
|
+
TemplateGlobalValues,
|
|
215
|
+
{
|
|
216
|
+
values: globals.values,
|
|
217
|
+
...{ baseLink, t, classes, selectedItem }
|
|
218
|
+
}
|
|
219
|
+
)
|
|
220
|
+
] });
|
|
221
|
+
};
|
|
222
|
+
const TemplatingExtensionsPage = () => {
|
|
223
|
+
const navigate = useNavigate();
|
|
224
|
+
const editorLink = useRouteRef(editRouteRef);
|
|
225
|
+
const tasksLink = useRouteRef(scaffolderListTaskRouteRef);
|
|
226
|
+
const createLink = useRouteRef(rootRouteRef);
|
|
227
|
+
const actionsLink = useRouteRef(actionsRouteRef);
|
|
228
|
+
const scaffolderPageContextMenuProps = {
|
|
229
|
+
onEditorClicked: () => navigate(editorLink()),
|
|
230
|
+
onActionsClicked: () => navigate(actionsLink()),
|
|
231
|
+
onTasksClicked: () => navigate(tasksLink()),
|
|
232
|
+
onCreateClicked: () => navigate(createLink())
|
|
233
|
+
};
|
|
234
|
+
const { t } = useTranslationRef(scaffolderTranslationRef);
|
|
235
|
+
return /* @__PURE__ */ jsxs(Page, { themeId: "home", children: [
|
|
236
|
+
/* @__PURE__ */ jsx(
|
|
237
|
+
Header,
|
|
238
|
+
{
|
|
239
|
+
pageTitleOverride: t("templatingExtensions.pageTitle"),
|
|
240
|
+
title: t("templatingExtensions.title"),
|
|
241
|
+
subtitle: t("templatingExtensions.subtitle"),
|
|
242
|
+
children: /* @__PURE__ */ jsx(ScaffolderPageContextMenu, { ...scaffolderPageContextMenuProps })
|
|
243
|
+
}
|
|
244
|
+
),
|
|
245
|
+
/* @__PURE__ */ jsx(Content, { children: /* @__PURE__ */ jsx(TemplatingExtensionsPageContent, { linkLocal: true }) })
|
|
246
|
+
] });
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
export { TemplatingExtensionsPage, TemplatingExtensionsPageContent };
|
|
250
|
+
//# sourceMappingURL=TemplatingExtensionsPage.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TemplatingExtensionsPage.esm.js","sources":["../../../src/components/TemplatingExtensionsPage/TemplatingExtensionsPage.tsx"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { useApi, useRouteRef } from '@backstage/core-plugin-api';\n\nimport {\n actionsRouteRef,\n editRouteRef,\n rootRouteRef,\n scaffolderListTaskRouteRef,\n templatingExtensionsRouteRef,\n} from '../../routes';\n\nimport { makeStyles } from '@material-ui/core/styles';\n\nimport { useTranslationRef } from '@backstage/core-plugin-api/alpha';\nimport { scaffolderTranslationRef } from '../../translation';\n\nimport {\n Content,\n EmptyState,\n ErrorPanel,\n Header,\n Link,\n Page,\n Progress,\n} from '@backstage/core-components';\nimport { scaffolderApiRef } from '@backstage/plugin-scaffolder-react';\nimport {\n ScaffolderPageContextMenu,\n ScaffolderPageContextMenuProps,\n} from '@backstage/plugin-scaffolder-react/alpha';\nimport Box from '@material-ui/core/Box';\nimport InputAdornment from '@material-ui/core/InputAdornment';\nimport ListItemText from '@material-ui/core/ListItemText';\nimport Tab from '@material-ui/core/Tab';\nimport Tabs from '@material-ui/core/Tabs';\nimport TextField from '@material-ui/core/TextField';\nimport AllInclusiveIcon from '@material-ui/icons/AllInclusive';\nimport FilterListIcon from '@material-ui/icons/FilterList';\nimport FunctionsIcon from '@material-ui/icons/Functions';\nimport LinkIcon from '@material-ui/icons/Link';\nimport SearchIcon from '@material-ui/icons/Search';\nimport Autocomplete from '@material-ui/lab/Autocomplete';\nimport { useEffect, useMemo, useState } from 'react';\nimport { useNavigate } from 'react-router-dom';\nimport useAsync from 'react-use/esm/useAsync';\nimport {\n Extension,\n ExtensionKind,\n listTemplatingExtensions,\n parseFragment,\n} from './navigation';\nimport { TemplateFilters } from './TemplateFilters';\nimport {\n TemplateGlobalFunctions,\n TemplateGlobalValues,\n} from './TemplateGlobals';\n\nconst useStyles = makeStyles(theme => ({\n code: {\n fontFamily: 'Menlo, monospace',\n padding: theme.spacing(1),\n backgroundColor:\n theme.palette.type === 'dark'\n ? theme.palette.grey[700]\n : theme.palette.grey[300],\n display: 'inline-block',\n borderRadius: 5,\n border: `1px solid ${theme.palette.grey[500]}`,\n position: 'relative',\n },\n\n codeRequired: {\n '&::after': {\n position: 'absolute',\n content: '\"*\"',\n top: 0,\n right: theme.spacing(0.5),\n fontWeight: 'bolder',\n color: theme.palette.error.light,\n },\n },\n\n argRequired: {\n position: 'relative',\n '& > *': {\n display: 'inline',\n position: 'relative',\n '&::after': {\n position: 'absolute',\n content: '\"*\"',\n top: 0,\n right: theme.spacing(-1),\n fontWeight: 'bolder',\n color: theme.palette.error.light,\n },\n },\n },\n\n link: {\n paddingLeft: theme.spacing(1),\n cursor: 'pointer',\n },\n\n tabs: {\n display: 'block',\n minHeight: 'initial',\n overflow: 'initial',\n },\n}));\n\nexport const TemplatingExtensionsPageContent = ({\n linkLocal,\n}: {\n linkLocal?: boolean;\n}) => {\n const api = useApi(scaffolderApiRef);\n const classes = useStyles();\n const { t } = useTranslationRef(scaffolderTranslationRef);\n\n const { loading, value, error } = useAsync(async () => {\n if (api.listTemplatingExtensions) {\n return api.listTemplatingExtensions();\n }\n // eslint-disable-next-line no-console\n console.warn(\n 'listTemplatingExtensions is not implemented in the scaffolderApi; please make sure to implement this method.',\n );\n return Promise.resolve({\n filters: {},\n globals: { functions: {}, values: {} },\n });\n }, [api]);\n\n const [tab, selectTab] = useState<ExtensionKind>('filter');\n const [selectedItem, setSelectedItem] = useState<Extension | null>(null);\n const [input, setInput] = useState<string>('');\n\n const handleTab = (_event: any, kind: ExtensionKind) => {\n if (selectedItem?.kind !== kind) {\n setSelectedItem(null);\n setInput('');\n }\n selectTab(kind);\n };\n\n const selectItem = (item: Extension | null) => {\n setSelectedItem(item);\n if (item) {\n selectTab(item.kind);\n }\n };\n\n useEffect(() => {\n if (value && window.location.hash) {\n try {\n selectTab(parseFragment(window.location.hash.substring(1)).kind);\n document.querySelector(window.location.hash)?.scrollIntoView();\n } catch (e) {\n // ignore bad link\n }\n }\n }, [value]);\n\n const extensionKinds = useMemo(\n () => ({\n filter: {\n icon: <FilterListIcon />,\n label: t('templatingExtensions.content.filters.title'),\n },\n function: {\n icon: <FunctionsIcon />,\n label: t('templatingExtensions.content.functions.title'),\n },\n value: {\n icon: <AllInclusiveIcon />,\n label: t('templatingExtensions.content.values.title'),\n },\n }),\n [t],\n );\n\n const templatingExtensionsLink = useRouteRef(templatingExtensionsRouteRef);\n\n if (loading) {\n return <Progress />;\n }\n if (error || !value) {\n return (\n <div data-testid=\"empty\">\n {error && <ErrorPanel error={error} />}\n <EmptyState\n missing=\"info\"\n title={t('templatingExtensions.content.emptyState.title')}\n description={t('templatingExtensions.content.emptyState.description')}\n />\n </div>\n );\n }\n const { filters, globals } = value;\n\n const baseLink = (\n <Link\n className={classes.link}\n to={templatingExtensionsLink()}\n {...(linkLocal ? {} : { target: '_blank', rel: 'noopener noreferrer' })}\n >\n <LinkIcon />\n </Link>\n );\n\n return (\n <>\n <Autocomplete\n renderInput={params => (\n <TextField\n {...params}\n aria-label={t(\n 'templatingExtensions.content.searchFieldPlaceholder',\n )}\n placeholder={t(\n 'templatingExtensions.content.searchFieldPlaceholder',\n )}\n variant=\"outlined\"\n InputProps={{\n ...params.InputProps,\n startAdornment: (\n <InputAdornment position=\"start\">\n <SearchIcon />\n </InputAdornment>\n ),\n }}\n />\n )}\n getOptionLabel={option => option.name}\n getOptionSelected={(lhs, rhs) => lhs === rhs}\n options={listTemplatingExtensions(value)}\n groupBy={option => option.kind}\n renderGroup={params => (\n <>\n <Box display=\"flex\" alignItems=\"center\">\n {extensionKinds[params.group as ExtensionKind].icon}\n <Box sx={{ ml: 1 }}>\n {extensionKinds[params.group as ExtensionKind].label}\n </Box>\n </Box>\n <ul>{params.children}</ul>\n </>\n )}\n renderOption={(option: Extension) => (\n <ListItemText primary={option.name} />\n )}\n onChange={(_event: any, option: Extension | null) => {\n selectItem(option);\n }}\n inputValue={input}\n onInputChange={(_event: any, s: string) => setInput(s)}\n loading={loading}\n fullWidth\n clearOnEscape\n />\n <Tabs value={tab} onChange={handleTab} centered className={classes.tabs}>\n {Object.entries(extensionKinds).map(([k, v]) => (\n <Tab key={k} value={k} {...v} />\n ))}\n </Tabs>\n {tab === 'filter' && (\n <TemplateFilters {...{ baseLink, t, classes, filters, selectedItem }} />\n )}\n {tab === 'function' && (\n <TemplateGlobalFunctions\n functions={globals.functions}\n {...{ baseLink, t, classes, selectedItem }}\n />\n )}\n {tab === 'value' && (\n <TemplateGlobalValues\n values={globals.values}\n {...{ baseLink, t, classes, selectedItem }}\n />\n )}\n </>\n );\n};\n\nexport const TemplatingExtensionsPage = () => {\n const navigate = useNavigate();\n const editorLink = useRouteRef(editRouteRef);\n const tasksLink = useRouteRef(scaffolderListTaskRouteRef);\n const createLink = useRouteRef(rootRouteRef);\n const actionsLink = useRouteRef(actionsRouteRef);\n\n const scaffolderPageContextMenuProps: ScaffolderPageContextMenuProps = {\n onEditorClicked: () => navigate(editorLink()),\n onActionsClicked: () => navigate(actionsLink()),\n onTasksClicked: () => navigate(tasksLink()),\n onCreateClicked: () => navigate(createLink()),\n };\n\n const { t } = useTranslationRef(scaffolderTranslationRef);\n\n return (\n <Page themeId=\"home\">\n <Header\n pageTitleOverride={t('templatingExtensions.pageTitle')}\n title={t('templatingExtensions.title')}\n subtitle={t('templatingExtensions.subtitle')}\n >\n <ScaffolderPageContextMenu {...scaffolderPageContextMenuProps} />\n </Header>\n <Content>\n <TemplatingExtensionsPageContent linkLocal />\n </Content>\n </Page>\n );\n};\n"],"names":[],"mappings":"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"}
|