@backstage/plugin-scaffolder 1.25.1 → 1.26.0-next.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (136) hide show
  1. package/CHANGELOG.md +59 -5
  2. package/alpha/package.json +1 -1
  3. package/dist/alpha/api/FormFieldsApi.esm.js +40 -0
  4. package/dist/alpha/api/FormFieldsApi.esm.js.map +1 -0
  5. package/dist/alpha/api/ref.esm.js +8 -0
  6. package/dist/alpha/api/ref.esm.js.map +1 -0
  7. package/dist/alpha/api.esm.js +27 -0
  8. package/dist/alpha/api.esm.js.map +1 -0
  9. package/dist/{next → alpha/components}/TemplateEditorPage/CustomFieldExplorer.esm.js +1 -1
  10. package/dist/alpha/components/TemplateEditorPage/CustomFieldExplorer.esm.js.map +1 -0
  11. package/dist/alpha/components/TemplateEditorPage/CustomFieldPlaygroud.esm.js +167 -0
  12. package/dist/alpha/components/TemplateEditorPage/CustomFieldPlaygroud.esm.js.map +1 -0
  13. package/dist/alpha/components/TemplateEditorPage/CustomFieldsPage.esm.js +33 -0
  14. package/dist/alpha/components/TemplateEditorPage/CustomFieldsPage.esm.js.map +1 -0
  15. package/dist/{next → alpha/components}/TemplateEditorPage/DirectoryEditorContext.esm.js +4 -7
  16. package/dist/alpha/components/TemplateEditorPage/DirectoryEditorContext.esm.js.map +1 -0
  17. package/dist/alpha/components/TemplateEditorPage/DryRunContext.esm.js.map +1 -0
  18. package/dist/{next → alpha/components}/TemplateEditorPage/DryRunResults/DryRunResults.esm.js +1 -1
  19. package/dist/alpha/components/TemplateEditorPage/DryRunResults/DryRunResults.esm.js.map +1 -0
  20. package/dist/{next → alpha/components}/TemplateEditorPage/DryRunResults/DryRunResultsList.esm.js +2 -2
  21. package/dist/alpha/components/TemplateEditorPage/DryRunResults/DryRunResultsList.esm.js.map +1 -0
  22. package/dist/alpha/components/TemplateEditorPage/DryRunResults/DryRunResultsSplitView.esm.js.map +1 -0
  23. package/dist/{next → alpha/components}/TemplateEditorPage/DryRunResults/DryRunResultsView.esm.js +2 -2
  24. package/dist/alpha/components/TemplateEditorPage/DryRunResults/DryRunResultsView.esm.js.map +1 -0
  25. package/dist/alpha/components/TemplateEditorPage/DryRunResults/IconLink.esm.js.map +1 -0
  26. package/dist/alpha/components/TemplateEditorPage/DryRunResults/TaskPageLinks.esm.js.map +1 -0
  27. package/dist/{next → alpha/components}/TemplateEditorPage/DryRunResults/TaskStatusStepper.esm.js +1 -1
  28. package/dist/alpha/components/TemplateEditorPage/DryRunResults/TaskStatusStepper.esm.js.map +1 -0
  29. package/dist/alpha/components/TemplateEditorPage/TemplateEditor.esm.js +94 -0
  30. package/dist/alpha/components/TemplateEditorPage/TemplateEditor.esm.js.map +1 -0
  31. package/dist/{next → alpha/components}/TemplateEditorPage/TemplateEditorBrowser.esm.js +36 -38
  32. package/dist/alpha/components/TemplateEditorPage/TemplateEditorBrowser.esm.js.map +1 -0
  33. package/dist/{next → alpha/components}/TemplateEditorPage/TemplateEditorForm.esm.js +12 -20
  34. package/dist/alpha/components/TemplateEditorPage/TemplateEditorForm.esm.js.map +1 -0
  35. package/dist/alpha/components/TemplateEditorPage/TemplateEditorIntro.esm.js +146 -0
  36. package/dist/alpha/components/TemplateEditorPage/TemplateEditorIntro.esm.js.map +1 -0
  37. package/dist/alpha/components/TemplateEditorPage/TemplateEditorPage.esm.js +53 -0
  38. package/dist/alpha/components/TemplateEditorPage/TemplateEditorPage.esm.js.map +1 -0
  39. package/dist/{next → alpha/components}/TemplateEditorPage/TemplateEditorTextArea.esm.js +36 -3
  40. package/dist/alpha/components/TemplateEditorPage/TemplateEditorTextArea.esm.js.map +1 -0
  41. package/dist/alpha/components/TemplateEditorPage/TemplateEditorToolbar.esm.js +98 -0
  42. package/dist/alpha/components/TemplateEditorPage/TemplateEditorToolbar.esm.js.map +1 -0
  43. package/dist/alpha/components/TemplateEditorPage/TemplateFormPage.esm.js +43 -0
  44. package/dist/alpha/components/TemplateEditorPage/TemplateFormPage.esm.js.map +1 -0
  45. package/dist/{next → alpha/components}/TemplateEditorPage/TemplateFormPreviewer.esm.js +77 -39
  46. package/dist/alpha/components/TemplateEditorPage/TemplateFormPreviewer.esm.js.map +1 -0
  47. package/dist/alpha/components/TemplateEditorPage/TemplatePage.esm.js +52 -0
  48. package/dist/alpha/components/TemplateEditorPage/TemplatePage.esm.js.map +1 -0
  49. package/dist/{next → alpha/components}/TemplateListPage/RegisterExistingButton.esm.js +1 -1
  50. package/dist/alpha/components/TemplateListPage/RegisterExistingButton.esm.js.map +1 -0
  51. package/dist/{next → alpha/components}/TemplateListPage/TemplateListPage.esm.js +2 -2
  52. package/dist/alpha/components/TemplateListPage/TemplateListPage.esm.js.map +1 -0
  53. package/dist/{next → alpha/components}/TemplateWizardPage/TemplateWizardPage.esm.js +2 -2
  54. package/dist/alpha/components/TemplateWizardPage/TemplateWizardPage.esm.js.map +1 -0
  55. package/dist/{next → alpha/components}/TemplateWizardPage/TemplateWizardPageContextMenu.esm.js +1 -1
  56. package/dist/alpha/components/TemplateWizardPage/TemplateWizardPageContextMenu.esm.js.map +1 -0
  57. package/dist/alpha/extensions.esm.js +30 -0
  58. package/dist/alpha/extensions.esm.js.map +1 -0
  59. package/dist/alpha/fields/RepoUrlPicker.esm.js +37 -0
  60. package/dist/alpha/fields/RepoUrlPicker.esm.js.map +1 -0
  61. package/dist/alpha/plugin.esm.js +32 -0
  62. package/dist/alpha/plugin.esm.js.map +1 -0
  63. package/dist/alpha.d.ts +80 -9
  64. package/dist/alpha.esm.js +1 -60
  65. package/dist/alpha.esm.js.map +1 -1
  66. package/dist/api.esm.js +19 -5
  67. package/dist/api.esm.js.map +1 -1
  68. package/dist/components/ActionsPage/ActionsPage.esm.js +30 -5
  69. package/dist/components/ActionsPage/ActionsPage.esm.js.map +1 -1
  70. package/dist/components/FileBrowser/FileBrowser.esm.js +4 -3
  71. package/dist/components/FileBrowser/FileBrowser.esm.js.map +1 -1
  72. package/dist/components/ListTasksPage/ListTasksPage.esm.js +17 -3
  73. package/dist/components/ListTasksPage/ListTasksPage.esm.js.map +1 -1
  74. package/dist/components/ListTasksPage/OwnerListPicker.esm.js +2 -2
  75. package/dist/components/ListTasksPage/OwnerListPicker.esm.js.map +1 -1
  76. package/dist/components/ListTasksPage/columns/CreatedAtColumn.esm.js +10 -5
  77. package/dist/components/ListTasksPage/columns/CreatedAtColumn.esm.js.map +1 -1
  78. package/dist/components/OngoingTask/ContextMenu.esm.js +15 -2
  79. package/dist/components/OngoingTask/ContextMenu.esm.js.map +1 -1
  80. package/dist/components/OngoingTask/OngoingTask.esm.js +24 -1
  81. package/dist/components/OngoingTask/OngoingTask.esm.js.map +1 -1
  82. package/dist/components/Router/Router.esm.js +35 -7
  83. package/dist/components/Router/Router.esm.js.map +1 -1
  84. package/dist/components/fields/EntityPicker/EntityPicker.esm.js +1 -1
  85. package/dist/components/fields/EntityPicker/EntityPicker.esm.js.map +1 -1
  86. package/dist/components/fields/MultiEntityPicker/MultiEntityPicker.esm.js +1 -0
  87. package/dist/components/fields/MultiEntityPicker/MultiEntityPicker.esm.js.map +1 -1
  88. package/dist/components/fields/RepoUrlPicker/RepoUrlPicker.esm.js.map +1 -1
  89. package/dist/components/fields/RepoUrlPicker/schema.esm.js +5 -6
  90. package/dist/components/fields/RepoUrlPicker/schema.esm.js.map +1 -1
  91. package/dist/components/fields/utils.esm.js +2 -1
  92. package/dist/components/fields/utils.esm.js.map +1 -1
  93. package/dist/index.d.ts +13 -8
  94. package/dist/lib/filesystem/WebFileSystemAccess.esm.js +34 -1
  95. package/dist/lib/filesystem/WebFileSystemAccess.esm.js.map +1 -1
  96. package/dist/lib/filesystem/createExampleTemplate.esm.js +76 -0
  97. package/dist/lib/filesystem/createExampleTemplate.esm.js.map +1 -0
  98. package/dist/packages/opaque-internal/src/OpaqueType.esm.js +103 -0
  99. package/dist/packages/opaque-internal/src/OpaqueType.esm.js.map +1 -0
  100. package/dist/packages/scaffolder-internal/src/wiring/InternalFormField.esm.js +6 -0
  101. package/dist/packages/scaffolder-internal/src/wiring/InternalFormField.esm.js.map +1 -0
  102. package/dist/plugin.esm.js +5 -2
  103. package/dist/plugin.esm.js.map +1 -1
  104. package/dist/routes.esm.js +16 -1
  105. package/dist/routes.esm.js.map +1 -1
  106. package/dist/translation.esm.js +22 -3
  107. package/dist/translation.esm.js.map +1 -1
  108. package/package.json +34 -23
  109. package/dist/next/TemplateEditorPage/CustomFieldExplorer.esm.js.map +0 -1
  110. package/dist/next/TemplateEditorPage/DirectoryEditorContext.esm.js.map +0 -1
  111. package/dist/next/TemplateEditorPage/DryRunContext.esm.js.map +0 -1
  112. package/dist/next/TemplateEditorPage/DryRunResults/DryRunResults.esm.js.map +0 -1
  113. package/dist/next/TemplateEditorPage/DryRunResults/DryRunResultsList.esm.js.map +0 -1
  114. package/dist/next/TemplateEditorPage/DryRunResults/DryRunResultsSplitView.esm.js.map +0 -1
  115. package/dist/next/TemplateEditorPage/DryRunResults/DryRunResultsView.esm.js.map +0 -1
  116. package/dist/next/TemplateEditorPage/DryRunResults/IconLink.esm.js.map +0 -1
  117. package/dist/next/TemplateEditorPage/DryRunResults/TaskPageLinks.esm.js.map +0 -1
  118. package/dist/next/TemplateEditorPage/DryRunResults/TaskStatusStepper.esm.js.map +0 -1
  119. package/dist/next/TemplateEditorPage/TemplateEditor.esm.js +0 -56
  120. package/dist/next/TemplateEditorPage/TemplateEditor.esm.js.map +0 -1
  121. package/dist/next/TemplateEditorPage/TemplateEditorBrowser.esm.js.map +0 -1
  122. package/dist/next/TemplateEditorPage/TemplateEditorForm.esm.js.map +0 -1
  123. package/dist/next/TemplateEditorPage/TemplateEditorIntro.esm.js +0 -91
  124. package/dist/next/TemplateEditorPage/TemplateEditorIntro.esm.js.map +0 -1
  125. package/dist/next/TemplateEditorPage/TemplateEditorPage.esm.js +0 -87
  126. package/dist/next/TemplateEditorPage/TemplateEditorPage.esm.js.map +0 -1
  127. package/dist/next/TemplateEditorPage/TemplateEditorTextArea.esm.js.map +0 -1
  128. package/dist/next/TemplateEditorPage/TemplateFormPreviewer.esm.js.map +0 -1
  129. package/dist/next/TemplateListPage/RegisterExistingButton.esm.js.map +0 -1
  130. package/dist/next/TemplateListPage/TemplateListPage.esm.js.map +0 -1
  131. package/dist/next/TemplateWizardPage/TemplateWizardPage.esm.js.map +0 -1
  132. package/dist/next/TemplateWizardPage/TemplateWizardPageContextMenu.esm.js.map +0 -1
  133. /package/dist/{next → alpha/components}/TemplateEditorPage/DryRunContext.esm.js +0 -0
  134. /package/dist/{next → alpha/components}/TemplateEditorPage/DryRunResults/DryRunResultsSplitView.esm.js +0 -0
  135. /package/dist/{next → alpha/components}/TemplateEditorPage/DryRunResults/IconLink.esm.js +0 -0
  136. /package/dist/{next → alpha/components}/TemplateEditorPage/DryRunResults/TaskPageLinks.esm.js +0 -0
