@backstage/plugin-scaffolder 1.4.0-next.3 → 1.5.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.
@@ -51,11 +51,15 @@ class ScaffolderClient {
51
51
  }
52
52
  async listTasks(options) {
53
53
  if (!this.identityApi) {
54
- throw new Error("IdentityApi is not available in the ScaffolderClient, please pass through the IdentityApi to the ScaffolderClient constructor in order to use the listTasks method");
54
+ throw new Error(
55
+ "IdentityApi is not available in the ScaffolderClient, please pass through the IdentityApi to the ScaffolderClient constructor in order to use the listTasks method"
56
+ );
55
57
  }
56
58
  const baseUrl = await this.discoveryApi.getBaseUrl("scaffolder");
57
59
  const { userEntityRef } = await this.identityApi.getBackstageIdentity();
58
- const query = qs.stringify(options.filterByOwnership === "owned" ? { createdBy: userEntityRef } : {});
60
+ const query = qs.stringify(
61
+ options.filterByOwnership === "owned" ? { createdBy: userEntityRef } : {}
62
+ );
59
63
  const response = await this.fetchApi.fetch(`${baseUrl}/v2/tasks?${query}`);
60
64
  if (!response.ok) {
61
65
  throw await ResponseError.fromResponse(response);
@@ -65,7 +69,9 @@ class ScaffolderClient {
65
69
  async getIntegrationsList(options) {
66
70
  const integrations = [
67
71
  ...this.scmIntegrationsApi.azure.list(),
68
- ...this.scmIntegrationsApi.bitbucket.list().filter((item) => !this.scmIntegrationsApi.bitbucketCloud.byHost(item.config.host) && !this.scmIntegrationsApi.bitbucketServer.byHost(item.config.host)),
72
+ ...this.scmIntegrationsApi.bitbucket.list().filter(
73
+ (item) => !this.scmIntegrationsApi.bitbucketCloud.byHost(item.config.host) && !this.scmIntegrationsApi.bitbucketServer.byHost(item.config.host)
74
+ ),
69
75
  ...this.scmIntegrationsApi.bitbucketCloud.list(),
70
76
  ...this.scmIntegrationsApi.bitbucketServer.list(),
71
77
  ...this.scmIntegrationsApi.gerrit.list(),
@@ -155,35 +161,40 @@ class ScaffolderClient {
155
161
  if (after !== void 0) {
156
162
  params.set("after", String(Number(after)));
157
163
  }
158
- this.discoveryApi.getBaseUrl("scaffolder").then((baseUrl) => {
159
- const url = `${baseUrl}/v2/tasks/${encodeURIComponent(taskId)}/eventstream`;
160
- const eventSource = new EventSource(url, { withCredentials: true });
161
- eventSource.addEventListener("log", (event) => {
162
- if (event.data) {
163
- try {
164
- subscriber.next(JSON.parse(event.data));
165
- } catch (ex) {
166
- subscriber.error(ex);
164
+ this.discoveryApi.getBaseUrl("scaffolder").then(
165
+ (baseUrl) => {
166
+ const url = `${baseUrl}/v2/tasks/${encodeURIComponent(
167
+ taskId
168
+ )}/eventstream`;
169
+ const eventSource = new EventSource(url, { withCredentials: true });
170
+ eventSource.addEventListener("log", (event) => {
171
+ if (event.data) {
172
+ try {
173
+ subscriber.next(JSON.parse(event.data));
174
+ } catch (ex) {
175
+ subscriber.error(ex);
176
+ }
167
177
  }
168
- }
169
- });
170
- eventSource.addEventListener("completion", (event) => {
171
- if (event.data) {
172
- try {
173
- subscriber.next(JSON.parse(event.data));
174
- } catch (ex) {
175
- subscriber.error(ex);
178
+ });
179
+ eventSource.addEventListener("completion", (event) => {
180
+ if (event.data) {
181
+ try {
182
+ subscriber.next(JSON.parse(event.data));
183
+ } catch (ex) {
184
+ subscriber.error(ex);
185
+ }
176
186
  }
177
- }
178
- eventSource.close();
179
- subscriber.complete();
180
- });
181
- eventSource.addEventListener("error", (event) => {
182
- subscriber.error(event);
183
- });
184
- }, (error) => {
185
- subscriber.error(error);
186
- });
187
+ eventSource.close();
188
+ subscriber.complete();
189
+ });
190
+ eventSource.addEventListener("error", (event) => {
191
+ subscriber.error(event);
192
+ });
193
+ },
194
+ (error) => {
195
+ subscriber.error(error);
196
+ }
197
+ );
187
198
  });
188
199
  }
189
200
  streamLogsPolling({
@@ -194,7 +205,9 @@ class ScaffolderClient {
194
205
  return new ObservableImpl((subscriber) => {
195
206
  this.discoveryApi.getBaseUrl("scaffolder").then(async (baseUrl) => {
196
207
  while (!subscriber.closed) {
197
- const url = `${baseUrl}/v2/tasks/${encodeURIComponent(taskId)}/events?${qs.stringify({ after })}`;
208
+ const url = `${baseUrl}/v2/tasks/${encodeURIComponent(
209
+ taskId
210
+ )}/events?${qs.stringify({ after })}`;
198
211
  const response = await this.fetchApi.fetch(url);
199
212
  if (!response.ok) {
200
213
  await new Promise((resolve) => setTimeout(resolve, 1e3));
@@ -237,11 +250,20 @@ const EntityPicker = (props) => {
237
250
  const allowedKinds = (_a = uiSchema["ui:options"]) == null ? void 0 : _a.allowedKinds;
238
251
  const defaultKind = (_b = uiSchema["ui:options"]) == null ? void 0 : _b.defaultKind;
239
252
  const catalogApi = useApi(catalogApiRef);
240
- const { value: entities, loading } = useAsync(() => catalogApi.getEntities(allowedKinds ? { filter: { kind: allowedKinds } } : void 0));
241
- const entityRefs = entities == null ? void 0 : entities.items.map((e) => humanizeEntityRef(e, { defaultKind }));
242
- const onSelect = useCallback((_, value) => {
243
- onChange(value || "");
244
- }, [onChange]);
253
+ const { value: entities, loading } = useAsync(
254
+ () => catalogApi.getEntities(
255
+ allowedKinds ? { filter: { kind: allowedKinds } } : void 0
256
+ )
257
+ );
258
+ const entityRefs = entities == null ? void 0 : entities.items.map(
259
+ (e) => humanizeEntityRef(e, { defaultKind })
260
+ );
261
+ const onSelect = useCallback(
262
+ (_, value) => {
263
+ onChange(value || "");
264
+ },
265
+ [onChange]
266
+ );
245
267
  useEffect(() => {
246
268
  if ((entityRefs == null ? void 0 : entityRefs.length) === 1) {
247
269
  onChange(entityRefs[0]);
@@ -263,8 +285,9 @@ const EntityPicker = (props) => {
263
285
  renderInput: (params) => /* @__PURE__ */ React.createElement(TextField, {
264
286
  ...params,
265
287
  label: title,
266
- margin: "normal",
288
+ margin: "dense",
267
289
  helperText: description,
290
+ FormHelperTextProps: { margin: "dense", style: { marginLeft: 0 } },
268
291
  variant: "outlined",
269
292
  required,
270
293
  InputProps: params.InputProps
@@ -299,7 +322,9 @@ const EntityNamePicker = (props) => {
299
322
 
300
323
  const entityNamePickerValidation = (value, validation) => {
301
324
  if (!KubernetesValidatorFunctions.isValidObjectName(value)) {
302
- validation.addError("must start and end with an alphanumeric character, and contain only alphanumeric characters, hyphens, underscores, and periods. Maximum length is 63 characters.");
325
+ validation.addError(
326
+ "must start and end with an alphanumeric character, and contain only alphanumeric characters, hyphens, underscores, and periods. Maximum length is 63 characters."
327
+ );
303
328
  }
304
329
  };
305
330
 
@@ -318,10 +343,12 @@ const EntityTagsPicker = (props) => {
318
343
  }
319
344
  const entities = await catalogApi.getEntities(tagsRequest);
320
345
  return [
321
- ...new Set(entities.items.flatMap((e) => {
322
- var _a2;
323
- return (_a2 = e.metadata) == null ? void 0 : _a2.tags;
324
- }).filter(Boolean))
346
+ ...new Set(
347
+ entities.items.flatMap((e) => {
348
+ var _a2;
349
+ return (_a2 = e.metadata) == null ? void 0 : _a2.tags;
350
+ }).filter(Boolean)
351
+ )
325
352
  ].sort();
326
353
  });
327
354
  const setTags = (_, values) => {
@@ -363,7 +390,7 @@ const EntityTagsPicker = (props) => {
363
390
  };
364
391
 
365
392
  const OwnerPicker = (props) => {
366
- var _a;
393
+ var _a, _b, _c;
367
394
  const {
368
395
  schema: { title = "Owner", description = "The owner of the component" },
369
396
  uiSchema,
@@ -376,7 +403,8 @@ const OwnerPicker = (props) => {
376
403
  "Group",
377
404
  "User"
378
405
  ],
379
- defaultKind: "Group"
406
+ defaultKind: "Group",
407
+ allowArbitraryValues: (_c = (_b = uiSchema["ui:options"]) == null ? void 0 : _b.allowArbitraryValues) != null ? _c : true
380
408
  }
381
409
  };
382
410
  return /* @__PURE__ */ React.createElement(EntityPicker, {
@@ -463,19 +491,27 @@ const AzureRepoPicker = (props) => {
463
491
  };
464
492
 
465
493
  const BitbucketRepoPicker = (props) => {
466
- const { onChange, rawErrors, state } = props;
494
+ const { allowedOwners = [], onChange, rawErrors, state } = props;
467
495
  const { host, workspace, project } = state;
496
+ const ownerItems = allowedOwners ? allowedOwners == null ? void 0 : allowedOwners.map((i) => ({ label: i, value: i })) : [];
468
497
  return /* @__PURE__ */ React.createElement(React.Fragment, null, host === "bitbucket.org" && /* @__PURE__ */ React.createElement(FormControl, {
469
498
  margin: "normal",
470
499
  required: true,
471
500
  error: (rawErrors == null ? void 0 : rawErrors.length) > 0 && !workspace
472
- }, /* @__PURE__ */ React.createElement(InputLabel, {
501
+ }, (allowedOwners == null ? void 0 : allowedOwners.length) ? /* @__PURE__ */ React.createElement(Select, {
502
+ native: true,
503
+ label: "Allowed Workspaces",
504
+ onChange: (s) => onChange({ workspace: String(Array.isArray(s) ? s[0] : s) }),
505
+ disabled: allowedOwners.length === 1,
506
+ selected: workspace,
507
+ items: ownerItems
508
+ }) : /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(InputLabel, {
473
509
  htmlFor: "workspaceInput"
474
510
  }, "Workspace"), /* @__PURE__ */ React.createElement(Input, {
475
511
  id: "workspaceInput",
476
512
  onChange: (e) => onChange({ workspace: e.target.value }),
477
513
  value: workspace
478
- }), /* @__PURE__ */ React.createElement(FormHelperText, null, "The Organization that this repo will belong to")), /* @__PURE__ */ React.createElement(FormControl, {
514
+ })), /* @__PURE__ */ React.createElement(FormHelperText, null, "The Organization that this repo will belong to")), /* @__PURE__ */ React.createElement(FormControl, {
479
515
  margin: "normal",
480
516
  required: true,
481
517
  error: (rawErrors == null ? void 0 : rawErrors.length) > 0 && !project
@@ -493,7 +529,6 @@ const GerritRepoPicker = (props) => {
493
529
  const { workspace, owner } = state;
494
530
  return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(FormControl, {
495
531
  margin: "normal",
496
- required: true,
497
532
  error: (rawErrors == null ? void 0 : rawErrors.length) > 0 && !workspace
498
533
  }, /* @__PURE__ */ React.createElement(InputLabel, {
499
534
  htmlFor: "ownerInput"
@@ -501,7 +536,7 @@ const GerritRepoPicker = (props) => {
501
536
  id: "ownerInput",
502
537
  onChange: (e) => onChange({ owner: e.target.value }),
503
538
  value: owner
504
- }), /* @__PURE__ */ React.createElement(FormHelperText, null, "The owner of the project")), /* @__PURE__ */ React.createElement(FormControl, {
539
+ }), /* @__PURE__ */ React.createElement(FormHelperText, null, "The owner of the project (optional)")), /* @__PURE__ */ React.createElement(FormControl, {
505
540
  margin: "normal",
506
541
  required: true,
507
542
  error: (rawErrors == null ? void 0 : rawErrors.length) > 0 && !workspace
@@ -517,11 +552,13 @@ const GerritRepoPicker = (props) => {
517
552
  const RepoUrlPickerHost = (props) => {
518
553
  const { host, hosts, onChange, rawErrors } = props;
519
554
  const scaffolderApi = useApi(scaffolderApiRef);
520
- const { value: { integrations } = { integrations: [] }, loading } = useAsync(async () => {
521
- return await scaffolderApi.getIntegrationsList({
522
- allowedHosts: hosts != null ? hosts : []
523
- });
524
- });
555
+ const { value: { integrations } = { integrations: [] }, loading } = useAsync(
556
+ async () => {
557
+ return await scaffolderApi.getIntegrationsList({
558
+ allowedHosts: hosts != null ? hosts : []
559
+ });
560
+ }
561
+ );
525
562
  useEffect(() => {
526
563
  if (!host) {
527
564
  if (hosts == null ? void 0 : hosts.length) {
@@ -624,7 +661,9 @@ function parseRepoPickerUrl(url) {
624
661
  return { host, owner, repoName, organization, workspace, project };
625
662
  }
626
663
 
627
- const SecretsContext = createContext(void 0);
664
+ const SecretsContext = createContext(
665
+ void 0
666
+ );
628
667
  const SecretsContextProvider = ({ children }) => {
629
668
  const [secrets, setSecrets] = useState({});
630
669
  return /* @__PURE__ */ React.createElement(SecretsContext.Provider, {
@@ -634,34 +673,50 @@ const SecretsContextProvider = ({ children }) => {
634
673
  const useTemplateSecrets = () => {
635
674
  const value = useContext(SecretsContext);
636
675
  if (!value) {
637
- throw new Error("useTemplateSecrets must be used within a SecretsContextProvider");
676
+ throw new Error(
677
+ "useTemplateSecrets must be used within a SecretsContextProvider"
678
+ );
638
679
  }
639
680
  const { setSecrets: updateSecrets } = value;
640
- const setSecrets = useCallback((input) => {
641
- updateSecrets((currentSecrets) => ({ ...currentSecrets, ...input }));
642
- }, [updateSecrets]);
681
+ const setSecrets = useCallback(
682
+ (input) => {
683
+ updateSecrets((currentSecrets) => ({ ...currentSecrets, ...input }));
684
+ },
685
+ [updateSecrets]
686
+ );
643
687
  return { setSecrets };
644
688
  };
645
689
 
646
690
  const RepoUrlPicker = (props) => {
647
691
  var _a, _b;
648
692
  const { uiSchema, onChange, rawErrors, formData } = props;
649
- const [state, setState] = useState(parseRepoPickerUrl(formData));
693
+ const [state, setState] = useState(
694
+ parseRepoPickerUrl(formData)
695
+ );
650
696
  const integrationApi = useApi(scmIntegrationsApiRef);
651
697
  const scmAuthApi = useApi(scmAuthApiRef);
652
698
  const { setSecrets } = useTemplateSecrets();
653
- const allowedHosts = useMemo(() => {
654
- var _a2, _b2;
655
- return (_b2 = (_a2 = uiSchema == null ? void 0 : uiSchema["ui:options"]) == null ? void 0 : _a2.allowedHosts) != null ? _b2 : [];
656
- }, [uiSchema]);
657
- const allowedOwners = useMemo(() => {
658
- var _a2, _b2;
659
- return (_b2 = (_a2 = uiSchema == null ? void 0 : uiSchema["ui:options"]) == null ? void 0 : _a2.allowedOwners) != null ? _b2 : [];
660
- }, [uiSchema]);
661
- const allowedRepos = useMemo(() => {
662
- var _a2, _b2;
663
- return (_b2 = (_a2 = uiSchema == null ? void 0 : uiSchema["ui:options"]) == null ? void 0 : _a2.allowedRepos) != null ? _b2 : [];
664
- }, [uiSchema]);
699
+ const allowedHosts = useMemo(
700
+ () => {
701
+ var _a2, _b2;
702
+ return (_b2 = (_a2 = uiSchema == null ? void 0 : uiSchema["ui:options"]) == null ? void 0 : _a2.allowedHosts) != null ? _b2 : [];
703
+ },
704
+ [uiSchema]
705
+ );
706
+ const allowedOwners = useMemo(
707
+ () => {
708
+ var _a2, _b2;
709
+ return (_b2 = (_a2 = uiSchema == null ? void 0 : uiSchema["ui:options"]) == null ? void 0 : _a2.allowedOwners) != null ? _b2 : [];
710
+ },
711
+ [uiSchema]
712
+ );
713
+ const allowedRepos = useMemo(
714
+ () => {
715
+ var _a2, _b2;
716
+ return (_b2 = (_a2 = uiSchema == null ? void 0 : uiSchema["ui:options"]) == null ? void 0 : _a2.allowedRepos) != null ? _b2 : [];
717
+ },
718
+ [uiSchema]
719
+ );
665
720
  useEffect(() => {
666
721
  onChange(serializeRepoPickerUrl(state));
667
722
  }, [state, onChange]);
@@ -675,29 +730,36 @@ const RepoUrlPicker = (props) => {
675
730
  setState((prevState) => ({ ...prevState, repoName: allowedRepos[0] }));
676
731
  }
677
732
  }, [setState, allowedRepos]);
678
- const updateLocalState = useCallback((newState) => {
679
- setState((prevState) => ({ ...prevState, ...newState }));
680
- }, [setState]);
681
- useDebounce(async () => {
682
- var _a2;
683
- const { requestUserCredentials } = (_a2 = uiSchema == null ? void 0 : uiSchema["ui:options"]) != null ? _a2 : {};
684
- if (!requestUserCredentials || !(state.host && state.owner && state.repoName)) {
685
- return;
686
- }
687
- const [host, owner, repoName] = [
688
- state.host,
689
- state.owner,
690
- state.repoName
691
- ].map(encodeURIComponent);
692
- const { token } = await scmAuthApi.getCredentials({
693
- url: `https://${host}/${owner}/${repoName}`,
694
- additionalScope: {
695
- repoWrite: true,
696
- customScopes: requestUserCredentials.additionalScopes
733
+ const updateLocalState = useCallback(
734
+ (newState) => {
735
+ setState((prevState) => ({ ...prevState, ...newState }));
736
+ },
737
+ [setState]
738
+ );
739
+ useDebounce(
740
+ async () => {
741
+ var _a2;
742
+ const { requestUserCredentials } = (_a2 = uiSchema == null ? void 0 : uiSchema["ui:options"]) != null ? _a2 : {};
743
+ if (!requestUserCredentials || !(state.host && state.owner && state.repoName)) {
744
+ return;
697
745
  }
698
- });
699
- setSecrets({ [requestUserCredentials.secretsKey]: token });
700
- }, 500, [state, uiSchema]);
746
+ const [host, owner, repoName] = [
747
+ state.host,
748
+ state.owner,
749
+ state.repoName
750
+ ].map(encodeURIComponent);
751
+ const { token } = await scmAuthApi.getCredentials({
752
+ url: `https://${host}/${owner}/${repoName}`,
753
+ additionalScope: {
754
+ repoWrite: true,
755
+ customScopes: requestUserCredentials.additionalScopes
756
+ }
757
+ });
758
+ setSecrets({ [requestUserCredentials.secretsKey]: token });
759
+ },
760
+ 500,
761
+ [state, uiSchema]
762
+ );
701
763
  const hostType = (_b = state.host && ((_a = integrationApi.byHost(state.host)) == null ? void 0 : _a.type)) != null ? _b : null;
702
764
  return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(RepoUrlPickerHost, {
703
765
  host: state.host,
@@ -715,6 +777,7 @@ const RepoUrlPicker = (props) => {
715
777
  state,
716
778
  onChange: updateLocalState
717
779
  }), hostType === "bitbucket" && /* @__PURE__ */ React.createElement(BitbucketRepoPicker, {
780
+ allowedOwners,
718
781
  rawErrors,
719
782
  state,
720
783
  onChange: updateLocalState
@@ -735,27 +798,37 @@ const RepoUrlPicker = (props) => {
735
798
  };
736
799
 
737
800
  const repoPickerValidation = (value, validation, context) => {
738
- var _a;
801
+ var _a, _b;
739
802
  try {
740
803
  const { host, searchParams } = new URL(`https://${value}`);
741
804
  const integrationApi = context.apiHolder.get(scmIntegrationsApiRef);
742
805
  if (!host) {
743
- validation.addError("Incomplete repository location provided, host not provided");
806
+ validation.addError(
807
+ "Incomplete repository location provided, host not provided"
808
+ );
744
809
  } else {
745
810
  if (((_a = integrationApi == null ? void 0 : integrationApi.byHost(host)) == null ? void 0 : _a.type) === "bitbucket") {
746
811
  if (host === "bitbucket.org" && !searchParams.get("workspace")) {
747
- validation.addError("Incomplete repository location provided, workspace not provided");
812
+ validation.addError(
813
+ "Incomplete repository location provided, workspace not provided"
814
+ );
748
815
  }
749
816
  if (!searchParams.get("project")) {
750
- validation.addError("Incomplete repository location provided, project not provided");
817
+ validation.addError(
818
+ "Incomplete repository location provided, project not provided"
819
+ );
751
820
  }
752
- } else {
821
+ } else if (((_b = integrationApi == null ? void 0 : integrationApi.byHost(host)) == null ? void 0 : _b.type) !== "gerrit") {
753
822
  if (!searchParams.get("owner")) {
754
- validation.addError("Incomplete repository location provided, owner not provided");
823
+ validation.addError(
824
+ "Incomplete repository location provided, owner not provided"
825
+ );
755
826
  }
756
827
  }
757
828
  if (!searchParams.get("repo")) {
758
- validation.addError("Incomplete repository location provided, repo not provided");
829
+ validation.addError(
830
+ "Incomplete repository location provided, repo not provided"
831
+ );
759
832
  }
760
833
  }
761
834
  } catch {
@@ -811,16 +884,18 @@ function useOwnedEntities(allowedKinds) {
811
884
  const { loading, value: refs } = useAsync(async () => {
812
885
  const identity = await identityApi.getBackstageIdentity();
813
886
  const identityRefs = identity.ownershipEntityRefs;
814
- const catalogs = await catalogApi.getEntities(allowedKinds ? {
815
- filter: {
816
- kind: allowedKinds,
817
- [`relations.${RELATION_OWNED_BY}`]: identityRefs || []
818
- }
819
- } : {
820
- filter: {
821
- [`relations.${RELATION_OWNED_BY}`]: identityRefs || []
887
+ const catalogs = await catalogApi.getEntities(
888
+ allowedKinds ? {
889
+ filter: {
890
+ kind: allowedKinds,
891
+ [`relations.${RELATION_OWNED_BY}`]: identityRefs || []
892
+ }
893
+ } : {
894
+ filter: {
895
+ [`relations.${RELATION_OWNED_BY}`]: identityRefs || []
896
+ }
822
897
  }
823
- });
898
+ );
824
899
  return catalogs;
825
900
  }, []);
826
901
  const ownedEntities = useMemo(() => {
@@ -835,13 +910,21 @@ function createScaffolderFieldExtension(options) {
835
910
  return {
836
911
  expose() {
837
912
  const FieldExtensionDataHolder = () => null;
838
- attachComponentData(FieldExtensionDataHolder, FIELD_EXTENSION_KEY, options);
913
+ attachComponentData(
914
+ FieldExtensionDataHolder,
915
+ FIELD_EXTENSION_KEY,
916
+ options
917
+ );
839
918
  return FieldExtensionDataHolder;
840
919
  }
841
920
  };
842
921
  }
843
922
  const ScaffolderFieldExtensions = () => null;
844
- attachComponentData(ScaffolderFieldExtensions, FIELD_EXTENSION_WRAPPER_KEY, true);
923
+ attachComponentData(
924
+ ScaffolderFieldExtensions,
925
+ FIELD_EXTENSION_WRAPPER_KEY,
926
+ true
927
+ );
845
928
 
846
929
  const registerComponentRouteRef = createExternalRouteRef({
847
930
  id: "register-component",
@@ -855,11 +938,19 @@ const legacySelectedTemplateRouteRef = createSubRouteRef({
855
938
  parent: rootRouteRef,
856
939
  path: "/templates/:templateName"
857
940
  });
941
+ const nextRouteRef = createRouteRef({
942
+ id: "scaffolder/next"
943
+ });
858
944
  const selectedTemplateRouteRef = createSubRouteRef({
859
945
  id: "scaffolder/selected-template",
860
946
  parent: rootRouteRef,
861
947
  path: "/templates/:namespace/:templateName"
862
948
  });
949
+ const nextSelectedTemplateRouteRef = createSubRouteRef({
950
+ id: "scaffolder/next/selected-template",
951
+ parent: nextRouteRef,
952
+ path: "/templates/:namespace/:templateName"
953
+ });
863
954
  const scaffolderTaskRouteRef = createSubRouteRef({
864
955
  id: "scaffolder/task",
865
956
  parent: rootRouteRef,
@@ -907,42 +998,58 @@ const scaffolderPlugin = createPlugin({
907
998
  registerComponent: registerComponentRouteRef
908
999
  }
909
1000
  });
910
- const EntityPickerFieldExtension = scaffolderPlugin.provide(createScaffolderFieldExtension({
911
- component: EntityPicker,
912
- name: "EntityPicker"
913
- }));
914
- const EntityNamePickerFieldExtension = scaffolderPlugin.provide(createScaffolderFieldExtension({
915
- component: EntityNamePicker,
916
- name: "EntityNamePicker",
917
- validation: entityNamePickerValidation
918
- }));
919
- const RepoUrlPickerFieldExtension = scaffolderPlugin.provide(createScaffolderFieldExtension({
920
- component: RepoUrlPicker,
921
- name: "RepoUrlPicker",
922
- validation: repoPickerValidation
923
- }));
924
- const OwnerPickerFieldExtension = scaffolderPlugin.provide(createScaffolderFieldExtension({
925
- component: OwnerPicker,
926
- name: "OwnerPicker"
927
- }));
928
- const ScaffolderPage = scaffolderPlugin.provide(createRoutableExtension({
929
- name: "ScaffolderPage",
930
- component: () => import('./Router-02ff57b3.esm.js').then((m) => m.Router),
931
- mountPoint: rootRouteRef
932
- }));
933
- const OwnedEntityPickerFieldExtension = scaffolderPlugin.provide(createScaffolderFieldExtension({
934
- component: OwnedEntityPicker,
935
- name: "OwnedEntityPicker"
936
- }));
937
- const EntityTagsPickerFieldExtension = scaffolderPlugin.provide(createScaffolderFieldExtension({
938
- component: EntityTagsPicker,
939
- name: "EntityTagsPicker"
940
- }));
941
- const NextScaffolderPage = scaffolderPlugin.provide(createRoutableExtension({
942
- name: "NextScaffolderPage",
943
- component: () => import('./index-4a5b6a07.esm.js').then((m) => m.Router),
944
- mountPoint: rootRouteRef
945
- }));
1001
+ const EntityPickerFieldExtension = scaffolderPlugin.provide(
1002
+ createScaffolderFieldExtension({
1003
+ component: EntityPicker,
1004
+ name: "EntityPicker"
1005
+ })
1006
+ );
1007
+ const EntityNamePickerFieldExtension = scaffolderPlugin.provide(
1008
+ createScaffolderFieldExtension({
1009
+ component: EntityNamePicker,
1010
+ name: "EntityNamePicker",
1011
+ validation: entityNamePickerValidation
1012
+ })
1013
+ );
1014
+ const RepoUrlPickerFieldExtension = scaffolderPlugin.provide(
1015
+ createScaffolderFieldExtension({
1016
+ component: RepoUrlPicker,
1017
+ name: "RepoUrlPicker",
1018
+ validation: repoPickerValidation
1019
+ })
1020
+ );
1021
+ const OwnerPickerFieldExtension = scaffolderPlugin.provide(
1022
+ createScaffolderFieldExtension({
1023
+ component: OwnerPicker,
1024
+ name: "OwnerPicker"
1025
+ })
1026
+ );
1027
+ const ScaffolderPage = scaffolderPlugin.provide(
1028
+ createRoutableExtension({
1029
+ name: "ScaffolderPage",
1030
+ component: () => import('./Router-fa1fcf0c.esm.js').then((m) => m.Router),
1031
+ mountPoint: rootRouteRef
1032
+ })
1033
+ );
1034
+ const OwnedEntityPickerFieldExtension = scaffolderPlugin.provide(
1035
+ createScaffolderFieldExtension({
1036
+ component: OwnedEntityPicker,
1037
+ name: "OwnedEntityPicker"
1038
+ })
1039
+ );
1040
+ const EntityTagsPickerFieldExtension = scaffolderPlugin.provide(
1041
+ createScaffolderFieldExtension({
1042
+ component: EntityTagsPicker,
1043
+ name: "EntityTagsPicker"
1044
+ })
1045
+ );
1046
+ const NextScaffolderPage = scaffolderPlugin.provide(
1047
+ createRoutableExtension({
1048
+ name: "NextScaffolderPage",
1049
+ component: () => import('./index-bdece754.esm.js').then((m) => m.Router),
1050
+ mountPoint: nextRouteRef
1051
+ })
1052
+ );
946
1053
 
947
1054
  const icon = /* @__PURE__ */ React.createElement(CheckBoxOutlineBlankIcon, {
948
1055
  fontSize: "small"
@@ -1061,43 +1168,51 @@ const useTaskEventStream = (taskId) => {
1061
1168
  let didCancel = false;
1062
1169
  let subscription;
1063
1170
  let logPusher;
1064
- scaffolderApi.getTask(taskId).then((task) => {
1065
- if (didCancel) {
1066
- return;
1067
- }
1068
- dispatch({ type: "INIT", data: task });
1069
- const observable = scaffolderApi.streamLogs({ taskId });
1070
- const collectedLogEvents = new Array();
1071
- function emitLogs() {
1072
- if (collectedLogEvents.length) {
1073
- const logs = collectedLogEvents.splice(0, collectedLogEvents.length);
1074
- dispatch({ type: "LOGS", data: logs });
1171
+ scaffolderApi.getTask(taskId).then(
1172
+ (task) => {
1173
+ if (didCancel) {
1174
+ return;
1075
1175
  }
1076
- }
1077
- logPusher = setInterval(emitLogs, 500);
1078
- subscription = observable.subscribe({
1079
- next: (event) => {
1080
- switch (event.type) {
1081
- case "log":
1082
- return collectedLogEvents.push(event);
1083
- case "completion":
1084
- emitLogs();
1085
- dispatch({ type: "COMPLETED", data: event });
1086
- return void 0;
1087
- default:
1088
- throw new Error(`Unhandled event type ${event.type} in observer`);
1176
+ dispatch({ type: "INIT", data: task });
1177
+ const observable = scaffolderApi.streamLogs({ taskId });
1178
+ const collectedLogEvents = new Array();
1179
+ function emitLogs() {
1180
+ if (collectedLogEvents.length) {
1181
+ const logs = collectedLogEvents.splice(
1182
+ 0,
1183
+ collectedLogEvents.length
1184
+ );
1185
+ dispatch({ type: "LOGS", data: logs });
1089
1186
  }
1090
- },
1091
- error: (error) => {
1092
- emitLogs();
1187
+ }
1188
+ logPusher = setInterval(emitLogs, 500);
1189
+ subscription = observable.subscribe({
1190
+ next: (event) => {
1191
+ switch (event.type) {
1192
+ case "log":
1193
+ return collectedLogEvents.push(event);
1194
+ case "completion":
1195
+ emitLogs();
1196
+ dispatch({ type: "COMPLETED", data: event });
1197
+ return void 0;
1198
+ default:
1199
+ throw new Error(
1200
+ `Unhandled event type ${event.type} in observer`
1201
+ );
1202
+ }
1203
+ },
1204
+ error: (error) => {
1205
+ emitLogs();
1206
+ dispatch({ type: "ERROR", data: error });
1207
+ }
1208
+ });
1209
+ },
1210
+ (error) => {
1211
+ if (!didCancel) {
1093
1212
  dispatch({ type: "ERROR", data: error });
1094
1213
  }
1095
- });
1096
- }, (error) => {
1097
- if (!didCancel) {
1098
- dispatch({ type: "ERROR", data: error });
1099
1214
  }
1100
- });
1215
+ );
1101
1216
  return () => {
1102
1217
  didCancel = true;
1103
1218
  if (subscription) {
@@ -1172,30 +1287,32 @@ const TaskPageLinks = ({ output }) => {
1172
1287
  };
1173
1288
 
1174
1289
  const humanizeDuration = require("humanize-duration");
1175
- const useStyles = makeStyles$1((theme) => createStyles({
1176
- root: {
1177
- width: "100%"
1178
- },
1179
- button: {
1180
- marginBottom: theme.spacing(2),
1181
- marginLeft: theme.spacing(2)
1182
- },
1183
- actionsContainer: {
1184
- marginBottom: theme.spacing(2)
1185
- },
1186
- resetContainer: {
1187
- padding: theme.spacing(3)
1188
- },
1189
- labelWrapper: {
1190
- display: "flex",
1191
- flex: 1,
1192
- flexDirection: "row",
1193
- justifyContent: "space-between"
1194
- },
1195
- stepWrapper: {
1196
- width: "100%"
1197
- }
1198
- }));
1290
+ const useStyles = makeStyles$1(
1291
+ (theme) => createStyles({
1292
+ root: {
1293
+ width: "100%"
1294
+ },
1295
+ button: {
1296
+ marginBottom: theme.spacing(2),
1297
+ marginLeft: theme.spacing(2)
1298
+ },
1299
+ actionsContainer: {
1300
+ marginBottom: theme.spacing(2)
1301
+ },
1302
+ resetContainer: {
1303
+ padding: theme.spacing(3)
1304
+ },
1305
+ labelWrapper: {
1306
+ display: "flex",
1307
+ flex: 1,
1308
+ flexDirection: "row",
1309
+ justifyContent: "space-between"
1310
+ },
1311
+ stepWrapper: {
1312
+ width: "100%"
1313
+ }
1314
+ })
1315
+ );
1199
1316
  const StepTimeTicker = ({ step }) => {
1200
1317
  const [time, setTime] = useState("");
1201
1318
  useInterval(() => {
@@ -1212,20 +1329,22 @@ const StepTimeTicker = ({ step }) => {
1212
1329
  variant: "caption"
1213
1330
  }, time);
1214
1331
  };
1215
- const useStepIconStyles = makeStyles$1((theme) => createStyles({
1216
- root: {
1217
- color: theme.palette.text.disabled,
1218
- display: "flex",
1219
- height: 22,
1220
- alignItems: "center"
1221
- },
1222
- completed: {
1223
- color: theme.palette.status.ok
1224
- },
1225
- error: {
1226
- color: theme.palette.status.error
1227
- }
1228
- }));
1332
+ const useStepIconStyles = makeStyles$1(
1333
+ (theme) => createStyles({
1334
+ root: {
1335
+ color: theme.palette.text.disabled,
1336
+ display: "flex",
1337
+ height: 22,
1338
+ alignItems: "center"
1339
+ },
1340
+ completed: {
1341
+ color: theme.palette.status.ok
1342
+ },
1343
+ error: {
1344
+ color: theme.palette.status.error
1345
+ }
1346
+ })
1347
+ );
1229
1348
  function TaskStepIconComponent(props) {
1230
1349
  const classes = useStepIconStyles();
1231
1350
  const { active, completed, error } = props;
@@ -1250,44 +1369,46 @@ function TaskStepIconComponent(props) {
1250
1369
  })
1251
1370
  }, getMiddle());
1252
1371
  }
1253
- const TaskStatusStepper = memo((props) => {
1254
- const { steps, currentStepId, onUserStepChange } = props;
1255
- const classes = useStyles(props);
1256
- return /* @__PURE__ */ React.createElement("div", {
1257
- className: classes.root
1258
- }, /* @__PURE__ */ React.createElement(Stepper, {
1259
- activeStep: steps.findIndex((s) => s.id === currentStepId),
1260
- orientation: "vertical",
1261
- nonLinear: true
1262
- }, steps.map((step, index) => {
1263
- const isCompleted = step.status === "completed";
1264
- const isFailed = step.status === "failed";
1265
- const isActive = step.status === "processing";
1266
- const isSkipped = step.status === "skipped";
1267
- return /* @__PURE__ */ React.createElement(Step, {
1268
- key: String(index),
1269
- expanded: true
1270
- }, /* @__PURE__ */ React.createElement(StepButton, {
1271
- onClick: () => onUserStepChange(step.id)
1272
- }, /* @__PURE__ */ React.createElement(StepLabel, {
1273
- StepIconProps: {
1274
- completed: isCompleted,
1275
- error: isFailed,
1276
- active: isActive
1277
- },
1278
- StepIconComponent: TaskStepIconComponent,
1279
- className: classes.stepWrapper
1280
- }, /* @__PURE__ */ React.createElement("div", {
1281
- className: classes.labelWrapper
1282
- }, /* @__PURE__ */ React.createElement(Typography$1, {
1283
- variant: "subtitle2"
1284
- }, step.name), isSkipped ? /* @__PURE__ */ React.createElement(Typography$1, {
1285
- variant: "caption"
1286
- }, "Skipped") : /* @__PURE__ */ React.createElement(StepTimeTicker, {
1287
- step
1288
- })))));
1289
- })));
1290
- });
1372
+ const TaskStatusStepper = memo(
1373
+ (props) => {
1374
+ const { steps, currentStepId, onUserStepChange } = props;
1375
+ const classes = useStyles(props);
1376
+ return /* @__PURE__ */ React.createElement("div", {
1377
+ className: classes.root
1378
+ }, /* @__PURE__ */ React.createElement(Stepper, {
1379
+ activeStep: steps.findIndex((s) => s.id === currentStepId),
1380
+ orientation: "vertical",
1381
+ nonLinear: true
1382
+ }, steps.map((step, index) => {
1383
+ const isCompleted = step.status === "completed";
1384
+ const isFailed = step.status === "failed";
1385
+ const isActive = step.status === "processing";
1386
+ const isSkipped = step.status === "skipped";
1387
+ return /* @__PURE__ */ React.createElement(Step, {
1388
+ key: String(index),
1389
+ expanded: true
1390
+ }, /* @__PURE__ */ React.createElement(StepButton, {
1391
+ onClick: () => onUserStepChange(step.id)
1392
+ }, /* @__PURE__ */ React.createElement(StepLabel, {
1393
+ StepIconProps: {
1394
+ completed: isCompleted,
1395
+ error: isFailed,
1396
+ active: isActive
1397
+ },
1398
+ StepIconComponent: TaskStepIconComponent,
1399
+ className: classes.stepWrapper
1400
+ }, /* @__PURE__ */ React.createElement("div", {
1401
+ className: classes.labelWrapper
1402
+ }, /* @__PURE__ */ React.createElement(Typography$1, {
1403
+ variant: "subtitle2"
1404
+ }, step.name), isSkipped ? /* @__PURE__ */ React.createElement(Typography$1, {
1405
+ variant: "caption"
1406
+ }, "Skipped") : /* @__PURE__ */ React.createElement(StepTimeTicker, {
1407
+ step
1408
+ })))));
1409
+ })));
1410
+ }
1411
+ );
1291
1412
  const hasLinks = ({ links = [] }) => links.length > 0;
1292
1413
  const TaskPage = ({ loadingText }) => {
1293
1414
  const classes = useStyles();
@@ -1295,23 +1416,30 @@ const TaskPage = ({ loadingText }) => {
1295
1416
  const rootPath = useRouteRef(rootRouteRef);
1296
1417
  const templateRoute = useRouteRef(selectedTemplateRouteRef);
1297
1418
  const [userSelectedStepId, setUserSelectedStepId] = useState(void 0);
1298
- const [lastActiveStepId, setLastActiveStepId] = useState(void 0);
1419
+ const [lastActiveStepId, setLastActiveStepId] = useState(
1420
+ void 0
1421
+ );
1299
1422
  const { taskId } = useParams();
1300
1423
  const taskStream = useTaskEventStream(taskId);
1301
1424
  const completed = taskStream.completed;
1302
- const steps = useMemo(() => {
1303
- var _a, _b;
1304
- return (_b = (_a = taskStream.task) == null ? void 0 : _a.spec.steps.map((step) => {
1305
- var _a2;
1306
- return {
1307
- ...step,
1308
- ...(_a2 = taskStream == null ? void 0 : taskStream.steps) == null ? void 0 : _a2[step.id]
1309
- };
1310
- })) != null ? _b : [];
1311
- }, [taskStream]);
1425
+ const steps = useMemo(
1426
+ () => {
1427
+ var _a, _b;
1428
+ return (_b = (_a = taskStream.task) == null ? void 0 : _a.spec.steps.map((step) => {
1429
+ var _a2;
1430
+ return {
1431
+ ...step,
1432
+ ...(_a2 = taskStream == null ? void 0 : taskStream.steps) == null ? void 0 : _a2[step.id]
1433
+ };
1434
+ })) != null ? _b : [];
1435
+ },
1436
+ [taskStream]
1437
+ );
1312
1438
  useEffect(() => {
1313
1439
  var _a;
1314
- const mostRecentFailedOrActiveStep = steps.find((step) => ["failed", "processing"].includes(step.status));
1440
+ const mostRecentFailedOrActiveStep = steps.find(
1441
+ (step) => ["failed", "processing"].includes(step.status)
1442
+ );
1315
1443
  if (completed && !mostRecentFailedOrActiveStep) {
1316
1444
  setLastActiveStepId((_a = steps[steps.length - 1]) == null ? void 0 : _a.id);
1317
1445
  return;
@@ -1338,10 +1466,14 @@ const TaskPage = ({ loadingText }) => {
1338
1466
  return;
1339
1467
  }
1340
1468
  const formData = taskStream.task.spec.parameters;
1341
- const { name, namespace } = parseEntityRef((_c = taskStream.task.spec.templateInfo) == null ? void 0 : _c.entityRef);
1342
- navigate(`${templateRoute({ templateName: name, namespace })}?${qs.stringify({
1343
- formData: JSON.stringify(formData)
1344
- })}`);
1469
+ const { name, namespace } = parseEntityRef(
1470
+ (_c = taskStream.task.spec.templateInfo) == null ? void 0 : _c.entityRef
1471
+ );
1472
+ navigate(
1473
+ `${templateRoute({ templateName: name, namespace })}?${qs.stringify({
1474
+ formData: JSON.stringify(formData)
1475
+ })}`
1476
+ );
1345
1477
  };
1346
1478
  return /* @__PURE__ */ React.createElement(Page, {
1347
1479
  themeId: "home"
@@ -1380,5 +1512,5 @@ const TaskPage = ({ loadingText }) => {
1380
1512
  })))))));
1381
1513
  };
1382
1514
 
1383
- export { OwnedEntityPickerFieldExtension as A, RepoUrlPickerFieldExtension as B, ScaffolderPage as C, scaffolderPlugin as D, EntityPicker as E, FIELD_EXTENSION_WRAPPER_KEY as F, useTemplateSecrets as G, NextScaffolderPage as N, OwnerPicker as O, RepoUrlPicker as R, SecretsContext as S, TemplateTypePicker as T, actionsRouteRef as a, scaffolderListTaskRouteRef as b, scaffolderApiRef as c, scaffolderTaskRouteRef as d, editRouteRef as e, rootRouteRef as f, TaskStatusStepper as g, TaskPageLinks as h, FIELD_EXTENSION_KEY as i, SecretsContextProvider as j, TaskPage as k, legacySelectedTemplateRouteRef as l, EntityNamePicker as m, entityNamePickerValidation as n, EntityTagsPicker as o, repoPickerValidation as p, OwnedEntityPicker as q, registerComponentRouteRef as r, selectedTemplateRouteRef as s, ScaffolderClient as t, createScaffolderFieldExtension as u, ScaffolderFieldExtensions as v, EntityPickerFieldExtension as w, EntityNamePickerFieldExtension as x, EntityTagsPickerFieldExtension as y, OwnerPickerFieldExtension as z };
1384
- //# sourceMappingURL=index-6000fac5.esm.js.map
1515
+ export { EntityTagsPickerFieldExtension as A, OwnerPickerFieldExtension as B, OwnedEntityPickerFieldExtension as C, RepoUrlPickerFieldExtension as D, EntityPicker as E, FIELD_EXTENSION_WRAPPER_KEY as F, ScaffolderPage as G, scaffolderPlugin as H, useTemplateSecrets as I, NextScaffolderPage as N, OwnerPicker as O, RepoUrlPicker as R, SecretsContext as S, TemplateTypePicker as T, actionsRouteRef as a, scaffolderListTaskRouteRef as b, scaffolderApiRef as c, scaffolderTaskRouteRef as d, editRouteRef as e, rootRouteRef as f, TaskStatusStepper as g, TaskPageLinks as h, FIELD_EXTENSION_KEY as i, SecretsContextProvider as j, TaskPage as k, legacySelectedTemplateRouteRef as l, EntityNamePicker as m, entityNamePickerValidation as n, EntityTagsPicker as o, repoPickerValidation as p, OwnedEntityPicker as q, registerComponentRouteRef as r, selectedTemplateRouteRef as s, nextSelectedTemplateRouteRef as t, nextRouteRef as u, ScaffolderClient as v, createScaffolderFieldExtension as w, ScaffolderFieldExtensions as x, EntityPickerFieldExtension as y, EntityNamePickerFieldExtension as z };
1516
+ //# sourceMappingURL=index-3b171258.esm.js.map