@backstage/plugin-scaffolder 1.19.3 → 1.19.4-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.
Files changed (152) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/alpha/package.json +1 -1
  3. package/dist/alpha.esm.js +3 -8
  4. package/dist/alpha.esm.js.map +1 -1
  5. package/dist/{esm/routes-BvToNy4N.esm.js → api.esm.js} +2 -46
  6. package/dist/api.esm.js.map +1 -0
  7. package/dist/components/ActionsPage/ActionsPage.esm.js +186 -0
  8. package/dist/components/ActionsPage/ActionsPage.esm.js.map +1 -0
  9. package/dist/components/FileBrowser/FileBrowser.esm.js +90 -0
  10. package/dist/components/FileBrowser/FileBrowser.esm.js.map +1 -0
  11. package/dist/components/ListTasksPage/ListTasksPage.esm.js +120 -0
  12. package/dist/components/ListTasksPage/ListTasksPage.esm.js.map +1 -0
  13. package/dist/components/ListTasksPage/OwnerListPicker.esm.js +88 -0
  14. package/dist/components/ListTasksPage/OwnerListPicker.esm.js.map +1 -0
  15. package/dist/components/ListTasksPage/columns/CreatedAtColumn.esm.js +13 -0
  16. package/dist/components/ListTasksPage/columns/CreatedAtColumn.esm.js.map +1 -0
  17. package/dist/components/ListTasksPage/columns/OwnerEntityColumn.esm.js +31 -0
  18. package/dist/components/ListTasksPage/columns/OwnerEntityColumn.esm.js.map +1 -0
  19. package/dist/components/ListTasksPage/columns/TaskStatusColumn.esm.js +17 -0
  20. package/dist/components/ListTasksPage/columns/TaskStatusColumn.esm.js.map +1 -0
  21. package/dist/components/ListTasksPage/columns/TemplateTitleColumn.esm.js +21 -0
  22. package/dist/components/ListTasksPage/columns/TemplateTitleColumn.esm.js.map +1 -0
  23. package/dist/components/OngoingTask/ContextMenu.esm.js +86 -0
  24. package/dist/components/OngoingTask/ContextMenu.esm.js.map +1 -0
  25. package/dist/components/OngoingTask/OngoingTask.esm.js +173 -0
  26. package/dist/components/OngoingTask/OngoingTask.esm.js.map +1 -0
  27. package/dist/components/Router/Router.esm.js +105 -0
  28. package/dist/components/Router/Router.esm.js.map +1 -0
  29. package/dist/components/Router/index.esm.js +2 -0
  30. package/dist/components/Router/index.esm.js.map +1 -0
  31. package/dist/components/TemplateTypePicker/TemplateTypePicker.esm.js +70 -0
  32. package/dist/components/TemplateTypePicker/TemplateTypePicker.esm.js.map +1 -0
  33. package/dist/components/fields/EntityNamePicker/EntityNamePicker.esm.js +34 -0
  34. package/dist/components/fields/EntityNamePicker/EntityNamePicker.esm.js.map +1 -0
  35. package/dist/components/fields/EntityNamePicker/schema.esm.js +8 -0
  36. package/dist/components/fields/EntityNamePicker/schema.esm.js.map +1 -0
  37. package/dist/components/fields/EntityNamePicker/validation.esm.js +12 -0
  38. package/dist/components/fields/EntityNamePicker/validation.esm.js.map +1 -0
  39. package/dist/components/fields/EntityPicker/EntityPicker.esm.js +151 -0
  40. package/dist/components/fields/EntityPicker/EntityPicker.esm.js.map +1 -0
  41. package/dist/components/fields/EntityPicker/schema.esm.js +29 -0
  42. package/dist/components/fields/EntityPicker/schema.esm.js.map +1 -0
  43. package/dist/components/fields/EntityTagsPicker/EntityTagsPicker.esm.js +84 -0
  44. package/dist/components/fields/EntityTagsPicker/EntityTagsPicker.esm.js.map +1 -0
  45. package/dist/components/fields/EntityTagsPicker/schema.esm.js +15 -0
  46. package/dist/components/fields/EntityTagsPicker/schema.esm.js.map +1 -0
  47. package/dist/components/fields/MultiEntityPicker/MultiEntityPicker.esm.js +168 -0
  48. package/dist/components/fields/MultiEntityPicker/MultiEntityPicker.esm.js.map +1 -0
  49. package/dist/components/fields/MultiEntityPicker/schema.esm.js +23 -0
  50. package/dist/components/fields/MultiEntityPicker/schema.esm.js.map +1 -0
  51. package/dist/components/fields/MyGroupsPicker/MyGroupsPicker.esm.js +83 -0
  52. package/dist/components/fields/MyGroupsPicker/MyGroupsPicker.esm.js.map +1 -0
  53. package/dist/components/fields/MyGroupsPicker/schema.esm.js +14 -0
  54. package/dist/components/fields/MyGroupsPicker/schema.esm.js.map +1 -0
  55. package/dist/components/fields/OwnedEntityPicker/OwnedEntityPicker.esm.js +68 -0
  56. package/dist/components/fields/OwnedEntityPicker/OwnedEntityPicker.esm.js.map +1 -0
  57. package/dist/components/fields/OwnedEntityPicker/schema.esm.js +24 -0
  58. package/dist/components/fields/OwnedEntityPicker/schema.esm.js.map +1 -0
  59. package/dist/components/fields/OwnerPicker/OwnerPicker.esm.js +37 -0
  60. package/dist/components/fields/OwnerPicker/OwnerPicker.esm.js.map +1 -0
  61. package/dist/components/fields/OwnerPicker/schema.esm.js +24 -0
  62. package/dist/components/fields/OwnerPicker/schema.esm.js.map +1 -0
  63. package/dist/components/fields/RepoUrlPicker/AzureRepoPicker.esm.js +75 -0
  64. package/dist/components/fields/RepoUrlPicker/AzureRepoPicker.esm.js.map +1 -0
  65. package/dist/components/fields/RepoUrlPicker/BitbucketRepoPicker.esm.js +80 -0
  66. package/dist/components/fields/RepoUrlPicker/BitbucketRepoPicker.esm.js.map +1 -0
  67. package/dist/components/fields/RepoUrlPicker/GerritRepoPicker.esm.js +38 -0
  68. package/dist/components/fields/RepoUrlPicker/GerritRepoPicker.esm.js.map +1 -0
  69. package/dist/components/fields/RepoUrlPicker/GiteaRepoPicker.esm.js +44 -0
  70. package/dist/components/fields/RepoUrlPicker/GiteaRepoPicker.esm.js.map +1 -0
  71. package/dist/components/fields/RepoUrlPicker/GithubRepoPicker.esm.js +42 -0
  72. package/dist/components/fields/RepoUrlPicker/GithubRepoPicker.esm.js.map +1 -0
  73. package/dist/components/fields/RepoUrlPicker/GitlabRepoPicker.esm.js +44 -0
  74. package/dist/components/fields/RepoUrlPicker/GitlabRepoPicker.esm.js.map +1 -0
  75. package/dist/components/fields/RepoUrlPicker/RepoUrlPicker.esm.js +200 -0
  76. package/dist/components/fields/RepoUrlPicker/RepoUrlPicker.esm.js.map +1 -0
  77. package/dist/components/fields/RepoUrlPicker/RepoUrlPickerHost.esm.js +56 -0
  78. package/dist/components/fields/RepoUrlPicker/RepoUrlPickerHost.esm.js.map +1 -0
  79. package/dist/components/fields/RepoUrlPicker/RepoUrlPickerRepoName.esm.js +48 -0
  80. package/dist/components/fields/RepoUrlPicker/RepoUrlPickerRepoName.esm.js.map +1 -0
  81. package/dist/components/fields/RepoUrlPicker/schema.esm.js +32 -0
  82. package/dist/components/fields/RepoUrlPicker/schema.esm.js.map +1 -0
  83. package/dist/components/fields/RepoUrlPicker/utils.esm.js +46 -0
  84. package/dist/components/fields/RepoUrlPicker/utils.esm.js.map +1 -0
  85. package/dist/components/fields/RepoUrlPicker/validation.esm.js +43 -0
  86. package/dist/components/fields/RepoUrlPicker/validation.esm.js.map +1 -0
  87. package/dist/components/fields/SecretInput/SecretInput.esm.js +48 -0
  88. package/dist/components/fields/SecretInput/SecretInput.esm.js.map +1 -0
  89. package/dist/components/fields/utils.esm.js +15 -0
  90. package/dist/components/fields/utils.esm.js.map +1 -0
  91. package/dist/deprecated.esm.js +13 -0
  92. package/dist/deprecated.esm.js.map +1 -0
  93. package/dist/extensions/default.esm.js +72 -0
  94. package/dist/extensions/default.esm.js.map +1 -0
  95. package/dist/index.esm.js +13 -214
  96. package/dist/index.esm.js.map +1 -1
  97. package/dist/lib/download/helpers.esm.js +11 -0
  98. package/dist/lib/download/helpers.esm.js.map +1 -0
  99. package/dist/lib/filesystem/WebFileSystemAccess.esm.js +56 -0
  100. package/dist/lib/filesystem/WebFileSystemAccess.esm.js.map +1 -0
  101. package/dist/next/TemplateEditorPage/CustomFieldExplorer.esm.js +151 -0
  102. package/dist/next/TemplateEditorPage/CustomFieldExplorer.esm.js.map +1 -0
  103. package/dist/next/TemplateEditorPage/DirectoryEditorContext.esm.js +186 -0
  104. package/dist/next/TemplateEditorPage/DirectoryEditorContext.esm.js.map +1 -0
  105. package/dist/next/TemplateEditorPage/DryRunContext.esm.js +110 -0
  106. package/dist/next/TemplateEditorPage/DryRunContext.esm.js.map +1 -0
  107. package/dist/next/TemplateEditorPage/DryRunResults/DryRunResults.esm.js +70 -0
  108. package/dist/next/TemplateEditorPage/DryRunResults/DryRunResults.esm.js.map +1 -0
  109. package/dist/next/TemplateEditorPage/DryRunResults/DryRunResultsList.esm.js +98 -0
  110. package/dist/next/TemplateEditorPage/DryRunResults/DryRunResultsList.esm.js.map +1 -0
  111. package/dist/next/TemplateEditorPage/DryRunResults/DryRunResultsSplitView.esm.js +31 -0
  112. package/dist/next/TemplateEditorPage/DryRunResults/DryRunResultsSplitView.esm.js.map +1 -0
  113. package/dist/next/TemplateEditorPage/DryRunResults/DryRunResultsView.esm.js +145 -0
  114. package/dist/next/TemplateEditorPage/DryRunResults/DryRunResultsView.esm.js.map +1 -0
  115. package/dist/next/TemplateEditorPage/DryRunResults/IconLink.esm.js +25 -0
  116. package/dist/next/TemplateEditorPage/DryRunResults/IconLink.esm.js.map +1 -0
  117. package/dist/next/TemplateEditorPage/DryRunResults/TaskPageLinks.esm.js +40 -0
  118. package/dist/next/TemplateEditorPage/DryRunResults/TaskPageLinks.esm.js.map +1 -0
  119. package/dist/next/TemplateEditorPage/DryRunResults/TaskStatusStepper.esm.js +135 -0
  120. package/dist/next/TemplateEditorPage/DryRunResults/TaskStatusStepper.esm.js.map +1 -0
  121. package/dist/next/TemplateEditorPage/TemplateEditor.esm.js +52 -0
  122. package/dist/next/TemplateEditorPage/TemplateEditor.esm.js.map +1 -0
  123. package/dist/next/TemplateEditorPage/TemplateEditorBrowser.esm.js +74 -0
  124. package/dist/next/TemplateEditorPage/TemplateEditorBrowser.esm.js.map +1 -0
  125. package/dist/next/TemplateEditorPage/TemplateEditorForm.esm.js +174 -0
  126. package/dist/next/TemplateEditorPage/TemplateEditorForm.esm.js.map +1 -0
  127. package/dist/next/TemplateEditorPage/TemplateEditorIntro.esm.js +93 -0
  128. package/dist/next/TemplateEditorPage/TemplateEditorIntro.esm.js.map +1 -0
  129. package/dist/next/TemplateEditorPage/TemplateEditorPage.esm.js +82 -0
  130. package/dist/next/TemplateEditorPage/TemplateEditorPage.esm.js.map +1 -0
  131. package/dist/next/TemplateEditorPage/TemplateEditorTextArea.esm.js +120 -0
  132. package/dist/next/TemplateEditorPage/TemplateEditorTextArea.esm.js.map +1 -0
  133. package/dist/next/TemplateEditorPage/TemplateFormPreviewer.esm.js +160 -0
  134. package/dist/next/TemplateEditorPage/TemplateFormPreviewer.esm.js.map +1 -0
  135. package/dist/next/TemplateListPage/RegisterExistingButton.esm.js +35 -0
  136. package/dist/next/TemplateListPage/RegisterExistingButton.esm.js.map +1 -0
  137. package/dist/next/TemplateListPage/TemplateListPage.esm.js +101 -0
  138. package/dist/next/TemplateListPage/TemplateListPage.esm.js.map +1 -0
  139. package/dist/next/TemplateWizardPage/TemplateWizardPage.esm.js +67 -0
  140. package/dist/next/TemplateWizardPage/TemplateWizardPage.esm.js.map +1 -0
  141. package/dist/next/TemplateWizardPage/TemplateWizardPageContextMenu.esm.js +60 -0
  142. package/dist/next/TemplateWizardPage/TemplateWizardPageContextMenu.esm.js.map +1 -0
  143. package/dist/plugin.esm.js +125 -0
  144. package/dist/plugin.esm.js.map +1 -0
  145. package/dist/routes.esm.js +47 -0
  146. package/dist/routes.esm.js.map +1 -0
  147. package/package.json +18 -18
  148. package/dist/esm/OngoingTask-ClfJCJcE.esm.js +0 -1575
  149. package/dist/esm/OngoingTask-ClfJCJcE.esm.js.map +0 -1
  150. package/dist/esm/index-UcPid-q1.esm.js +0 -2553
  151. package/dist/esm/index-UcPid-q1.esm.js.map +0 -1
  152. package/dist/esm/routes-BvToNy4N.esm.js.map +0 -1