package/CHANGELOG.md CHANGED
@@ -1,14 +1,68 @@
1
1
  # @backstage/plugin-scaffolder
2
2
 
3
- ## 1.25.1
3
+ ## 1.26.0-next.1
4
+
5
+ ### Minor Changes
6
+
7
+ - c433ae9: Improved the layout of the manage templates page (`/edit`) by adding icons and descriptions that better describe what each page is for. Updated the header menu to link back to the scaffolder create page.
8
+ - 7bfaf23: Text field content of the `EntityPicker` is now more readable as it uses entity title instead of entity reference.
4
9
 
5
10
  ### Patch Changes
6
11
 
12
+ - f6c15d8: Apply `defaultValue` props in `MultiEntityPicker`
13
+ - e969dc7: Move `@types/react` to a peer dependency.
14
+ - 785d68f: Add support for pagination in scaffolder tasks list
15
+ - 94a7bcd: Change "Register Existing Component" CTA to outlined as it's not a primary action on the scaffolder pages
7
16
  - Updated dependencies
8
- - @backstage/integration-react@1.1.32
9
- - @backstage/plugin-catalog-react@1.13.1
10
- - @backstage/core-compat-api@0.3.0
11
- - @backstage/plugin-scaffolder-react@1.12.1
17
+ - @backstage/core-components@0.15.1-next.1
18
+ - @backstage/frontend-plugin-api@0.9.0-next.1
19
+ - @backstage/integration-react@1.2.0-next.1
20
+ - @backstage/core-compat-api@0.3.1-next.1
21
+ - @backstage/core-plugin-api@1.10.0-next.1
22
+ - @backstage/plugin-permission-react@0.4.27-next.1
23
+ - @backstage/plugin-scaffolder-react@1.13.0-next.1
24
+ - @backstage/plugin-catalog-react@1.14.0-next.1
25
+ - @backstage/integration@1.15.1-next.0
26
+ - @backstage/catalog-client@1.7.0
27
+ - @backstage/catalog-model@1.7.0
28
+ - @backstage/errors@1.2.4
29
+ - @backstage/types@1.1.1
30
+ - @backstage/plugin-catalog-common@1.1.0
31
+ - @backstage/plugin-scaffolder-common@1.5.6
32
+
33
+ ## 1.26.0-next.0
34
+
35
+ ### Minor Changes
36
+
37
+ - bf6eaf3: Added support for `FormFieldBlueprint` to create field extensions in the Scaffolder plugin
38
+ - cc3f80c: Added ability to create a new local scaffolder template to ease onboarding when creating new templates.
39
+ - 5492eb6: Added ability to link to a specific action on the actions page
40
+
41
+ ### Patch Changes
42
+
43
+ - b2b2aa8: Fix extra divider displayed in owner list picker on list tasks page
44
+ - 7f1f483: Create a separate route for the Scaffolder template editor and add the ability to refresh the page without closing the directory. Also, when the directory is closed, the user will stay on the editor page and can load a template folder from there.
45
+ - 7a3d622: Create a separate route for the template form editor so we refresh it without being redirected to scaffolder edit page.
46
+ - 4698646: Change task list created at column to show timestamp
47
+ - 4130291: Create a separate route for the custom fields explorer so we refresh it without being redirected to scaffolder edit page.
48
+ - 11e0752: Make it possible to manually retry the scaffolder template from the step it failed
49
+ - 09fcd95: Update the Scaffolder template editor to quickly access installed custom fields and actions when editing a template.
50
+ - Updated dependencies
51
+ - @backstage/frontend-plugin-api@0.9.0-next.0
52
+ - @backstage/plugin-scaffolder-react@1.13.0-next.0
53
+ - @backstage/core-compat-api@0.3.1-next.0
54
+ - @backstage/core-components@0.15.1-next.0
55
+ - @backstage/core-plugin-api@1.10.0-next.0
56
+ - @backstage/plugin-catalog-react@1.13.1-next.0
57
+ - @backstage/catalog-client@1.7.0
58
+ - @backstage/catalog-model@1.7.0
59
+ - @backstage/errors@1.2.4
60
+ - @backstage/integration@1.15.0
61
+ - @backstage/integration-react@1.1.32-next.0
62
+ - @backstage/types@1.1.1
63
+ - @backstage/plugin-catalog-common@1.1.0
64
+ - @backstage/plugin-permission-react@0.4.27-next.0
65
+ - @backstage/plugin-scaffolder-common@1.5.6
12
66
 
13
67
  ## 1.25.0
14
68
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/plugin-scaffolder__alpha",
3
- "version": "1.25.1",
3
+ "version": "1.26.0-next.1",
4
4
  "main": "../dist/alpha.esm.js",
5
5
  "module": "../dist/alpha.esm.js",
6
6
  "types": "../dist/alpha.d.ts"
@@ -0,0 +1,40 @@
1
+ import { ApiBlueprint, createExtensionInput, createApiFactory } from '@backstage/frontend-plugin-api';
2
+ import { formFieldsApiRef } from './ref.esm.js';
3
+ import { FormFieldBlueprint } from '@backstage/plugin-scaffolder-react/alpha';
4
+ import { OpaqueFormField } from '../../packages/scaffolder-internal/src/wiring/InternalFormField.esm.js';
5
+
6
+ class DefaultScaffolderFormFieldsApi {
7
+ constructor(formFieldLoaders = []) {
8
+ this.formFieldLoaders = formFieldLoaders;
9
+ }
10
+ async getFormFields() {
11
+ const formFields = await Promise.all(
12
+ this.formFieldLoaders.map((loader) => loader())
13
+ );
14
+ const internalFormFields = formFields.map(OpaqueFormField.toInternal);
15
+ return internalFormFields;
16
+ }
17
+ }
18
+ const formFieldsApi = ApiBlueprint.makeWithOverrides({
19
+ name: "form-fields",
20
+ inputs: {
21
+ formFields: createExtensionInput([
22
+ FormFieldBlueprint.dataRefs.formFieldLoader
23
+ ])
24
+ },
25
+ factory(originalFactory, { inputs }) {
26
+ const formFieldLoaders = inputs.formFields.map(
27
+ (e) => e.get(FormFieldBlueprint.dataRefs.formFieldLoader)
28
+ );
29
+ return originalFactory({
30
+ factory: createApiFactory({
31
+ api: formFieldsApiRef,
32
+ deps: {},
33
+ factory: () => new DefaultScaffolderFormFieldsApi(formFieldLoaders)
34
+ })
35
+ });
36
+ }
37
+ });
38
+
39
+ export { formFieldsApi };
40
+ //# sourceMappingURL=FormFieldsApi.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FormFieldsApi.esm.js","sources":["../../../src/alpha/api/FormFieldsApi.ts"],"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 {\n ApiBlueprint,\n createApiFactory,\n createExtensionInput,\n} from '@backstage/frontend-plugin-api';\nimport { formFieldsApiRef } from './ref';\nimport { ScaffolderFormFieldsApi } from './types';\nimport { FormFieldBlueprint } from '@backstage/plugin-scaffolder-react/alpha';\nimport { FormField, OpaqueFormField } from '@internal/scaffolder';\n\nclass DefaultScaffolderFormFieldsApi implements ScaffolderFormFieldsApi {\n constructor(\n private readonly formFieldLoaders: Array<() => Promise<FormField>> = [],\n ) {}\n\n async getFormFields() {\n const formFields = await Promise.all(\n this.formFieldLoaders.map(loader => loader()),\n );\n\n const internalFormFields = formFields.map(OpaqueFormField.toInternal);\n\n return internalFormFields;\n }\n}\n\nexport const formFieldsApi = ApiBlueprint.makeWithOverrides({\n name: 'form-fields',\n inputs: {\n formFields: createExtensionInput([\n FormFieldBlueprint.dataRefs.formFieldLoader,\n ]),\n },\n factory(originalFactory, { inputs }) {\n const formFieldLoaders = inputs.formFields.map(e =>\n e.get(FormFieldBlueprint.dataRefs.formFieldLoader),\n );\n\n return originalFactory({\n factory: createApiFactory({\n api: formFieldsApiRef,\n deps: {},\n factory: () => new DefaultScaffolderFormFieldsApi(formFieldLoaders),\n }),\n });\n },\n});\n"],"names":[],"mappings":";;;;;AA0BA,MAAM,8BAAkE,CAAA;AAAA,EACtE,WAAA,CACmB,gBAAoD,GAAA,EACrE,EAAA;AADiB,IAAA,IAAA,CAAA,gBAAA,GAAA,gBAAA,CAAA;AAAA,GAChB;AAAA,EAEH,MAAM,aAAgB,GAAA;AACpB,IAAM,MAAA,UAAA,GAAa,MAAM,OAAQ,CAAA,GAAA;AAAA,MAC/B,IAAK,CAAA,gBAAA,CAAiB,GAAI,CAAA,CAAA,MAAA,KAAU,QAAQ,CAAA;AAAA,KAC9C,CAAA;AAEA,IAAA,MAAM,kBAAqB,GAAA,UAAA,CAAW,GAAI,CAAA,eAAA,CAAgB,UAAU,CAAA,CAAA;AAEpE,IAAO,OAAA,kBAAA,CAAA;AAAA,GACT;AACF,CAAA;AAEa,MAAA,aAAA,GAAgB,aAAa,iBAAkB,CAAA;AAAA,EAC1D,IAAM,EAAA,aAAA;AAAA,EACN,MAAQ,EAAA;AAAA,IACN,YAAY,oBAAqB,CAAA;AAAA,MAC/B,mBAAmB,QAAS,CAAA,eAAA;AAAA,KAC7B,CAAA;AAAA,GACH;AAAA,EACA,OAAQ,CAAA,eAAA,EAAiB,EAAE,MAAA,EAAU,EAAA;AACnC,IAAM,MAAA,gBAAA,GAAmB,OAAO,UAAW,CAAA,GAAA;AAAA,MAAI,CAC7C,CAAA,KAAA,CAAA,CAAE,GAAI,CAAA,kBAAA,CAAmB,SAAS,eAAe,CAAA;AAAA,KACnD,CAAA;AAEA,IAAA,OAAO,eAAgB,CAAA;AAAA,MACrB,SAAS,gBAAiB,CAAA;AAAA,QACxB,GAAK,EAAA,gBAAA;AAAA,QACL,MAAM,EAAC;AAAA,QACP,OAAS,EAAA,MAAM,IAAI,8BAAA,CAA+B,gBAAgB,CAAA;AAAA,OACnE,CAAA;AAAA,KACF,CAAA,CAAA;AAAA,GACH;AACF,CAAC;;;;"}
@@ -0,0 +1,8 @@
1
+ import { createApiRef } from '@backstage/frontend-plugin-api';
2
+
3
+ const formFieldsApiRef = createApiRef({
4
+ id: "plugin.scaffolder.form-fields"
5
+ });
6
+
7
+ export { formFieldsApiRef };
8
+ //# sourceMappingURL=ref.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ref.esm.js","sources":["../../../src/alpha/api/ref.ts"],"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 { createApiRef } from '@backstage/frontend-plugin-api';\nimport { ScaffolderFormFieldsApi } from './types';\n\nexport const formFieldsApiRef = createApiRef<ScaffolderFormFieldsApi>({\n id: 'plugin.scaffolder.form-fields',\n});\n"],"names":[],"mappings":";;AAmBO,MAAM,mBAAmB,YAAsC,CAAA;AAAA,EACpE,EAAI,EAAA,+BAAA;AACN,CAAC;;;;"}
@@ -0,0 +1,27 @@
1
+ import { ApiBlueprint, createApiFactory, discoveryApiRef, fetchApiRef, identityApiRef } from '@backstage/frontend-plugin-api';
2
+ import { scmIntegrationsApiRef } from '@backstage/integration-react';
3
+ import { scaffolderApiRef } from '@backstage/plugin-scaffolder-react';
4
+ import { ScaffolderClient } from '../api.esm.js';
5
+
6
+ const scaffolderApi = ApiBlueprint.make({
7
+ params: {
8
+ factory: createApiFactory({
9
+ api: scaffolderApiRef,
10
+ deps: {
11
+ discoveryApi: discoveryApiRef,
12
+ scmIntegrationsApi: scmIntegrationsApiRef,
13
+ fetchApi: fetchApiRef,
14
+ identityApi: identityApiRef
15
+ },
16
+ factory: ({ discoveryApi, scmIntegrationsApi, fetchApi, identityApi }) => new ScaffolderClient({
17
+ discoveryApi,
18
+ scmIntegrationsApi,
19
+ fetchApi,
20
+ identityApi
21
+ })
22
+ })
23
+ }
24
+ });
25
+
26
+ export { scaffolderApi };
27
+ //# sourceMappingURL=api.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.esm.js","sources":["../../src/alpha/api.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 */\nimport {\n ApiBlueprint,\n createApiFactory,\n discoveryApiRef,\n fetchApiRef,\n identityApiRef,\n} from '@backstage/frontend-plugin-api';\nimport { scmIntegrationsApiRef } from '@backstage/integration-react';\nimport { scaffolderApiRef } from '@backstage/plugin-scaffolder-react';\nimport { ScaffolderClient } from '../api';\n\nexport const scaffolderApi = ApiBlueprint.make({\n params: {\n factory: createApiFactory({\n api: scaffolderApiRef,\n deps: {\n discoveryApi: discoveryApiRef,\n scmIntegrationsApi: scmIntegrationsApiRef,\n fetchApi: fetchApiRef,\n identityApi: identityApiRef,\n },\n factory: ({ discoveryApi, scmIntegrationsApi, fetchApi, identityApi }) =>\n new ScaffolderClient({\n discoveryApi,\n scmIntegrationsApi,\n fetchApi,\n identityApi,\n }),\n }),\n },\n});\n"],"names":[],"mappings":";;;;;AA0Ba,MAAA,aAAA,GAAgB,aAAa,IAAK,CAAA;AAAA,EAC7C,MAAQ,EAAA;AAAA,IACN,SAAS,gBAAiB,CAAA;AAAA,MACxB,GAAK,EAAA,gBAAA;AAAA,MACL,IAAM,EAAA;AAAA,QACJ,YAAc,EAAA,eAAA;AAAA,QACd,kBAAoB,EAAA,qBAAA;AAAA,QACpB,QAAU,EAAA,WAAA;AAAA,QACV,WAAa,EAAA,cAAA;AAAA,OACf;AAAA,MACA,OAAA,EAAS,CAAC,EAAE,YAAA,EAAc,oBAAoB,QAAU,EAAA,WAAA,EACtD,KAAA,IAAI,gBAAiB,CAAA;AAAA,QACnB,YAAA;AAAA,QACA,kBAAA;AAAA,QACA,QAAA;AAAA,QACA,WAAA;AAAA,OACD,CAAA;AAAA,KACJ,CAAA;AAAA,GACH;AACF,CAAC;;;;"}
@@ -18,7 +18,7 @@ import { Form } from '@backstage/plugin-scaffolder-react/alpha';
18
18
  import { TemplateEditorForm } from './TemplateEditorForm.esm.js';
