@backstage/plugin-scaffolder 1.25.0 → 1.26.0-next.0
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 +34 -0
- package/alpha/package.json +1 -1
- package/dist/alpha/api/FormFieldsApi.esm.js +40 -0
- package/dist/alpha/api/FormFieldsApi.esm.js.map +1 -0
- package/dist/alpha/api/ref.esm.js +8 -0
- package/dist/alpha/api/ref.esm.js.map +1 -0
- package/dist/alpha/api.esm.js +27 -0
- package/dist/alpha/api.esm.js.map +1 -0
- package/dist/{next → alpha/components}/TemplateEditorPage/CustomFieldExplorer.esm.js +1 -1
- package/dist/alpha/components/TemplateEditorPage/CustomFieldExplorer.esm.js.map +1 -0
- package/dist/alpha/components/TemplateEditorPage/CustomFieldPlaygroud.esm.js +167 -0
- package/dist/alpha/components/TemplateEditorPage/CustomFieldPlaygroud.esm.js.map +1 -0
- package/dist/alpha/components/TemplateEditorPage/CustomFieldsPage.esm.js +33 -0
- package/dist/alpha/components/TemplateEditorPage/CustomFieldsPage.esm.js.map +1 -0
- package/dist/{next → alpha/components}/TemplateEditorPage/DirectoryEditorContext.esm.js +4 -7
- package/dist/alpha/components/TemplateEditorPage/DirectoryEditorContext.esm.js.map +1 -0
- package/dist/alpha/components/TemplateEditorPage/DryRunContext.esm.js.map +1 -0
- package/dist/{next → alpha/components}/TemplateEditorPage/DryRunResults/DryRunResults.esm.js +1 -1
- package/dist/alpha/components/TemplateEditorPage/DryRunResults/DryRunResults.esm.js.map +1 -0
- package/dist/{next → alpha/components}/TemplateEditorPage/DryRunResults/DryRunResultsList.esm.js +2 -2
- package/dist/alpha/components/TemplateEditorPage/DryRunResults/DryRunResultsList.esm.js.map +1 -0
- package/dist/alpha/components/TemplateEditorPage/DryRunResults/DryRunResultsSplitView.esm.js.map +1 -0
- package/dist/{next → alpha/components}/TemplateEditorPage/DryRunResults/DryRunResultsView.esm.js +2 -2
- package/dist/alpha/components/TemplateEditorPage/DryRunResults/DryRunResultsView.esm.js.map +1 -0
- package/dist/alpha/components/TemplateEditorPage/DryRunResults/IconLink.esm.js.map +1 -0
- package/dist/alpha/components/TemplateEditorPage/DryRunResults/TaskPageLinks.esm.js.map +1 -0
- package/dist/{next → alpha/components}/TemplateEditorPage/DryRunResults/TaskStatusStepper.esm.js +1 -1
- package/dist/alpha/components/TemplateEditorPage/DryRunResults/TaskStatusStepper.esm.js.map +1 -0
- package/dist/alpha/components/TemplateEditorPage/TemplateEditor.esm.js +94 -0
- package/dist/alpha/components/TemplateEditorPage/TemplateEditor.esm.js.map +1 -0
- package/dist/{next → alpha/components}/TemplateEditorPage/TemplateEditorBrowser.esm.js +36 -38
- package/dist/alpha/components/TemplateEditorPage/TemplateEditorBrowser.esm.js.map +1 -0
- package/dist/{next → alpha/components}/TemplateEditorPage/TemplateEditorForm.esm.js +12 -20
- package/dist/alpha/components/TemplateEditorPage/TemplateEditorForm.esm.js.map +1 -0
- package/dist/{next → alpha/components}/TemplateEditorPage/TemplateEditorIntro.esm.js +39 -2
- package/dist/alpha/components/TemplateEditorPage/TemplateEditorIntro.esm.js.map +1 -0
- package/dist/alpha/components/TemplateEditorPage/TemplateEditorPage.esm.js +61 -0
- package/dist/alpha/components/TemplateEditorPage/TemplateEditorPage.esm.js.map +1 -0
- package/dist/{next → alpha/components}/TemplateEditorPage/TemplateEditorTextArea.esm.js +36 -3
- package/dist/alpha/components/TemplateEditorPage/TemplateEditorTextArea.esm.js.map +1 -0
- package/dist/alpha/components/TemplateEditorPage/TemplateEditorToolbar.esm.js +98 -0
- package/dist/alpha/components/TemplateEditorPage/TemplateEditorToolbar.esm.js.map +1 -0
- package/dist/alpha/components/TemplateEditorPage/TemplateFormPage.esm.js +43 -0
- package/dist/alpha/components/TemplateEditorPage/TemplateFormPage.esm.js.map +1 -0
- package/dist/{next → alpha/components}/TemplateEditorPage/TemplateFormPreviewer.esm.js +77 -39
- package/dist/alpha/components/TemplateEditorPage/TemplateFormPreviewer.esm.js.map +1 -0
- package/dist/alpha/components/TemplateEditorPage/TemplatePage.esm.js +52 -0
- package/dist/alpha/components/TemplateEditorPage/TemplatePage.esm.js.map +1 -0
- package/dist/alpha/components/TemplateListPage/RegisterExistingButton.esm.js.map +1 -0
- package/dist/{next → alpha/components}/TemplateListPage/TemplateListPage.esm.js +2 -2
- package/dist/alpha/components/TemplateListPage/TemplateListPage.esm.js.map +1 -0
- package/dist/{next → alpha/components}/TemplateWizardPage/TemplateWizardPage.esm.js +2 -2
- package/dist/alpha/components/TemplateWizardPage/TemplateWizardPage.esm.js.map +1 -0
- package/dist/{next → alpha/components}/TemplateWizardPage/TemplateWizardPageContextMenu.esm.js +1 -1
- package/dist/alpha/components/TemplateWizardPage/TemplateWizardPageContextMenu.esm.js.map +1 -0
- package/dist/alpha/extensions.esm.js +30 -0
- package/dist/alpha/extensions.esm.js.map +1 -0
- package/dist/alpha/fields/RepoUrlPicker.esm.js +37 -0
- package/dist/alpha/fields/RepoUrlPicker.esm.js.map +1 -0
- package/dist/alpha/plugin.esm.js +32 -0
- package/dist/alpha/plugin.esm.js.map +1 -0
- package/dist/alpha.d.ts +78 -7
- package/dist/alpha.esm.js +1 -60
- package/dist/alpha.esm.js.map +1 -1
- package/dist/api.esm.js +14 -2
- package/dist/api.esm.js.map +1 -1
- package/dist/components/ActionsPage/ActionsPage.esm.js +30 -5
- package/dist/components/ActionsPage/ActionsPage.esm.js.map +1 -1
- package/dist/components/FileBrowser/FileBrowser.esm.js +4 -3
- package/dist/components/FileBrowser/FileBrowser.esm.js.map +1 -1
- package/dist/components/ListTasksPage/OwnerListPicker.esm.js +2 -2
- package/dist/components/ListTasksPage/OwnerListPicker.esm.js.map +1 -1
- package/dist/components/ListTasksPage/columns/CreatedAtColumn.esm.js +10 -5
- package/dist/components/ListTasksPage/columns/CreatedAtColumn.esm.js.map +1 -1
- package/dist/components/OngoingTask/ContextMenu.esm.js +15 -2
- package/dist/components/OngoingTask/ContextMenu.esm.js.map +1 -1
- package/dist/components/OngoingTask/OngoingTask.esm.js +24 -1
- package/dist/components/OngoingTask/OngoingTask.esm.js.map +1 -1
- package/dist/components/Router/Router.esm.js +35 -7
- package/dist/components/Router/Router.esm.js.map +1 -1
- package/dist/components/fields/RepoUrlPicker/RepoUrlPicker.esm.js.map +1 -1
- package/dist/components/fields/RepoUrlPicker/schema.esm.js +5 -6
- package/dist/components/fields/RepoUrlPicker/schema.esm.js.map +1 -1
- package/dist/components/fields/utils.esm.js +2 -1
- package/dist/components/fields/utils.esm.js.map +1 -1
- package/dist/index.d.ts +10 -8
- package/dist/lib/filesystem/WebFileSystemAccess.esm.js +34 -1
- package/dist/lib/filesystem/WebFileSystemAccess.esm.js.map +1 -1
- package/dist/lib/filesystem/createExampleTemplate.esm.js +76 -0
- package/dist/lib/filesystem/createExampleTemplate.esm.js.map +1 -0
- package/dist/packages/opaque-internal/src/OpaqueType.esm.js +103 -0
- package/dist/packages/opaque-internal/src/OpaqueType.esm.js.map +1 -0
- package/dist/packages/scaffolder-internal/src/wiring/InternalFormField.esm.js +6 -0
- package/dist/packages/scaffolder-internal/src/wiring/InternalFormField.esm.js.map +1 -0
- package/dist/plugin.esm.js +5 -2
- package/dist/plugin.esm.js.map +1 -1
- package/dist/routes.esm.js +16 -1
- package/dist/routes.esm.js.map +1 -1
- package/dist/translation.esm.js +20 -1
- package/dist/translation.esm.js.map +1 -1
- package/package.json +16 -14
- package/dist/next/TemplateEditorPage/CustomFieldExplorer.esm.js.map +0 -1
- package/dist/next/TemplateEditorPage/DirectoryEditorContext.esm.js.map +0 -1
- package/dist/next/TemplateEditorPage/DryRunContext.esm.js.map +0 -1
- package/dist/next/TemplateEditorPage/DryRunResults/DryRunResults.esm.js.map +0 -1
- package/dist/next/TemplateEditorPage/DryRunResults/DryRunResultsList.esm.js.map +0 -1
- package/dist/next/TemplateEditorPage/DryRunResults/DryRunResultsSplitView.esm.js.map +0 -1
- package/dist/next/TemplateEditorPage/DryRunResults/DryRunResultsView.esm.js.map +0 -1
- package/dist/next/TemplateEditorPage/DryRunResults/IconLink.esm.js.map +0 -1
- package/dist/next/TemplateEditorPage/DryRunResults/TaskPageLinks.esm.js.map +0 -1
- package/dist/next/TemplateEditorPage/DryRunResults/TaskStatusStepper.esm.js.map +0 -1
- package/dist/next/TemplateEditorPage/TemplateEditor.esm.js +0 -56
- package/dist/next/TemplateEditorPage/TemplateEditor.esm.js.map +0 -1
- package/dist/next/TemplateEditorPage/TemplateEditorBrowser.esm.js.map +0 -1
- package/dist/next/TemplateEditorPage/TemplateEditorForm.esm.js.map +0 -1
- package/dist/next/TemplateEditorPage/TemplateEditorIntro.esm.js.map +0 -1
- package/dist/next/TemplateEditorPage/TemplateEditorPage.esm.js +0 -87
- package/dist/next/TemplateEditorPage/TemplateEditorPage.esm.js.map +0 -1
- package/dist/next/TemplateEditorPage/TemplateEditorTextArea.esm.js.map +0 -1
- package/dist/next/TemplateEditorPage/TemplateFormPreviewer.esm.js.map +0 -1
- package/dist/next/TemplateListPage/RegisterExistingButton.esm.js.map +0 -1
- package/dist/next/TemplateListPage/TemplateListPage.esm.js.map +0 -1
- package/dist/next/TemplateWizardPage/TemplateWizardPage.esm.js.map +0 -1
- package/dist/next/TemplateWizardPage/TemplateWizardPageContextMenu.esm.js.map +0 -1
- /package/dist/{next → alpha/components}/TemplateEditorPage/DryRunContext.esm.js +0 -0
- /package/dist/{next → alpha/components}/TemplateEditorPage/DryRunResults/DryRunResultsSplitView.esm.js +0 -0
- /package/dist/{next → alpha/components}/TemplateEditorPage/DryRunResults/IconLink.esm.js +0 -0
- /package/dist/{next → alpha/components}/TemplateEditorPage/DryRunResults/TaskPageLinks.esm.js +0 -0
- /package/dist/{next → alpha/components}/TemplateListPage/RegisterExistingButton.esm.js +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TemplateEditorPage.esm.js","sources":["../../../../src/alpha/components/TemplateEditorPage/TemplateEditorPage.tsx"],"sourcesContent":["/*\n * Copyright 2022 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 React from 'react';\nimport { Content, Header, Page } from '@backstage/core-components';\n\nimport { WebFileSystemAccess } from '../../../lib/filesystem';\n\nimport { TemplateEditorIntro } from './TemplateEditorIntro';\nimport { ScaffolderPageContextMenu } from '@backstage/plugin-scaffolder-react/alpha';\nimport { useNavigate } from 'react-router-dom';\nimport { useRouteRef } from '@backstage/core-plugin-api';\nimport {\n actionsRouteRef,\n editorRouteRef,\n customFieldsRouteRef,\n rootRouteRef,\n scaffolderListTaskRouteRef,\n templateFormRouteRef,\n} from '../../../routes';\nimport { useTranslationRef } from '@backstage/core-plugin-api/alpha';\nimport { scaffolderTranslationRef } from '../../../translation';\nimport { WebFileSystemStore } from '../../../lib/filesystem/WebFileSystemAccess';\nimport { createExampleTemplate } from '../../../lib/filesystem/createExampleTemplate';\n\nexport function TemplateEditorPage() {\n const navigate = useNavigate();\n const actionsLink = useRouteRef(actionsRouteRef);\n const tasksLink = useRouteRef(scaffolderListTaskRouteRef);\n const createLink = useRouteRef(rootRouteRef);\n const editorLink = useRouteRef(editorRouteRef);\n const customFieldsLink = useRouteRef(customFieldsRouteRef);\n const templateFormLink = useRouteRef(templateFormRouteRef);\n const { t } = useTranslationRef(scaffolderTranslationRef);\n\n const scaffolderPageContextMenuProps = {\n onEditorClicked: undefined,\n onActionsClicked: () => navigate(actionsLink()),\n onTasksClicked: () => navigate(tasksLink()),\n onCreateClicked: () => navigate(createLink()),\n };\n\n return (\n <Page themeId=\"home\">\n <Header\n title={t('templateEditorPage.title')}\n subtitle={t('templateEditorPage.subtitle')}\n >\n <ScaffolderPageContextMenu {...scaffolderPageContextMenuProps} />\n </Header>\n <Content>\n <TemplateEditorIntro\n onSelect={option => {\n if (option === 'local') {\n WebFileSystemAccess.requestDirectoryAccess()\n .then(directory => WebFileSystemStore.setDirectory(directory))\n .then(() => navigate(editorLink()))\n .catch(() => {});\n } else if (option === 'create-template') {\n WebFileSystemAccess.requestDirectoryAccess()\n .then(directory => {\n createExampleTemplate(directory).then(() => {\n WebFileSystemStore.setDirectory(directory);\n navigate(editorLink());\n });\n })\n .catch(() => {});\n } else if (option === 'form') {\n navigate(templateFormLink());\n } else if (option === 'field-explorer') {\n navigate(customFieldsLink());\n }\n }}\n />\n </Content>\n </Page>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;;;AAqCO,SAAS,kBAAqB,GAAA;AACnC,EAAA,MAAM,WAAW,WAAY,EAAA,CAAA;AAC7B,EAAM,MAAA,WAAA,GAAc,YAAY,eAAe,CAAA,CAAA;AAC/C,EAAM,MAAA,SAAA,GAAY,YAAY,0BAA0B,CAAA,CAAA;AACxD,EAAM,MAAA,UAAA,GAAa,YAAY,YAAY,CAAA,CAAA;AAC3C,EAAM,MAAA,UAAA,GAAa,YAAY,cAAc,CAAA,CAAA;AAC7C,EAAM,MAAA,gBAAA,GAAmB,YAAY,oBAAoB,CAAA,CAAA;AACzD,EAAM,MAAA,gBAAA,GAAmB,YAAY,oBAAoB,CAAA,CAAA;AACzD,EAAA,MAAM,EAAE,CAAA,EAAM,GAAA,iBAAA,CAAkB,wBAAwB,CAAA,CAAA;AAExD,EAAA,MAAM,8BAAiC,GAAA;AAAA,IACrC,eAAiB,EAAA,KAAA,CAAA;AAAA,IACjB,gBAAkB,EAAA,MAAM,QAAS,CAAA,WAAA,EAAa,CAAA;AAAA,IAC9C,cAAgB,EAAA,MAAM,QAAS,CAAA,SAAA,EAAW,CAAA;AAAA,IAC1C,eAAiB,EAAA,MAAM,QAAS,CAAA,UAAA,EAAY,CAAA;AAAA,GAC9C,CAAA;AAEA,EACE,uBAAA,KAAA,CAAA,aAAA,CAAC,IAAK,EAAA,EAAA,OAAA,EAAQ,MACZ,EAAA,kBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,MAAA;AAAA,IAAA;AAAA,MACC,KAAA,EAAO,EAAE,0BAA0B,CAAA;AAAA,MACnC,QAAA,EAAU,EAAE,6BAA6B,CAAA;AAAA,KAAA;AAAA,oBAEzC,KAAA,CAAA,aAAA,CAAC,yBAA2B,EAAA,EAAA,GAAG,8BAAgC,EAAA,CAAA;AAAA,GACjE,sCACC,OACC,EAAA,IAAA,kBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,mBAAA;AAAA,IAAA;AAAA,MACC,UAAU,CAAU,MAAA,KAAA;AAClB,QAAA,IAAI,WAAW,OAAS,EAAA;AACtB,UAAA,mBAAA,CAAoB,wBACjB,CAAA,IAAA,CAAK,CAAa,SAAA,KAAA,kBAAA,CAAmB,aAAa,SAAS,CAAC,CAC5D,CAAA,IAAA,CAAK,MAAM,QAAS,CAAA,UAAA,EAAY,CAAC,CAAA,CACjC,MAAM,MAAM;AAAA,WAAE,CAAA,CAAA;AAAA,SACnB,MAAA,IAAW,WAAW,iBAAmB,EAAA;AACvC,UAAoB,mBAAA,CAAA,sBAAA,EACjB,CAAA,IAAA,CAAK,CAAa,SAAA,KAAA;AACjB,YAAsB,qBAAA,CAAA,SAAS,CAAE,CAAA,IAAA,CAAK,MAAM;AAC1C,cAAA,kBAAA,CAAmB,aAAa,SAAS,CAAA,CAAA;AACzC,cAAA,QAAA,CAAS,YAAY,CAAA,CAAA;AAAA,aACtB,CAAA,CAAA;AAAA,WACF,CACA,CAAA,KAAA,CAAM,MAAM;AAAA,WAAE,CAAA,CAAA;AAAA,SACnB,MAAA,IAAW,WAAW,MAAQ,EAAA;AAC5B,UAAA,QAAA,CAAS,kBAAkB,CAAA,CAAA;AAAA,SAC7B,MAAA,IAAW,WAAW,gBAAkB,EAAA;AACtC,UAAA,QAAA,CAAS,kBAAkB,CAAA,CAAA;AAAA,SAC7B;AAAA,OACF;AAAA,KAAA;AAAA,GAEJ,CACF,CAAA,CAAA;AAEJ;;;;"}
|
|
@@ -4,6 +4,8 @@ import { showPanel } from '@codemirror/view';
|
|
|
4
4
|
import IconButton from '@material-ui/core/IconButton';
|
|
5
5
|
import Paper from '@material-ui/core/Paper';
|
|
6
6
|
import Tooltip from '@material-ui/core/Tooltip';
|
|
7
|
+
import Link from '@material-ui/core/Link';
|
|
8
|
+
import Typography from '@material-ui/core/Typography';
|
|
7
9
|
import { makeStyles } from '@material-ui/core/styles';
|
|
8
10
|
import RefreshIcon from '@material-ui/icons/Refresh';
|
|
9
11
|
import SaveIcon from '@material-ui/icons/Save';
|
|
@@ -12,7 +14,7 @@ import CodeMirror from '@uiw/react-codemirror';
|
|
|
12
14
|
import React, { useMemo } from 'react';
|
|
13
15
|
import { useDirectoryEditor } from './DirectoryEditorContext.esm.js';
|
|
14
16
|
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
|
|
15
|
-
import { scaffolderTranslationRef } from '
|
|
17
|
+
import { scaffolderTranslationRef } from '../../../translation.esm.js';
|
|
16
18
|
|
|
17
19
|
const useStyles = makeStyles((theme) => ({
|
|
18
20
|
container: {
|
|
@@ -20,6 +22,12 @@ const useStyles = makeStyles((theme) => ({
|
|
|
20
22
|
width: "100%",
|
|
21
23
|
height: "100%"
|
|
22
24
|
},
|
|
25
|
+
typography: {
|
|
26
|
+
padding: theme.spacing(1.5)
|
|
27
|
+
},
|
|
28
|
+
button: {
|
|
29
|
+
verticalAlign: "top"
|
|
30
|
+
},
|
|
23
31
|
codeMirror: {
|
|
24
32
|
position: "absolute",
|
|
25
33
|
top: 0,
|
|
@@ -106,8 +114,33 @@ function TemplateEditorTextArea(props) {
|
|
|
106
114
|
))));
|
|
107
115
|
}
|
|
108
116
|
function TemplateEditorDirectoryEditorTextArea(props) {
|
|
117
|
+
const classes = useStyles();
|
|
109
118
|
const directoryEditor = useDirectoryEditor();
|
|
110
|
-
|
|
119
|
+
if (!directoryEditor) {
|
|
120
|
+
return /* @__PURE__ */ React.createElement(
|
|
121
|
+
Typography,
|
|
122
|
+
{
|
|
123
|
+
className: classes.typography,
|
|
124
|
+
color: "textSecondary",
|
|
125
|
+
align: "center"
|
|
126
|
+
},
|
|
127
|
+
"Please",
|
|
128
|
+
" ",
|
|
129
|
+
/* @__PURE__ */ React.createElement(
|
|
130
|
+
Link,
|
|
131
|
+
{
|
|
132
|
+
className: classes.button,
|
|
133
|
+
component: "button",
|
|
134
|
+
variant: "body1",
|
|
135
|
+
onClick: props.onLoad
|
|
136
|
+
},
|
|
137
|
+
"load"
|
|
138
|
+
),
|
|
139
|
+
" ",
|
|
140
|
+
"a template directory."
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
const actions = directoryEditor?.selectedFile?.dirty ? {
|
|
111
144
|
onSave: () => directoryEditor.save(),
|
|
112
145
|
onReload: () => directoryEditor.reload()
|
|
113
146
|
} : {
|
|
@@ -118,7 +151,7 @@ function TemplateEditorDirectoryEditorTextArea(props) {
|
|
|
118
151
|
{
|
|
119
152
|
errorText: props.errorText,
|
|
120
153
|
content: directoryEditor.selectedFile?.content,
|
|
121
|
-
onUpdate: (content) => directoryEditor
|
|
154
|
+
onUpdate: (content) => directoryEditor?.selectedFile?.updateContent(content),
|
|
122
155
|
...actions
|
|
123
156
|
}
|
|
124
157
|
);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TemplateEditorTextArea.esm.js","sources":["../../../../src/alpha/components/TemplateEditorPage/TemplateEditorTextArea.tsx"],"sourcesContent":["/*\n * Copyright 2022 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 */\n\nimport { StreamLanguage } from '@codemirror/language';\nimport { yaml as yamlSupport } from '@codemirror/legacy-modes/mode/yaml';\nimport { showPanel } from '@codemirror/view';\nimport IconButton from '@material-ui/core/IconButton';\nimport Paper from '@material-ui/core/Paper';\nimport Tooltip from '@material-ui/core/Tooltip';\nimport Link from '@material-ui/core/Link';\nimport Typography from '@material-ui/core/Typography';\nimport { makeStyles } from '@material-ui/core/styles';\nimport RefreshIcon from '@material-ui/icons/Refresh';\nimport SaveIcon from '@material-ui/icons/Save';\nimport { useKeyboardEvent } from '@react-hookz/web';\nimport CodeMirror from '@uiw/react-codemirror';\nimport React, { useMemo } from 'react';\nimport { useDirectoryEditor } from './DirectoryEditorContext';\nimport { useTranslationRef } from '@backstage/core-plugin-api/alpha';\nimport { scaffolderTranslationRef } from '../../../translation';\n\nconst useStyles = makeStyles(theme => ({\n container: {\n position: 'relative',\n width: '100%',\n height: '100%',\n },\n typography: {\n padding: theme.spacing(1.5),\n },\n button: {\n verticalAlign: 'top',\n },\n codeMirror: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n left: 0,\n right: 0,\n },\n errorPanel: {\n color: theme.palette.error.main,\n lineHeight: 2,\n margin: theme.spacing(0, 1),\n },\n floatingButtons: {\n position: 'absolute',\n top: theme.spacing(1),\n right: theme.spacing(3),\n },\n floatingButton: {\n padding: theme.spacing(1),\n },\n}));\n\n/** A wrapper around CodeMirror with an error panel and extra actions available */\nexport function TemplateEditorTextArea(props: {\n content?: string;\n onUpdate?: (content: string) => void;\n errorText?: string;\n onSave?: () => void;\n onReload?: () => void;\n}) {\n const { errorText } = props;\n const classes = useStyles();\n const { t } = useTranslationRef(scaffolderTranslationRef);\n\n const panelExtension = useMemo(() => {\n if (!errorText) {\n return showPanel.of(null);\n }\n\n const dom = document.createElement('div');\n dom.classList.add(classes.errorPanel);\n dom.textContent = errorText;\n return showPanel.of(() => ({ dom, bottom: true }));\n }, [classes, errorText]);\n\n useKeyboardEvent(\n e => e.key === 's' && (e.ctrlKey || e.metaKey),\n e => {\n e.preventDefault();\n if (props.onSave) {\n props.onSave();\n }\n },\n );\n\n return (\n <div className={classes.container}>\n <CodeMirror\n className={classes.codeMirror}\n theme=\"dark\"\n height=\"100%\"\n extensions={[StreamLanguage.define(yamlSupport), panelExtension]}\n value={props.content}\n onChange={props.onUpdate}\n />\n {(props.onSave || props.onReload) && (\n <div className={classes.floatingButtons}>\n <Paper>\n {props.onSave && (\n <Tooltip\n title={t(\n 'templateEditorPage.templateEditorTextArea.saveIconTooltip',\n )}\n >\n <IconButton\n className={classes.floatingButton}\n onClick={() => props.onSave?.()}\n >\n <SaveIcon />\n </IconButton>\n </Tooltip>\n )}\n {props.onReload && (\n <Tooltip\n title={t(\n 'templateEditorPage.templateEditorTextArea.refreshIconTooltip',\n )}\n >\n <IconButton\n className={classes.floatingButton}\n onClick={() => props.onReload?.()}\n >\n <RefreshIcon />\n </IconButton>\n </Tooltip>\n )}\n </Paper>\n </div>\n )}\n </div>\n );\n}\n\n/** A version of the TemplateEditorTextArea that is connected to the DirectoryEditor context */\nexport function TemplateEditorDirectoryEditorTextArea(props: {\n errorText?: string;\n onLoad?: () => void;\n}) {\n const classes = useStyles();\n const directoryEditor = useDirectoryEditor();\n\n if (!directoryEditor) {\n return (\n <Typography\n className={classes.typography}\n color=\"textSecondary\"\n align=\"center\"\n >\n Please{' '}\n <Link\n className={classes.button}\n component=\"button\"\n variant=\"body1\"\n onClick={props.onLoad}\n >\n load\n </Link>{' '}\n a template directory.\n </Typography>\n );\n }\n\n const actions = directoryEditor?.selectedFile?.dirty\n ? {\n onSave: () => directoryEditor.save(),\n onReload: () => directoryEditor.reload(),\n }\n : {\n onReload: () => directoryEditor.reload(),\n };\n\n return (\n <TemplateEditorTextArea\n errorText={props.errorText}\n content={directoryEditor.selectedFile?.content}\n onUpdate={content =>\n directoryEditor?.selectedFile?.updateContent(content)\n }\n {...actions}\n />\n );\n}\n\nTemplateEditorTextArea.DirectoryEditor = TemplateEditorDirectoryEditorTextArea;\n"],"names":["yamlSupport"],"mappings":"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"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import { makeStyles } from '@material-ui/core/styles';
|
|
3
|
+
import AppBar from '@material-ui/core/AppBar';
|
|
4
|
+
import Toolbar from '@material-ui/core/Toolbar';
|
|
5
|
+
import Tooltip from '@material-ui/core/Tooltip';
|
|
6
|
+
import ButtonGroup from '@material-ui/core/ButtonGroup';
|
|
7
|
+
import Button from '@material-ui/core/Button';
|
|
8
|
+
import Drawer from '@material-ui/core/Drawer';
|
|
9
|
+
import Dialog from '@material-ui/core/Dialog';
|
|
10
|
+
import DialogTitle from '@material-ui/core/DialogTitle';
|
|
11
|
+
import DialogContent from '@material-ui/core/DialogContent';
|
|
12
|
+
import DialogContentText from '@material-ui/core/DialogContentText';
|
|
13
|
+
import DialogActions from '@material-ui/core/DialogActions';
|
|
14
|
+
import ExtensionIcon from '@material-ui/icons/Extension';
|
|
15
|
+
import DescriptionIcon from '@material-ui/icons/Description';
|
|
16
|
+
import { Link } from '@backstage/core-components';
|
|
17
|
+
import { ActionPageContent } from '../../../components/ActionsPage/ActionsPage.esm.js';
|
|
18
|
+
import { CustomFieldPlaygroud } from './CustomFieldPlaygroud.esm.js';
|
|
19
|
+
|
|
20
|
+
const useStyles = makeStyles(
|
|
21
|
+
(theme) => ({
|
|
22
|
+
paper: {
|
|
23
|
+
width: "40%",
|
|
24
|
+
padding: theme.spacing(2),
|
|
25
|
+
backgroundColor: theme.palette.background.default
|
|
26
|
+
},
|
|
27
|
+
appbar: {
|
|
28
|
+
zIndex: 1
|
|
29
|
+
},
|
|
30
|
+
toolbar: {
|
|
31
|
+
display: "grid",
|
|
32
|
+
gridTemplateColumns: "auto 1fr",
|
|
33
|
+
gridGap: theme.spacing(1),
|
|
34
|
+
padding: theme.spacing(0, 1),
|
|
35
|
+
backgroundColor: theme.palette.background.paper
|
|
36
|
+
},
|
|
37
|
+
toolbarCustomActions: {
|
|
38
|
+
display: "grid",
|
|
39
|
+
alignItems: "center",
|
|
40
|
+
gridAutoFlow: "Column",
|
|
41
|
+
gridGap: theme.spacing(1)
|
|
42
|
+
},
|
|
43
|
+
toolbarDefaultActions: {
|
|
44
|
+
justifySelf: "end"
|
|
45
|
+
}
|
|
46
|
+
}),
|
|
47
|
+
{ name: "ScaffolderTemplateEditorToolbar" }
|
|
48
|
+
);
|
|
49
|
+
function TemplateEditorToolbar(props) {
|
|
50
|
+
const { children, fieldExtensions } = props;
|
|
51
|
+
const classes = useStyles();
|
|
52
|
+
const [showFieldsDrawer, setShowFieldsDrawer] = useState(false);
|
|
53
|
+
const [showActionsDrawer, setShowActionsDrawer] = useState(false);
|
|
54
|
+
const [showPublishModal, setShowPublishModal] = useState(false);
|
|
55
|
+
return /* @__PURE__ */ React.createElement(AppBar, { className: classes.appbar, position: "relative" }, /* @__PURE__ */ React.createElement(Toolbar, { className: classes.toolbar }, /* @__PURE__ */ React.createElement("div", { className: classes.toolbarCustomActions }, children), /* @__PURE__ */ React.createElement(
|
|
56
|
+
ButtonGroup,
|
|
57
|
+
{
|
|
58
|
+
className: classes.toolbarDefaultActions,
|
|
59
|
+
variant: "outlined",
|
|
60
|
+
color: "primary"
|
|
61
|
+
},
|
|
62
|
+
/* @__PURE__ */ React.createElement(Tooltip, { title: "Custom Fields Explorer" }, /* @__PURE__ */ React.createElement(Button, { onClick: () => setShowFieldsDrawer(true) }, /* @__PURE__ */ React.createElement(ExtensionIcon, null))),
|
|
63
|
+
/* @__PURE__ */ React.createElement(Tooltip, { title: "Installed Actions Documentation" }, /* @__PURE__ */ React.createElement(Button, { onClick: () => setShowActionsDrawer(true) }, /* @__PURE__ */ React.createElement(DescriptionIcon, null))),
|
|
64
|
+
/* @__PURE__ */ React.createElement(Button, { onClick: () => setShowPublishModal(true) }, "Publish")
|
|
65
|
+
), /* @__PURE__ */ React.createElement(
|
|
66
|
+
Drawer,
|
|
67
|
+
{
|
|
68
|
+
classes: { paper: classes.paper },
|
|
69
|
+
anchor: "right",
|
|
70
|
+
open: showFieldsDrawer,
|
|
71
|
+
onClose: () => setShowFieldsDrawer(false)
|
|
72
|
+
},
|
|
73
|
+
/* @__PURE__ */ React.createElement(CustomFieldPlaygroud, { fieldExtensions })
|
|
74
|
+
), /* @__PURE__ */ React.createElement(
|
|
75
|
+
Drawer,
|
|
76
|
+
{
|
|
77
|
+
classes: { paper: classes.paper },
|
|
78
|
+
anchor: "right",
|
|
79
|
+
open: showActionsDrawer,
|
|
80
|
+
onClose: () => setShowActionsDrawer(false)
|
|
81
|
+
},
|
|
82
|
+
/* @__PURE__ */ React.createElement(ActionPageContent, null)
|
|
83
|
+
), /* @__PURE__ */ React.createElement(
|
|
84
|
+
Dialog,
|
|
85
|
+
{
|
|
86
|
+
onClose: () => setShowPublishModal(false),
|
|
87
|
+
open: showPublishModal,
|
|
88
|
+
"aria-labelledby": "publish-dialog-title",
|
|
89
|
+
"aria-describedby": "publish-dialog-description"
|
|
90
|
+
},
|
|
91
|
+
/* @__PURE__ */ React.createElement(DialogTitle, { id: "publish-dialog-title" }, "Publish changes"),
|
|
92
|
+
/* @__PURE__ */ React.createElement(DialogContent, { dividers: true }, /* @__PURE__ */ React.createElement(DialogContentText, { id: "publish-dialog-slide-description" }, "Follow the instructions below to create or update a template:", /* @__PURE__ */ React.createElement("ol", null, /* @__PURE__ */ React.createElement("li", null, "Save the template files in a local directory"), /* @__PURE__ */ React.createElement("li", null, "Create a pull request to a new or existing git repository"), /* @__PURE__ */ React.createElement("li", null, "If the template already exists, the changes will be reflected in the software catalog once the pull request gets merged"), /* @__PURE__ */ React.createElement("li", null, "But if you are creating a new template, follow this", " ", /* @__PURE__ */ React.createElement(Link, { to: "https://backstage.io/docs/features/software-templates/adding-templates/" }, "documentation"), " ", "to register the new template repository in software catalog")))),
|
|
93
|
+
/* @__PURE__ */ React.createElement(DialogActions, null, /* @__PURE__ */ React.createElement(Button, { color: "primary", onClick: () => setShowPublishModal(false) }, "Close"))
|
|
94
|
+
)));
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export { TemplateEditorToolbar };
|
|
98
|
+
//# sourceMappingURL=TemplateEditorToolbar.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TemplateEditorToolbar.esm.js","sources":["../../../../src/alpha/components/TemplateEditorPage/TemplateEditorToolbar.tsx"],"sourcesContent":["/*\n * Copyright 2024 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 */\n\nimport React, { ReactNode, useState } from 'react';\n\nimport { makeStyles } from '@material-ui/core/styles';\nimport AppBar from '@material-ui/core/AppBar';\nimport Toolbar from '@material-ui/core/Toolbar';\nimport Tooltip from '@material-ui/core/Tooltip';\nimport ButtonGroup from '@material-ui/core/ButtonGroup';\nimport Button from '@material-ui/core/Button';\nimport Drawer from '@material-ui/core/Drawer';\nimport Dialog from '@material-ui/core/Dialog';\nimport DialogTitle from '@material-ui/core/DialogTitle';\nimport DialogContent from '@material-ui/core/DialogContent';\nimport DialogContentText from '@material-ui/core/DialogContentText';\nimport DialogActions from '@material-ui/core/DialogActions';\nimport ExtensionIcon from '@material-ui/icons/Extension';\nimport DescriptionIcon from '@material-ui/icons/Description';\n\nimport { Link } from '@backstage/core-components';\nimport { FieldExtensionOptions } from '@backstage/plugin-scaffolder-react';\n\nimport { ActionPageContent } from '../../../components/ActionsPage/ActionsPage';\nimport { CustomFieldPlaygroud } from './CustomFieldPlaygroud';\n\nconst useStyles = makeStyles(\n theme => ({\n paper: {\n width: '40%',\n padding: theme.spacing(2),\n backgroundColor: theme.palette.background.default,\n },\n appbar: {\n zIndex: 1,\n },\n toolbar: {\n display: 'grid',\n gridTemplateColumns: 'auto 1fr',\n gridGap: theme.spacing(1),\n padding: theme.spacing(0, 1),\n backgroundColor: theme.palette.background.paper,\n },\n toolbarCustomActions: {\n display: 'grid',\n alignItems: 'center',\n gridAutoFlow: 'Column',\n gridGap: theme.spacing(1),\n },\n toolbarDefaultActions: {\n justifySelf: 'end',\n },\n }),\n { name: 'ScaffolderTemplateEditorToolbar' },\n);\n\nexport function TemplateEditorToolbar(props: {\n children?: ReactNode;\n fieldExtensions?: FieldExtensionOptions<any, any>[];\n}) {\n const { children, fieldExtensions } = props;\n const classes = useStyles();\n const [showFieldsDrawer, setShowFieldsDrawer] = useState(false);\n const [showActionsDrawer, setShowActionsDrawer] = useState(false);\n const [showPublishModal, setShowPublishModal] = useState(false);\n\n return (\n <AppBar className={classes.appbar} position=\"relative\">\n <Toolbar className={classes.toolbar}>\n <div className={classes.toolbarCustomActions}>{children}</div>\n <ButtonGroup\n className={classes.toolbarDefaultActions}\n variant=\"outlined\"\n color=\"primary\"\n >\n <Tooltip title=\"Custom Fields Explorer\">\n <Button onClick={() => setShowFieldsDrawer(true)}>\n <ExtensionIcon />\n </Button>\n </Tooltip>\n <Tooltip title=\"Installed Actions Documentation\">\n <Button onClick={() => setShowActionsDrawer(true)}>\n <DescriptionIcon />\n </Button>\n </Tooltip>\n <Button onClick={() => setShowPublishModal(true)}>Publish</Button>\n </ButtonGroup>\n <Drawer\n classes={{ paper: classes.paper }}\n anchor=\"right\"\n open={showFieldsDrawer}\n onClose={() => setShowFieldsDrawer(false)}\n >\n <CustomFieldPlaygroud fieldExtensions={fieldExtensions} />\n </Drawer>\n <Drawer\n classes={{ paper: classes.paper }}\n anchor=\"right\"\n open={showActionsDrawer}\n onClose={() => setShowActionsDrawer(false)}\n >\n <ActionPageContent />\n </Drawer>\n <Dialog\n onClose={() => setShowPublishModal(false)}\n open={showPublishModal}\n aria-labelledby=\"publish-dialog-title\"\n aria-describedby=\"publish-dialog-description\"\n >\n <DialogTitle id=\"publish-dialog-title\">Publish changes</DialogTitle>\n <DialogContent dividers>\n <DialogContentText id=\"publish-dialog-slide-description\">\n Follow the instructions below to create or update a template:\n <ol>\n <li>Save the template files in a local directory</li>\n <li>\n Create a pull request to a new or existing git repository\n </li>\n <li>\n If the template already exists, the changes will be reflected\n in the software catalog once the pull request gets merged\n </li>\n <li>\n But if you are creating a new template, follow this{' '}\n <Link to=\"https://backstage.io/docs/features/software-templates/adding-templates/\">\n documentation\n </Link>{' '}\n to register the new template repository in software catalog\n </li>\n </ol>\n </DialogContentText>\n </DialogContent>\n <DialogActions>\n <Button color=\"primary\" onClick={() => setShowPublishModal(false)}>\n Close\n </Button>\n </DialogActions>\n </Dialog>\n </Toolbar>\n </AppBar>\n );\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import React, { useCallback } from 'react';
|
|
2
|
+
import { useNavigate } from 'react-router-dom';
|
|
3
|
+
import { makeStyles } from '@material-ui/core/styles';
|
|
4
|
+
import { Page, Header, Content } from '@backstage/core-components';
|
|
5
|
+
import { useRouteRef } from '@backstage/core-plugin-api';
|
|
6
|
+
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
|
|
7
|
+
import { editRouteRef } from '../../../routes.esm.js';
|
|
8
|
+
import { scaffolderTranslationRef } from '../../../translation.esm.js';
|
|
9
|
+
import { TemplateFormPreviewer } from './TemplateFormPreviewer.esm.js';
|
|
10
|
+
|
|
11
|
+
const useStyles = makeStyles({
|
|
12
|
+
root: {
|
|
13
|
+
padding: 0
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
function TemplateFormPage(props) {
|
|
17
|
+
const classes = useStyles();
|
|
18
|
+
const navigate = useNavigate();
|
|
19
|
+
const editLink = useRouteRef(editRouteRef);
|
|
20
|
+
const { t } = useTranslationRef(scaffolderTranslationRef);
|
|
21
|
+
const handleClose = useCallback(() => {
|
|
22
|
+
navigate(editLink());
|
|
23
|
+
}, [navigate, editLink]);
|
|
24
|
+
return /* @__PURE__ */ React.createElement(Page, { themeId: "home" }, /* @__PURE__ */ React.createElement(
|
|
25
|
+
Header,
|
|
26
|
+
{
|
|
27
|
+
title: t("templateFormPage.title"),
|
|
28
|
+
subtitle: t("templateFormPage.subtitle")
|
|
29
|
+
}
|
|
30
|
+
), /* @__PURE__ */ React.createElement(Content, { className: classes.root }, /* @__PURE__ */ React.createElement(
|
|
31
|
+
TemplateFormPreviewer,
|
|
32
|
+
{
|
|
33
|
+
layouts: props.layouts,
|
|
34
|
+
formProps: props.formProps,
|
|
35
|
+
customFieldExtensions: props.fieldExtensions,
|
|
36
|
+
defaultPreviewTemplate: props.defaultPreviewTemplate,
|
|
37
|
+
onClose: handleClose
|
|
38
|
+
}
|
|
39
|
+
)));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export { TemplateFormPage };
|
|
43
|
+
//# sourceMappingURL=TemplateFormPage.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TemplateFormPage.esm.js","sources":["../../../../src/alpha/components/TemplateEditorPage/TemplateFormPage.tsx"],"sourcesContent":["/*\n * Copyright 2024 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 */\n\nimport React, { useCallback } from 'react';\nimport { useNavigate } from 'react-router-dom';\n\nimport { makeStyles } from '@material-ui/core/styles';\n\nimport { Page, Header, Content } from '@backstage/core-components';\nimport { useRouteRef } from '@backstage/core-plugin-api';\nimport { useTranslationRef } from '@backstage/core-plugin-api/alpha';\nimport {\n FormProps,\n LayoutOptions,\n FieldExtensionOptions,\n} from '@backstage/plugin-scaffolder-react';\n\nimport { editRouteRef } from '../../../routes';\nimport { scaffolderTranslationRef } from '../../../translation';\n\nimport { TemplateFormPreviewer } from './TemplateFormPreviewer';\n\nconst useStyles = makeStyles({\n root: {\n padding: 0,\n },\n});\n\ninterface TemplateFormPageProps {\n layouts?: LayoutOptions[];\n formProps?: FormProps;\n fieldExtensions?: FieldExtensionOptions<any, any>[];\n defaultPreviewTemplate?: string;\n}\n\nexport function TemplateFormPage(props: TemplateFormPageProps) {\n const classes = useStyles();\n const navigate = useNavigate();\n const editLink = useRouteRef(editRouteRef);\n const { t } = useTranslationRef(scaffolderTranslationRef);\n\n const handleClose = useCallback(() => {\n navigate(editLink());\n }, [navigate, editLink]);\n\n return (\n <Page themeId=\"home\">\n <Header\n title={t('templateFormPage.title')}\n subtitle={t('templateFormPage.subtitle')}\n />\n <Content className={classes.root}>\n <TemplateFormPreviewer\n layouts={props.layouts}\n formProps={props.formProps}\n customFieldExtensions={props.fieldExtensions}\n defaultPreviewTemplate={props.defaultPreviewTemplate}\n onClose={handleClose}\n />\n </Content>\n </Page>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;AAmCA,MAAM,YAAY,UAAW,CAAA;AAAA,EAC3B,IAAM,EAAA;AAAA,IACJ,OAAS,EAAA,CAAA;AAAA,GACX;AACF,CAAC,CAAA,CAAA;AASM,SAAS,iBAAiB,KAA8B,EAAA;AAC7D,EAAA,MAAM,UAAU,SAAU,EAAA,CAAA;AAC1B,EAAA,MAAM,WAAW,WAAY,EAAA,CAAA;AAC7B,EAAM,MAAA,QAAA,GAAW,YAAY,YAAY,CAAA,CAAA;AACzC,EAAA,MAAM,EAAE,CAAA,EAAM,GAAA,iBAAA,CAAkB,wBAAwB,CAAA,CAAA;AAExD,EAAM,MAAA,WAAA,GAAc,YAAY,MAAM;AACpC,IAAA,QAAA,CAAS,UAAU,CAAA,CAAA;AAAA,GAClB,EAAA,CAAC,QAAU,EAAA,QAAQ,CAAC,CAAA,CAAA;AAEvB,EACE,uBAAA,KAAA,CAAA,aAAA,CAAC,IAAK,EAAA,EAAA,OAAA,EAAQ,MACZ,EAAA,kBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,MAAA;AAAA,IAAA;AAAA,MACC,KAAA,EAAO,EAAE,wBAAwB,CAAA;AAAA,MACjC,QAAA,EAAU,EAAE,2BAA2B,CAAA;AAAA,KAAA;AAAA,GAEzC,kBAAA,KAAA,CAAA,aAAA,CAAC,OAAQ,EAAA,EAAA,SAAA,EAAW,QAAQ,IAC1B,EAAA,kBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,qBAAA;AAAA,IAAA;AAAA,MACC,SAAS,KAAM,CAAA,OAAA;AAAA,MACf,WAAW,KAAM,CAAA,SAAA;AAAA,MACjB,uBAAuB,KAAM,CAAA,eAAA;AAAA,MAC7B,wBAAwB,KAAM,CAAA,sBAAA;AAAA,MAC9B,OAAS,EAAA,WAAA;AAAA,KAAA;AAAA,GAEb,CACF,CAAA,CAAA;AAEJ;;;;"}
|
|
@@ -1,20 +1,23 @@
|
|
|
1
1
|
import { useApi, alertApiRef } from '@backstage/core-plugin-api';
|
|
2
2
|
import { catalogApiRef, humanizeEntityRef } from '@backstage/plugin-catalog-react';
|
|
3
|
+
import LinearProgress from '@material-ui/core/LinearProgress';
|
|
4
|
+
import Paper from '@material-ui/core/Paper';
|
|
3
5
|
import FormControl from '@material-ui/core/FormControl';
|
|
6
|
+
import Input from '@material-ui/core/Input';
|
|
7
|
+
import Select from '@material-ui/core/Select';
|
|
8
|
+
import Tooltip from '@material-ui/core/Tooltip';
|
|
4
9
|
import IconButton from '@material-ui/core/IconButton';
|
|
5
|
-
import InputLabel from '@material-ui/core/InputLabel';
|
|
6
|
-
import LinearProgress from '@material-ui/core/LinearProgress';
|
|
7
10
|
import MenuItem from '@material-ui/core/MenuItem';
|
|
8
|
-
import Select from '@material-ui/core/Select';
|
|
9
11
|
import { makeStyles } from '@material-ui/core/styles';
|
|
10
12
|
import CloseIcon from '@material-ui/icons/Close';
|
|
11
13
|
import React, { useState, useCallback } from 'react';
|
|
12
14
|
import useAsync from 'react-use/esm/useAsync';
|
|
13
15
|
import yaml from 'yaml';
|
|
16
|
+
import { TemplateEditorToolbar } from './TemplateEditorToolbar.esm.js';
|
|
14
17
|
import { TemplateEditorForm } from './TemplateEditorForm.esm.js';
|
|
15
18
|
import { TemplateEditorTextArea } from './TemplateEditorTextArea.esm.js';
|
|
16
19
|
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
|
|
17
|
-
import { scaffolderTranslationRef } from '
|
|
20
|
+
import { scaffolderTranslationRef } from '../../../translation.esm.js';
|
|
18
21
|
|
|
19
22
|
const EXAMPLE_TEMPLATE_PARAMS_YAML = `# Edit the template parameters below to see how they will render in the scaffolder form UI
|
|
20
23
|
parameters:
|
|
@@ -57,27 +60,40 @@ steps:
|
|
|
57
60
|
const useStyles = makeStyles(
|
|
58
61
|
(theme) => ({
|
|
59
62
|
root: {
|
|
63
|
+
height: "100%",
|
|
60
64
|
gridArea: "pageContent",
|
|
61
65
|
display: "grid",
|
|
62
66
|
gridTemplateAreas: `
|
|
63
|
-
"
|
|
67
|
+
"toolbar toolbar"
|
|
64
68
|
"textArea preview"
|
|
65
69
|
`,
|
|
66
70
|
gridTemplateRows: "auto 1fr",
|
|
67
71
|
gridTemplateColumns: "1fr 1fr"
|
|
68
72
|
},
|
|
69
|
-
|
|
70
|
-
gridArea: "
|
|
71
|
-
display: "flex",
|
|
72
|
-
flexFlow: "row nowrap",
|
|
73
|
-
alignItems: "center",
|
|
74
|
-
margin: theme.spacing(1)
|
|
73
|
+
toolbar: {
|
|
74
|
+
gridArea: "toolbar"
|
|
75
75
|
},
|
|
76
76
|
textArea: {
|
|
77
|
-
gridArea: "textArea"
|
|
77
|
+
gridArea: "textArea",
|
|
78
|
+
height: "100%"
|
|
78
79
|
},
|
|
79
80
|
preview: {
|
|
80
|
-
gridArea: "preview"
|
|
81
|
+
gridArea: "preview",
|
|
82
|
+
position: "relative",
|
|
83
|
+
borderLeft: `1px solid ${theme.palette.divider}`,
|
|
84
|
+
backgroundColor: theme.palette.background.default
|
|
85
|
+
},
|
|
86
|
+
scroll: {
|
|
87
|
+
position: "absolute",
|
|
88
|
+
top: 0,
|
|
89
|
+
left: 0,
|
|
90
|
+
right: 0,
|
|
91
|
+
bottom: 0,
|
|
92
|
+
padding: theme.spacing(1)
|
|
93
|
+
},
|
|
94
|
+
formControl: {
|
|
95
|
+
minWidth: 120,
|
|
96
|
+
maxWidth: 300
|
|
81
97
|
}
|
|
82
98
|
}),
|
|
83
99
|
{ name: "ScaffolderTemplateFormPreviewer" }
|
|
@@ -93,8 +109,8 @@ const TemplateFormPreviewer = ({
|
|
|
93
109
|
const { t } = useTranslationRef(scaffolderTranslationRef);
|
|
94
110
|
const alertApi = useApi(alertApiRef);
|
|
95
111
|
const catalogApi = useApi(catalogApiRef);
|
|
96
|
-
const [selectedTemplate, setSelectedTemplate] = useState("");
|
|
97
112
|
const [errorText, setErrorText] = useState();
|
|
113
|
+
const [selectedTemplate, setSelectedTemplate] = useState(null);
|
|
98
114
|
const [templateOptions, setTemplateOptions] = useState([]);
|
|
99
115
|
const [templateYaml, setTemplateYaml] = useState(defaultPreviewTemplate);
|
|
100
116
|
const { loading } = useAsync(
|
|
@@ -132,33 +148,55 @@ const TemplateFormPreviewer = ({
|
|
|
132
148
|
},
|
|
133
149
|
[setTemplateYaml]
|
|
134
150
|
);
|
|
135
|
-
return /* @__PURE__ */ React.createElement(React.Fragment, null, loading && /* @__PURE__ */ React.createElement(LinearProgress, null), /* @__PURE__ */ React.createElement(
|
|
136
|
-
|
|
151
|
+
return /* @__PURE__ */ React.createElement(React.Fragment, null, loading && /* @__PURE__ */ React.createElement(LinearProgress, null), /* @__PURE__ */ React.createElement(
|
|
152
|
+
Paper,
|
|
137
153
|
{
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
154
|
+
className: classes.root,
|
|
155
|
+
component: "main",
|
|
156
|
+
variant: "outlined",
|
|
157
|
+
square: true
|
|
142
158
|
},
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
159
|
+
/* @__PURE__ */ React.createElement("div", { className: classes.toolbar }, /* @__PURE__ */ React.createElement(TemplateEditorToolbar, { fieldExtensions: customFieldExtensions }, /* @__PURE__ */ React.createElement(Tooltip, { title: "Close editor" }, /* @__PURE__ */ React.createElement(IconButton, { onClick: onClose }, /* @__PURE__ */ React.createElement(CloseIcon, null))), /* @__PURE__ */ React.createElement(FormControl, { className: classes.formControl }, /* @__PURE__ */ React.createElement(
|
|
160
|
+
Select,
|
|
161
|
+
{
|
|
162
|
+
displayEmpty: true,
|
|
163
|
+
value: selectedTemplate,
|
|
164
|
+
onChange: (e) => handleSelectChange(e.target.value),
|
|
165
|
+
input: /* @__PURE__ */ React.createElement(Input, null),
|
|
166
|
+
renderValue: (selected) => {
|
|
167
|
+
if (!selected) {
|
|
168
|
+
return t("templateEditorPage.templateFormPreviewer.title");
|
|
169
|
+
}
|
|
170
|
+
return selected.metadata.title;
|
|
171
|
+
},
|
|
172
|
+
inputProps: {
|
|
173
|
+
"aria-label": t(
|
|
174
|
+
"templateEditorPage.templateFormPreviewer.title"
|
|
175
|
+
)
|
|
176
|
+
}
|
|
177
|
+
},
|
|
178
|
+
templateOptions.map((option, index) => /* @__PURE__ */ React.createElement(MenuItem, { key: index, value: option.value }, option.label))
|
|
179
|
+
)))),
|
|
180
|
+
/* @__PURE__ */ React.createElement("div", { className: classes.textArea }, /* @__PURE__ */ React.createElement(
|
|
181
|
+
TemplateEditorTextArea,
|
|
182
|
+
{
|
|
183
|
+
content: templateYaml,
|
|
184
|
+
onUpdate: setTemplateYaml,
|
|
185
|
+
errorText
|
|
186
|
+
}
|
|
187
|
+
)),
|
|
188
|
+
/* @__PURE__ */ React.createElement("div", { className: classes.preview }, /* @__PURE__ */ React.createElement("div", { className: classes.scroll }, /* @__PURE__ */ React.createElement(
|
|
189
|
+
TemplateEditorForm,
|
|
190
|
+
{
|
|
191
|
+
content: templateYaml,
|
|
192
|
+
contentIsSpec: true,
|
|
193
|
+
fieldExtensions: customFieldExtensions,
|
|
194
|
+
setErrorText,
|
|
195
|
+
layouts,
|
|
196
|
+
formProps
|
|
197
|
+
}
|
|
198
|
+
)))
|
|
199
|
+
));
|
|
162
200
|
};
|
|
163
201
|
|
|
164
202
|
export { TemplateFormPreviewer };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TemplateFormPreviewer.esm.js","sources":["../../../../src/alpha/components/TemplateEditorPage/TemplateFormPreviewer.tsx"],"sourcesContent":["/*\n * Copyright 2022 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 */\n\nimport { Entity } from '@backstage/catalog-model';\nimport { alertApiRef, useApi } from '@backstage/core-plugin-api';\nimport {\n catalogApiRef,\n humanizeEntityRef,\n} from '@backstage/plugin-catalog-react';\nimport LinearProgress from '@material-ui/core/LinearProgress';\nimport Paper from '@material-ui/core/Paper';\nimport FormControl from '@material-ui/core/FormControl';\nimport Input from '@material-ui/core/Input';\nimport Select from '@material-ui/core/Select';\nimport Tooltip from '@material-ui/core/Tooltip';\nimport IconButton from '@material-ui/core/IconButton';\nimport MenuItem from '@material-ui/core/MenuItem';\nimport { makeStyles } from '@material-ui/core/styles';\nimport CloseIcon from '@material-ui/icons/Close';\nimport React, { useCallback, useState } from 'react';\nimport useAsync from 'react-use/esm/useAsync';\nimport yaml from 'yaml';\nimport {\n LayoutOptions,\n FieldExtensionOptions,\n FormProps,\n} from '@backstage/plugin-scaffolder-react';\nimport { TemplateEditorToolbar } from './TemplateEditorToolbar';\nimport { TemplateEditorForm } from './TemplateEditorForm';\nimport { TemplateEditorTextArea } from './TemplateEditorTextArea';\nimport { useTranslationRef } from '@backstage/core-plugin-api/alpha';\nimport { scaffolderTranslationRef } from '../../../translation';\n\nconst EXAMPLE_TEMPLATE_PARAMS_YAML = `# Edit the template parameters below to see how they will render in the scaffolder form UI\nparameters:\n - title: Fill in some steps\n required:\n - name\n properties:\n name:\n title: Name\n type: string\n description: Unique name of the component\n owner:\n title: Owner\n type: string\n description: Owner of the component\n ui:field: OwnerPicker\n ui:options:\n catalogFilter:\n kind: Group\n - title: Choose a location\n required:\n - repoUrl\n properties:\n repoUrl:\n title: Repository Location\n type: string\n ui:field: RepoUrlPicker\n ui:options:\n allowedHosts:\n - github.com\nsteps:\n - id: fetch-base\n name: Fetch Base\n action: fetch:template\n input:\n url: ./template\n values:\n name: \\${{parameters.name}}\n`;\n\ntype TemplateOption = {\n label: string;\n value: Entity;\n};\n\n/** @public */\nexport type ScaffolderTemplateFormPreviewerClassKey =\n | 'root'\n | 'controls'\n | 'textArea'\n | 'preview';\n\nconst useStyles = makeStyles(\n theme => ({\n root: {\n height: '100%',\n gridArea: 'pageContent',\n display: 'grid',\n gridTemplateAreas: `\n \"toolbar toolbar\"\n \"textArea preview\"\n `,\n gridTemplateRows: 'auto 1fr',\n gridTemplateColumns: '1fr 1fr',\n },\n toolbar: {\n gridArea: 'toolbar',\n },\n textArea: {\n gridArea: 'textArea',\n height: '100%',\n },\n preview: {\n gridArea: 'preview',\n position: 'relative',\n borderLeft: `1px solid ${theme.palette.divider}`,\n backgroundColor: theme.palette.background.default,\n },\n scroll: {\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n padding: theme.spacing(1),\n },\n formControl: {\n minWidth: 120,\n maxWidth: 300,\n },\n }),\n { name: 'ScaffolderTemplateFormPreviewer' },\n);\n\nexport const TemplateFormPreviewer = ({\n defaultPreviewTemplate = EXAMPLE_TEMPLATE_PARAMS_YAML,\n customFieldExtensions = [],\n onClose,\n layouts = [],\n formProps,\n}: {\n defaultPreviewTemplate?: string;\n customFieldExtensions?: FieldExtensionOptions<any, any>[];\n onClose?: () => void;\n layouts?: LayoutOptions[];\n formProps?: FormProps;\n}) => {\n const classes = useStyles();\n const { t } = useTranslationRef(scaffolderTranslationRef);\n const alertApi = useApi(alertApiRef);\n const catalogApi = useApi(catalogApiRef);\n const [errorText, setErrorText] = useState<string>();\n const [selectedTemplate, setSelectedTemplate] =\n useState<TemplateOption | null>(null);\n const [templateOptions, setTemplateOptions] = useState<TemplateOption[]>([]);\n const [templateYaml, setTemplateYaml] = useState(defaultPreviewTemplate);\n\n const { loading } = useAsync(\n () =>\n catalogApi\n .getEntities({\n filter: { kind: 'template' },\n fields: [\n 'kind',\n 'metadata.namespace',\n 'metadata.name',\n 'metadata.title',\n 'spec.parameters',\n 'spec.steps',\n 'spec.output',\n ],\n })\n .then(({ items }) =>\n setTemplateOptions(\n items.map(template => ({\n label:\n template.metadata.title ??\n humanizeEntityRef(template, { defaultKind: 'template' }),\n value: template,\n })),\n ),\n )\n .catch(e =>\n alertApi.post({\n message: `Error loading exisiting templates: ${e.message}`,\n severity: 'error',\n }),\n ),\n [catalogApi],\n );\n\n const handleSelectChange = useCallback(\n // TODO(Rugvip): Afaik this should be Entity, but didn't want to make runtime changes while fixing types\n (selected: any) => {\n setSelectedTemplate(selected);\n setTemplateYaml(yaml.stringify(selected.spec));\n },\n [setTemplateYaml],\n );\n\n return (\n <>\n {loading && <LinearProgress />}\n <Paper\n className={classes.root}\n component=\"main\"\n variant=\"outlined\"\n square\n >\n <div className={classes.toolbar}>\n <TemplateEditorToolbar fieldExtensions={customFieldExtensions}>\n <Tooltip title=\"Close editor\">\n <IconButton onClick={onClose}>\n <CloseIcon />\n </IconButton>\n </Tooltip>\n <FormControl className={classes.formControl}>\n <Select\n displayEmpty\n value={selectedTemplate}\n onChange={e => handleSelectChange(e.target.value)}\n input={<Input />}\n renderValue={selected => {\n if (!selected) {\n return t('templateEditorPage.templateFormPreviewer.title');\n }\n return (selected as Entity).metadata.title;\n }}\n inputProps={{\n 'aria-label': t(\n 'templateEditorPage.templateFormPreviewer.title',\n ),\n }}\n >\n {templateOptions.map((option, index) => (\n <MenuItem key={index} value={option.value as any}>\n {option.label}\n </MenuItem>\n ))}\n </Select>\n </FormControl>\n </TemplateEditorToolbar>\n </div>\n <div className={classes.textArea}>\n <TemplateEditorTextArea\n content={templateYaml}\n onUpdate={setTemplateYaml}\n errorText={errorText}\n />\n </div>\n <div className={classes.preview}>\n <div className={classes.scroll}>\n <TemplateEditorForm\n content={templateYaml}\n contentIsSpec\n fieldExtensions={customFieldExtensions}\n setErrorText={setErrorText}\n layouts={layouts}\n formProps={formProps}\n />\n </div>\n </div>\n </Paper>\n </>\n );\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import React, { useCallback } from 'react';
|
|
2
|
+
import useAsyncRetry from 'react-use/esm/useAsyncRetry';
|
|
3
|
+
import { Page, Header, Content, Progress } from '@backstage/core-components';
|
|
4
|
+
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
|
|
5
|
+
import { scaffolderTranslationRef } from '../../../translation.esm.js';
|
|
6
|
+
import { WebFileSystemStore, WebFileSystemAccess } from '../../../lib/filesystem/WebFileSystemAccess.esm.js';
|
|
7
|
+
import { TemplateEditor } from './TemplateEditor.esm.js';
|
|
8
|
+
import { makeStyles } from '@material-ui/core/styles';
|
|
9
|
+
|
|
10
|
+
const useStyles = makeStyles(
|
|
11
|
+
{
|
|
12
|
+
content: {
|
|
13
|
+
padding: 0
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
{ name: "ScaffolderTemplateEditorToolbar" }
|
|
17
|
+
);
|
|
18
|
+
function TemplatePage(props) {
|
|
19
|
+
const classes = useStyles();
|
|
20
|
+
const { t } = useTranslationRef(scaffolderTranslationRef);
|
|
21
|
+
const { value, loading, retry } = useAsyncRetry(async () => {
|
|
22
|
+
const directory = await WebFileSystemStore.getDirectory();
|
|
23
|
+
if (!directory) return void 0;
|
|
24
|
+
return WebFileSystemAccess.fromHandle(directory);
|
|
25
|
+
}, []);
|
|
26
|
+
const handleLoadDirectory = useCallback(() => {
|
|
27
|
+
WebFileSystemAccess.requestDirectoryAccess().then(WebFileSystemStore.setDirectory).then(retry);
|
|
28
|
+
}, [retry]);
|
|
29
|
+
const handleCloseDirectory = useCallback(() => {
|
|
30
|
+
WebFileSystemStore.setDirectory(void 0).then(retry);
|
|
31
|
+
}, [retry]);
|
|
32
|
+
return /* @__PURE__ */ React.createElement(Page, { themeId: "home" }, /* @__PURE__ */ React.createElement(
|
|
33
|
+
Header,
|
|
34
|
+
{
|
|
35
|
+
title: t("templateEditorPage.title"),
|
|
36
|
+
subtitle: t("templateEditorPage.subtitle")
|
|
37
|
+
}
|
|
38
|
+
), /* @__PURE__ */ React.createElement(Content, { className: classes.content }, loading ? /* @__PURE__ */ React.createElement(Progress, null) : /* @__PURE__ */ React.createElement(
|
|
39
|
+
TemplateEditor,
|
|
40
|
+
{
|
|
41
|
+
directory: value,
|
|
42
|
+
layouts: props.layouts,
|
|
43
|
+
formProps: props.formProps,
|
|
44
|
+
fieldExtensions: props.fieldExtensions,
|
|
45
|
+
onClose: handleCloseDirectory,
|
|
46
|
+
onLoad: handleLoadDirectory
|
|
47
|
+
}
|
|
48
|
+
)));
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export { TemplatePage };
|
|
52
|
+
//# sourceMappingURL=TemplatePage.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TemplatePage.esm.js","sources":["../../../../src/alpha/components/TemplateEditorPage/TemplatePage.tsx"],"sourcesContent":["/*\n * Copyright 2024 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 */\n\nimport React, { useCallback } from 'react';\nimport useAsyncRetry from 'react-use/esm/useAsyncRetry';\n\nimport { Page, Header, Content, Progress } from '@backstage/core-components';\nimport { useTranslationRef } from '@backstage/core-plugin-api/alpha';\nimport {\n FormProps,\n FieldExtensionOptions,\n type LayoutOptions,\n} from '@backstage/plugin-scaffolder-react';\n\nimport { scaffolderTranslationRef } from '../../../translation';\nimport {\n WebFileSystemAccess,\n WebFileSystemStore,\n} from '../../../lib/filesystem';\nimport { TemplateEditor } from './TemplateEditor';\n\nimport { makeStyles } from '@material-ui/core/styles';\n\nconst useStyles = makeStyles(\n {\n content: {\n padding: 0,\n },\n },\n { name: 'ScaffolderTemplateEditorToolbar' },\n);\n\ninterface TemplatePageProps {\n defaultPreviewTemplate?: string;\n fieldExtensions?: FieldExtensionOptions<any, any>[];\n layouts?: LayoutOptions[];\n formProps?: FormProps;\n}\n\nexport function TemplatePage(props: TemplatePageProps) {\n const classes = useStyles();\n const { t } = useTranslationRef(scaffolderTranslationRef);\n\n const { value, loading, retry } = useAsyncRetry(async () => {\n const directory = await WebFileSystemStore.getDirectory();\n if (!directory) return undefined;\n return WebFileSystemAccess.fromHandle(directory);\n }, []);\n\n const handleLoadDirectory = useCallback(() => {\n WebFileSystemAccess.requestDirectoryAccess()\n .then(WebFileSystemStore.setDirectory)\n .then(retry);\n }, [retry]);\n\n const handleCloseDirectory = useCallback(() => {\n WebFileSystemStore.setDirectory(undefined).then(retry);\n }, [retry]);\n\n return (\n <Page themeId=\"home\">\n <Header\n title={t('templateEditorPage.title')}\n subtitle={t('templateEditorPage.subtitle')}\n />\n <Content className={classes.content}>\n {loading ? (\n <Progress />\n ) : (\n <TemplateEditor\n directory={value}\n layouts={props.layouts}\n formProps={props.formProps}\n fieldExtensions={props.fieldExtensions}\n onClose={handleCloseDirectory}\n onLoad={handleLoadDirectory}\n />\n )}\n </Content>\n </Page>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;AAoCA,MAAM,SAAY,GAAA,UAAA;AAAA,EAChB;AAAA,IACE,OAAS,EAAA;AAAA,MACP,OAAS,EAAA,CAAA;AAAA,KACX;AAAA,GACF;AAAA,EACA,EAAE,MAAM,iCAAkC,EAAA;AAC5C,CAAA,CAAA;AASO,SAAS,aAAa,KAA0B,EAAA;AACrD,EAAA,MAAM,UAAU,SAAU,EAAA,CAAA;AAC1B,EAAA,MAAM,EAAE,CAAA,EAAM,GAAA,iBAAA,CAAkB,wBAAwB,CAAA,CAAA;AAExD,EAAA,MAAM,EAAE,KAAO,EAAA,OAAA,EAAS,KAAM,EAAA,GAAI,cAAc,YAAY;AAC1D,IAAM,MAAA,SAAA,GAAY,MAAM,kBAAA,CAAmB,YAAa,EAAA,CAAA;AACxD,IAAI,IAAA,CAAC,WAAkB,OAAA,KAAA,CAAA,CAAA;AACvB,IAAO,OAAA,mBAAA,CAAoB,WAAW,SAAS,CAAA,CAAA;AAAA,GACjD,EAAG,EAAE,CAAA,CAAA;AAEL,EAAM,MAAA,mBAAA,GAAsB,YAAY,MAAM;AAC5C,IAAA,mBAAA,CAAoB,wBACjB,CAAA,IAAA,CAAK,mBAAmB,YAAY,CAAA,CACpC,KAAK,KAAK,CAAA,CAAA;AAAA,GACf,EAAG,CAAC,KAAK,CAAC,CAAA,CAAA;AAEV,EAAM,MAAA,oBAAA,GAAuB,YAAY,MAAM;AAC7C,IAAA,kBAAA,CAAmB,YAAa,CAAA,KAAA,CAAS,CAAE,CAAA,IAAA,CAAK,KAAK,CAAA,CAAA;AAAA,GACvD,EAAG,CAAC,KAAK,CAAC,CAAA,CAAA;AAEV,EACE,uBAAA,KAAA,CAAA,aAAA,CAAC,IAAK,EAAA,EAAA,OAAA,EAAQ,MACZ,EAAA,kBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,MAAA;AAAA,IAAA;AAAA,MACC,KAAA,EAAO,EAAE,0BAA0B,CAAA;AAAA,MACnC,QAAA,EAAU,EAAE,6BAA6B,CAAA;AAAA,KAAA;AAAA,GAC3C,sCACC,OAAQ,EAAA,EAAA,SAAA,EAAW,QAAQ,OACzB,EAAA,EAAA,OAAA,mBACE,KAAA,CAAA,aAAA,CAAA,QAAA,EAAA,IAAS,CAEV,mBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,cAAA;AAAA,IAAA;AAAA,MACC,SAAW,EAAA,KAAA;AAAA,MACX,SAAS,KAAM,CAAA,OAAA;AAAA,MACf,WAAW,KAAM,CAAA,SAAA;AAAA,MACjB,iBAAiB,KAAM,CAAA,eAAA;AAAA,MACvB,OAAS,EAAA,oBAAA;AAAA,MACT,MAAQ,EAAA,mBAAA;AAAA,KAAA;AAAA,GAGd,CACF,CAAA,CAAA;AAEJ;;;;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RegisterExistingButton.esm.js","sources":["../../../../src/alpha/components/TemplateListPage/RegisterExistingButton.tsx"],"sourcesContent":["/*\n * Copyright 2021 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 */\n\nimport Button from '@material-ui/core/Button';\nimport IconButton from '@material-ui/core/IconButton';\nimport useMediaQuery from '@material-ui/core/useMediaQuery';\nimport React from 'react';\nimport { Link as RouterLink, LinkProps } from 'react-router-dom';\nimport AddCircleOutline from '@material-ui/icons/AddCircleOutline';\nimport { catalogEntityCreatePermission } from '@backstage/plugin-catalog-common/alpha';\nimport { usePermission } from '@backstage/plugin-permission-react';\nimport { Theme } from '@material-ui/core/styles';\n\n/**\n * Properties for {@link RegisterExistingButton}\n *\n * @alpha\n */\nexport type RegisterExistingButtonProps = {\n title: string;\n} & Partial<Pick<LinkProps, 'to'>>;\n\n/**\n * A button that helps users to register an existing component.\n * @alpha\n */\nexport const RegisterExistingButton = (props: RegisterExistingButtonProps) => {\n const { title, to } = props;\n const { allowed } = usePermission({\n permission: catalogEntityCreatePermission,\n });\n const isXSScreen = useMediaQuery<Theme>(theme =>\n theme.breakpoints.down('xs'),\n );\n\n if (!to || !allowed) {\n return null;\n }\n\n return isXSScreen ? (\n <IconButton\n component={RouterLink}\n color=\"primary\"\n title={title}\n size=\"small\"\n to={to}\n >\n <AddCircleOutline />\n </IconButton>\n ) : (\n <Button component={RouterLink} variant=\"contained\" color=\"primary\" to={to}>\n {title}\n </Button>\n );\n};\n"],"names":["RouterLink","AddCircleOutline"],"mappings":";;;;;;;;;AAuCa,MAAA,sBAAA,GAAyB,CAAC,KAAuC,KAAA;AAC5E,EAAM,MAAA,EAAE,KAAO,EAAA,EAAA,EAAO,GAAA,KAAA,CAAA;AACtB,EAAM,MAAA,EAAE,OAAQ,EAAA,GAAI,aAAc,CAAA;AAAA,IAChC,UAAY,EAAA,6BAAA;AAAA,GACb,CAAA,CAAA;AACD,EAAA,MAAM,UAAa,GAAA,aAAA;AAAA,IAAqB,CACtC,KAAA,KAAA,KAAA,CAAM,WAAY,CAAA,IAAA,CAAK,IAAI,CAAA;AAAA,GAC7B,CAAA;AAEA,EAAI,IAAA,CAAC,EAAM,IAAA,CAAC,OAAS,EAAA;AACnB,IAAO,OAAA,IAAA,CAAA;AAAA,GACT;AAEA,EAAA,OAAO,UACL,mBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,UAAA;AAAA,IAAA;AAAA,MACC,SAAW,EAAAA,IAAA;AAAA,MACX,KAAM,EAAA,SAAA;AAAA,MACN,KAAA;AAAA,MACA,IAAK,EAAA,OAAA;AAAA,MACL,EAAA;AAAA,KAAA;AAAA,wCAECC,mBAAiB,EAAA,IAAA,CAAA;AAAA,GACpB,mBAEC,KAAA,CAAA,aAAA,CAAA,MAAA,EAAA,EAAO,SAAW,EAAAD,IAAA,EAAY,SAAQ,WAAY,EAAA,KAAA,EAAM,SAAU,EAAA,EAAA,EAAA,EAChE,KACH,CAAA,CAAA;AAEJ;;;;"}
|
|
@@ -5,10 +5,10 @@ import { DocsIcon, Page, Header, Content, ContentHeader, SupportButton } from '@
|
|
|
5
5
|
import { EntityListProvider, CatalogFilterLayout, EntitySearchBar, EntityKindPicker, UserListPicker, EntityTagPicker, EntityOwnerPicker } from '@backstage/plugin-catalog-react';
|
|
6
6
|
import { ScaffolderPageContextMenu, TemplateCategoryPicker, TemplateGroups } from '@backstage/plugin-scaffolder-react/alpha';
|
|
7
7
|
import { RegisterExistingButton } from './RegisterExistingButton.esm.js';
|
|
8
|
-
import { registerComponentRouteRef, editRouteRef, actionsRouteRef, scaffolderListTaskRouteRef, viewTechDocRouteRef, selectedTemplateRouteRef } from '
|
|
8
|
+
import { registerComponentRouteRef, editRouteRef, actionsRouteRef, scaffolderListTaskRouteRef, viewTechDocRouteRef, selectedTemplateRouteRef } from '../../../routes.esm.js';
|
|
9
9
|
import { parseEntityRef, stringifyEntityRef } from '@backstage/catalog-model';
|
|
10
10
|
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
|
|
11
|
-
import { scaffolderTranslationRef } from '
|
|
11
|
+
import { scaffolderTranslationRef } from '../../../translation.esm.js';
|
|
12
12
|
|
|
13
13
|
const createGroupsWithOther = (groups, t) => [
|
|
14
14
|
...groups,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TemplateListPage.esm.js","sources":["../../../../src/alpha/components/TemplateListPage/TemplateListPage.tsx"],"sourcesContent":["/*\n * Copyright 2022 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 */\n\nimport React, { useCallback } from 'react';\nimport { useNavigate } from 'react-router-dom';\nimport { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common';\nimport { useApp, useRouteRef } from '@backstage/core-plugin-api';\n\nimport {\n Content,\n ContentHeader,\n DocsIcon,\n Header,\n Page,\n SupportButton,\n} from '@backstage/core-components';\nimport {\n EntityKindPicker,\n EntityListProvider,\n EntitySearchBar,\n EntityTagPicker,\n CatalogFilterLayout,\n UserListPicker,\n EntityOwnerPicker,\n} from '@backstage/plugin-catalog-react';\nimport {\n ScaffolderPageContextMenu,\n TemplateCategoryPicker,\n TemplateGroups,\n} from '@backstage/plugin-scaffolder-react/alpha';\n\nimport { RegisterExistingButton } from './RegisterExistingButton';\nimport {\n actionsRouteRef,\n editRouteRef,\n registerComponentRouteRef,\n scaffolderListTaskRouteRef,\n selectedTemplateRouteRef,\n viewTechDocRouteRef,\n} from '../../../routes';\nimport { parseEntityRef, stringifyEntityRef } from '@backstage/catalog-model';\nimport { TemplateGroupFilter } from '@backstage/plugin-scaffolder-react';\nimport {\n TranslationFunction,\n useTranslationRef,\n} from '@backstage/core-plugin-api/alpha';\nimport { scaffolderTranslationRef } from '../../../translation';\n\n/**\n * @alpha\n */\nexport type TemplateListPageProps = {\n TemplateCardComponent?: React.ComponentType<{\n template: TemplateEntityV1beta3;\n }>;\n groups?: TemplateGroupFilter[];\n templateFilter?: (entity: TemplateEntityV1beta3) => boolean;\n contextMenu?: {\n editor?: boolean;\n actions?: boolean;\n tasks?: boolean;\n };\n headerOptions?: {\n pageTitleOverride?: string;\n title?: string;\n subtitle?: string;\n };\n};\n\nconst createGroupsWithOther = (\n groups: TemplateGroupFilter[],\n t: TranslationFunction<typeof scaffolderTranslationRef.T>,\n): TemplateGroupFilter[] => [\n ...groups,\n {\n title: t('templateListPage.templateGroups.otherTitle'),\n filter: e => ![...groups].some(({ filter }) => filter(e)),\n },\n];\n\n/**\n * @alpha\n */\nexport const TemplateListPage = (props: TemplateListPageProps) => {\n const registerComponentLink = useRouteRef(registerComponentRouteRef);\n const {\n TemplateCardComponent,\n groups: givenGroups = [],\n templateFilter,\n headerOptions,\n } = props;\n const navigate = useNavigate();\n const editorLink = useRouteRef(editRouteRef);\n const actionsLink = useRouteRef(actionsRouteRef);\n const tasksLink = useRouteRef(scaffolderListTaskRouteRef);\n const viewTechDocsLink = useRouteRef(viewTechDocRouteRef);\n const templateRoute = useRouteRef(selectedTemplateRouteRef);\n const app = useApp();\n const { t } = useTranslationRef(scaffolderTranslationRef);\n\n const groups = givenGroups.length\n ? createGroupsWithOther(givenGroups, t)\n : [\n {\n title: t('templateListPage.templateGroups.defaultTitle'),\n filter: () => true,\n },\n ];\n\n const scaffolderPageContextMenuProps = {\n onEditorClicked:\n props?.contextMenu?.editor !== false\n ? () => navigate(editorLink())\n : undefined,\n onActionsClicked:\n props?.contextMenu?.actions !== false\n ? () => navigate(actionsLink())\n : undefined,\n onTasksClicked:\n props?.contextMenu?.tasks !== false\n ? () => navigate(tasksLink())\n : undefined,\n };\n\n const additionalLinksForEntity = useCallback(\n (template: TemplateEntityV1beta3) => {\n const { kind, namespace, name } = parseEntityRef(\n stringifyEntityRef(template),\n );\n return template.metadata.annotations?.['backstage.io/techdocs-ref'] &&\n viewTechDocsLink\n ? [\n {\n icon: app.getSystemIcon('docs') ?? DocsIcon,\n text: t(\n 'templateListPage.additionalLinksForEntity.viewTechDocsTitle',\n ),\n url: viewTechDocsLink({ kind, namespace, name }),\n },\n ]\n : [];\n },\n [app, viewTechDocsLink, t],\n );\n\n const onTemplateSelected = useCallback(\n (template: TemplateEntityV1beta3) => {\n const { namespace, name } = parseEntityRef(stringifyEntityRef(template));\n\n navigate(templateRoute({ namespace, templateName: name }));\n },\n [navigate, templateRoute],\n );\n\n return (\n <EntityListProvider>\n <Page themeId=\"home\">\n <Header\n pageTitleOverride={t('templateListPage.pageTitle')}\n title={t('templateListPage.title')}\n subtitle={t('templateListPage.subtitle')}\n {...headerOptions}\n >\n <ScaffolderPageContextMenu {...scaffolderPageContextMenuProps} />\n </Header>\n <Content>\n <ContentHeader>\n <RegisterExistingButton\n title={t(\n 'templateListPage.contentHeader.registerExistingButtonTitle',\n )}\n to={registerComponentLink && registerComponentLink()}\n />\n <SupportButton>\n {t('templateListPage.contentHeader.supportButtonTitle')}\n </SupportButton>\n </ContentHeader>\n\n <CatalogFilterLayout>\n <CatalogFilterLayout.Filters>\n <EntitySearchBar />\n <EntityKindPicker initialFilter=\"template\" hidden />\n <UserListPicker\n initialFilter=\"all\"\n availableFilters={['all', 'starred']}\n />\n <TemplateCategoryPicker />\n <EntityTagPicker />\n <EntityOwnerPicker />\n </CatalogFilterLayout.Filters>\n <CatalogFilterLayout.Content>\n <TemplateGroups\n groups={groups}\n templateFilter={templateFilter}\n TemplateCardComponent={TemplateCardComponent}\n onTemplateSelected={onTemplateSelected}\n additionalLinksForEntity={additionalLinksForEntity}\n />\n </CatalogFilterLayout.Content>\n </CatalogFilterLayout>\n </Content>\n </Page>\n </EntityListProvider>\n );\n};\n"],"names":[],"mappings":"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"}
|