@@ -0,0 +1,174 @@
1
+ import { useApiHolder } from '@backstage/core-plugin-api';
2
+ import { makeStyles } from '@material-ui/core/styles';
3
+ import React, { useState, useMemo, Component } from 'react';
4
+ import useDebounce from 'react-use/esm/useDebounce';
5
+ import yaml from 'yaml';
6
+ import { createAsyncValidators, Stepper } from '@backstage/plugin-scaffolder-react/alpha';
7
+ import { useDryRun } from './DryRunContext.esm.js';
8
+ import { useDirectoryEditor } from './DirectoryEditorContext.esm.js';
9
+
10
+ var __defProp = Object.defineProperty;
11
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
12
+ var __publicField = (obj, key, value) => {
13
+ __defNormalProp(obj, key + "" , value);
14
+ return value;
15
+ };
16
+ const useStyles = makeStyles({
17
+ containerWrapper: {
18
+ position: "relative",
19
+ width: "100%",
20
+ height: "100%"
21
+ },
22
+ container: {
23
+ position: "absolute",
24
+ top: 0,
25
+ bottom: 0,
26
+ left: 0,
27
+ right: 0,
28
+ overflow: "auto"
29
+ }
30
+ });
31
+ class ErrorBoundary extends Component {
32
+ constructor() {
33
+ super(...arguments);
34
+ __publicField(this, "state", {
35
+ shouldRender: true
36
+ });
37
+ }
38
+ componentDidUpdate(prevProps) {
39
+ if (prevProps.invalidator !== this.props.invalidator) {
40
+ this.setState({ shouldRender: true });
41
+ }
42
+ }
43
+ componentDidCatch(error) {
44
+ this.props.setErrorText(error.message);
45
+ this.setState({ shouldRender: false });
46
+ }
47
+ render() {
48
+ return this.state.shouldRender ? this.props.children : null;
49
+ }
50
+ }
51
+ function isJsonObject(value) {
52
+ return typeof value === "object" && value !== null && !Array.isArray(value);
53
+ }
54
+ function TemplateEditorForm(props) {
55
+ const {
56
+ content,
57
+ contentIsSpec,
58
+ onDryRun,
59
+ setErrorText,
60
+ fieldExtensions = [],
61
+ layouts = []
62
+ } = props;
63
+ const classes = useStyles();
64
+ const apiHolder = useApiHolder();
65
+ const [steps, setSteps] = useState();
66
+ const fields = useMemo(() => {
67
+ return Object.fromEntries(
68
+ fieldExtensions.map(({ name, component }) => [name, component])
69
+ );
70
+ }, [fieldExtensions]);
71
+ useDebounce(
72
+ () => {
73
+ try {
74
+ if (!content) {
75
+ setSteps(void 0);
76
+ return;
77
+ }
78
+ const parsed = yaml.parseAllDocuments(content).filter((c) => c).map((c) => c.toJSON())[0];
79
+ if (!isJsonObject(parsed)) {
80
+ setSteps(void 0);
81
+ return;
82
+ }
83
+ let rootObj = parsed;
84
+ if (!contentIsSpec) {
85
+ const isTemplate = String(parsed.kind).toLocaleLowerCase("en-US") === "template";
86
+ if (!isTemplate) {
87
+ setSteps(void 0);
88
+ return;
89
+ }
90
+ rootObj = isJsonObject(parsed.spec) ? parsed.spec : {};
91
+ }
92
+ const { parameters } = rootObj;
93
+ if (!Array.isArray(parameters)) {
94
+ setErrorText("Template parameters must be an array");
95
+ setSteps(void 0);
96
+ return;
97
+ }
98
+ const fieldValidators = Object.fromEntries(
99
+ fieldExtensions.map(({ name, validation }) => [name, validation])
100
+ );
101
+ setErrorText();
102
+ setSteps(
103
+ parameters.flatMap(
104
+ (param) => isJsonObject(param) ? [
105
+ {
106
+ title: String(param.title),
107
+ schema: param,
108
+ validate: createAsyncValidators(param, fieldValidators, {
109
+ apiHolder
110
+ })
111
+ }
112
+ ] : []
113
+ )
114
+ );
115
+ } catch (e) {
116
+ setErrorText(e.message);
117
+ }
118
+ },
119
+ 250,
120
+ [contentIsSpec, content, apiHolder]
121
+ );
122
+ if (!steps) {
123
+ return null;
124
+ }
125
+ return /* @__PURE__ */ React.createElement("div", { className: classes.containerWrapper }, /* @__PURE__ */ React.createElement("div", { className: classes.container }, /* @__PURE__ */ React.createElement(ErrorBoundary, { invalidator: steps, setErrorText }, /* @__PURE__ */ React.createElement(
126
+ Stepper,
127
+ {
128
+ manifest: { steps, title: "Template Editor" },
129
+ extensions: fieldExtensions,
130
+ components: fields,
131
+ onCreate: async (options) => {
132
+ await (onDryRun == null ? void 0 : onDryRun(options));
133
+ },
134
+ layouts
135
+ }
136
+ ))));
137
+ }
138
+ function TemplateEditorFormDirectoryEditorDryRun(props) {
139
+ const { setErrorText, fieldExtensions = [], layouts } = props;
140
+ const dryRun = useDryRun();
141
+ const directoryEditor = useDirectoryEditor();
142
+ const { selectedFile } = directoryEditor;
143
+ const handleDryRun = async (data) => {
144
+ if (!selectedFile) {
145
+ return;
146
+ }
147
+ try {
148
+ await dryRun.execute({
149
+ templateContent: selectedFile.content,
150
+ values: data,
151
+ files: directoryEditor.files
152
+ });
153
+ setErrorText();
154
+ } catch (e) {
155
+ setErrorText(String(e.cause || e));
156
+ throw e;
157
+ }
158
+ };
159
+ const content = selectedFile && selectedFile.path.match(/\.ya?ml$/) ? selectedFile.content : void 0;
160
+ return /* @__PURE__ */ React.createElement(
161
+ TemplateEditorForm,
162
+ {
163
+ onDryRun: handleDryRun,
164
+ fieldExtensions,
165
+ setErrorText,
166
+ content,
167
+ layouts
168
+ }
169
+ );
170
+ }
171
+ TemplateEditorForm.DirectoryEditorDryRun = TemplateEditorFormDirectoryEditorDryRun;
172
+
173
+ export { TemplateEditorForm, TemplateEditorFormDirectoryEditorDryRun };
174
+ //# sourceMappingURL=TemplateEditorForm.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TemplateEditorForm.esm.js","sources":["../../../src/next/TemplateEditorPage/TemplateEditorForm.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 { useApiHolder } from '@backstage/core-plugin-api';\nimport { JsonObject, JsonValue } from '@backstage/types';\nimport { makeStyles } from '@material-ui/core/styles';\nimport React, { Component, ReactNode, useMemo, useState } from 'react';\nimport useDebounce from 'react-use/esm/useDebounce';\nimport yaml from 'yaml';\nimport {\n LayoutOptions,\n TemplateParameterSchema,\n FieldExtensionOptions,\n} from '@backstage/plugin-scaffolder-react';\nimport {\n Stepper,\n createAsyncValidators,\n} from '@backstage/plugin-scaffolder-react/alpha';\nimport { useDryRun } from './DryRunContext';\nimport { useDirectoryEditor } from './DirectoryEditorContext';\n\nconst useStyles = makeStyles({\n containerWrapper: {\n position: 'relative',\n width: '100%',\n height: '100%',\n },\n container: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n left: 0,\n right: 0,\n overflow: 'auto',\n },\n});\n\ninterface ErrorBoundaryProps {\n invalidator: unknown;\n setErrorText(errorText: string | undefined): void;\n children: ReactNode;\n}\n\ninterface ErrorBoundaryState {\n shouldRender: boolean;\n}\n\nclass ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {\n state = {\n shouldRender: true,\n };\n\n componentDidUpdate(prevProps: { invalidator: unknown }) {\n if (prevProps.invalidator !== this.props.invalidator) {\n this.setState({ shouldRender: true });\n }\n }\n\n componentDidCatch(error: Error) {\n this.props.setErrorText(error.message);\n this.setState({ shouldRender: false });\n }\n\n render() {\n return this.state.shouldRender ? this.props.children : null;\n }\n}\n\ninterface TemplateEditorFormProps {\n content?: string;\n /** Setting this to true will cause the content to be parsed as if it is the template entity spec */\n contentIsSpec?: boolean;\n setErrorText: (errorText?: string) => void;\n\n onDryRun?: (data: JsonObject) => Promise<void>;\n fieldExtensions?: FieldExtensionOptions<any, any>[];\n layouts?: LayoutOptions[];\n}\n\nfunction isJsonObject(value: JsonValue | undefined): value is JsonObject {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\n/** Shows the a template form that is parsed from the provided content */\nexport function TemplateEditorForm(props: TemplateEditorFormProps) {\n const {\n content,\n contentIsSpec,\n onDryRun,\n setErrorText,\n fieldExtensions = [],\n layouts = [],\n } = props;\n const classes = useStyles();\n const apiHolder = useApiHolder();\n\n const [steps, setSteps] = useState<TemplateParameterSchema['steps']>();\n\n const fields = useMemo(() => {\n return Object.fromEntries(\n fieldExtensions.map(({ name, component }) => [name, component]),\n );\n }, [fieldExtensions]);\n\n useDebounce(\n () => {\n try {\n if (!content) {\n setSteps(undefined);\n return;\n }\n const parsed: JsonValue = yaml\n .parseAllDocuments(content)\n .filter(c => c)\n .map(c => c.toJSON())[0];\n\n if (!isJsonObject(parsed)) {\n setSteps(undefined);\n return;\n }\n\n let rootObj = parsed;\n if (!contentIsSpec) {\n const isTemplate =\n String(parsed.kind).toLocaleLowerCase('en-US') === 'template';\n if (!isTemplate) {\n setSteps(undefined);\n return;\n }\n\n rootObj = isJsonObject(parsed.spec) ? parsed.spec : {};\n }\n\n const { parameters } = rootObj;\n\n if (!Array.isArray(parameters)) {\n setErrorText('Template parameters must be an array');\n setSteps(undefined);\n return;\n }\n\n const fieldValidators = Object.fromEntries(\n fieldExtensions.map(({ name, validation }) => [name, validation]),\n );\n\n setErrorText();\n setSteps(\n parameters.flatMap(param =>\n isJsonObject(param)\n ? [\n {\n title: String(param.title),\n schema: param,\n validate: createAsyncValidators(param, fieldValidators, {\n apiHolder,\n }),\n },\n ]\n : [],\n ),\n );\n } catch (e) {\n setErrorText(e.message);\n }\n },\n 250,\n [contentIsSpec, content, apiHolder],\n );\n\n if (!steps) {\n return null;\n }\n\n return (\n <div className={classes.containerWrapper}>\n <div className={classes.container}>\n <ErrorBoundary invalidator={steps} setErrorText={setErrorText}>\n <Stepper\n manifest={{ steps, title: 'Template Editor' }}\n extensions={fieldExtensions}\n components={fields}\n onCreate={async options => {\n await onDryRun?.(options);\n }}\n layouts={layouts}\n />\n </ErrorBoundary>\n </div>\n </div>\n );\n}\n\n/** A version of the TemplateEditorForm that is connected to the DirectoryEditor and DryRun contexts */\nexport function TemplateEditorFormDirectoryEditorDryRun(\n props: Pick<\n TemplateEditorFormProps,\n 'setErrorText' | 'fieldExtensions' | 'layouts'\n >,\n) {\n const { setErrorText, fieldExtensions = [], layouts } = props;\n const dryRun = useDryRun();\n\n const directoryEditor = useDirectoryEditor();\n const { selectedFile } = directoryEditor;\n\n const handleDryRun = async (data: JsonObject) => {\n if (!selectedFile) {\n return;\n }\n\n try {\n await dryRun.execute({\n templateContent: selectedFile.content,\n values: data,\n files: directoryEditor.files,\n });\n setErrorText();\n } catch (e) {\n setErrorText(String(e.cause || e));\n throw e;\n }\n };\n\n const content =\n selectedFile && selectedFile.path.match(/\\.ya?ml$/)\n ? selectedFile.content\n : undefined;\n\n return (\n <TemplateEditorForm\n onDryRun={handleDryRun}\n fieldExtensions={fieldExtensions}\n setErrorText={setErrorText}\n content={content}\n layouts={layouts}\n />\n );\n}\n\nTemplateEditorForm.DirectoryEditorDryRun =\n TemplateEditorFormDirectoryEditorDryRun;\n"],"names":[],"mappings":";;;;;;;;;;;;;;;AAiCA,MAAM,YAAY,UAAW,CAAA;AAAA,EAC3B,gBAAkB,EAAA;AAAA,IAChB,QAAU,EAAA,UAAA;AAAA,IACV,KAAO,EAAA,MAAA;AAAA,IACP,MAAQ,EAAA,MAAA;AAAA,GACV;AAAA,EACA,SAAW,EAAA;AAAA,IACT,QAAU,EAAA,UAAA;AAAA,IACV,GAAK,EAAA,CAAA;AAAA,IACL,MAAQ,EAAA,CAAA;AAAA,IACR,IAAM,EAAA,CAAA;AAAA,IACN,KAAO,EAAA,CAAA;AAAA,IACP,QAAU,EAAA,MAAA;AAAA,GACZ;AACF,CAAC,CAAA,CAAA;AAYD,MAAM,sBAAsB,SAAkD,CAAA;AAAA,EAA9E,WAAA,GAAA;AAAA,IAAA,KAAA,CAAA,GAAA,SAAA,CAAA,CAAA;AACE,IAAQ,aAAA,CAAA,IAAA,EAAA,OAAA,EAAA;AAAA,MACN,YAAc,EAAA,IAAA;AAAA,KAChB,CAAA,CAAA;AAAA,GAAA;AAAA,EAEA,mBAAmB,SAAqC,EAAA;AACtD,IAAA,IAAI,SAAU,CAAA,WAAA,KAAgB,IAAK,CAAA,KAAA,CAAM,WAAa,EAAA;AACpD,MAAA,IAAA,CAAK,QAAS,CAAA,EAAE,YAAc,EAAA,IAAA,EAAM,CAAA,CAAA;AAAA,KACtC;AAAA,GACF;AAAA,EAEA,kBAAkB,KAAc,EAAA;AAC9B,IAAK,IAAA,CAAA,KAAA,CAAM,YAAa,CAAA,KAAA,CAAM,OAAO,CAAA,CAAA;AACrC,IAAA,IAAA,CAAK,QAAS,CAAA,EAAE,YAAc,EAAA,KAAA,EAAO,CAAA,CAAA;AAAA,GACvC;AAAA,EAEA,MAAS,GAAA;AACP,IAAA,OAAO,IAAK,CAAA,KAAA,CAAM,YAAe,GAAA,IAAA,CAAK,MAAM,QAAW,GAAA,IAAA,CAAA;AAAA,GACzD;AACF,CAAA;AAaA,SAAS,aAAa,KAAmD,EAAA;AACvE,EAAO,OAAA,OAAO,UAAU,QAAY,IAAA,KAAA,KAAU,QAAQ,CAAC,KAAA,CAAM,QAAQ,KAAK,CAAA,CAAA;AAC5E,CAAA;AAGO,SAAS,mBAAmB,KAAgC,EAAA;AACjE,EAAM,MAAA;AAAA,IACJ,OAAA;AAAA,IACA,aAAA;AAAA,IACA,QAAA;AAAA,IACA,YAAA;AAAA,IACA,kBAAkB,EAAC;AAAA,IACnB,UAAU,EAAC;AAAA,GACT,GAAA,KAAA,CAAA;AACJ,EAAA,MAAM,UAAU,SAAU,EAAA,CAAA;AAC1B,EAAA,MAAM,YAAY,YAAa,EAAA,CAAA;AAE/B,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAI,QAA2C,EAAA,CAAA;AAErE,EAAM,MAAA,MAAA,GAAS,QAAQ,MAAM;AAC3B,IAAA,OAAO,MAAO,CAAA,WAAA;AAAA,MACZ,eAAA,CAAgB,GAAI,CAAA,CAAC,EAAE,IAAA,EAAM,WAAgB,KAAA,CAAC,IAAM,EAAA,SAAS,CAAC,CAAA;AAAA,KAChE,CAAA;AAAA,GACF,EAAG,CAAC,eAAe,CAAC,CAAA,CAAA;AAEpB,EAAA,WAAA;AAAA,IACE,MAAM;AACJ,MAAI,IAAA;AACF,QAAA,IAAI,CAAC,OAAS,EAAA;AACZ,UAAA,QAAA,CAAS,KAAS,CAAA,CAAA,CAAA;AAClB,UAAA,OAAA;AAAA,SACF;AACA,QAAA,MAAM,MAAoB,GAAA,IAAA,CACvB,iBAAkB,CAAA,OAAO,EACzB,MAAO,CAAA,CAAA,CAAA,KAAK,CAAC,CAAA,CACb,IAAI,CAAK,CAAA,KAAA,CAAA,CAAE,MAAO,EAAC,EAAE,CAAC,CAAA,CAAA;AAEzB,QAAI,IAAA,CAAC,YAAa,CAAA,MAAM,CAAG,EAAA;AACzB,UAAA,QAAA,CAAS,KAAS,CAAA,CAAA,CAAA;AAClB,UAAA,OAAA;AAAA,SACF;AAEA,QAAA,IAAI,OAAU,GAAA,MAAA,CAAA;AACd,QAAA,IAAI,CAAC,aAAe,EAAA;AAClB,UAAA,MAAM,aACJ,MAAO,CAAA,MAAA,CAAO,IAAI,CAAE,CAAA,iBAAA,CAAkB,OAAO,CAAM,KAAA,UAAA,CAAA;AACrD,UAAA,IAAI,CAAC,UAAY,EAAA;AACf,YAAA,QAAA,CAAS,KAAS,CAAA,CAAA,CAAA;AAClB,YAAA,OAAA;AAAA,WACF;AAEA,UAAA,OAAA,GAAU,aAAa,MAAO,CAAA,IAAI,CAAI,GAAA,MAAA,CAAO,OAAO,EAAC,CAAA;AAAA,SACvD;AAEA,QAAM,MAAA,EAAE,YAAe,GAAA,OAAA,CAAA;AAEvB,QAAA,IAAI,CAAC,KAAA,CAAM,OAAQ,CAAA,UAAU,CAAG,EAAA;AAC9B,UAAA,YAAA,CAAa,sCAAsC,CAAA,CAAA;AACnD,UAAA,QAAA,CAAS,KAAS,CAAA,CAAA,CAAA;AAClB,UAAA,OAAA;AAAA,SACF;AAEA,QAAA,MAAM,kBAAkB,MAAO,CAAA,WAAA;AAAA,UAC7B,eAAA,CAAgB,GAAI,CAAA,CAAC,EAAE,IAAA,EAAM,YAAiB,KAAA,CAAC,IAAM,EAAA,UAAU,CAAC,CAAA;AAAA,SAClE,CAAA;AAEA,QAAa,YAAA,EAAA,CAAA;AACb,QAAA,QAAA;AAAA,UACE,UAAW,CAAA,OAAA;AAAA,YAAQ,CAAA,KAAA,KACjB,YAAa,CAAA,KAAK,CACd,GAAA;AAAA,cACE;AAAA,gBACE,KAAA,EAAO,MAAO,CAAA,KAAA,CAAM,KAAK,CAAA;AAAA,gBACzB,MAAQ,EAAA,KAAA;AAAA,gBACR,QAAA,EAAU,qBAAsB,CAAA,KAAA,EAAO,eAAiB,EAAA;AAAA,kBACtD,SAAA;AAAA,iBACD,CAAA;AAAA,eACH;AAAA,gBAEF,EAAC;AAAA,WACP;AAAA,SACF,CAAA;AAAA,eACO,CAAG,EAAA;AACV,QAAA,YAAA,CAAa,EAAE,OAAO,CAAA,CAAA;AAAA,OACxB;AAAA,KACF;AAAA,IACA,GAAA;AAAA,IACA,CAAC,aAAe,EAAA,OAAA,EAAS,SAAS,CAAA;AAAA,GACpC,CAAA;AAEA,EAAA,IAAI,CAAC,KAAO,EAAA;AACV,IAAO,OAAA,IAAA,CAAA;AAAA,GACT;AAEA,EAAA,uBACG,KAAA,CAAA,aAAA,CAAA,KAAA,EAAA,EAAI,SAAW,EAAA,OAAA,CAAQ,oCACrB,KAAA,CAAA,aAAA,CAAA,KAAA,EAAA,EAAI,SAAW,EAAA,OAAA,CAAQ,SACtB,EAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,aAAc,EAAA,EAAA,WAAA,EAAa,OAAO,YACjC,EAAA,kBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,OAAA;AAAA,IAAA;AAAA,MACC,QAAU,EAAA,EAAE,KAAO,EAAA,KAAA,EAAO,iBAAkB,EAAA;AAAA,MAC5C,UAAY,EAAA,eAAA;AAAA,MACZ,UAAY,EAAA,MAAA;AAAA,MACZ,QAAA,EAAU,OAAM,OAAW,KAAA;AACzB,QAAA,OAAM,QAAW,IAAA,IAAA,GAAA,KAAA,CAAA,GAAA,QAAA,CAAA,OAAA,CAAA,CAAA,CAAA;AAAA,OACnB;AAAA,MACA,OAAA;AAAA,KAAA;AAAA,GAEJ,CACF,CACF,CAAA,CAAA;AAEJ,CAAA;AAGO,SAAS,wCACd,KAIA,EAAA;AACA,EAAA,MAAM,EAAE,YAAc,EAAA,eAAA,GAAkB,EAAC,EAAG,SAAY,GAAA,KAAA,CAAA;AACxD,EAAA,MAAM,SAAS,SAAU,EAAA,CAAA;AAEzB,EAAA,MAAM,kBAAkB,kBAAmB,EAAA,CAAA;AAC3C,EAAM,MAAA,EAAE,cAAiB,GAAA,eAAA,CAAA;AAEzB,EAAM,MAAA,YAAA,GAAe,OAAO,IAAqB,KAAA;AAC/C,IAAA,IAAI,CAAC,YAAc,EAAA;AACjB,MAAA,OAAA;AAAA,KACF;AAEA,IAAI,IAAA;AACF,MAAA,MAAM,OAAO,OAAQ,CAAA;AAAA,QACnB,iBAAiB,YAAa,CAAA,OAAA;AAAA,QAC9B,MAAQ,EAAA,IAAA;AAAA,QACR,OAAO,eAAgB,CAAA,KAAA;AAAA,OACxB,CAAA,CAAA;AACD,MAAa,YAAA,EAAA,CAAA;AAAA,aACN,CAAG,EAAA;AACV,MAAA,YAAA,CAAa,MAAO,CAAA,CAAA,CAAE,KAAS,IAAA,CAAC,CAAC,CAAA,CAAA;AACjC,MAAM,MAAA,CAAA,CAAA;AAAA,KACR;AAAA,GACF,CAAA;AAEA,EAAM,MAAA,OAAA,GACJ,gBAAgB,YAAa,CAAA,IAAA,CAAK,MAAM,UAAU,CAAA,GAC9C,aAAa,OACb,GAAA,KAAA,CAAA,CAAA;AAEN,EACE,uBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,kBAAA;AAAA,IAAA;AAAA,MACC,QAAU,EAAA,YAAA;AAAA,MACV,eAAA;AAAA,MACA,YAAA;AAAA,MACA,OAAA;AAAA,MACA,OAAA;AAAA,KAAA;AAAA,GACF,CAAA;AAEJ,CAAA;AAEA,kBAAA,CAAmB,qBACjB,GAAA,uCAAA;;;;"}
@@ -0,0 +1,93 @@
1
+ import React from 'react';
2
+ import Card from '@material-ui/core/Card';
3
+ import CardActionArea from '@material-ui/core/CardActionArea';
4
+ import CardContent from '@material-ui/core/CardContent';
5
+ import Tooltip from '@material-ui/core/Tooltip';
6
+ import Typography from '@material-ui/core/Typography';
7
+ import InfoOutlinedIcon from '@material-ui/icons/InfoOutlined';
8
+ import { makeStyles } from '@material-ui/core/styles';
9
+ import { WebFileSystemAccess } from '../../lib/filesystem/WebFileSystemAccess.esm.js';
10
+
11
+ const useStyles = makeStyles((theme) => ({
12
+ introText: {
13
+ textAlign: "center",
14
+ marginTop: theme.spacing(2)
15
+ },
16
+ card: {
17
+ position: "relative",
18
+ maxWidth: 340,
19
+ marginTop: theme.spacing(4),
20
+ margin: theme.spacing(0, 2)
21
+ },
22
+ infoIcon: {
23
+ position: "absolute",
24
+ top: theme.spacing(1),
25
+ right: theme.spacing(1)
26
+ }
27
+ }));
28
+ function TemplateEditorIntro(props) {
29
+ const classes = useStyles();
30
+ const supportsLoad = WebFileSystemAccess.isSupported();
31
+ const cardLoadLocal = /* @__PURE__ */ React.createElement(Card, { className: classes.card, elevation: 4 }, /* @__PURE__ */ React.createElement(
32
+ CardActionArea,
33
+ {
34
+ disabled: !supportsLoad,
35
+ onClick: () => {
36
+ var _a;
37
+ return (_a = props.onSelect) == null ? void 0 : _a.call(props, "local");
38
+ }
39
+ },
40
+ /* @__PURE__ */ React.createElement(CardContent, null, /* @__PURE__ */ React.createElement(
41
+ Typography,
42
+ {
43
+ variant: "h4",
44
+ component: "h3",
45
+ gutterBottom: true,
46
+ color: supportsLoad ? void 0 : "textSecondary",
47
+ style: { display: "flex", flexFlow: "row nowrap" }
48
+ },
49
+ "Load Template Directory"
50
+ ), /* @__PURE__ */ React.createElement(
51
+ Typography,
52
+ {
53
+ variant: "body1",
54
+ color: supportsLoad ? void 0 : "textSecondary"
55
+ },
56
+ "Load a local template directory, allowing you to both edit and try executing your own template."
57
+ ))
58
+ ), !supportsLoad && /* @__PURE__ */ React.createElement("div", { className: classes.infoIcon }, /* @__PURE__ */ React.createElement(
59
+ Tooltip,
60
+ {
61
+ placement: "top",
62
+ title: "Only supported in some Chromium-based browsers"
63
+ },
64
+ /* @__PURE__ */ React.createElement(InfoOutlinedIcon, null)
65
+ )));
66
+ const cardFormEditor = /* @__PURE__ */ React.createElement(Card, { className: classes.card, elevation: 4 }, /* @__PURE__ */ React.createElement(CardActionArea, { onClick: () => {
67
+ var _a;
68
+ return (_a = props.onSelect) == null ? void 0 : _a.call(props, "form");
69
+ } }, /* @__PURE__ */ React.createElement(CardContent, null, /* @__PURE__ */ React.createElement(Typography, { variant: "h4", component: "h3", gutterBottom: true }, "Edit Template Form"), /* @__PURE__ */ React.createElement(Typography, { variant: "body1" }, "Preview and edit a template form, either using a sample template or by loading a template from the catalog."))));
70
+ const cardFieldExplorer = /* @__PURE__ */ React.createElement(Card, { className: classes.card, elevation: 4 }, /* @__PURE__ */ React.createElement(CardActionArea, { onClick: () => {
71
+ var _a;
72
+ return (_a = props.onSelect) == null ? void 0 : _a.call(props, "field-explorer");
73
+ } }, /* @__PURE__ */ React.createElement(CardContent, null, /* @__PURE__ */ React.createElement(Typography, { variant: "h4", component: "h3", gutterBottom: true }, "Custom Field Explorer"), /* @__PURE__ */ React.createElement(Typography, { variant: "body1" }, "View and play around with available installed custom field extensions."))));
74
+ return /* @__PURE__ */ React.createElement("div", { style: props.style }, /* @__PURE__ */ React.createElement(Typography, { variant: "h4", component: "h2", className: classes.introText }, "Get started by choosing one of the options below"), /* @__PURE__ */ React.createElement(
75
+ "div",
76
+ {
77
+ style: {
78
+ display: "flex",
79
+ flexFlow: "row wrap",
80
+ alignItems: "flex-start",
81
+ justifyContent: "center",
82
+ alignContent: "flex-start"
83
+ }
84
+ },
85
+ supportsLoad && cardLoadLocal,
86
+ cardFormEditor,
87
+ !supportsLoad && cardLoadLocal,
88
+ cardFieldExplorer
89
+ ));
90
+ }
91
+
92
+ export { TemplateEditorIntro };
93
+ //# sourceMappingURL=TemplateEditorIntro.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TemplateEditorIntro.esm.js","sources":["../../../src/next/TemplateEditorPage/TemplateEditorIntro.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 from 'react';\nimport Card from '@material-ui/core/Card';\nimport CardActionArea from '@material-ui/core/CardActionArea';\nimport CardContent from '@material-ui/core/CardContent';\nimport Tooltip from '@material-ui/core/Tooltip';\nimport Typography from '@material-ui/core/Typography';\nimport InfoOutlinedIcon from '@material-ui/icons/InfoOutlined';\nimport { makeStyles } from '@material-ui/core/styles';\nimport { WebFileSystemAccess } from '../../lib/filesystem';\n\nconst useStyles = makeStyles(theme => ({\n introText: {\n textAlign: 'center',\n marginTop: theme.spacing(2),\n },\n card: {\n position: 'relative',\n maxWidth: 340,\n marginTop: theme.spacing(4),\n margin: theme.spacing(0, 2),\n },\n infoIcon: {\n position: 'absolute',\n top: theme.spacing(1),\n right: theme.spacing(1),\n },\n}));\n\ninterface EditorIntroProps {\n style?: JSX.IntrinsicElements['div']['style'];\n onSelect?: (option: 'local' | 'form' | 'field-explorer') => void;\n}\n\nexport function TemplateEditorIntro(props: EditorIntroProps) {\n const classes = useStyles();\n const supportsLoad = WebFileSystemAccess.isSupported();\n\n const cardLoadLocal = (\n <Card className={classes.card} elevation={4}>\n <CardActionArea\n disabled={!supportsLoad}\n onClick={() => props.onSelect?.('local')}\n >\n <CardContent>\n <Typography\n variant=\"h4\"\n component=\"h3\"\n gutterBottom\n color={supportsLoad ? undefined : 'textSecondary'}\n style={{ display: 'flex', flexFlow: 'row nowrap' }}\n >\n Load Template Directory\n </Typography>\n <Typography\n variant=\"body1\"\n color={supportsLoad ? undefined : 'textSecondary'}\n >\n Load a local template directory, allowing you to both edit and try\n executing your own template.\n </Typography>\n </CardContent>\n </CardActionArea>\n {!supportsLoad && (\n <div className={classes.infoIcon}>\n <Tooltip\n placement=\"top\"\n title=\"Only supported in some Chromium-based browsers\"\n >\n <InfoOutlinedIcon />\n </Tooltip>\n </div>\n )}\n </Card>\n );\n\n const cardFormEditor = (\n <Card className={classes.card} elevation={4}>\n <CardActionArea onClick={() => props.onSelect?.('form')}>\n <CardContent>\n <Typography variant=\"h4\" component=\"h3\" gutterBottom>\n Edit Template Form\n </Typography>\n <Typography variant=\"body1\">\n Preview and edit a template form, either using a sample template or\n by loading a template from the catalog.\n </Typography>\n </CardContent>\n </CardActionArea>\n </Card>\n );\n\n const cardFieldExplorer = (\n <Card className={classes.card} elevation={4}>\n <CardActionArea onClick={() => props.onSelect?.('field-explorer')}>\n <CardContent>\n <Typography variant=\"h4\" component=\"h3\" gutterBottom>\n Custom Field Explorer\n </Typography>\n <Typography variant=\"body1\">\n View and play around with available installed custom field\n extensions.\n </Typography>\n </CardContent>\n </CardActionArea>\n </Card>\n );\n\n return (\n <div style={props.style}>\n <Typography variant=\"h4\" component=\"h2\" className={classes.introText}>\n Get started by choosing one of the options below\n </Typography>\n <div\n style={{\n display: 'flex',\n flexFlow: 'row wrap',\n alignItems: 'flex-start',\n justifyContent: 'center',\n alignContent: 'flex-start',\n }}\n >\n {supportsLoad && cardLoadLocal}\n {cardFormEditor}\n {!supportsLoad && cardLoadLocal}\n {cardFieldExplorer}\n </div>\n </div>\n );\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,82 @@
1
+ import React, { useState } from 'react';
2
+ import { Page, Header, Content } from '@backstage/core-components';
3
+ import { WebFileSystemAccess } from '../../lib/filesystem/WebFileSystemAccess.esm.js';
4
+ import { CustomFieldExplorer } from './CustomFieldExplorer.esm.js';
5
+ import { TemplateEditor } from './TemplateEditor.esm.js';
6
+ import { TemplateFormPreviewer } from './TemplateFormPreviewer.esm.js';
7
+ import { TemplateEditorIntro } from './TemplateEditorIntro.esm.js';
8
+ import { ScaffolderPageContextMenu } from '@backstage/plugin-scaffolder-react/alpha';
9
+ import { useNavigate } from 'react-router-dom';
10
+ import { useRouteRef } from '@backstage/core-plugin-api';
11
+ import { actionsRouteRef, scaffolderListTaskRouteRef, rootRouteRef } from '../../routes.esm.js';
12
+
13
+ function TemplateEditorPage(props) {
14
+ const [selection, setSelection] = useState();
15
+ const navigate = useNavigate();
16
+ const actionsLink = useRouteRef(actionsRouteRef);
17
+ const tasksLink = useRouteRef(scaffolderListTaskRouteRef);
18
+ const createLink = useRouteRef(rootRouteRef);
19
+ const scaffolderPageContextMenuProps = {
20
+ onEditorClicked: void 0,
21
+ onActionsClicked: () => navigate(actionsLink()),
22
+ onTasksClicked: () => navigate(tasksLink()),
23
+ onCreateClicked: () => navigate(createLink())
24
+ };
25
+ let content = null;
26
+ if ((selection == null ? void 0 : selection.type) === "local") {
27
+ content = /* @__PURE__ */ React.createElement(
28
+ TemplateEditor,
29
+ {
30
+ directory: selection.directory,
31
+ fieldExtensions: props.customFieldExtensions,
32
+ onClose: () => setSelection(void 0),
33
+ layouts: props.layouts
34
+ }
35
+ );
36
+ } else if ((selection == null ? void 0 : selection.type) === "form") {
37
+ content = /* @__PURE__ */ React.createElement(
38
+ TemplateFormPreviewer,
39
+ {
40
+ defaultPreviewTemplate: props.defaultPreviewTemplate,
41
+ customFieldExtensions: props.customFieldExtensions,
42
+ onClose: () => setSelection(void 0),
43
+ layouts: props.layouts
44
+ }
45
+ );
46
+ } else if ((selection == null ? void 0 : selection.type) === "field-explorer") {
47
+ content = /* @__PURE__ */ React.createElement(
48
+ CustomFieldExplorer,
49
+ {
50
+ customFieldExtensions: props.customFieldExtensions,
51
+ onClose: () => setSelection(void 0)
52
+ }
53
+ );
54
+ } else {
55
+ content = /* @__PURE__ */ React.createElement(Content, null, /* @__PURE__ */ React.createElement(
56
+ TemplateEditorIntro,
57
+ {
58
+ onSelect: (option) => {
59
+ if (option === "local") {
60
+ WebFileSystemAccess.requestDirectoryAccess().then((directory) => setSelection({ type: "local", directory })).catch(() => {
61
+ });
62
+ } else if (option === "form") {
63
+ setSelection({ type: "form" });
64
+ } else if (option === "field-explorer") {
65
+ setSelection({ type: "field-explorer" });
66
+ }
67
+ }
68
+ }
69
+ ));
70
+ }
71
+ return /* @__PURE__ */ React.createElement(Page, { themeId: "home" }, /* @__PURE__ */ React.createElement(
72
+ Header,
73
+ {
74
+ title: "Template Editor",
75
+ subtitle: "Edit, preview, and try out templates and template forms"
76
+ },
77
+ /* @__PURE__ */ React.createElement(ScaffolderPageContextMenu, { ...scaffolderPageContextMenuProps })
78
+ ), content);
79
+ }
80
+
81
+ export { TemplateEditorPage };
82
+ //# sourceMappingURL=TemplateEditorPage.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TemplateEditorPage.esm.js","sources":["../../../src/next/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, { useState } from 'react';\nimport { Content, Header, Page } from '@backstage/core-components';\nimport {\n TemplateDirectoryAccess,\n WebFileSystemAccess,\n} from '../../lib/filesystem';\nimport { CustomFieldExplorer } from './CustomFieldExplorer';\nimport { TemplateEditor } from './TemplateEditor';\nimport { TemplateFormPreviewer } from './TemplateFormPreviewer';\nimport {\n FieldExtensionOptions,\n type LayoutOptions,\n} from '@backstage/plugin-scaffolder-react';\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 rootRouteRef,\n scaffolderListTaskRouteRef,\n} from '../../routes';\n\ntype Selection =\n | {\n type: 'local';\n directory: TemplateDirectoryAccess;\n }\n | {\n type: 'form';\n }\n | {\n type: 'field-explorer';\n };\n\ninterface TemplateEditorPageProps {\n defaultPreviewTemplate?: string;\n customFieldExtensions?: FieldExtensionOptions<any, any>[];\n layouts?: LayoutOptions[];\n}\n\nexport function TemplateEditorPage(props: TemplateEditorPageProps) {\n const [selection, setSelection] = useState<Selection>();\n const navigate = useNavigate();\n const actionsLink = useRouteRef(actionsRouteRef);\n const tasksLink = useRouteRef(scaffolderListTaskRouteRef);\n const createLink = useRouteRef(rootRouteRef);\n\n const scaffolderPageContextMenuProps = {\n onEditorClicked: undefined,\n onActionsClicked: () => navigate(actionsLink()),\n onTasksClicked: () => navigate(tasksLink()),\n onCreateClicked: () => navigate(createLink()),\n };\n\n let content: JSX.Element | null = null;\n if (selection?.type === 'local') {\n content = (\n <TemplateEditor\n directory={selection.directory}\n fieldExtensions={props.customFieldExtensions}\n onClose={() => setSelection(undefined)}\n layouts={props.layouts}\n />\n );\n } else if (selection?.type === 'form') {\n content = (\n <TemplateFormPreviewer\n defaultPreviewTemplate={props.defaultPreviewTemplate}\n customFieldExtensions={props.customFieldExtensions}\n onClose={() => setSelection(undefined)}\n layouts={props.layouts}\n />\n );\n } else if (selection?.type === 'field-explorer') {\n content = (\n <CustomFieldExplorer\n customFieldExtensions={props.customFieldExtensions}\n onClose={() => setSelection(undefined)}\n />\n );\n } else {\n content = (\n <Content>\n <TemplateEditorIntro\n onSelect={option => {\n if (option === 'local') {\n WebFileSystemAccess.requestDirectoryAccess()\n .then(directory => setSelection({ type: 'local', directory }))\n .catch(() => {});\n } else if (option === 'form') {\n setSelection({ type: 'form' });\n } else if (option === 'field-explorer') {\n setSelection({ type: 'field-explorer' });\n }\n }}\n />\n </Content>\n );\n }\n\n return (\n <Page themeId=\"home\">\n <Header\n title=\"Template Editor\"\n subtitle=\"Edit, preview, and try out templates and template forms\"\n >\n <ScaffolderPageContextMenu {...scaffolderPageContextMenuProps} />\n </Header>\n {content}\n </Page>\n );\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,120 @@
1
+ import { StreamLanguage } from '@codemirror/language';
2
+ import { yaml } from '@codemirror/legacy-modes/mode/yaml';
3
+ import { showPanel } from '@codemirror/view';
4
+ import IconButton from '@material-ui/core/IconButton';
5
+ import Paper from '@material-ui/core/Paper';
6
+ import Tooltip from '@material-ui/core/Tooltip';
7
+ import { makeStyles } from '@material-ui/core/styles';
8
+ import RefreshIcon from '@material-ui/icons/Refresh';
9
+ import SaveIcon from '@material-ui/icons/Save';
10
+ import { useKeyboardEvent } from '@react-hookz/web';
11
+ import CodeMirror from '@uiw/react-codemirror';
12
+ import React, { useMemo } from 'react';
13
+ import { useDirectoryEditor } from './DirectoryEditorContext.esm.js';
14
+
15
+ const useStyles = makeStyles((theme) => ({
16
+ container: {
17
+ position: "relative",
18
+ width: "100%",
19
+ height: "100%"
20
+ },
21
+ codeMirror: {
22
+ position: "absolute",
23
+ top: 0,
24
+ bottom: 0,
25
+ left: 0,
26
+ right: 0
27
+ },
28
+ errorPanel: {
29
+ color: theme.palette.error.main,
30
+ lineHeight: 2,
31
+ margin: theme.spacing(0, 1)
32
+ },
33
+ floatingButtons: {
34
+ position: "absolute",
35
+ top: theme.spacing(1),
36
+ right: theme.spacing(3)
37
+ },
38
+ floatingButton: {
39
+ padding: theme.spacing(1)
40
+ }
41
+ }));
42
+ function TemplateEditorTextArea(props) {
43
+ const { errorText } = props;
44
+ const classes = useStyles();
45
+ const panelExtension = useMemo(() => {
46
+ if (!errorText) {
47
+ return showPanel.of(null);
48
+ }
49
+ const dom = document.createElement("div");
50
+ dom.classList.add(classes.errorPanel);
51
+ dom.textContent = errorText;
52
+ return showPanel.of(() => ({ dom, bottom: true }));
53
+ }, [classes, errorText]);
54
+ useKeyboardEvent(
55
+ (e) => e.key === "s" && (e.ctrlKey || e.metaKey),
56
+ (e) => {
57
+ e.preventDefault();
58
+ if (props.onSave) {
59
+ props.onSave();
60
+ }
61
+ }
62
+ );
63
+ return /* @__PURE__ */ React.createElement("div", { className: classes.container }, /* @__PURE__ */ React.createElement(
64
+ CodeMirror,
65
+ {
66
+ className: classes.codeMirror,
67
+ theme: "dark",
68
+ height: "100%",
69
+ extensions: [StreamLanguage.define(yaml), panelExtension],
70
+ value: props.content,
71
+ onChange: props.onUpdate
72
+ }
73
+ ), (props.onSave || props.onReload) && /* @__PURE__ */ React.createElement("div", { className: classes.floatingButtons }, /* @__PURE__ */ React.createElement(Paper, null, props.onSave && /* @__PURE__ */ React.createElement(Tooltip, { title: "Save file" }, /* @__PURE__ */ React.createElement(
74
+ IconButton,
75
+ {
76
+ className: classes.floatingButton,
77
+ onClick: () => {
78
+ var _a;
79
+ return (_a = props.onSave) == null ? void 0 : _a.call(props);
80
+ }
81
+ },
82
+ /* @__PURE__ */ React.createElement(SaveIcon, null)
83
+ )), props.onReload && /* @__PURE__ */ React.createElement(Tooltip, { title: "Reload file" }, /* @__PURE__ */ React.createElement(
84
+ IconButton,
85
+ {
86
+ className: classes.floatingButton,
87
+ onClick: () => {
88
+ var _a;
89
+ return (_a = props.onReload) == null ? void 0 : _a.call(props);
90
+ }
91
+ },
92
+ /* @__PURE__ */ React.createElement(RefreshIcon, null)
93
+ )))));
94
+ }
95
+ function TemplateEditorDirectoryEditorTextArea(props) {
96
+ var _a, _b;
97
+ const directoryEditor = useDirectoryEditor();
98
+ const actions = ((_a = directoryEditor.selectedFile) == null ? void 0 : _a.dirty) ? {
99
+ onSave: () => directoryEditor.save(),
100
+ onReload: () => directoryEditor.reload()
101
+ } : {
102
+ onReload: () => directoryEditor.reload()
103
+ };
104
+ return /* @__PURE__ */ React.createElement(
105
+ TemplateEditorTextArea,
106
+ {
107
+ errorText: props.errorText,
108
+ content: (_b = directoryEditor.selectedFile) == null ? void 0 : _b.content,
109
+ onUpdate: (content) => {
110
+ var _a2;
111
+ return (_a2 = directoryEditor.selectedFile) == null ? void 0 : _a2.updateContent(content);
112
+ },
113
+ ...actions
114
+ }
115
+ );
116
+ }
117
+ TemplateEditorTextArea.DirectoryEditor = TemplateEditorDirectoryEditorTextArea;
118
+
119
+ export { TemplateEditorDirectoryEditorTextArea, TemplateEditorTextArea };
120
+ //# sourceMappingURL=TemplateEditorTextArea.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TemplateEditorTextArea.esm.js","sources":["../../../src/next/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 { 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';\n\nconst useStyles = makeStyles(theme => ({\n container: {\n position: 'relative',\n width: '100%',\n height: '100%',\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\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 title=\"Save file\">\n <IconButton\n className={classes.floatingButton}\n onClick={() => props.onSave?.()}\n >\n <SaveIcon />\n </IconButton>\n </Tooltip>\n )}\n {props.onReload && (\n <Tooltip title=\"Reload file\">\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}) {\n const directoryEditor = useDirectoryEditor();\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 => directoryEditor.selectedFile?.updateContent(content)}\n {...actions}\n />\n );\n}\n\nTemplateEditorTextArea.DirectoryEditor = TemplateEditorDirectoryEditorTextArea;\n"],"names":["yamlSupport","_a"],"mappings":"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"}