19
19
  import validator from '@rjsf/validator-ajv8';
20
20
  import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
21
- import { scaffolderTranslationRef } from '../../translation.esm.js';
21
+ import { scaffolderTranslationRef } from '../../../translation.esm.js';
22
22
 
23
23
  const useStyles = makeStyles(
24
24
  (theme) => ({
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CustomFieldExplorer.esm.js","sources":["../../../../src/alpha/components/TemplateEditorPage/CustomFieldExplorer.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 { StreamLanguage } from '@codemirror/language';\nimport { yaml as yamlSupport } from '@codemirror/legacy-modes/mode/yaml';\nimport Button from '@material-ui/core/Button';\nimport Card from '@material-ui/core/Card';\nimport CardContent from '@material-ui/core/CardContent';\nimport CardHeader from '@material-ui/core/CardHeader';\nimport FormControl from '@material-ui/core/FormControl';\nimport IconButton from '@material-ui/core/IconButton';\nimport InputLabel from '@material-ui/core/InputLabel';\nimport MenuItem from '@material-ui/core/MenuItem';\nimport Select from '@material-ui/core/Select';\nimport { makeStyles } from '@material-ui/core/styles';\nimport CloseIcon from '@material-ui/icons/Close';\nimport CodeMirror from '@uiw/react-codemirror';\nimport React, { useCallback, useMemo, useState } from 'react';\nimport yaml from 'yaml';\nimport { Form } from '@backstage/plugin-scaffolder-react/alpha';\nimport { TemplateEditorForm } from './TemplateEditorForm';\nimport validator from '@rjsf/validator-ajv8';\nimport { FieldExtensionOptions } from '@backstage/plugin-scaffolder-react';\nimport { useTranslationRef } from '@backstage/core-plugin-api/alpha';\nimport { scaffolderTranslationRef } from '../../../translation';\n\n/** @public */\nexport type ScaffolderCustomFieldExplorerClassKey =\n | 'root'\n | 'controls'\n | 'fieldForm'\n | 'preview';\n\nconst useStyles = makeStyles(\n theme => ({\n root: {\n gridArea: 'pageContent',\n display: 'grid',\n gridTemplateAreas: `\n \"controls controls\"\n \"fieldForm preview\"\n `,\n gridTemplateRows: 'auto 1fr',\n gridTemplateColumns: '1fr 1fr',\n },\n controls: {\n gridArea: 'controls',\n display: 'flex',\n flexFlow: 'row nowrap',\n alignItems: 'center',\n margin: theme.spacing(1),\n },\n fieldForm: {\n gridArea: 'fieldForm',\n },\n preview: {\n gridArea: 'preview',\n },\n }),\n { name: 'ScaffolderCustomFieldExplorer' },\n);\n\nexport const CustomFieldExplorer = ({\n customFieldExtensions = [],\n onClose,\n}: {\n customFieldExtensions?: FieldExtensionOptions<any, any>[];\n onClose?: () => void;\n}) => {\n const classes = useStyles();\n const { t } = useTranslationRef(scaffolderTranslationRef);\n const fieldOptions = customFieldExtensions.filter(field => !!field.schema);\n const [selectedField, setSelectedField] = useState(fieldOptions[0]);\n const [fieldFormState, setFieldFormState] = useState({});\n const [refreshKey, setRefreshKey] = useState(Date.now());\n const sampleFieldTemplate = useMemo(\n () =>\n yaml.stringify({\n parameters: [\n {\n title: `${selectedField.name} Example`,\n properties: {\n [selectedField.name]: {\n type: selectedField.schema?.returnValue?.type,\n 'ui:field': selectedField.name,\n 'ui:options': fieldFormState,\n },\n },\n },\n ],\n }),\n [fieldFormState, selectedField],\n );\n\n const fieldComponents = useMemo(() => {\n return Object.fromEntries(\n customFieldExtensions.map(({ name, component }) => [name, component]),\n );\n }, [customFieldExtensions]);\n\n const handleSelectionChange = useCallback(\n (selection: FieldExtensionOptions) => {\n setSelectedField(selection);\n setFieldFormState({});\n },\n [setFieldFormState, setSelectedField],\n );\n\n const handleFieldConfigChange = useCallback(\n (state: {}) => {\n setFieldFormState(state);\n // Force TemplateEditorForm to re-render since some fields\n // may not be responsive to ui:option changes\n setRefreshKey(Date.now());\n },\n [setFieldFormState, setRefreshKey],\n );\n\n return (\n <main className={classes.root}>\n <div className={classes.controls}>\n <FormControl variant=\"outlined\" size=\"small\" fullWidth>\n <InputLabel id=\"select-field-label\">\n {t('templateEditorPage.customFieldExplorer.selectFieldLabel')}\n </InputLabel>\n <Select\n value={selectedField}\n label={t('templateEditorPage.customFieldExplorer.selectFieldLabel')}\n labelId=\"select-field-label\"\n onChange={e =>\n handleSelectionChange(e.target.value as FieldExtensionOptions)\n }\n >\n {fieldOptions.map((option, idx) => (\n <MenuItem key={idx} value={option as any}>\n {option.name}\n </MenuItem>\n ))}\n </Select>\n </FormControl>\n\n <IconButton size=\"medium\" onClick={onClose} aria-label=\"Close\">\n <CloseIcon />\n </IconButton>\n </div>\n <div className={classes.fieldForm}>\n <Card>\n <CardHeader\n title={t('templateEditorPage.customFieldExplorer.fieldForm.title')}\n />\n <CardContent>\n <Form\n showErrorList={false}\n fields={{ ...fieldComponents }}\n noHtml5Validate\n formData={fieldFormState}\n formContext={{ fieldFormState }}\n onSubmit={e => handleFieldConfigChange(e.formData)}\n validator={validator}\n schema={selectedField.schema?.uiOptions || {}}\n experimental_defaultFormStateBehavior={{\n allOf: 'populateDefaults',\n }}\n >\n <Button\n variant=\"contained\"\n color=\"primary\"\n type=\"submit\"\n disabled={!selectedField.schema?.uiOptions}\n >\n {t(\n 'templateEditorPage.customFieldExplorer.fieldForm.applyButtonTitle',\n )}\n </Button>\n </Form>\n </CardContent>\n </Card>\n </div>\n <div className={classes.preview}>\n <Card>\n <CardHeader\n title={t('templateEditorPage.customFieldExplorer.preview.title')}\n />\n <CardContent>\n <CodeMirror\n readOnly\n theme=\"dark\"\n height=\"100%\"\n extensions={[StreamLanguage.define(yamlSupport)]}\n value={sampleFieldTemplate}\n />\n </CardContent>\n </Card>\n <TemplateEditorForm\n key={refreshKey}\n content={sampleFieldTemplate}\n contentIsSpec\n fieldExtensions={customFieldExtensions}\n setErrorText={() => null}\n />\n </div>\n </main>\n );\n};\n"],"names":["yamlSupport"],"mappings":"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"}
@@ -0,0 +1,167 @@
1
+ import React, { useState, useMemo, useCallback } from 'react';
2
+ import yaml from 'yaml';
3
+ import validator from '@rjsf/validator-ajv8';
4
+ import CodeMirror from '@uiw/react-codemirror';
5
+ import { StreamLanguage } from '@codemirror/language';
6
+ import { yaml as yaml$1 } from '@codemirror/legacy-modes/mode/yaml';
7
+ import { makeStyles } from '@material-ui/core/styles';
8
+ import FormControl from '@material-ui/core/FormControl';
9
+ import InputLabel from '@material-ui/core/InputLabel';
10
+ import MenuItem from '@material-ui/core/MenuItem';
11
+ import Select from '@material-ui/core/Select';
12
+ import Accordion from '@material-ui/core/Accordion';
13
+ import AccordionSummary from '@material-ui/core/AccordionSummary';
14
+ import AccordionDetails from '@material-ui/core/AccordionDetails';
15
+ import Button from '@material-ui/core/Button';
16
+ import Typography from '@material-ui/core/Typography';
17
+ import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
18
+ import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
19
+ import { Form } from '@backstage/plugin-scaffolder-react/alpha';
20
+ import { scaffolderTranslationRef } from '../../../translation.esm.js';
21
+ import { TemplateEditorForm } from './TemplateEditorForm.esm.js';
22
+
23
+ const useStyles = makeStyles(
24
+ (theme) => ({
25
+ root: {
26
+ gridArea: "pageContent",
27
+ display: "grid",
28
+ gridTemplateRows: "auto 1fr"
29
+ },
30
+ controls: {
31
+ marginBottom: theme.spacing(2)
32
+ },
33
+ code: {
34
+ width: "100%"
35
+ }
36
+ }),
37
+ { name: "ScaffolderCustomFieldExtensionsPlaygroud" }
38
+ );
39
+ const CustomFieldPlaygroud = ({
40
+ fieldExtensions = []
41
+ }) => {
42
+ const classes = useStyles();
43
+ const { t } = useTranslationRef(scaffolderTranslationRef);
44
+ const fieldOptions = fieldExtensions.filter((field) => !!field.schema);
45
+ const [refreshKey, setRefreshKey] = useState(Date.now());
46
+ const [fieldFormState, setFieldFormState] = useState({});
47
+ const [selectedField, setSelectedField] = useState(fieldOptions[0]);
48
+ const sampleFieldTemplate = useMemo(
49
+ () => yaml.stringify({
50
+ parameters: [
51
+ {
52
+ title: `${selectedField.name} Example`,
53
+ properties: {
54
+ [selectedField.name]: {
55
+ type: selectedField.schema?.returnValue?.type,
56
+ "ui:field": selectedField.name,
57
+ "ui:options": fieldFormState
58
+ }
59
+ }
60
+ }
61
+ ]
62
+ }),
63
+ [fieldFormState, selectedField]
64
+ );
65
+ const fieldComponents = useMemo(() => {
66
+ return Object.fromEntries(
67
+ fieldExtensions.map(({ name, component }) => [name, component])
68
+ );
69
+ }, [fieldExtensions]);
70
+ const handleSelectionChange = useCallback(
71
+ (selection) => {
72
+ setSelectedField(selection);
73
+ setFieldFormState({});
74
+ },
75
+ [setFieldFormState, setSelectedField]
76
+ );
77
+ const handleFieldConfigChange = useCallback(
78
+ (state) => {
79
+ setFieldFormState(state);
80
+ setRefreshKey(Date.now());
81
+ },
82
+ [setFieldFormState, setRefreshKey]
83
+ );
84
+ return /* @__PURE__ */ React.createElement("main", { className: classes.root }, /* @__PURE__ */ React.createElement("div", { className: classes.controls }, /* @__PURE__ */ React.createElement(FormControl, { variant: "outlined", fullWidth: true }, /* @__PURE__ */ React.createElement(InputLabel, { id: "select-field-label" }, t("templateEditorPage.customFieldExplorer.selectFieldLabel")), /* @__PURE__ */ React.createElement(
85
+ Select,
86
+ {
87
+ value: selectedField,
88
+ label: t("templateEditorPage.customFieldExplorer.selectFieldLabel"),
89
+ labelId: "select-field-label",
90
+ onChange: (e) => handleSelectionChange(e.target.value)
91
+ },
92
+ fieldOptions.map((option, idx) => /* @__PURE__ */ React.createElement(MenuItem, { key: idx, value: option }, option.name))
93
+ ))), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement(Accordion, { defaultExpanded: true }, /* @__PURE__ */ React.createElement(
94
+ AccordionSummary,
95
+ {
96
+ expandIcon: /* @__PURE__ */ React.createElement(ExpandMoreIcon, null),
97
+ "aria-controls": "panel-code-content",
98
+ id: "panel-code-header"
99
+ },
100
+ /* @__PURE__ */ React.createElement(Typography, { variant: "h6" }, t("templateEditorPage.customFieldExplorer.preview.title"))
101
+ ), /* @__PURE__ */ React.createElement(AccordionDetails, null, /* @__PURE__ */ React.createElement("div", { className: classes.code }, /* @__PURE__ */ React.createElement(
102
+ CodeMirror,
103
+ {
104
+ readOnly: true,
105
+ theme: "dark",
106
+ height: "100%",
107
+ width: "100%",
108
+ extensions: [StreamLanguage.define(yaml$1)],
109
+ value: sampleFieldTemplate
110
+ }
111
+ )))), /* @__PURE__ */ React.createElement(Accordion, { defaultExpanded: true }, /* @__PURE__ */ React.createElement(
112
+ AccordionSummary,
113
+ {
114
+ expandIcon: /* @__PURE__ */ React.createElement(ExpandMoreIcon, null),
115
+ "aria-controls": "panel-preview-content",
116
+ id: "panel-preview-header"
117
+ },
118
+ /* @__PURE__ */ React.createElement(Typography, { variant: "h6" }, t("templateEditorPage.customFieldExplorer.fieldPreview.title"))
119
+ ), /* @__PURE__ */ React.createElement(AccordionDetails, null, /* @__PURE__ */ React.createElement(
120
+ TemplateEditorForm,
121
+ {
122
+ key: refreshKey,
123
+ content: sampleFieldTemplate,
124
+ contentIsSpec: true,
125
+ fieldExtensions,
126
+ setErrorText: () => null
127
+ }
128
+ ))), /* @__PURE__ */ React.createElement(Accordion, { defaultExpanded: true }, /* @__PURE__ */ React.createElement(
129
+ AccordionSummary,
130
+ {
131
+ expandIcon: /* @__PURE__ */ React.createElement(ExpandMoreIcon, null),
132
+ "aria-controls": "panel-options-content",
133
+ id: "panel-options-header"
134
+ },
135
+ /* @__PURE__ */ React.createElement(Typography, { variant: "h6" }, t("templateEditorPage.customFieldExplorer.fieldForm.title"))
136
+ ), /* @__PURE__ */ React.createElement(AccordionDetails, null, /* @__PURE__ */ React.createElement(
137
+ Form,
138
+ {
139
+ showErrorList: false,
140
+ fields: { ...fieldComponents },
141
+ noHtml5Validate: true,
142
+ formData: fieldFormState,
143
+ formContext: { fieldFormState },
144
+ onSubmit: (e) => handleFieldConfigChange(e.formData),
145
+ validator,
146
+ schema: selectedField.schema?.uiOptions || {},
147
+ experimental_defaultFormStateBehavior: {
148
+ allOf: "populateDefaults"
149
+ }
150
+ },
151
+ /* @__PURE__ */ React.createElement(
152
+ Button,
153
+ {
154
+ variant: "contained",
155
+ color: "primary",
156
+ type: "submit",
157
+ disabled: !selectedField.schema?.uiOptions
158
+ },
159
+ t(
160
+ "templateEditorPage.customFieldExplorer.fieldForm.applyButtonTitle"
161
+ )
162
+ )
163
+ )))));
164
+ };
165
+
166
+ export { CustomFieldPlaygroud };
167
+ //# sourceMappingURL=CustomFieldPlaygroud.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CustomFieldPlaygroud.esm.js","sources":["../../../../src/alpha/components/TemplateEditorPage/CustomFieldPlaygroud.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, useMemo, useState } from 'react';\nimport yaml from 'yaml';\nimport validator from '@rjsf/validator-ajv8';\nimport CodeMirror from '@uiw/react-codemirror';\nimport { StreamLanguage } from '@codemirror/language';\nimport { yaml as yamlSupport } from '@codemirror/legacy-modes/mode/yaml';\n\nimport { makeStyles } from '@material-ui/core/styles';\nimport FormControl from '@material-ui/core/FormControl';\nimport InputLabel from '@material-ui/core/InputLabel';\nimport MenuItem from '@material-ui/core/MenuItem';\nimport Select from '@material-ui/core/Select';\nimport Accordion from '@material-ui/core/Accordion';\nimport AccordionSummary from '@material-ui/core/AccordionSummary';\nimport AccordionDetails from '@material-ui/core/AccordionDetails';\nimport Button from '@material-ui/core/Button';\nimport Typography from '@material-ui/core/Typography';\nimport ExpandMoreIcon from '@material-ui/icons/ExpandMore';\n\nimport { useTranslationRef } from '@backstage/core-plugin-api/alpha';\nimport { Form } from '@backstage/plugin-scaffolder-react/alpha';\nimport { FieldExtensionOptions } from '@backstage/plugin-scaffolder-react';\n\nimport { scaffolderTranslationRef } from '../../../translation';\nimport { TemplateEditorForm } from './TemplateEditorForm';\n\nconst useStyles = makeStyles(\n theme => ({\n root: {\n gridArea: 'pageContent',\n display: 'grid',\n gridTemplateRows: 'auto 1fr',\n },\n controls: {\n marginBottom: theme.spacing(2),\n },\n code: {\n width: '100%',\n },\n }),\n { name: 'ScaffolderCustomFieldExtensionsPlaygroud' },\n);\n\nexport const CustomFieldPlaygroud = ({\n fieldExtensions = [],\n}: {\n fieldExtensions?: FieldExtensionOptions<any, any>[];\n}) => {\n const classes = useStyles();\n const { t } = useTranslationRef(scaffolderTranslationRef);\n const fieldOptions = fieldExtensions.filter(field => !!field.schema);\n const [refreshKey, setRefreshKey] = useState(Date.now());\n const [fieldFormState, setFieldFormState] = useState({});\n const [selectedField, setSelectedField] = useState(fieldOptions[0]);\n const sampleFieldTemplate = useMemo(\n () =>\n yaml.stringify({\n parameters: [\n {\n title: `${selectedField.name} Example`,\n properties: {\n [selectedField.name]: {\n type: selectedField.schema?.returnValue?.type,\n 'ui:field': selectedField.name,\n 'ui:options': fieldFormState,\n },\n },\n },\n ],\n }),\n [fieldFormState, selectedField],\n );\n\n const fieldComponents = useMemo(() => {\n return Object.fromEntries(\n fieldExtensions.map(({ name, component }) => [name, component]),\n );\n }, [fieldExtensions]);\n\n const handleSelectionChange = useCallback(\n (selection: FieldExtensionOptions) => {\n setSelectedField(selection);\n setFieldFormState({});\n },\n [setFieldFormState, setSelectedField],\n );\n\n const handleFieldConfigChange = useCallback(\n (state: {}) => {\n setFieldFormState(state);\n // Force TemplateEditorForm to re-render since some fields\n // may not be responsive to ui:option changes\n setRefreshKey(Date.now());\n },\n [setFieldFormState, setRefreshKey],\n );\n\n return (\n <main className={classes.root}>\n <div className={classes.controls}>\n <FormControl variant=\"outlined\" fullWidth>\n <InputLabel id=\"select-field-label\">\n {t('templateEditorPage.customFieldExplorer.selectFieldLabel')}\n </InputLabel>\n <Select\n value={selectedField}\n label={t('templateEditorPage.customFieldExplorer.selectFieldLabel')}\n labelId=\"select-field-label\"\n onChange={e =>\n handleSelectionChange(e.target.value as FieldExtensionOptions)\n }\n >\n {fieldOptions.map((option, idx) => (\n <MenuItem key={idx} value={option as any}>\n {option.name}\n </MenuItem>\n ))}\n </Select>\n </FormControl>\n </div>\n <div>\n <Accordion defaultExpanded>\n <AccordionSummary\n expandIcon={<ExpandMoreIcon />}\n aria-controls=\"panel-code-content\"\n id=\"panel-code-header\"\n >\n <Typography variant=\"h6\">\n {t('templateEditorPage.customFieldExplorer.preview.title')}\n </Typography>\n </AccordionSummary>\n <AccordionDetails>\n <div className={classes.code}>\n <CodeMirror\n readOnly\n theme=\"dark\"\n height=\"100%\"\n width=\"100%\"\n extensions={[StreamLanguage.define(yamlSupport)]}\n value={sampleFieldTemplate}\n />\n </div>\n </AccordionDetails>\n </Accordion>\n <Accordion defaultExpanded>\n <AccordionSummary\n expandIcon={<ExpandMoreIcon />}\n aria-controls=\"panel-preview-content\"\n id=\"panel-preview-header\"\n >\n <Typography variant=\"h6\">\n {t('templateEditorPage.customFieldExplorer.fieldPreview.title')}\n </Typography>\n </AccordionSummary>\n <AccordionDetails>\n <TemplateEditorForm\n key={refreshKey}\n content={sampleFieldTemplate}\n contentIsSpec\n fieldExtensions={fieldExtensions}\n setErrorText={() => null}\n />\n </AccordionDetails>\n </Accordion>\n <Accordion defaultExpanded>\n <AccordionSummary\n expandIcon={<ExpandMoreIcon />}\n aria-controls=\"panel-options-content\"\n id=\"panel-options-header\"\n >\n <Typography variant=\"h6\">\n {t('templateEditorPage.customFieldExplorer.fieldForm.title')}\n </Typography>\n </AccordionSummary>\n <AccordionDetails>\n <Form\n showErrorList={false}\n fields={{ ...fieldComponents }}\n noHtml5Validate\n formData={fieldFormState}\n formContext={{ fieldFormState }}\n onSubmit={e => handleFieldConfigChange(e.formData)}\n validator={validator}\n schema={selectedField.schema?.uiOptions || {}}\n experimental_defaultFormStateBehavior={{\n allOf: 'populateDefaults',\n }}\n >\n <Button\n variant=\"contained\"\n color=\"primary\"\n type=\"submit\"\n disabled={!selectedField.schema?.uiOptions}\n >\n {t(\n 'templateEditorPage.customFieldExplorer.fieldForm.applyButtonTitle',\n )}\n </Button>\n </Form>\n </AccordionDetails>\n </Accordion>\n </div>\n </main>\n );\n};\n"],"names":["yamlSupport"],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ import React, { useCallback } from 'react';
2
+ import { useNavigate } from 'react-router-dom';
3
+ import { Page, Header, Content } from '@backstage/core-components';
4
+ import { useRouteRef } from '@backstage/core-plugin-api';
5
+ import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
6
+ import { editRouteRef } from '../../../routes.esm.js';
7
+ import { scaffolderTranslationRef } from '../../../translation.esm.js';
8
+ import { CustomFieldExplorer } from './CustomFieldExplorer.esm.js';
9
+
10
+ function CustomFieldsPage(props) {
11
+ const navigate = useNavigate();
12
+ const editLink = useRouteRef(editRouteRef);
13
+ const { t } = useTranslationRef(scaffolderTranslationRef);
14
+ const handleClose = useCallback(() => {
15
+ navigate(editLink());
16
+ }, [navigate, editLink]);
17
+ return /* @__PURE__ */ React.createElement(Page, { themeId: "home" }, /* @__PURE__ */ React.createElement(
18
+ Header,
19
+ {
20
+ title: t("templateEditorPage.title"),
21
+ subtitle: t("templateEditorPage.subtitle")
22
+ }
23
+ ), /* @__PURE__ */ React.createElement(Content, null, /* @__PURE__ */ React.createElement(
24
+ CustomFieldExplorer,
25
+ {
26
+ customFieldExtensions: props.fieldExtensions,
27
+ onClose: handleClose
28
+ }
29
+ )));
30
+ }
31
+
32
+ export { CustomFieldsPage };
33
+ //# sourceMappingURL=CustomFieldsPage.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CustomFieldsPage.esm.js","sources":["../../../../src/alpha/components/TemplateEditorPage/CustomFieldsPage.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 { Page, Header, Content } from '@backstage/core-components';\nimport { useRouteRef } from '@backstage/core-plugin-api';\nimport { useTranslationRef } from '@backstage/core-plugin-api/alpha';\nimport { FieldExtensionOptions } from '@backstage/plugin-scaffolder-react';\n\nimport { editRouteRef } from '../../../routes';\nimport { scaffolderTranslationRef } from '../../../translation';\n\nimport { CustomFieldExplorer } from './CustomFieldExplorer';\n\ninterface CustomFieldsPageProps {\n fieldExtensions?: FieldExtensionOptions<any, any>[];\n}\n\nexport function CustomFieldsPage(props: CustomFieldsPageProps) {\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('templateEditorPage.title')}\n subtitle={t('templateEditorPage.subtitle')}\n />\n <Content>\n <CustomFieldExplorer\n customFieldExtensions={props.fieldExtensions}\n onClose={handleClose}\n />\n </Content>\n </Page>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;AAiCO,SAAS,iBAAiB,KAA8B,EAAA;AAC7D,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,0BAA0B,CAAA;AAAA,MACnC,QAAA,EAAU,EAAE,6BAA6B,CAAA;AAAA,KAAA;AAAA,GAC3C,sCACC,OACC,EAAA,IAAA,kBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,mBAAA;AAAA,IAAA;AAAA,MACC,uBAAuB,KAAM,CAAA,eAAA;AAAA,MAC7B,OAAS,EAAA,WAAA;AAAA,KAAA;AAAA,GAEb,CACF,CAAA,CAAA;AAEJ;;;;"}
@@ -1,4 +1,4 @@
1
- import { ErrorPanel, Progress } from '@backstage/core-components';
1
+ import { ErrorPanel } from '@backstage/core-components';
2
2
  import { useAsync, useRerender } from '@react-hookz/web';
3
3
  import React, { createContext, useEffect, useContext } from 'react';
4
4
 
@@ -117,9 +117,6 @@ function useDirectoryEditor() {
117
117
  const value = useContext(DirectoryEditorContext);
118
118
  const rerender = useRerender();
119
119
  useEffect(() => value?.subscribe(rerender), [value, rerender]);
120
- if (!value) {
121
- throw new Error("must be used within a DirectoryEditorProvider");
122
- }
123
120
  return value;
124
121
  }
125
122
  function DirectoryEditorProvider(props) {
@@ -136,12 +133,12 @@ function DirectoryEditorProvider(props) {
136
133
  }
137
134
  );
138
135
  useEffect(() => {
139
- execute(directory);
136
+ if (directory) {
137
+ execute(directory);
138
+ }
140
139
  }, [execute, directory]);
141
140
  if (error) {
142
141
  return /* @__PURE__ */ React.createElement(ErrorPanel, { error });
143
- } else if (!result) {
144
- return /* @__PURE__ */ React.createElement(Progress, null);
145
142
  }
146
143
  return /* @__PURE__ */ React.createElement(DirectoryEditorContext.Provider, { value: result }, props.children);
147
144
  }
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DirectoryEditorContext.esm.js","sources":["../../../../src/alpha/components/TemplateEditorPage/DirectoryEditorContext.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 { ErrorPanel } from '@backstage/core-components';\nimport { useAsync, useRerender } from '@react-hookz/web';\nimport React, { createContext, ReactNode, useContext, useEffect } from 'react';\nimport {\n TemplateDirectoryAccess,\n TemplateFileAccess,\n} from '../../../lib/filesystem';\n\nconst MAX_SIZE = 1024 * 1024;\nconst MAX_SIZE_MESSAGE = 'This file is too large to be displayed';\n\ninterface DirectoryEditorFile {\n /** The path of the file relative to the root directory */\n path: string;\n /** The staged content of the file */\n content: string;\n /** Whether the staged content matches what is on disk */\n dirty: boolean;\n\n /** Update the staged content of the file without saving */\n updateContent(content: string): void;\n /** Save the staged content of the file to disk */\n save(): Promise<void>;\n /** Reload the staged content of the file from disk */\n reload(): Promise<void>;\n}\n\ninterface DirectoryEditor {\n /** A list of all files in the edited directory */\n files: Array<DirectoryEditorFile>;\n\n /** The currently selected file */\n selectedFile: DirectoryEditorFile | undefined;\n /** Switch the selected file */\n setSelectedFile(path: string | undefined): void;\n\n /** Save all files to disk */\n save(): Promise<void>;\n /** Reload all files from disk */\n reload(): Promise<void>;\n\n subscribe(listener: () => void): () => void;\n}\n\nclass DirectoryEditorFileManager implements DirectoryEditorFile {\n readonly #access: TemplateFileAccess;\n readonly #signalUpdate: () => void;\n\n #content?: string;\n #savedContent?: string;\n\n constructor(access: TemplateFileAccess, signalUpdate: () => void) {\n this.#access = access;\n this.#signalUpdate = signalUpdate;\n }\n\n get path() {\n return this.#access.path;\n }\n\n get content() {\n return this.#content ?? MAX_SIZE_MESSAGE;\n }\n\n updateContent(content: string): void {\n if (this.#content === undefined) {\n return;\n }\n this.#content = content;\n this.#signalUpdate();\n }\n\n get dirty() {\n return this.#content !== this.#savedContent;\n }\n\n async save(): Promise<void> {\n if (this.#content !== undefined) {\n await this.#access.save(this.#content);\n this.#savedContent = this.#content;\n this.#signalUpdate();\n }\n }\n\n async reload(): Promise<void> {\n const file = await this.#access.file();\n if (file.size > MAX_SIZE) {\n if (this.#content !== undefined) {\n this.#content = undefined;\n this.#savedContent = undefined;\n this.#signalUpdate();\n }\n return;\n }\n\n const content = await file.text();\n if (this.#content !== content) {\n this.#content = content;\n this.#savedContent = content;\n this.#signalUpdate();\n }\n }\n}\n\nclass DirectoryEditorManager implements DirectoryEditor {\n readonly #access: TemplateDirectoryAccess;\n readonly #listeners = new Set<() => void>();\n\n #files: DirectoryEditorFile[] = [];\n #selectedFile: DirectoryEditorFile | undefined;\n\n constructor(access: TemplateDirectoryAccess) {\n this.#access = access;\n }\n\n get files() {\n return this.#files;\n }\n\n get selectedFile() {\n return this.#selectedFile;\n }\n\n setSelectedFile = (path: string | undefined): void => {\n const prev = this.#selectedFile;\n const next = this.#files.find(file => file.path === path);\n if (prev !== next) {\n this.#selectedFile = next;\n this.#signalUpdate();\n }\n };\n\n get dirty() {\n return this.#files.some(file => file.dirty);\n }\n\n async save(): Promise<void> {\n await Promise.all(this.#files.map(file => file.save()));\n }\n\n async reload(): Promise<void> {\n const selectedPath = this.#selectedFile?.path;\n\n const files = await this.#access.listFiles();\n const fileManagers = await Promise.all(\n files.map(async file => {\n const manager = new DirectoryEditorFileManager(\n file,\n this.#signalUpdate,\n );\n await manager.reload();\n return manager;\n }),\n );\n this.#files.length = 0;\n this.#files.push(...fileManagers);\n\n this.setSelectedFile(selectedPath);\n this.#signalUpdate();\n }\n\n subscribe(listener: () => void): () => void {\n this.#listeners.add(listener);\n return () => {\n this.#listeners.delete(listener);\n };\n }\n\n #signalUpdate = () => {\n this.#listeners.forEach(listener => listener());\n };\n}\n\nconst DirectoryEditorContext = createContext<DirectoryEditor | undefined>(\n undefined,\n);\n\nexport function useDirectoryEditor(): DirectoryEditor | undefined {\n const value = useContext(DirectoryEditorContext);\n const rerender = useRerender();\n\n useEffect(() => value?.subscribe(rerender), [value, rerender]);\n\n return value;\n}\n\ninterface DirectoryEditorProviderProps {\n directory?: TemplateDirectoryAccess;\n children?: ReactNode;\n}\n\nexport function DirectoryEditorProvider(props: DirectoryEditorProviderProps) {\n const { directory } = props;\n\n const [{ result, error }, { execute }] = useAsync(\n async (dir: TemplateDirectoryAccess) => {\n const manager = new DirectoryEditorManager(dir);\n await manager.reload();\n\n const firstYaml = manager.files.find(file => file.path.match(/\\.ya?ml$/));\n if (firstYaml) {\n manager.setSelectedFile(firstYaml.path);\n }\n\n return manager;\n },\n );\n\n useEffect(() => {\n if (directory) {\n execute(directory);\n }\n }, [execute, directory]);\n\n if (error) {\n return <ErrorPanel error={error} />;\n }\n\n return (\n <DirectoryEditorContext.Provider value={result}>\n {props.children}\n </DirectoryEditorContext.Provider>\n );\n}\n"],"names":[],"mappings":";;;;AAwBA,MAAM,WAAW,IAAO,GAAA,IAAA,CAAA;AACxB,MAAM,gBAAmB,GAAA,wCAAA,CAAA;AAmCzB,MAAM,0BAA0D,CAAA;AAAA,EACrD,OAAA,CAAA;AAAA,EACA,aAAA,CAAA;AAAA,EAET,QAAA,CAAA;AAAA,EACA,aAAA,CAAA;AAAA,EAEA,WAAA,CAAY,QAA4B,YAA0B,EAAA;AAChE,IAAA,IAAA,CAAK,OAAU,GAAA,MAAA,CAAA;AACf,IAAA,IAAA,CAAK,aAAgB,GAAA,YAAA,CAAA;AAAA,GACvB;AAAA,EAEA,IAAI,IAAO,GAAA;AACT,IAAA,OAAO,KAAK,OAAQ,CAAA,IAAA,CAAA;AAAA,GACtB;AAAA,EAEA,IAAI,OAAU,GAAA;AACZ,IAAA,OAAO,KAAK,QAAY,IAAA,gBAAA,CAAA;AAAA,GAC1B;AAAA,EAEA,cAAc,OAAuB,EAAA;AACnC,IAAI,IAAA,IAAA,CAAK,aAAa,KAAW,CAAA,EAAA;AAC/B,MAAA,OAAA;AAAA,KACF;AACA,IAAA,IAAA,CAAK,QAAW,GAAA,OAAA,CAAA;AAChB,IAAA,IAAA,CAAK,aAAc,EAAA,CAAA;AAAA,GACrB;AAAA,EAEA,IAAI,KAAQ,GAAA;AACV,IAAO,OAAA,IAAA,CAAK,aAAa,IAAK,CAAA,aAAA,CAAA;AAAA,GAChC;AAAA,EAEA,MAAM,IAAsB,GAAA;AAC1B,IAAI,IAAA,IAAA,CAAK,aAAa,KAAW,CAAA,EAAA;AAC/B,MAAA,MAAM,IAAK,CAAA,OAAA,CAAQ,IAAK,CAAA,IAAA,CAAK,QAAQ,CAAA,CAAA;AACrC,MAAA,IAAA,CAAK,gBAAgB,IAAK,CAAA,QAAA,CAAA;AAC1B,MAAA,IAAA,CAAK,aAAc,EAAA,CAAA;AAAA,KACrB;AAAA,GACF;AAAA,EAEA,MAAM,MAAwB,GAAA;AAC5B,IAAA,MAAM,IAAO,GAAA,MAAM,IAAK,CAAA,OAAA,CAAQ,IAAK,EAAA,CAAA;AACrC,IAAI,IAAA,IAAA,CAAK,OAAO,QAAU,EAAA;AACxB,MAAI,IAAA,IAAA,CAAK,aAAa,KAAW,CAAA,EAAA;AAC/B,QAAA,IAAA,CAAK,QAAW,GAAA,KAAA,CAAA,CAAA;AAChB,QAAA,IAAA,CAAK,aAAgB,GAAA,KAAA,CAAA,CAAA;AACrB,QAAA,IAAA,CAAK,aAAc,EAAA,CAAA;AAAA,OACrB;AACA,MAAA,OAAA;AAAA,KACF;AAEA,IAAM,MAAA,OAAA,GAAU,MAAM,IAAA,CAAK,IAAK,EAAA,CAAA;AAChC,IAAI,IAAA,IAAA,CAAK,aAAa,OAAS,EAAA;AAC7B,MAAA,IAAA,CAAK,QAAW,GAAA,OAAA,CAAA;AAChB,MAAA,IAAA,CAAK,aAAgB,GAAA,OAAA,CAAA;AACrB,MAAA,IAAA,CAAK,aAAc,EAAA,CAAA;AAAA,KACrB;AAAA,GACF;AACF,CAAA;AAEA,MAAM,sBAAkD,CAAA;AAAA,EAC7C,OAAA,CAAA;AAAA,EACA,UAAA,uBAAiB,GAAgB,EAAA,CAAA;AAAA,EAE1C,SAAgC,EAAC,CAAA;AAAA,EACjC,aAAA,CAAA;AAAA,EAEA,YAAY,MAAiC,EAAA;AAC3C,IAAA,IAAA,CAAK,OAAU,GAAA,MAAA,CAAA;AAAA,GACjB;AAAA,EAEA,IAAI,KAAQ,GAAA;AACV,IAAA,OAAO,IAAK,CAAA,MAAA,CAAA;AAAA,GACd;AAAA,EAEA,IAAI,YAAe,GAAA;AACjB,IAAA,OAAO,IAAK,CAAA,aAAA,CAAA;AAAA,GACd;AAAA,EAEA,eAAA,GAAkB,CAAC,IAAmC,KAAA;AACpD,IAAA,MAAM,OAAO,IAAK,CAAA,aAAA,CAAA;AAClB,IAAA,MAAM,OAAO,IAAK,CAAA,MAAA,CAAO,KAAK,CAAQ,IAAA,KAAA,IAAA,CAAK,SAAS,IAAI,CAAA,CAAA;AACxD,IAAA,IAAI,SAAS,IAAM,EAAA;AACjB,MAAA,IAAA,CAAK,aAAgB,GAAA,IAAA,CAAA;AACrB,MAAA,IAAA,CAAK,aAAc,EAAA,CAAA;AAAA,KACrB;AAAA,GACF,CAAA;AAAA,EAEA,IAAI,KAAQ,GAAA;AACV,IAAA,OAAO,IAAK,CAAA,MAAA,CAAO,IAAK,CAAA,CAAA,IAAA,KAAQ,KAAK,KAAK,CAAA,CAAA;AAAA,GAC5C;AAAA,EAEA,MAAM,IAAsB,GAAA;AAC1B,IAAM,MAAA,OAAA,CAAQ,IAAI,IAAK,CAAA,MAAA,CAAO,IAAI,CAAQ,IAAA,KAAA,IAAA,CAAK,IAAK,EAAC,CAAC,CAAA,CAAA;AAAA,GACxD;AAAA,EAEA,MAAM,MAAwB,GAAA;AAC5B,IAAM,MAAA,YAAA,GAAe,KAAK,aAAe,EAAA,IAAA,CAAA;AAEzC,IAAA,MAAM,KAAQ,GAAA,MAAM,IAAK,CAAA,OAAA,CAAQ,SAAU,EAAA,CAAA;AAC3C,IAAM,MAAA,YAAA,GAAe,MAAM,OAAQ,CAAA,GAAA;AAAA,MACjC,KAAA,CAAM,GAAI,CAAA,OAAM,IAAQ,KAAA;AACtB,QAAA,MAAM,UAAU,IAAI,0BAAA;AAAA,UAClB,IAAA;AAAA,UACA,IAAK,CAAA,aAAA;AAAA,SACP,CAAA;AACA,QAAA,MAAM,QAAQ,MAAO,EAAA,CAAA;AACrB,QAAO,OAAA,OAAA,CAAA;AAAA,OACR,CAAA;AAAA,KACH,CAAA;AACA,IAAA,IAAA,CAAK,OAAO,MAAS,GAAA,CAAA,CAAA;AACrB,IAAK,IAAA,CAAA,MAAA,CAAO,IAAK,CAAA,GAAG,YAAY,CAAA,CAAA;AAEhC,IAAA,IAAA,CAAK,gBAAgB,YAAY,CAAA,CAAA;AACjC,IAAA,IAAA,CAAK,aAAc,EAAA,CAAA;AAAA,GACrB;AAAA,EAEA,UAAU,QAAkC,EAAA;AAC1C,IAAK,IAAA,CAAA,UAAA,CAAW,IAAI,QAAQ,CAAA,CAAA;AAC5B,IAAA,OAAO,MAAM;AACX,MAAK,IAAA,CAAA,UAAA,CAAW,OAAO,QAAQ,CAAA,CAAA;AAAA,KACjC,CAAA;AAAA,GACF;AAAA,EAEA,gBAAgB,MAAM;AACpB,IAAA,IAAA,CAAK,UAAW,CAAA,OAAA,CAAQ,CAAY,QAAA,KAAA,QAAA,EAAU,CAAA,CAAA;AAAA,GAChD,CAAA;AACF,CAAA;AAEA,MAAM,sBAAyB,GAAA,aAAA;AAAA,EAC7B,KAAA,CAAA;AACF,CAAA,CAAA;AAEO,SAAS,kBAAkD,GAAA;AAChE,EAAM,MAAA,KAAA,GAAQ,WAAW,sBAAsB,CAAA,CAAA;AAC/C,EAAA,MAAM,WAAW,WAAY,EAAA,CAAA;AAE7B,EAAU,SAAA,CAAA,MAAM,OAAO,SAAU,CAAA,QAAQ,GAAG,CAAC,KAAA,EAAO,QAAQ,CAAC,CAAA,CAAA;AAE7D,EAAO,OAAA,KAAA,CAAA;AACT,CAAA;AAOO,SAAS,wBAAwB,KAAqC,EAAA;AAC3E,EAAM,MAAA,EAAE,WAAc,GAAA,KAAA,CAAA;AAEtB,EAAM,MAAA,CAAC,EAAE,MAAQ,EAAA,KAAA,IAAS,EAAE,OAAA,EAAS,CAAI,GAAA,QAAA;AAAA,IACvC,OAAO,GAAiC,KAAA;AACtC,MAAM,MAAA,OAAA,GAAU,IAAI,sBAAA,CAAuB,GAAG,CAAA,CAAA;AAC9C,MAAA,MAAM,QAAQ,MAAO,EAAA,CAAA;AAErB,MAAM,MAAA,SAAA,GAAY,QAAQ,KAAM,CAAA,IAAA,CAAK,UAAQ,IAAK,CAAA,IAAA,CAAK,KAAM,CAAA,UAAU,CAAC,CAAA,CAAA;AACxE,MAAA,IAAI,SAAW,EAAA;AACb,QAAQ,OAAA,CAAA,eAAA,CAAgB,UAAU,IAAI,CAAA,CAAA;AAAA,OACxC;AAEA,MAAO,OAAA,OAAA,CAAA;AAAA,KACT;AAAA,GACF,CAAA;AAEA,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,SAAW,EAAA;AACb,MAAA,OAAA,CAAQ,SAAS,CAAA,CAAA;AAAA,KACnB;AAAA,GACC,EAAA,CAAC,OAAS,EAAA,SAAS,CAAC,CAAA,CAAA;AAEvB,EAAA,IAAI,KAAO,EAAA;AACT,IAAO,uBAAA,KAAA,CAAA,aAAA,CAAC,cAAW,KAAc,EAAA,CAAA,CAAA;AAAA,GACnC;AAEA,EAAA,2CACG,sBAAuB,CAAA,QAAA,EAAvB,EAAgC,KAAO,EAAA,MAAA,EAAA,EACrC,MAAM,QACT,CAAA,CAAA;AAEJ;;;;"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DryRunContext.esm.js","sources":["../../../../src/alpha/components/TemplateEditorPage/DryRunContext.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 yaml from 'yaml';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { JsonObject } from '@backstage/types';\nimport React, {\n createContext,\n ReactNode,\n useCallback,\n useContext,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport {\n scaffolderApiRef,\n ScaffolderDryRunResponse,\n} from '@backstage/plugin-scaffolder-react';\n\nconst MAX_CONTENT_SIZE = 64 * 1024;\nconst CHUNK_SIZE = 32 * 1024;\n\ninterface DryRunOptions {\n templateContent: string;\n values: JsonObject;\n files: Array<{ path: string; content: string }>;\n}\n\nexport interface DryRunResult extends ScaffolderDryRunResponse {\n id: number;\n}\n\ninterface DryRun {\n results: DryRunResult[];\n selectedResult: DryRunResult | undefined;\n\n selectResult(id: number): void;\n deleteResult(id: number): void;\n execute(options: DryRunOptions): Promise<void>;\n}\n\nconst DryRunContext = createContext<DryRun | undefined>(undefined);\n\ninterface DryRunProviderProps {\n children: ReactNode;\n}\n\nexport function base64EncodeContent(content: string): string {\n if (content.length > MAX_CONTENT_SIZE) {\n return window.btoa('<file too large>');\n }\n\n try {\n return window.btoa(content);\n } catch {\n const decoder = new TextEncoder();\n const buffer = decoder.encode(content);\n\n const chunks = new Array<string>();\n for (let offset = 0; offset < buffer.length; offset += CHUNK_SIZE) {\n chunks.push(\n String.fromCharCode(...buffer.slice(offset, offset + CHUNK_SIZE)),\n );\n }\n return window.btoa(chunks.join(''));\n }\n}\n\nexport function DryRunProvider(props: DryRunProviderProps) {\n const scaffolderApi = useApi(scaffolderApiRef);\n\n const [state, setState] = useState<\n Pick<DryRun, 'results' | 'selectedResult'>\n >({\n results: [],\n selectedResult: undefined,\n });\n const idRef = useRef(1);\n\n const selectResult = useCallback((id: number) => {\n setState(prevState => {\n const result = prevState.results.find(r => r.id === id);\n if (result === prevState.selectedResult) {\n return prevState;\n }\n return {\n results: prevState.results,\n selectedResult: result,\n };\n });\n }, []);\n\n const deleteResult = useCallback((id: number) => {\n setState(prevState => {\n const index = prevState.results.findIndex(r => r.id === id);\n if (index === -1) {\n return prevState;\n }\n const newResults = prevState.results.slice();\n const [deleted] = newResults.splice(index, 1);\n return {\n results: newResults,\n selectedResult:\n prevState.selectedResult?.id === deleted.id\n ? newResults[0]\n : prevState.selectedResult,\n };\n });\n }, []);\n\n const execute = useCallback(\n async (options: DryRunOptions) => {\n if (!scaffolderApi.dryRun) {\n throw new Error('Scaffolder API does not support dry-run');\n }\n\n const parsed = yaml.parse(options.templateContent);\n\n const response = await scaffolderApi.dryRun({\n template: parsed,\n values: options.values,\n secrets: {},\n directoryContents: options.files.map(file => ({\n path: file.path,\n base64Content: base64EncodeContent(file.content),\n })),\n });\n\n const result = {\n ...response,\n id: idRef.current++,\n };\n\n setState(prevState => ({\n results: [...prevState.results, result],\n selectedResult: prevState.selectedResult ?? result,\n }));\n },\n [scaffolderApi],\n );\n\n const dryRun = useMemo(\n () => ({\n ...state,\n selectResult,\n deleteResult,\n execute,\n }),\n [state, selectResult, deleteResult, execute],\n );\n\n return (\n <DryRunContext.Provider value={dryRun}>\n {props.children}\n </DryRunContext.Provider>\n );\n}\n\nexport function useDryRun(): DryRun {\n const value = useContext(DryRunContext);\n if (!value) {\n throw new Error('must be used within a DryRunProvider');\n }\n return value;\n}\n"],"names":[],"mappings":"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"}
@@ -11,7 +11,7 @@ import { useDryRun } from '../DryRunContext.esm.js';
11
11
  import { DryRunResultsList } from './DryRunResultsList.esm.js';
12
12
  import { DryRunResultsView } from './DryRunResultsView.esm.js';
13
13
  import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
14
- import { scaffolderTranslationRef } from '../../../translation.esm.js';
14
+ import { scaffolderTranslationRef } from '../../../../translation.esm.js';
15
15
 
16
16
  const useStyles = makeStyles((theme) => ({
17
17
  header: {
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DryRunResults.esm.js","sources":["../../../../../src/alpha/components/TemplateEditorPage/DryRunResults/DryRunResults.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 Accordion from '@material-ui/core/Accordion';\nimport AccordionDetails from '@material-ui/core/AccordionDetails';\nimport AccordionSummary from '@material-ui/core/AccordionSummary';\nimport Divider from '@material-ui/core/Divider';\nimport { makeStyles } from '@material-ui/core/styles';\nimport Typography from '@material-ui/core/Typography';\nimport ExpandMoreIcon from '@material-ui/icons/ExpandLess';\nimport { usePrevious } from '@react-hookz/web';\nimport React, { useEffect, useState } from 'react';\nimport { useDryRun } from '../DryRunContext';\nimport { DryRunResultsList } from './DryRunResultsList';\nimport { DryRunResultsView } from './DryRunResultsView';\nimport { useTranslationRef } from '@backstage/core-plugin-api/alpha';\nimport { scaffolderTranslationRef } from '../../../../translation';\n\nconst useStyles = makeStyles(theme => ({\n header: {\n height: 48,\n minHeight: 0,\n '&.Mui-expanded': {\n height: 48,\n minHeight: 0,\n },\n },\n content: {\n display: 'grid',\n background: theme.palette.background.default,\n gridTemplateColumns: '180px auto 1fr',\n gridTemplateRows: '1fr',\n padding: 0,\n height: 400,\n },\n}));\n\nexport function DryRunResults() {\n const classes = useStyles();\n const dryRun = useDryRun();\n const [expanded, setExpanded] = useState(false);\n const [hidden, setHidden] = useState(true);\n const { t } = useTranslationRef(scaffolderTranslationRef);\n\n const resultsLength = dryRun.results.length;\n const prevResultsLength = usePrevious(resultsLength);\n useEffect(() => {\n if (prevResultsLength === 0 && resultsLength === 1) {\n setHidden(false);\n setExpanded(true);\n } else if (prevResultsLength === 1 && resultsLength === 0) {\n setExpanded(false);\n }\n }, [prevResultsLength, resultsLength]);\n\n return (\n <>\n <Accordion\n variant=\"outlined\"\n expanded={expanded}\n hidden={resultsLength === 0 && hidden}\n onChange={(_, exp) => setExpanded(exp)}\n onTransitionEnd={() => resultsLength === 0 && setHidden(true)}\n >\n <AccordionSummary\n className={classes.header}\n expandIcon={<ExpandMoreIcon />}\n >\n <Typography>{t('templateEditorPage.dryRunResults.title')}</Typography>\n </AccordionSummary>\n <Divider orientation=\"horizontal\" />\n <AccordionDetails className={classes.content}>\n <DryRunResultsList />\n <Divider orientation=\"horizontal\" />\n <DryRunResultsView />\n </AccordionDetails>\n </Accordion>\n </>\n );\n}\n"],"names":["ExpandMoreIcon"],"mappings":"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"}
@@ -11,9 +11,9 @@ import DeleteIcon from '@material-ui/icons/Delete';
11
11
  import DownloadIcon from '@material-ui/icons/GetApp';
12
12
  import React from 'react';
13
13
  import { useDryRun } from '../DryRunContext.esm.js';
14
- import { downloadBlob } from '../../../lib/download/helpers.esm.js';
14
+ import { downloadBlob } from '../../../../lib/download/helpers.esm.js';
15
15
  import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
16
- import { scaffolderTranslationRef } from '../../../translation.esm.js';
16
+ import { scaffolderTranslationRef } from '../../../../translation.esm.js';
17
17
 
18
18
  const useStyles = makeStyles((theme) => ({
19
19
  root: {
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DryRunResultsList.esm.js","sources":["../../../../../src/alpha/components/TemplateEditorPage/DryRunResults/DryRunResultsList.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 IconButton from '@material-ui/core/IconButton';\nimport List from '@material-ui/core/List';\nimport ListItem from '@material-ui/core/ListItem';\nimport ListItemIcon from '@material-ui/core/ListItemIcon';\nimport ListItemSecondaryAction from '@material-ui/core/ListItemSecondaryAction';\nimport ListItemText from '@material-ui/core/ListItemText';\nimport { makeStyles } from '@material-ui/core/styles';\nimport CancelIcon from '@material-ui/icons/Cancel';\nimport CheckIcon from '@material-ui/icons/Check';\nimport DeleteIcon from '@material-ui/icons/Delete';\nimport DownloadIcon from '@material-ui/icons/GetApp';\nimport React from 'react';\nimport { useDryRun } from '../DryRunContext';\nimport { downloadBlob } from '../../../../lib/download';\nimport { useTranslationRef } from '@backstage/core-plugin-api/alpha';\nimport { scaffolderTranslationRef } from '../../../../translation';\n\nconst useStyles = makeStyles(theme => ({\n root: {\n overflowY: 'auto',\n background: theme.palette.background.default,\n },\n iconSuccess: {\n minWidth: 0,\n marginRight: theme.spacing(1),\n color: theme.palette.status.ok,\n },\n iconFailure: {\n minWidth: 0,\n marginRight: theme.spacing(1),\n color: theme.palette.status.error,\n },\n}));\n\nexport function DryRunResultsList() {\n const classes = useStyles();\n const dryRun = useDryRun();\n const { t } = useTranslationRef(scaffolderTranslationRef);\n\n return (\n <List className={classes.root} dense>\n {dryRun.results.map(result => {\n const failed = result.log.some(l => l.body.status === 'failed');\n let isLoading = false;\n\n async function downloadResult() {\n isLoading = true;\n await downloadDirectoryContents(\n result.directoryContents,\n `dry-run-result-${result.id}.zip`,\n );\n isLoading = false;\n }\n\n return (\n <ListItem\n button\n key={result.id}\n selected={dryRun.selectedResult?.id === result.id}\n onClick={() => dryRun.selectResult(result.id)}\n >\n <ListItemIcon\n className={failed ? classes.iconFailure : classes.iconSuccess}\n >\n {failed ? <CancelIcon /> : <CheckIcon />}\n </ListItemIcon>\n <ListItemText\n primary={t('templateEditorPage.dryRunResultsList.title', {\n resultId: `${result.id}`,\n })}\n />\n <ListItemSecondaryAction>\n <IconButton\n edge=\"end\"\n aria-label=\"download\"\n title={t(\n 'templateEditorPage.dryRunResultsList.downloadButtonTitle',\n )}\n disabled={isLoading}\n onClick={() => downloadResult()}\n >\n <DownloadIcon />\n </IconButton>\n <IconButton\n edge=\"end\"\n aria-label=\"delete\"\n title={t(\n 'templateEditorPage.dryRunResultsList.deleteButtonTitle',\n )}\n onClick={() => dryRun.deleteResult(result.id)}\n >\n <DeleteIcon />\n </IconButton>\n </ListItemSecondaryAction>\n </ListItem>\n );\n })}\n </List>\n );\n}\n\nasync function downloadDirectoryContents(\n directoryContents: {\n path: string;\n base64Content: string;\n executable: boolean;\n }[],\n name: string,\n) {\n const { default: JSZip } = await import('jszip');\n const zip = new JSZip();\n\n for (const d of directoryContents) {\n // Decode text content from base64 to ascii\n const converted = atob(d.base64Content);\n\n // add folder/file to zip\n await zip.file(d.path, converted);\n }\n\n const blob = await zip.generateAsync({ type: 'blob' });\n downloadBlob(blob, name);\n}\n"],"names":["CancelIcon"],"mappings":";;;;;;;;;;;;;;;;;AAiCA,MAAM,SAAA,GAAY,WAAW,CAAU,KAAA,MAAA;AAAA,EACrC,IAAM,EAAA;AAAA,IACJ,SAAW,EAAA,MAAA;AAAA,IACX,UAAA,EAAY,KAAM,CAAA,OAAA,CAAQ,UAAW,CAAA,OAAA;AAAA,GACvC;AAAA,EACA,WAAa,EAAA;AAAA,IACX,QAAU,EAAA,CAAA;AAAA,IACV,WAAA,EAAa,KAAM,CAAA,OAAA,CAAQ,CAAC,CAAA;AAAA,IAC5B,KAAA,EAAO,KAAM,CAAA,OAAA,CAAQ,MAAO,CAAA,EAAA;AAAA,GAC9B;AAAA,EACA,WAAa,EAAA;AAAA,IACX,QAAU,EAAA,CAAA;AAAA,IACV,WAAA,EAAa,KAAM,CAAA,OAAA,CAAQ,CAAC,CAAA;AAAA,IAC5B,KAAA,EAAO,KAAM,CAAA,OAAA,CAAQ,MAAO,CAAA,KAAA;AAAA,GAC9B;AACF,CAAE,CAAA,CAAA,CAAA;AAEK,SAAS,iBAAoB,GAAA;AAClC,EAAA,MAAM,UAAU,SAAU,EAAA,CAAA;AAC1B,EAAA,MAAM,SAAS,SAAU,EAAA,CAAA;AACzB,EAAA,MAAM,EAAE,CAAA,EAAM,GAAA,iBAAA,CAAkB,wBAAwB,CAAA,CAAA;AAExD,EACE,uBAAA,KAAA,CAAA,aAAA,CAAC,IAAK,EAAA,EAAA,SAAA,EAAW,OAAQ,CAAA,IAAA,EAAM,OAAK,IACjC,EAAA,EAAA,MAAA,CAAO,OAAQ,CAAA,GAAA,CAAI,CAAU,MAAA,KAAA;AAC5B,IAAM,MAAA,MAAA,GAAS,OAAO,GAAI,CAAA,IAAA,CAAK,OAAK,CAAE,CAAA,IAAA,CAAK,WAAW,QAAQ,CAAA,CAAA;AAC9D,IAAA,IAAI,SAAY,GAAA,KAAA,CAAA;AAEhB,IAAA,eAAe,cAAiB,GAAA;AAC9B,MAAY,SAAA,GAAA,IAAA,CAAA;AACZ,MAAM,MAAA,yBAAA;AAAA,QACJ,MAAO,CAAA,iBAAA;AAAA,QACP,CAAA,eAAA,EAAkB,OAAO,EAAE,CAAA,IAAA,CAAA;AAAA,OAC7B,CAAA;AACA,MAAY,SAAA,GAAA,KAAA,CAAA;AAAA,KACd;AAEA,IACE,uBAAA,KAAA,CAAA,aAAA;AAAA,MAAC,QAAA;AAAA,MAAA;AAAA,QACC,MAAM,EAAA,IAAA;AAAA,QACN,KAAK,MAAO,CAAA,EAAA;AAAA,QACZ,QAAU,EAAA,MAAA,CAAO,cAAgB,EAAA,EAAA,KAAO,MAAO,CAAA,EAAA;AAAA,QAC/C,OAAS,EAAA,MAAM,MAAO,CAAA,YAAA,CAAa,OAAO,EAAE,CAAA;AAAA,OAAA;AAAA,sBAE5C,KAAA,CAAA,aAAA;AAAA,QAAC,YAAA;AAAA,QAAA;AAAA,UACC,SAAW,EAAA,MAAA,GAAS,OAAQ,CAAA,WAAA,GAAc,OAAQ,CAAA,WAAA;AAAA,SAAA;AAAA,QAEjD,MAAS,mBAAA,KAAA,CAAA,aAAA,CAACA,MAAW,EAAA,IAAA,CAAA,uCAAM,SAAU,EAAA,IAAA,CAAA;AAAA,OACxC;AAAA,sBACA,KAAA,CAAA,aAAA;AAAA,QAAC,YAAA;AAAA,QAAA;AAAA,UACC,OAAA,EAAS,EAAE,4CAA8C,EAAA;AAAA,YACvD,QAAA,EAAU,CAAG,EAAA,MAAA,CAAO,EAAE,CAAA,CAAA;AAAA,WACvB,CAAA;AAAA,SAAA;AAAA,OACH;AAAA,0CACC,uBACC,EAAA,IAAA,kBAAA,KAAA,CAAA,aAAA;AAAA,QAAC,UAAA;AAAA,QAAA;AAAA,UACC,IAAK,EAAA,KAAA;AAAA,UACL,YAAW,EAAA,UAAA;AAAA,UACX,KAAO,EAAA,CAAA;AAAA,YACL,0DAAA;AAAA,WACF;AAAA,UACA,QAAU,EAAA,SAAA;AAAA,UACV,OAAA,EAAS,MAAM,cAAe,EAAA;AAAA,SAAA;AAAA,4CAE7B,YAAa,EAAA,IAAA,CAAA;AAAA,OAEhB,kBAAA,KAAA,CAAA,aAAA;AAAA,QAAC,UAAA;AAAA,QAAA;AAAA,UACC,IAAK,EAAA,KAAA;AAAA,UACL,YAAW,EAAA,QAAA;AAAA,UACX,KAAO,EAAA,CAAA;AAAA,YACL,wDAAA;AAAA,WACF;AAAA,UACA,OAAS,EAAA,MAAM,MAAO,CAAA,YAAA,CAAa,OAAO,EAAE,CAAA;AAAA,SAAA;AAAA,4CAE3C,UAAW,EAAA,IAAA,CAAA;AAAA,OAEhB,CAAA;AAAA,KACF,CAAA;AAAA,GAEH,CACH,CAAA,CAAA;AAEJ,CAAA;AAEA,eAAe,yBAAA,CACb,mBAKA,IACA,EAAA;AACA,EAAA,MAAM,EAAE,OAAS,EAAA,KAAA,EAAU,GAAA,MAAM,OAAO,OAAO,CAAA,CAAA;AAC/C,EAAM,MAAA,GAAA,GAAM,IAAI,KAAM,EAAA,CAAA;AAEtB,EAAA,KAAA,MAAW,KAAK,iBAAmB,EAAA;AAEjC,IAAM,MAAA,SAAA,GAAY,IAAK,CAAA,CAAA,CAAE,aAAa,CAAA,CAAA;AAGtC,IAAA,MAAM,GAAI,CAAA,IAAA,CAAK,CAAE,CAAA,IAAA,EAAM,SAAS,CAAA,CAAA;AAAA,GAClC;AAEA,EAAA,MAAM,OAAO,MAAM,GAAA,CAAI,cAAc,EAAE,IAAA,EAAM,QAAQ,CAAA,CAAA;AACrD,EAAA,YAAA,CAAa,MAAM,IAAI,CAAA,CAAA;AACzB;;;;"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DryRunResultsSplitView.esm.js","sources":["../../../../../src/alpha/components/TemplateEditorPage/DryRunResults/DryRunResultsSplitView.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 { makeStyles } from '@material-ui/core/styles';\nimport Divider from '@material-ui/core/Divider';\nimport React, { Children, ReactNode } from 'react';\nimport classNames from 'classnames';\n\nconst useStyles = makeStyles(theme => ({\n root: {\n display: 'grid',\n gridTemplateColumns: '280px auto 3fr',\n gridTemplateRows: '1fr',\n },\n child: {\n overflowY: 'auto',\n height: '100%',\n minHeight: 0,\n },\n firstChild: {\n background: theme.palette.background.paper,\n },\n}));\n\nexport function DryRunResultsSplitView(props: { children: ReactNode }) {\n const classes = useStyles();\n const childArray = Children.toArray(props.children);\n\n if (childArray.length !== 2) {\n throw new Error('must have exactly 2 children');\n }\n\n return (\n <div className={classes.root}>\n <div className={classNames(classes.child, classes.firstChild)}>\n {childArray[0]}\n </div>\n <Divider orientation=\"horizontal\" />\n <div className={classes.child}>{childArray[1]}</div>\n </div>\n );\n}\n"],"names":[],"mappings":";;;;;AAqBA,MAAM,SAAA,GAAY,WAAW,CAAU,KAAA,MAAA;AAAA,EACrC,IAAM,EAAA;AAAA,IACJ,OAAS,EAAA,MAAA;AAAA,IACT,mBAAqB,EAAA,gBAAA;AAAA,IACrB,gBAAkB,EAAA,KAAA;AAAA,GACpB;AAAA,EACA,KAAO,EAAA;AAAA,IACL,SAAW,EAAA,MAAA;AAAA,IACX,MAAQ,EAAA,MAAA;AAAA,IACR,SAAW,EAAA,CAAA;AAAA,GACb;AAAA,EACA,UAAY,EAAA;AAAA,IACV,UAAA,EAAY,KAAM,CAAA,OAAA,CAAQ,UAAW,CAAA,KAAA;AAAA,GACvC;AACF,CAAE,CAAA,CAAA,CAAA;AAEK,SAAS,uBAAuB,KAAgC,EAAA;AACrE,EAAA,MAAM,UAAU,SAAU,EAAA,CAAA;AAC1B,EAAA,MAAM,UAAa,GAAA,QAAA,CAAS,OAAQ,CAAA,KAAA,CAAM,QAAQ,CAAA,CAAA;AAElD,EAAI,IAAA,UAAA,CAAW,WAAW,CAAG,EAAA;AAC3B,IAAM,MAAA,IAAI,MAAM,8BAA8B,CAAA,CAAA;AAAA,GAChD;AAEA,EAAA,uBACG,KAAA,CAAA,aAAA,CAAA,KAAA,EAAA,EAAI,SAAW,EAAA,OAAA,CAAQ,IACtB,EAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,KAAI,EAAA,EAAA,SAAA,EAAW,UAAW,CAAA,OAAA,CAAQ,KAAO,EAAA,OAAA,CAAQ,UAAU,CACzD,EAAA,EAAA,UAAA,CAAW,CAAC,CACf,CACA,kBAAA,KAAA,CAAA,aAAA,CAAC,OAAQ,EAAA,EAAA,WAAA,EAAY,cAAa,CAClC,kBAAA,KAAA,CAAA,aAAA,CAAC,KAAI,EAAA,EAAA,SAAA,EAAW,OAAQ,CAAA,KAAA,EAAA,EAAQ,UAAW,CAAA,CAAC,CAAE,CAChD,CAAA,CAAA;AAEJ;;;;"}